.REQUIRE "c.pub" SOURCE!FILE
.SEND TITLEPAGE $(
.BEGIN
.CENTER
.SKIPTOLINE 10
A COMPUTATIONAL LOGIC
.SKIPLINES 5
by
Robert S. Boyer and J Strother Moore
.FLUSH LEFT
.SKIPLINES 5
Copyright SRI International
.END
.)$
.ACKNOWLEDGE $(
Mechanical theorem-proving is crucial to the automation of reasoning
about computer programs. Today, few computer programs can be
mechanically certified to be free of "bugs." The principal reason is
the lack of mechanical theorem-proving power.
In current research on automating program
analysis, a common approach to overcoming the lack of mechanical theorem-proving power has been to require that the user direct a proof-checking program. That is, the
user is required to construct a formal proof employing only the
simplest rules of inference,
such as __modus ponens_, instantiation of variables, or substitution of equals
for equals. The proof-checking program guarantees the correctness
of the formal proof. We have found proof-checking programs
too frustrating to use because
they require too much direction.
Another approach to overcoming the lack of
mechanical theorem-proving power is to use a weak theorem-proving program and to introduce axioms freely.
Often these axioms are called "lemmas," but they are
usually not proved. While using a proof checker is
only frustrating, introducing axioms freely is
deplorable.
This approach has been abused so far as to be ludicrous:##we have seen researchers "verify" a program
by first obtaining formulas that imply the program's correctness,
then running the formulas
through a simplifier, and finally assuming the resulting slightly simplified
formulas as axioms. Some researchers admit
that these "lemmas" ought to be proved, but never
get around to proving them because they lack the mechanical
theorem-proving power. Others, however, believe that
it is reasonable to assume lots of "lemmas" and never try
to prove them. We are strongly opposed to this latter attitude
because it so completely undermines the spirit of
proof, and we therefore reply to the arguments
we have heard
in its defense.
.BULLET
It is argued that the axioms assumed are obvious
facts about the concepts involved. We say that a great number
of mistakes in computer programs arise from false "obvious"
observations, and we have already seen researchers
present proofs based on false lemmas. Furthermore, the
concepts involved in the complicated computer systems
one hopes eventually to certify are so insufficiently
canonized that one man's "obvious" is another man's "difficult"
and a third man's "false."
It is argued that one must assume some axioms. We
agree, but observe that mathematicians do not contrive their
axioms to solve the problem at hand. Yet often the "lemmas"
assumed in program verification
are remarkably close to the main idea or trick in the
program being checked.
It is argued that
mathematicians use lemmas. We agree. In fact,
our theorem-proving system relies heavily on lemmas.
But no proof is complete until
the lemmas have been proved, too. The
assumption of lemmas in program proving often amounts to sweeping
under the rug the hard
and interesting inferences.
It is argued that the definition of concepts
necessarily involves the addition of axioms.
But the axioms that arise from proper definitions,
unlike most "lemmas," have a very special form that
guarantees two important properties.
First, adding a definition never
renders one's theory inconsistent. Second, the
definition of a concept involved in the proof of a
subsidiary result (but not in the statement of
one's main conjecture) can be safely forgotten.
It does not matter if the definition was of the "wrong"
concept.
But an ordinary axiom (or "lemma"), once used, always remains
a hypothesis of any later inference. If the
axiom is "wrong," the whole proof may be worthless and
the validity of the main conjecture is in doubt.
.ENDCROWN
.)$
.SEND ACKNOWLEDGMENTS $(
One reason that researchers have had to
assume "lemmas" so freely is that they
have not implemented the principle of mathematical induction
in their theorem-proving systems. Since mathematical
induction is a fundamental rule of inference for the
objects about which computer programmers think (e.g., integers, sequences, trees), it
is surprising that anyone would implement a theorem prover for program verification
that could not make inductive arguments. Why has
the mechanization of mathematical induction received scant attention?
Perhaps it has been neglected because the main research
on mechanical theorem-proving, the resolution theorem-proving
tradition (see Chang and Lee {REF CHANG} and Loveland {REF LOVELAND}),
does not handle axiom schemes, such
as mathematical induction.
We suspect, however, that the mechanization of mathematical induction has
been neglected because many researchers believe that the only need for
induction is in program semantics. Program
semantics enables one to obtain from a
given program and specification some
conjectures ("verification conditions") that imply the program is correct.
The study of program
semantics has produced a plethora of ways to use
induction. Because some programs do not terminate,
the role of induction in program semantics is fascinating
and subtle. Great effort has been invested in
mechanizing induction in program semantics. For example, the
many "verification condition generation" programs implicitly
rely upon induction to provide the semantics of iteration.
But program semantics is not the only place induction is necessary.
The conjectures that verification condition generators produce often
require inductive proofs because they concern inductively
defined concepts such as the integers, sequences, trees,
grammars, formulas, stacks, queues, and lists.
If you cannot make an
inductive argument about an inductively defined concept,
then you are doomed to assume
what you want to prove.
This book addresses the use of induction in proving theorems
rather than the use of induction in program semantics.
We will present a formal theory providing for inductively
constructed objects, recursive definitions, and inductive proofs.
Readers familiar with programming languages will see a strong stylistic
resemblance between the language of our theory and that fragment of
the programming language LISP known as "pure LISP" (see McCarthy et al. {REF LISPMANUAL}).
We chose pure LISP as a model for our language because
pure LISP was designed as a mathematical language
whose formulas could be easily represented within
computers. Because of its mathematical nature (e.g., one cannot
"destructively transform" the ordered pair <7,3> into
<8,3>),
pure LISP is considered a "toy" programming language.
It is an easy jump to the __non sequitur_:##"The language
and theory presented in this book are
irrelevant to real program analysis
problems because they deal with a toy programming language."
But that statement misses the point. It is indeed true that our theory may be viewed
as a programming language. In fact, many programs are naturally written as functions
in our theory.
But our theory is a mathematical tool for making precise assertions
about the properties of discrete objects. As such, it can be used in
conjunction with any of the usual program specification methods to state and prove
properties of programs written in any programming language
whatsoever.
When
we began our research into
proving theorems about recursive functions {REF JACM}, {REF THESIS},
we thought of ourselves as proving theorems only about pure LISP
and viewed our work as an implementation of
McCarthy's {REF MCCARTHYBASIS} functional style of program analysis.
However, we now also regard recursion
as a natural
alternative to quantification when making assertions about programs.
Using recursive functions to make assertions about computer programs
no more limits the programming language to one
that implements recursion than using the ordinary quantifiers
limits the programming language to one that implements quantification!
In this book we use both the functional style and Floyd's inductive
assertion style {REF FLOYD} of program specification in examples. (For the benefit of
readers not familiar with the program verification literature,
we briefly explain both ideas when they are first used.)
.)$
.SEND ACKNOWLEDGMENTS $(
We have relegated the foregoing remarks to the preface because
we are not in general interested in program semantics in this book.
We are interested in how one proves theorems about inductively
constructed objects.
Our work on induction and theorem-proving in general has been deeply influenced by
that of Bledsoe {REF BLEDSOEPROVER}, {REF BLEDSOELIMIT}.
Some early versions of our work have
been previously reported in {REF JACM}, {REF THESIS},
{REF SIGART}, {REF IEEE}, and
{REF IJCAI77}. Work closely related to
our work on induction has been done by
Brotz {REF BROTZ}, Aubin {REF AUBIN}, and Cartwright {REF CARTWRIGHT}.
We thank Anne Boyer, Jacqueline Handley, Paul Gloess, John Laski, Greg Nelson,
Richard Pattis, and Jay Spitzen for their
careful criticisms of this book.
We also thank Jay Spitzen for showing us how to prove the prime
factorization theorem.
Finally, we thank our wives and children for their usually cheerful
long-suffering through the years of late hours behind this book.
Our work has been supported by the National Science Foundation under
Grant MCS-7681425 and by the Office of Naval Research under Contract
N00014-75-C-0816. We are very grateful to these agencies for their
support.
.ASIS
Computer Science Laboratory
SRI International
Menlo Park, California
December, 1978
.ENDASIS
.)$
.SEC |INTRODUCTION|
Unlike most texts on logic and mathematics, this book is about
how to prove theorems rather than the proofs of specific results.
We give our answers to such questions as:
.CROWN(8,0,0)
When should induction be used?
How does one invent an appropriate induction argument?
When should a definition be expanded?
.ENDBULLET
We assume the reader is familiar with the mathematical
notion of equality and with the logical connectives "and," "or," "not,"
and "implies" of propositional calculus. We present a logical theory
in which one can introduce inductively constructed objects (such as the
natural numbers and finite sequences) and prove theorems
about them. Then we explain how we prove theorems in our theory.
We illustrate our proof techniques by using them to discover proofs
of many theorems. For example, we formalize a version of
the propositional calculus in our theory, and, using our techniques, we
formally prove the correctness of a decision procedure
for that version of propositional calculus.
In another example, we develop elementary number theory from axioms
introducing the natural numbers and finite sequences through
the prime factorization theorem.
Since our theory is undecidable, our proof techniques are
not perfect. But we know that they are unambiguous, well integrated,
and successful on a large number of theorems because we have programmed
a computer to follow our rules and have observed the program prove
many interesting theorems. In fact, the proofs we describe are actually
those discovered by our program.
.SS |Motivation|
Suppose it were practical to reason, mechanically and with mathematical
certainty, about computer programs. For example, suppose it were practical
to prove mechanically that a given program satisfied some specification, or
exhibited the same output behavior as another program, or
executed in certain time or space bounds.{FNOTE |See Manna and Waldinger {REF MW} for
. a description of the many other ways that formal reasoning can be
. usefully applied in computer programming.|}
Then there would follow a tremendous improvement in the reliability of
computer programs and a subsequent reduction of the overall cost of
producing and maintaining programs.
To reason mechanically about programs, one must have a formal program
semantics, a formal logical theory, and a mechanical theorem prover for that
theory.
The study of formal program semantics
has provided a variety of alternative methods for specifying and
modeling programs. But all the methods have one thing in common:##they
reduce the question "Does this program have the desired property?"
to the question "Are these formulas theorems?" Because of the
nature of computers, the formulas in question almost
exclusively involve inductively constructed mathematical objects: the integers,
finite sequences, n-tuples, trees, grammars, expressions, stacks, queues, buffers,
etc. Thus, regardless of which program semantics
we use to obtain the formulas to be proved, our formal theory and
mechanical theorem prover must permit
definition and proof by induction.
This book is
about such a theory and a mechanical theorem prover for it.
.SS |Our Formal Theory|
We will present a logical theory that we have tailored
to the needs of thinking about computer programs.
It provides for the introduction of new
"types" of objects, a general principle of induction on well-founded
relations (Noetherian Induction {REF BOURBAKI}), and a
principle permitting the definition of recursive
functions.
Recursive functions offer such a powerful form
of expression when dealing with discrete mathematics (such as underlies
computer programs) that we do not use any additional
form of quantification.{FNOTE |The program of using recursive
. functions and induction to understand computer programs, and the use of
. computers to aid the generation of the proofs, were
. begun by McCarthy {REF MCCARTHYCHECKING}, {REF MCCARTHYBASIS}.
. See also Burstall {REF BURSTALL}.
. The idea of using recursive functions and induction but no
. other form of quantification in the foundations
. of mathematics (or at least of arithmetic) was first presented
. by Skolem in 1919 {REF SKOLEM}. See also Goodstein {REF GOODSTEIN}.|}
.SS |Proof Techniques|
After defining our formal theory, we describe
many techniques we have developed for proving theorems
in it. We devote eleven {SECTIONORCHAPTER}s to the description of these
techniques and how, when, and where they should be applied to prove theorems.
The most important of these techniques is the use of induction. The formulation
of an induction argument for a conjecture is based on an analysis of the
recursive definitions of the concepts involved in the conjecture. Thus the
use of recursively defined functions facilitates proving theorems
about inductively defined objects. Many of the other proof techniques
are designed to support our induction heuristics.
.SS |Examples|
All the techniques are illustrated with examples. Most of
our techniques are first illustrated with simple theorems about functions
on lists and trees.
These elementary functions
are simple to define and are worth knowing
if one is interested in mechanical theorem-proving (as we assume many readers will be). In addition, it
is more fun to work through the proofs of novel theorems than through the proofs
of, say, the familiar theorems of elementary number theory.
We have also included four complicated examples,
chosen from several different subject domains, to illustrate the
general applicability of the theory and our proof methods.
In the first such example, we write a tautology
checker as a recursive function on
trees representing formulas in propositional calculus.
We exercise
the theory and proof techniques in an interesting way by stating and
proving that the tautology checker
always returns an answer, recognizes only
tautologies, and recognizes all tautologies. This example serves two important
purposes:##it illustrates the theory and proof techniques in use,
and it gives the reader a precise definition of a simple
mechanical theorem prover (i.e., the tautology checker) without requiring a digression into programming
languages or computational issues.
In the second major example, we prove the correctness
of a simple algorithm that "optimizes" and "compiles" arithmetic
expressions into sequences of instructions for a hand-held calculator.
In order to specify the algorithm and the calculator, we use
(and briefly explain) McCarthy's "functional semantics" {REF MCCARTHYBASIS} for programs.
This example is the first part of the book that deals explicitly with
computational (rather than mathematical) ideas. Because the example is
simple (compared to real compilers and real hardware) and because it is
ideally suited to our mathematical language, the reader unfamiliar
with computing should be able to read this {SECTIONORCHAPTER} comfortably
(and even learn the basic ideas behind compiling expressions and one style of program
specification).
In the third major example, we prove the correctness of a
fast string searching algorithm. The algorithm finds the
first occurrence of one character sequence in another (if such an occurrence exists), and on the average, is the fastest such algorithm currently known. In this example
we explain and use a second program specification style, called
the "inductive assertion" method (Floyd {REF FLOYD}).
Finally, we demonstrate that the theory and proof techniques
can be used to prove theorems that are generally considered difficult
(rather than just theorems that have not been generally considered)
by proving our statement of the unique prime factorization theorem:##(a) any
positive integer can be represented as the product of a finite sequence of
primes and (b) any two finite sequences of primes with the same product are in fact
permutations of one another. We derive this theorem starting from
the axioms of Peano arithmetic and finite sequences.
.SS |Our Mechanical Theorem Prover|
It is one thing to describe a loosely connected
set of heuristics that a human might use to discover proofs and quite
a different thing to formulate them so that a machine can use them to discover proofs.{FNOTE |For a survey of non-resolution theorem-proving,
. see {REF BLEDSOESURVEY}.|}
All of the heuristics described have been implemented and together
comprise our automatic theorem-proving program.
Our description of the heuristics makes little or no
reference to the fact that they can be mechanized. However, we want
competent readers to be able to reproduce and build upon
our results. Thus, we are more precise than we would be
had we desired only to teach a student how we prove theorems.
All of the example proofs discussed in this book are actually
produced by our program.
We present the theorem prover's proofs in an informal
style. While describing proof techniques we present small
inference steps, but as we move on to the interesting examples
we ascend to the level upon which humans usually deal with
proofs. By the time we reach the prime factorization theorem,
the proofs we describe are very much like those in number
theory textbooks:##we make large inference leaps, use lemmas
without describing their proofs, and dismiss whole theorems
with phrases like "the proof is by induction on X."
However, our high-level descriptions of the machine's proofs
should not be confused with what the machine does:##before pronouncing a conjecture proved, the machine
discovers a complete sequence of applications of our proof techniques
establishing the conjecture from axioms and previously proved lemmas.
Furthermore, given the detailed presentation of our proof techniques
and their orchestration, the reader should also be able to discover
the proofs mechanically.
It is perhaps easiest to think of our program much as one would think of a
reasonably good mathematics student:##given the axioms of
Peano, he could hardly be expected to prove (much less discover) the
prime factorization theorem. However, he could cope quite well if given
the axioms of Peano and a list of theorems to prove
(e.g., "prove that addition is commutative," ... "prove that multiplication distributes over
addition," ... "prove that the result returned by the GCD function divides both of
its arguments," ... "prove that if the products over two sequences of
primes are identical, then the two sequences are
permutations of one another").
The examples discussed are just part of a standard sequence of approximately
400 definitions and theorems the program is expected to reestablish whenever
we incorporate a new technique. The sequence contains theorems some readers
will have trouble proving before they read the heuristics.
In {APP APPTHMS} we list the entire sequence as evidence
that the heuristics are generally useful and well integrated. It should
be noted that when the latter theorems of the sequence are proved
the theorem prover is aware of the earlier theorems. The fact that previously proved results are remembered permits
their use as lemmas in later proofs. The theorem prover would fail to prove
many of its most interesting theorems in the absence of such lemmas. However, the more a theorem-proving program knows, the more
difficult it becomes for it to prove theorems because the program
is often tempted to consider using theorems that have no relevance
to the task at hand. That our theorem-proving program does prove
the entire list of theorems sequentially is a measure of its capacity
to avoid being confused by what it knows.
.SS |Artificial Intelligence or Logic?|
While drawing heavily upon important facts of mathematical logic, our research
is really more artificial intelligence than logic. The principal question
we ask (and sometimes answer) is "how do we discover proofs?"
It has been argued that mechanical theorem-proving is an impossible task
because certain theories are known to be undecidable or super-super-exponential in complexity.
Such metamathematical results are, of course, no more of an impediment to
mechanical theorem-proving than to human theorem-proving.{FNOTE |Nils Nilsson, private communication.|} They only
make the task more interesting.
.SS |Organization|
This book is structured as follows. We begin informally
in {YONSEC SECOVERVIEW} by sketching our logical theory,
formulating a simple conjecture, and proving that conjecture by using many of the
techniques we will discuss.
We present the theory formally in {YONSEC SECTHEFORMALTHEORY}.
In {YONSEC SECTAUTOLOGYCHECKER}
we state and prove in our theory the correctness of a function for recognizing
tautologies.
In {YONSEC SECPROVE} through {YONSEC SECINDUCTION} we develop
and explain our heuristics for proving theorems. These heuristics are
illustrated with simple proof steps taken from many theorems.
In {YONSEC SECELEMENTARY}, our theorem prover develops an interesting
initial segment of elementary number theory.
Finally, in {YONSEC SECCOMPILER} through {YONSEC SECPRIMEFACTORIZATION} we
discuss three complex examples:##the proof of correctness of
a simple optimizing compiler for arithmetic expressions, the
correctness of a fast string searching algorithm, and the proof of
the unique prime factorization theorem.
Readers interested in ascertaining the
power of our automatic theorem-proving program and in seeing how recursive functions
can be used to formalize a variety of problems should first read the informal
overview ({YONSEC SECOVERVIEW}) and then look at the {SECTIONORCHAPTER}s
on the tautology checker ({YONSEC SECTAUTOLOGYCHECKER}), compiler ({YONSEC SECCOMPILER}),
string searching algorithm ({YONSEC SECFSTRPOS}), and prime
factorization theorem ({YONSEC SECPRIMEFACTORIZATION}).
The book has three appendixes. The first lists all the definitions
and theorems the theorem prover routinely proves.
The second appendix presents implementation details concerning
the introduction of new types.
The third appendix exhibits, in clausal form, the axioms of our
theory.
.SEC |A SKETCH OF THE THEORY AND TWO SIMPLE EXAMPLES|, SECOVERVIEW:
To prove theorems formally one must have in mind a formal theory in
which the proofs are to be constructed. We will present our formal
theory in {YONSEC SECTHEFORMALTHEORY}. Following the precise presentation
of the theory, we describe, in great detail, how we discover
proofs. However, before descending into detail, we here sketch the
theory informally, exhibit and explain several simple recursive function
definitions, and (without regard for mechanization) work through several
simple inductive proofs.
.SS |An Informal Sketch of the Theory|
.SSS |IF and EQUAL|
We employ the prefix notation of Church's lambda calculus {REF CHURCHLAMBDA}
and McCarthy's LISP {REF LISPMANUAL} when writing down terms. Thus,
we write
.ASIS
(PLUS (H X) (B))
.ENDASIS
when others write
.ASIS
PLUS(H(X),B())
.ENDASIS
or even
.ASIS
H(X) + B()
.ENDASIS
to denote the application of the two-argument function PLUS to (1) the
application of H to X and (2) the constant (i.e., function of no arguments) B.
We wish to make it easy to define new functions and predicates on
inductively constructed objects.
For example, given axioms for the natural numbers we would like
to define functions such as addition and multiplication, and
predicates such as whether a given number is prime; given the axioms
for sequences we would like to define operations such as sequence concatenation
and predicates such as whether one sequence is a permutation of
another.
We find it most convenient to define new functions with equality axioms of the form:
.ASIS
(f x[&1] ... x[&n]) = body
.ENDASIS
where certain constraints are placed on f, the x[&i], and the term body.
It is often necessary to make conditional definitions.
For example,
(PLUS X Y) is defined to be one thing if X=0, and another thing
if X=$m-1/0.
In order for definitions to be equality axioms, the right-hand
side of the definition, body, must be a term.
But in the usual treatment of logic it is not
permitted to embed a proposition (such as X=0) in a term.
Thus, we find it necessary to reproduce the logic of truth functions
and equality at the term level.
We add to the usual propositional calculus with variables, function
symbols, and equality an axiom
supposing the existence of two distinct constants, (TRUE) and (FALSE)
(henceforth written T and F),
and four axioms defining the new function symbols EQUAL and IF.
The axioms are:
.ASIS
Axiom.
T /$M-1= F
Axiom.
X = Y -> (EQUAL X Y) = T
Axiom.
X /$M-1= Y -> (EQUAL X Y) = F
Axiom.
X = F -> (IF X Y Z) = Z
Axiom.
X /$M-1= F -> (IF X Y Z) = Y.
.ENDASIS
We can paraphrase the above axioms as follows. T is not F. For all X and Y,
(EQUAL X Y) is T if X is Y,
and is F if X is not Y.
(IF X Y Z) is Y if X is non-F and is Z otherwise.
Thus
(IF (EQUAL X 0) Y Z)
is equal to Y if X is 0 and is equal to Z otherwise.
Strictly speaking, we never define "predicates," for they can only be used
in the construction of
formulas and thus cannot be used in terms (such as function
bodies). Without loss of generality, we restrict our attention to
functions.
For example, we will later define
the __function_ PRIME, so that (PRIME X) is T if X is prime and F
otherwise.
To permit terms or functions to test logical combinations of expressions,
it is convenient to define the functional versions of "not," "and," "or," and "implies."
For example, we want (NOT P) to be T if P is F and
to be F if P is not F. Similarly, we want (AND P Q) to be T if both P and Q
are non-F, and F otherwise.
Thus, we define the functions NOT, AND, OR, and IMPLIES as follows:
.ASIS
Definition.
(NOT P)
=
(IF P F T)
Definition.
(AND P Q)
=
(IF P (IF Q T F) F)
Definition.
(OR P Q)
=
(IF P T (IF Q T F))
Definition.
(IMPLIES P Q)
=
(IF P (IF Q T F) T).
.ENDASIS
(We adopt the notational convention of treating AND and OR as
though they took an arbitrary number of arguments. For example,
(AND p q r) is an abbreviation for (AND p (AND q r)).)
It is easy to show that these definitions capture the semantics
of the ordinary logical
connectives. For example, it is a theorem that:
.ASIS
(P/$M-1=F -> Q/$M-1=F) <-> (IMPLIES P Q) /$M-1= F.
.ENDASIS
Thus, it is also easy to prove that:
.ASIS
(IMPLIES (AND P Q) (OR P Q))
.ENDASIS
is not equal to F.
Because of our emphasis on terms rather than formulas we find it
convenient to call a term, p, a "theorem" if it can be proved
that p/$M-1=F. Of course, calling a
term a "theorem" is an abuse of terminology, since
theorems are in fact understood to be formulas.
However, whenever we use a term, p,
as though it were a formula, it is always acceptable to read the formula "p/$M-1=F" in its place.
.SSS |Inductively Constructed Objects|
Any theory concerned with the mathematics behind computing must
provide inductively constructed objects. For example, it is
clear that we must be able to talk formally about the
natural numbers, and so we will add to our theory axioms for the natural numbers.
In formalizing properties
of programs we have found that it is convenient to allow the introduction
of "new" types of inductively constructed objects, of which the integers
are just a single example.
To eliminate the possibility that the axioms
for a new type will render the theory inconsistent (or not fully
specify the properties of the type) we have included in our
theory a general principle under which one can introduce new types.
We call the principle the "shell" principle. The name "shell"
derives from imagining the new objects to be colored structures
encapsulating a fixed number of components (possibly of certain colors).
It is actually with the shell principle that we add the axioms defining
the nonnegative integers. We also use the principle to add the set of
literal atoms (i.e., atomic symbols such as "NIL" and "X"), and
the set of ordered pairs.
For example, to axiomatize the set of ordered pairs we incant:
.ASIS
Add the shell CONS,
with recognizer LISTP, and
accessors CAR and CDR that return "NIL" on non-LISTP objects,
.ENDASIS
which is a shorthand for adding a set of axioms that specifies (CONS X Y) to be
the red, say, ordered pair containing X and Y, LISTP to be the function that returns
T if its argument is a red pair and F otherwise, and CAR and CDR to be
the functions that return the first and second components of red
pairs (or "NIL" if given an object other than a red pair).
For example, here are some of the axioms added by the above
incantation:
.ASIS
Axiom. LISTP.CONS:
(LISTP (CONS X1 X2))
Axiom. CAR.CONS:
(EQUAL (CAR (CONS X1 X2)) X1)
Axiom. CDR.CONS:
(EQUAL (CDR (CONS X1 X2)) X2)
Axiom. CAR/CDR.ELIM:
(IMPLIES (LISTP X)
(EQUAL (CONS (CAR X) (CDR X)) X))
Axiom. CONS.EQUAL:
(EQUAL (EQUAL (CONS X1 X2)
(CONS Y1 Y2))
(AND (EQUAL X1 Y1)
(EQUAL X2 Y2)))
Axiom. CAR.LESSP:
(IMPLIES (LISTP X)
(LESSP (COUNT (CAR X)) (COUNT X)))
Axiom. CDR.LESSP:
(IMPLIES (LISTP X)
(LESSP (COUNT (CDR X)) (COUNT X))).
.ENDASIS
LESSP is the "less-than" function on the nonnegative integers.
The complete set of axioms for the CONS shell is given schematically in {YONSEC SECTHEFORMALTHEORY}.
Among the axioms not shown above are, for example, axioms specifying
that (CAR X) is "NIL" if X is not a LISTP, and that the set of LISTP
objects does not overlap the set of numbers, literal atoms, or other
types.
We use ordered pairs in a variety of ways. For example, to talk
about finite sequences (sometimes called "lists") we thing of "NIL" as
the empty sequence, and
we think of (CONS X Y) as
the sequence whose first element is X and whose
remaining elements are those of Y. Thus, we think of
.ASIS
(CONS 1 (CONS 2 (CONS 3 "NIL")))
.ENDASIS
as the sequence containing 1, 2, and 3.
.SSS |Recursively Defined Functions|
Our theory includes a principle of definition allowing the introduction
of recursive functions. The principle is based on the notion of well-founded
relations. In particular, (f x[&1] ... x[&n]) may be defined
to be some term, body, involving "recursive calls" of the form
(f y[&1] ... y[&n]), provided there is a measure and well-founded relation
such that in every recursive call the measure of the y[&i] is
smaller, according to the well-founded relation, than the measure of
the x[&i].
Since "well-founded" means that there is no infinite sequence
of objects, each of which is smaller than its predecessor in the sequence,
the above restriction, together with a few simple syntactic requirements,
ensures that there exists one and only one function satisfying
the definition. The existence of a function satisfying the
definition implies that adding the definition as an axiom does not
render the theory inconsistent.
We explicitly assume that LESSP
is well-founded. Furthermore, when the
CONS shell is added, the axioms
CAR.LESSP and CDR.LESSP, above, inform us that the CAR and CDR of a pair
both have smaller size (as measured by the function COUNT) than the pair itself.
Thus, if in every recursive call of a function some particular argument is
replaced by
its own CAR or CDR, and we can establish that in each such case that
argument is a pair, then the principle of definition would
admit the function.
To illustrate a definition by recursion, suppose we wished to concatenate two finite
sequences X and Y. If X is empty, then the result of
concatenating X and Y is just Y. If X is nonempty, then X has
a first element, (CAR X), and some remaining elements, (CDR X).
The concatenation of X and Y in this case is the
sequence whose first element is (CAR X) and whose remaining elements
are those in the concatenation of (CDR X) and Y. Formally, we define the function
APPEND so that (APPEND X Y) is the concatenation of X and Y:
.ASIS
Definition.
(APPEND X Y)
=
(IF (LISTP X)
(CONS (CAR X) (APPEND (CDR X) Y))
Y).
.ENDASIS
APPEND is a particularly simple recursive function. It is
easy to see why it is accepted under our principle of definition:#
the axiom CDR.LESSP, above, establishes that
(COUNT X) gets LESSP-smaller in each (i.e., the) recursive call.
Later in the book we will introduce more interesting recursive
functions -- functions for which a measure as obvious as the size of
one argument will not suffice to justify their definition.
By the axioms of equality, we can replace any instance of (APPEND X Y)
with the corresponding instance of the right-hand side of the definition
above. For example, we can show that (APPEND (CONS A D) Y)
is equal to (CONS A (APPEND D Y)) as follows. By
definition, (APPEND (CONS A D) Y) is equal to the instantiated body:
.ASIS
(IF (LISTP (CONS A D))
(CONS (CAR (CONS A D))
(APPEND (CDR (CONS A D)) Y))
Y).
.ENDASIS
By the axiom LISTP.CONS, above, (LISTP (CONS A D)) is non-F.
But, by the axioms defining IF, we know
that when the first argument in an IF-expression is non-F, the IF-expression is
equal to its second argument. Thus, the above IF-expression can be
replaced by its second argument:
.ASIS
(CONS (CAR (CONS A D)) (APPEND (CDR (CONS A D)) Y)).
.ENDASIS
Finally, applying the axioms CAR.CONS and CDR.CONS, above, we
rewrite (CAR (CONS A D)) to A, and (CDR (CONS A D)) to D, obtaining:
.ASIS
(CONS A (APPEND D Y))
.ENDASIS
as desired.
Similarly, we can prove that (APPEND "NIL" Y) is Y.
We can use a series of such simplifications to "compute" the result
of concatenating the sequence containing 1, 2, and 3, to the
sequence containing 4 and 5:
.ASIS
(APPEND (CONS 1 (CONS 2 (CONS 3 "NIL")))
(CONS 4 (CONS 5 "NIL")))
=
(CONS 1 (APPEND (CONS 2 (CONS 3 "NIL"))
(CONS 4 (CONS 5 "NIL"))))
=
(CONS 1 (CONS 2 (APPEND (CONS 3 "NIL")
(CONS 4 (CONS 5 "NIL")))))
=
(CONS 1 (CONS 2 (CONS 3 (APPEND "NIL"
(CONS 4 (CONS 5 "NIL"))))))
=
(CONS 1 (CONS 2 (CONS 3 (CONS 4 (CONS 5 "NIL"))))).
.ENDASIS
Using recursion, we can introduce, under our principle of definition,
almost all the concepts in which we are interested. Indeed, recursion is
a very important tool when dealing with inductively constructed objects
such as the integers or sequences. For instance, recursion can be regarded
as a form of quantification:##we can use recursion to check that all or
some elements of a sequence have some property.
We do not use any
other form of quantification in our formal theory.
.SSS |Induction|
Because we are interested in proving theorems about inductively constructed
objects such as the natural numbers, sequences, pairs, etc.,
we need a rule of inference that embodies the construction
process itself. For example, we know that if X is a pair, then it can be constructed
by applying CONS to two "previously" constructed objects, namely (CAR X) and (CDR X).
Thus, we can prove that some property
holds for all X by considering two cases. The first case, called the
"base case," is to prove that all nonpairs have the property in question.
The second case, called the "induction step," is to assume that X is
a pair and that (CAR X) and (CDR X) have the desired property, and
to prove that X has the property. Such a proof is called a proof by "induction."
The magic idea behind induction, the idea that made it appear
unsound to both authors when they first encountered the idea
in high school, is that one gets to assume instances of
the conjecture being proved during its own proof.
Why is induction sound?
For example, why can we conclude, after proving the two cases above, that any
X must have the property? Suppose some object does not have the property.
Then let X be a minimal object not having the property, where we
compare two such objects by comparing their COUNTs using the
LESSP function.
There __is_ a minimal object not having the property in question since,
by the well-foundedness of LESSP, there is no infinite sequence
of objects, each of which has smaller COUNT than the previous one.
X must be a pair, because otherwise the base case
establishes that X has the property. But if X is a pair,
(CAR X) and (CDR X) are both smaller than X (as measured by
COUNT and LESSP). Therefore, since everything smaller than X has
the property in question, (CAR X) and (CDR X) have the
property. But in that case the induction step establishes that X must have it
also. Thus the assumption that some object does not have the property
has lead to a contradiction.
In general, the induction principle in our theory permits one to assume
arbitrary instances of the conjecture being proved, provided those
instantiations decrease some measure in some well-founded
ordering. Because our induction principle allows the use of arbitrary measures
and well-founded relations, we can make
inductive arguments that are much more subtle than the "structural induction"
illustrated above.{FNOTE |The use of structural induction
. to prove programs correct is beautifully described by Burstall in {REF BURSTALL}.|}
We will illustrate more subtle inductions later in the book.
Throughout this {SECTIONORCHAPTER} we confine ourselves to structural induction.
.SS |A Simple Inductive Proof|
One of the hardest problems in discovering an inductive proof
is discovering an appropriate application of the principle of induction itself. But the
similarity between recursion and induction offers an insight into
the problem. For example, suppose we were trying to prove
some conjecture involving the expression (APPEND A term).
When APPEND was introduced
into the theory we were required to exhibit a measure of its
arguments that was decreasing. In particular, every time APPEND
recurses, the COUNT of its first argument goes down.
Thus (APPEND A term) "suggests" an induction:##were we to
apply the definition of APPEND to "open up"
(APPEND A term) we would find ourselves recursively decomposing A into its
constituents and would want information about those constituents.
But by the observation above, we know those constituents
are smaller than A in some well-founded order. Thus, by the induction
principle, we can supply ourselves with inductive instances about those
constituents.
We illustrate the above reasoning with a simple example.
We will prove:
.ASIS
Theorem. ASSOCIATIVITY.OF.APPEND:
(EQUAL (APPEND (APPEND A B) C)
(APPEND A (APPEND B C))).
.ENDASIS
.BEGIN
.SINGLE SPACE
Name the conjecture *1.
The proof is by induction. Three terms -- each APPEND
expression with a variable in its first argument -- suggest "plausible"
inductions. Two of these inductions are on A and the third is
on B. All occurrences of A are in argument positions
being recursively decomposed. Thus, by appropriately opening up
APPEND expressions we can reexpress *1 in terms of (CDR A),
about which we can supply an inductive hypothesis. (In this case
we say that the induction on A is "unflawed.")
The induction on B is flawed:
B occurs sometimes as
the first argument to APPEND and sometimes as the second (which is never changed in recursion). No
matter how we expand APPEND expressions, the conjecture will
still involve B and (CDR B), and we are unable to supply an
induction hypothesis about B while inducting on B.
Thus, we will induct on A, using the following scheme:
.END
.ASIS
(AND (IMPLIES (NOT (LISTP A)) (p A B C))
(IMPLIES (AND (LISTP A)
(p (CDR A) B C))
(p A B C))).
.ENDASIS
.BEGIN
.SINGLE SPACE
That is, letting (p A B C) be a schematic representation of *1,
we will prove that (p A B C) holds when A is not a LISTP, and we will
prove that if A is a LISTP and (p (CDR A) B C) holds, then (p A B C) holds.
The induction is sound because the axiom
CDR.LESSP establishes that (COUNT A) decreases according to
the well-founded relation LESSP in the induction step of the
scheme. Instantiating the scheme above with
*1 we obtain two new goals. We block indent the proofs of
the two goals:
.END
.ASIS
Case 1. (IMPLIES (NOT (LISTP A))
(EQUAL (APPEND (APPEND A B) C)
(APPEND A (APPEND B C)))).
This is the base case. Since A is non-LISTP, (APPEND A B)
is equal to its second argument, B, by the definition of APPEND.
Similarly, (APPEND A (APPEND B C)) is equal to its second argument,
(APPEND B C). By rewriting these two terms in the conclusion
above we obtain:
(IMPLIES (NOT (LISTP A))
(EQUAL (APPEND B C)
(APPEND B C))),
which simplifies, using the axiom X=Y -> (EQUAL X Y)=T, to:
(TRUE).
Case 2. (IMPLIES (AND (LISTP A)
(EQUAL (APPEND (APPEND (CDR A) B) C)
(APPEND (CDR A) (APPEND B C))))
(EQUAL (APPEND (APPEND A B) C)
(APPEND A (APPEND B C)))).
This is the induction step. Since A is a LISTP here,
(APPEND A Y), for any Y, is equal to (CONS (CAR A)
(APPEND (CDR A) Y)), by the definition of APPEND. Thus,
we can "unfold" the two (APPEND A term) expressions in the
conclusion above to get:
(IMPLIES (AND (LISTP A)
(EQUAL (APPEND (APPEND (CDR A) B) C)
(APPEND (CDR A) (APPEND B C))))
(EQUAL (APPEND (CONS (CAR A)
(APPEND (CDR A) B))
C)
(CONS (CAR A)
(APPEND (CDR A) (APPEND B C))))).
But, by opening up the definition of APPEND, we know that
(APPEND (CONS A D) Y) is equal to (CONS A (APPEND D Y)).
Thus, we can expand the first APPEND term in the conclusion above,
to get:
(IMPLIES (AND (LISTP A)
(EQUAL (APPEND (APPEND (CDR A) B) C)
(APPEND (CDR A) (APPEND B C))))
(EQUAL (CONS (CAR A)
(APPEND (APPEND (CDR A) B) C))
(CONS (CAR A)
(APPEND (CDR A) (APPEND B C))))).
Note that the conclusion above is of the form:
(EQUAL (CONS x y) (CONS u v)).
But according to CONS.EQUAL, two pairs are equal if and
only if the components are pairwise equal. That is, the
concluding equality may be rewritten to the conjunction of
(EQUAL x u) and (EQUAL y v). But in the above application
x and u are identical -- they are both (CAR A). Thus, we
replace the concluding equality above with (EQUAL y v):
(IMPLIES (AND (LISTP A)
(EQUAL (APPEND (APPEND (CDR A) B) C)
(APPEND (CDR A) (APPEND B C))))
(EQUAL (APPEND (APPEND (CDR A) B) C)
(APPEND (CDR A) (APPEND B C)))).
However, this simplifies to:
(TRUE),
because the conclusion is identical to the second hypothesis.
In particular, by opening up the correct APPEND expressions we
transformed the induction conclusion into the induction hypothesis.
That finishes the proof of *1. Q.E.D.
.ENDASIS
.SS |A More Difficult Problem|
The proof of the associativity of APPEND illustrates two of
the proof techniques we describe later:##induction and
simplification. Some of the other heuristics we will describe are:
.CROWN(8,0,0)
It is sometimes useful to trade "bad" terms for "good" ones by
re-representing terms in the conjecture. For example,
one might transform a conjecture about
I and I-J to one about K+J and K, trading difference for addition, by
replacing all occurrences of I by K+J.
One obvious way to use an equality hypothesis, (EQUAL x y),
is to substitute x for y throughout the conjecture. But it is sometimes useful to
replace only some of the y's by x's and then to "throw away" the
equality hypothesis, so as to produce a more general conjecture to
prove by induction. We call such use of an equality hypothesis "cross-fertilization."
In proofs by induction, it is
easier to prove strong theorems than weak ones, because strong
theorems permit one to obtain strong induction hypotheses with which to
work. Thus, one should look for ways to generalize a conjecture
to be proved by induction.
.ENDCROWN
We illustrate these proof techniques by working through another
simple example.
Consider the idea of the "fringe" of a tree of CONSes.
Given the tree:
.ASIS
*
/ \
* 3
/ \
1 2
.ENDASIS
that is, (CONS (CONS 1 2) 3), we wish to return the sequence of tips of the tree,
1, 2, 3, that is, (CONS 1 (CONS 2 (CONS 3 "NIL"))).
An obvious way to
"flatten" a tree, X, is to ask first whether (LISTP X) is true. If so, X is a fork in
the tree. The fringe of a fork is the concatenation (as with APPEND) of
the fringes of the left and right subtrees (i.e., the recursively obtained
fringes of (CAR X) and (CDR X)).
If (LISTP X) is false, X is a tip of the tree. The fringe of
a tip is the singleton sequence containing the tip, i.e., (CONS X "NIL").{FNOTE |Computing the fringe of binary trees
. brings to mind one of the lesser chestnuts of Artificial Intelligence:
. how to compute that two binary trees have the same fringe
. without using much storage (in particular, without simply computing
. both fringes and comparing them). We believe the original formulation of
. the problem was by Carl Hewitt. Burstall and Darlington {REF BURSTALLTRANS} have investigated
. the solution of this problem by automatic program transformations.
. McCarthy (private communication) has written a recursive function,
. exhibited as SAMEFRINGE in {APP APPTHMS}, that is more or less the
. recursive realization of the usual "coroutining" solution
. to the problem. Our system can prove the correctness of SAMEFRINGE, and we refer
. the interested reader to {APP APPTHMS}. The problem of computing
. the fringe of a tree relates to
. computer science as a whole, since similar tree processing underlies
. such fundamental algorithms as parsers and compilers.|}
The above description can be immediately transcribed into
the definition of a recursive function that we will call FLATTEN. We exhibit the
definition of FLATTEN later, when we formalize the problem.
Considered as a recipe for computing the fringe of a tree, FLATTEN
is somewhat inefficient. It visits every fork and tip of the tree once, but
for every fork, the concatenation process revisits
every tip of the left-hand branch. In trees heavily nested to the left,
FLATTEN computes in time n^^2^, where n is the number of tips.
John McCarthy (private communication)
suggested the following more efficient algorithm, which computes
in linear time and which we call MC.FLATTEN.
The basic idea is that to collect all the tips in a
tree one can initialize a collection site to "NIL", and then
sweep the tree adding tips to the site as they are encountered.
If the tips are added to the front of the collection site, the answer will be in
exactly the reverse of the order in which the tips were visited.
If we sweep the tree from right to left (instead of left to right), the result will be
in the order desired.
To write the algorithm as a recursive function, we
use a second argument, ANS, as the collection site. At a tip, we add the tip to the front of
ANS (with CONS) and return the new list as the answer. At a fork, we first
collect the tips in the CDR (the right branch), and, using the resulting answer
as the collection site,
we then collect the tips in the CAR (the left
branch). Thus, (MC.FLATTEN X ANS) should
append the fringe of X onto ANS.
The formal statement of the relationship between MC.FLATTEN and FLATTEN
is:
.ASIS
(EQUAL (MC.FLATTEN X ANS)
(APPEND (FLATTEN X) ANS)).
.ENDASIS
In the next {SUBSECTIONORSECTION} we define FLATTEN and MC.FLATTEN
formally, explain why they are admitted under our principle of definition,
and then work through the proof of the conjecture above.
.SS |A More Difficult Proof|
.ASIS
Definition.
(FLATTEN X)
=
(IF (LISTP X)
(APPEND (FLATTEN (CAR X))
(FLATTEN (CDR X)))
(CONS X "NIL"))
The lemmas CAR.LESSP and CDR.LESSP establish that (COUNT X) goes
down according to the well-founded relation LESSP in each recursive
call. Hence, FLATTEN is accepted under the definition principle.
Observe that (LISTP (FLATTEN X)) is a theorem.
Definition.
(MC.FLATTEN X ANS)
=
(IF (LISTP X)
(MC.FLATTEN (CAR X)
(MC.FLATTEN (CDR X) ANS))
(CONS X ANS))
The lemmas CDR.LESSP and CAR.LESSP establish that (COUNT X)
decreases according to the well-founded relation LESSP in each
recursive call. Hence, MC.FLATTEN is accepted under the definition
principle. Note that (LISTP (MC.FLATTEN X ANS)) is a theorem.
Theorem. FLATTEN.MC.FLATTEN:
(EQUAL (MC.FLATTEN X ANS)
(APPEND (FLATTEN X) ANS))
Name the conjecture *1.
Let us appeal to the induction principle. There are two plausible
inductions. However, they merge into one likely candidate induction.
We will induct according to the following scheme:
(AND (IMPLIES (NOT (LISTP X)) (p X ANS))
(IMPLIES (AND (LISTP X)
(p (CAR X) (MC.FLATTEN (CDR X) ANS))
(p (CDR X) ANS))
(p X ANS))).
The inequalities CAR.LESSP and CDR.LESSP establish that the measure
(COUNT X) decreases according to the well-founded relation LESSP in
the induction step of the scheme. Note, however, the inductive
instances chosen for ANS. The above induction scheme produces two new
formulas:
Case 1. (IMPLIES (NOT (LISTP X))
(EQUAL (MC.FLATTEN X ANS)
(APPEND (FLATTEN X) ANS))),
which simplifies, applying CDR.CONS and CAR.CONS, and expanding the
definitions of MC.FLATTEN, FLATTEN and APPEND, to:
(TRUE).
Case 2. (IMPLIES (AND (LISTP X)
(EQUAL (MC.FLATTEN (CAR X)
(MC.FLATTEN (CDR X) ANS))
(APPEND (FLATTEN (CAR X))
(MC.FLATTEN (CDR X) ANS)))
(EQUAL (MC.FLATTEN (CDR X) ANS)
(APPEND (FLATTEN (CDR X)) ANS)))
(EQUAL (MC.FLATTEN X ANS)
(APPEND (FLATTEN X) ANS))).
This simplifies, unfolding the definitions of MC.FLATTEN and FLATTEN,
to:
(IMPLIES (AND (LISTP X)
(EQUAL (MC.FLATTEN (CAR X)
(MC.FLATTEN (CDR X) ANS))
(APPEND (FLATTEN (CAR X))
(MC.FLATTEN (CDR X) ANS)))
(EQUAL (MC.FLATTEN (CDR X) ANS)
(APPEND (FLATTEN (CDR X)) ANS)))
(EQUAL (MC.FLATTEN (CAR X)
(MC.FLATTEN (CDR X) ANS))
(APPEND (APPEND (FLATTEN (CAR X))
(FLATTEN (CDR X)))
ANS))).
Appealing to the lemma CAR/CDR.ELIM, we now replace X by (CONS Z V)
to eliminate (CAR X) and (CDR X). This generates:
(IMPLIES (AND (LISTP (CONS Z V))
(EQUAL (MC.FLATTEN Z (MC.FLATTEN V ANS))
(APPEND (FLATTEN Z)
(MC.FLATTEN V ANS)))
(EQUAL (MC.FLATTEN V ANS)
(APPEND (FLATTEN V) ANS)))
(EQUAL (MC.FLATTEN Z (MC.FLATTEN V ANS))
(APPEND (APPEND (FLATTEN Z) (FLATTEN V))
ANS))),
which further simplifies, clearly, to:
(IMPLIES (AND (EQUAL (MC.FLATTEN Z (MC.FLATTEN V ANS))
(APPEND (FLATTEN Z)
(MC.FLATTEN V ANS)))
(EQUAL (MC.FLATTEN V ANS)
(APPEND (FLATTEN V) ANS)))
(EQUAL (MC.FLATTEN Z (MC.FLATTEN V ANS))
(APPEND (APPEND (FLATTEN Z) (FLATTEN V))
ANS))).
We use the first equality hypothesis by cross-fertilizing:
(APPEND (FLATTEN Z)
(MC.FLATTEN V ANS))
for (MC.FLATTEN Z (MC.FLATTEN V ANS)) and throwing away the equality.
This generates:
(IMPLIES (EQUAL (MC.FLATTEN V ANS)
(APPEND (FLATTEN V) ANS))
(EQUAL (APPEND (FLATTEN Z)
(MC.FLATTEN V ANS))
(APPEND (APPEND (FLATTEN Z) (FLATTEN V))
ANS))).
We now use the above equality hypothesis by cross-fertilizing
(APPEND (FLATTEN V) ANS) for (MC.FLATTEN V ANS) and throwing away
the equality. We thus obtain:
(EQUAL (APPEND (FLATTEN Z)
(APPEND (FLATTEN V) ANS))
(APPEND (APPEND (FLATTEN Z) (FLATTEN V))
ANS)),
which we generalize by replacing (FLATTEN V) by Y and (FLATTEN Z)
by A. We restrict the new variables by appealing to the type
restriction lemma noted when FLATTEN was introduced. The result is:
(IMPLIES (AND (LISTP Y) (LISTP A))
(EQUAL (APPEND A (APPEND Y ANS))
(APPEND (APPEND A Y) ANS))),
which we will finally name *1.1.
Let us appeal to the induction principle. The recursive terms
in the conjecture suggest three inductions. They merge into two
likely candidate inductions. However, only one is unflawed. We will
induct according to the following scheme:
(AND (IMPLIES (NOT (LISTP A)) (p A Y ANS))
(IMPLIES (AND (LISTP A) (p (CDR A) Y ANS))
(p A Y ANS))).
The inequality CDR.LESSP establishes that the measure (COUNT A)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme generates
two new conjectures:
Case 1. (IMPLIES (AND (NOT (LISTP (CDR A)))
(LISTP Y)
(LISTP A))
(EQUAL (APPEND A (APPEND Y ANS))
(APPEND (APPEND A Y) ANS))).
This simplifies, appealing to the lemmas CDR.CONS, CAR.CONS and
CONS.EQUAL, and expanding APPEND, to:
(IMPLIES (AND (NOT (LISTP (CDR A)))
(LISTP Y)
(LISTP A))
(EQUAL (APPEND (CDR A) (APPEND Y ANS))
(APPEND (APPEND (CDR A) Y) ANS))).
However this again simplifies, unfolding APPEND, to:
(TRUE).
Case 2. (IMPLIES (AND (EQUAL (APPEND (CDR A) (APPEND Y ANS))
(APPEND (APPEND (CDR A) Y) ANS))
(LISTP Y)
(LISTP A))
(EQUAL (APPEND A (APPEND Y ANS))
(APPEND (APPEND A Y) ANS))).
This simplifies, applying the lemmas CDR.CONS, CAR.CONS and
CONS.EQUAL, and expanding the definition of APPEND, to:
(TRUE).
That finishes the proof of *1.1, which, consequently, finishes the
proof of *1. Q.E.D.
.ENDASIS
.SS |Summary|
The purpose of this {SECTIONORCHAPTER} was to provide an introduction to
our function-based theory and to indicate how we prove theorems in the theory.
As noted, all our proof techniques have
been implemented in an automatic theorem-proving program.
In fact, the last {SUBSECTIONORSECTION} was written, in its entirety,
by our automatic theorem prover in
response to three user commands supplying the definitions
of FLATTEN and MC.FLATTEN and the statement of the theorem to be
proved.
This book is about such questions as how function definitions are
analyzed by our theorem-proving system to establish their admissibility, how the system discovers that
(LISTP (FLATTEN X)) is a theorem when presented with the definition of
FLATTEN, why the system chooses the inductions it does, and why some
functions are expanded and others are not. We describe our proof
techniques in detail after presenting a precise statement of our
formal theory.
.SS |Notes|
To illustrate several proof techniques, we instructed the
theorem prover to conduct the FLATTEN.MC.FLATTEN proof
in an environment in which it was aware only of the
axioms of our basic theory and the definitions of APPEND,
FLATTEN, and MC.FLATTEN.
In the proof, the program derived a version of
the associativity of APPEND (formula *1.1) and proved it with a
second induction. Had the theorem prover
previously proved the associativity of APPEND (and been instructed to
remember it), the proof above would have been much shorter, as the
lemma would have been involved in early simplifications. Later in the book,
when we deal with more complicated examples such as the system's
proof of the Fundamental Theorem of Arithmetic, we will show the
system working primarily from previously proved theorems rather than
axioms.
The total amount of
CPU time required to analyze the two definitions above and produce
the proof is five-and-a-half seconds running compiled INTERLISP
{REF TEITELMAN}, {REF VM} on a Digital Equipment Corporation KL-10. For an
introduction to LISP see Allen's {REF JOHNALLEN}.
The English commentary produced during the definition-time analysis of
functions and during proofs is typical of the system's
output. Examples will be found throughout the book.
The steps in a proof are described in real-time,
as the proof is developed, so that the user can follow the theorem prover's
progress. To avoid boring the reader with repetitious phrasing, the system
varies its sentence structure.
.SEC |A PRECISE DEFINITION OF THE THEORY|, SECTHEFORMALTHEORY:
In this {SECTIONORCHAPTER}, we precisely
define the mathematical theory underlying our proof
techniques, the theory in which our theorem prover
proves theorems. We will present the axioms and
principles of definition and induction to which
the system appeals. We will not present
the usual elementary rules of logic and equality,
but instead we assume the reader is familiar with
these rules. The parts of this chapter that are
important are set off in boxes.
The remainder of the text is motivation
for the boxed material. In this motivational
material we shall speak in a language of "naive"
set theory. It is possible to embed
our theory within a theory of sets and to
derive our "principles" therein. However, we do not regard
set theory or even quantification as being a part
of our theory. The proofs our system produces depend only upon (a)
the propositional calculus with variables and function symbols,
(b) equality reasoning, (c) the rule of instantiation which
permits us to infer that any instance of a theorem is a theorem,
and (d) the boxed material that follows.
.SS |Syntax|
.STARRS
We will use uppercase words, sometimes with embedded periods, hyphens, slashes, or digits,
as variable symbols and function symbols. Examples are X, X1, PLUS, and PRIME.FACTORS.
Associated with each function symbol is a nonnegative integer, the number
of arguments the function symbol expects. The number of arguments
associated with certain function symbols will become apparent as we proceed.
A __term_ is a variable or a sequence consisting of a function symbol
of n arguments followed by n terms. If the term t is not a variable
and begins with the function symbol f, we say that t is a __call of_ f.
We depart from the usual notation of F(X,Y) for
function application and will instead write (F X Y).
Examples of terms are thus:##X, (TRUE), and (P (ADD1 X) Y). The first term
is just a variable, the second is the application of the 0-ary
function symbol TRUE to no arguments (and hence denotes a constant),
and the third is the application of the dyadic function symbol P to the
term (ADD1 X) and the variable Y.
To talk about terms, it is convenient to use so-called
"metavariables" that are understood by the reader to stand for certain
variables, function symbols, or terms. We will use
only lower case words as metavariables, and we will make clear
what type of syntactic object the symbol is to denote. For example, if
f denotes the function symbol G, and
t denotes the term (ADD1 Y), then (f t X) denotes the term (G (ADD1 Y) X).
When we are speaking in naive set theory we use both upper and lower case
words as variables ranging over numbers, sets, functions, etc. Context
will make clear the range of these variables.
We imagine that axioms, such as function definitions, are added as
"time goes by." Whenever we add a new shell or function
definition, we insist that certain function symbols not have been
mentioned in any previous axiom. We call a function symbol
__new_ until an axiom mentioning the function symbol has been added.
If i is an integer, then by an abuse of notation we let
Xi denote the variable whose
first character is X and whose other characters are the
decimal representation of i. Thus, if i is 4, Xi is the variable X4.
A finite set s of ordered pairs is said to be a __substitution_
provided that for each ordered pair in s, v is a variable, t is
a term and no other member of s has v as its first component.
The __result of substituting_ a substitution s __into_ a term p
(denoted p/s) is the term obtained by simultaneously replacing, for
each in s, each occurrence of v as a variable in p with t.
.STARRS
.SS |The Theory of IF and EQUAL|
.STARRS
We find it necessary to reproduce the logic
of truth functional propositions and equality at the term level. We
assume the existence of two distinguished constants, (TRUE) and (FALSE). We
use T and F as abbreviations for (TRUE) and (FALSE), respectively.
We never use T or F as a variable.
We axiomatize below the function EQUAL, of two arguments,
to return T or F, depending on whether its two
arguments are equal.
We also axiomatize the function IF, of three arguments, to return
its third argument if the first is F and otherwise return its second
argument.
.ASIS
Axiom.
T /$M-1= F
Axiom.
X = Y -> (EQUAL X Y) = T
Axiom.
X /$M-1= Y -> (EQUAL X Y) = F
Axiom.
X = F -> (IF X Y Z) = Z
Axiom.
X /$M-1= F -> (IF X Y Z) = Y.
.ENDASIS
The logical functions
are defined with the following equations:
.ASIS
Definition.
(NOT P)
=
(IF P F T)
Definition.
(AND P Q)
=
(IF P (IF Q T F) F)
Definition.
(OR P Q)
=
(IF P T (IF Q T F))
Definition.
(IMPLIES P Q)
=
(IF P (IF Q T F) T).
.ENDASIS
We adopt the notational convention of writing (AND a b c)
for (AND a (AND b c)), (AND a b c d) for (AND a (AND b (AND c d))), and
so on. We make the same convention for OR.
We also adopt
the notational convention of sometimes writing a term where a formula
is expected (e.g., we may refer to the "theorem" p, where p is a term).
When we write a term p where a formula is expected,
it is an abbreviation for the formula p/$M-1=F.
If a term p is a theorem, then by the rule of instantiation,
the result of substituting any substitution into p is a theorem.
.STARRS
.SS |Well-founded Relations|
In the following {SUBSECTIONORSECTION}s we state a principle of induction,
introduce inductively constructed objects such as the
natural numbers and ordered pairs, and state a principle of definition
for recursive functions.
All of these extensions hinge on the idea of a "well-founded relation."
A function r of two arguments is said to be a __well-founded relation_ if
there is no infinite sequence
x[&1], x[&2], x[&3], ... with the property that
(r x[&i+1] x[&i])/$m-1=F for all integers i greater than 0.
For example, suppose that (L x y) is T if x and y are
nonnegative integers and x is less than y, and that (L x y) is F
otherwise. Then L is a well-founded relation
because there is no infinite sequence of nonnegative
integers with
the property that each successive integer is less than the previous one.
That is, there is no infinite sequence x[&1], x[&2], x[&3], x[&4], ... such that
.ASIS
... x[&4] < x[&3] < x[&2] < x[&1].
.ENDASIS
On the other hand, suppose that (LE x y) is T if
x and y are nonnegative integers and x <$M-1_ y. LE is not a well-founded relation
because the infinite sequence 1, 1, 1, ...
has the property that:
.ASIS
... 1 <$M-1_ 1 <$M-1_ 1 <$M-1_ 1.
.ENDASIS
If r is a well-founded relation
and (r x y) holds, we say that x is
r__-smaller than_ y.
For the purposes of our theory, functions are known to be well-founded only
by assumption in one of the following three ways:
.LIST(8,0,0)
.ITEM
Whenever we axiomatize an inductively generated type of object, e.g., the integers,
we explicitly assume a certain new function to be a well-founded relation.
Such
an assumption is inherent in any axiomatization of an inductively generated
type. See {YONSS SSNEWDATATYPES}.
.ITEM
We assume explicitly that the function LESSP is a well-founded relation in {YONSS SSLESSP}.
We present there an informal proof that LESSP is well-founded.
.ITEM
Whenever we have two previously assumed well-founded relations, we assume
that the lexicographic relation induced by them is well-founded. In {YONSS SSLEX}
we define "induced" and present an informal proof of the well-foundedness
of induced lexicographic relations.
.ENDLIST
The fact that a function has been assumed to be a well-founded relation is used only
in our principles of induction and definition and in the formation of
induced lexicographic relations.
It is possible to define formally in a theory
of sets (for example, see Morse {REF MORSE} or Kelley {REF KELLEY}) the concept of well-founded relation, to
prove that certain relations are well-founded, and to derive
as metatheorems our principles of induction and definition. However, such
a development is not within the scope of this work.
We say that x is an r-__minimal
element of_ S provided x is a member of S and no member of S
is r-smaller than x. Later in this {SECTIONORCHAPTER} we use the fact that if
r is well-founded, then for each nonempty set S, there exists
an r-minimal element of S. Proof. Suppose that r is well-founded and S is a nonempty set with no r-minimal element.
Let f be a choice function on the power set of S. That is, suppose
that for each nonempty subset s of S that (f s) is a member of s.
Define the sequence x[&1], x[&2], x[&3], ... by
letting x[&1] be (f S) and by letting x[&i+1] be (f s[&i]), where s[&i]
is the set of all z in S r-smaller than x[&i].
For each i, s[&i+1] is nonempty (otherwise,
x[&i] would be r-minimal). And for each i, x[&i+1] is
r-smaller than x[&i]. Q.E.D.
.SS |Induction|
A rough
sketch of our principle of induction is:
.CROWN(8,0,0)
Suppose that r denotes a well-founded
relation, x is a variable, d is a function symbol,
q is a term and (IMPLIES q (r (d x) x)) is a theorem.
Then, to prove p it is sufficient to prove
the following two things:
.CROWN(8,0,0)
(base case): (IMPLIES (NOT q) p), and
(induction step): (IMPLIES (AND q p') p),
where p' is the result of substituting (d x) for x in p.
.ENDCROWN
.ENDCROWN
This is a version of the Generalized Principle of Induction or Noetherian
Induction (see Bourbaki {REF BOURBAKI} and Burstall {REF BURSTALL}).
The induction principle we actually use generalizes the principle sketched above in three ways:##
.CROWN(8,0,0)
Instead of
limiting the principle to one variable that is getting r-smaller, we use an n-tuple x[&1], ..., x[&n] of variables and some function m
such that (m x[&1] ... x[&n]) is getting r-smaller. The function m
is called a "measure function."
Instead of case splitting
on q, we consider k+1 cases, of which one is a base case and the
remaining k are induction steps.
We
permit each of the k induction steps to have several induction
hypotheses.
.ENDCROWN
.STARRS
.BEGIN
.CENTER
The Induction Principle
.END
.ASIS
Suppose:
(a) p is a term;
(b) r is a function symbol that denotes a
well-founded relation;
(c) m is a function symbol of n arguments;
(d) x[&1], ..., x[&n] are distinct variables;
(e) q[&1], ..., q[&k] are terms;
(f) h[&1], ..., h[&k] are positive integers; and
(g) for 1<$M-1_i<$M-1_k and 1<$M-1_j<$M-1_h[&i], s[&i,j]
is a substitution and it is a theorem that:
(IMPLIES q[&i] (r (m x[&1] ... x[&n])/s[&i,j] (m x[&1] ... x[&n]))).
Then p is a theorem if
(IMPLIES (AND (NOT q[&1]) ... (NOT q[&k]))
p)
is a theorem and
for each 1<$M-1_i<$M-1_k,
(IMPLIES (AND q[&i] p/s[&i,1] ... p/s[&i,h{SUB "i"}])
p)
is a theorem.
.ENDASIS
.STARRS
Note in particular that we have to prove k+1 things (the "base case" and k
"induction steps"). Each induction step distinguishes a given case with
one of the q[&i]'s and provides h[&i] inductive instances of the conjecture
being proved.
We now illustrate an application of the induction principle.
Imagine that LESSP is well-founded,
that the axioms CAR.LESSP and CDR.LESSP have been added, and that
FLATTEN and MC.FLATTEN have been introduced as in {YONSEC SECOVERVIEW}.
The first induction performed in the proof of the FLATTEN.MC.FLATTEN
theorem of {YONSEC SECOVERVIEW} is obtained by the following
instance of our induction principle. p is the term (EQUAL (MC.FLATTEN X ANS)
(APPEND (FLATTEN X) ANS)); r is LESSP; m is COUNT; n is 1; x[&1] is X;
k is 1; q[&1] is the term (LISTP X); h[&1] is 2; s[&1,1] is
$a{,}; s[&1,2] is
$a{,}; the axioms CAR.LESSP and CDR.LESSP establish
the two theorems required by condition (g). The base case and the induction
steps produced by this application of the induction principle
are those exhibited in {YONSEC SECOVERVIEW}.
We now prove that our induction principle is sound.
Suppose we have in mind particular p, r, m, x[&i],
q[&i], h[&i], and s[&i,j] satisfying conditions (a) through
(g) above, and suppose the base case and induction steps are
theorems. Below is a set theoretic proof of p.
Proof. Without loss of generality we assume that the
x[&i] are X1, X2, ..., Xn; that r is R; that m is M;
that Xn+1, Xn+2, ..., Xz are all of the variables other
than X1, X2, ..., Xn in p, the q[&i], and either component
of any pair in any s[&i,j]; that p is (P X1 ... Xz); that
q[&i] is (Qi X1 ... Xz); and that s[&i,j] replaces X[&v], 1<$m-1_v<$m-1_z,
with some term d[&i,j,v].
Let RM be the dyadic function on z-tuples defined by
(RM ) = (R (M U1 ... Uz) (M V1 ... Vz)).
Note that RM is well-founded. If p is not a theorem there must
exist a z-tuple such that (P X1 ... Xz)=F.
Let be an RM-minimal such z-tuple.
We now consider the cases on which, if any, of the q[&i] are
true on the chosen z-tuple.
Case 1: Suppose no q[&i] is true, i.e., suppose (Q1 X1 ... Xz)=F,
(Q2 X1 ... Xz)=F, ..., and (Qk X1 ... Xz)=F. Then by the base case
(P X1 ... Xz)/$m-1=F, contradicting the assumption that (P X1 ... Xz)=F.
Case 2: Suppose that at least one of the q[&i] is true.
Without loss of generality we can assume that (Q1 X1 ... Xz)/$m-1=F.
By condition (g) above we have:
.ASIS
(R (M d[&1,1,1] ... d[&1,1,n]) (M X1 ... Xn)),
(R (M d[&1,2,1] ... d[&1,2,n]) (M X1 ... Xn)),
..., and
(R (M d[&1,h{SUB "1"},1] ... d[&1,h{SUB "1"},n]) (M X1 ... Xn)).
.ENDASIS
Thus, by the definition of RM, we have:
.ASIS
(RM ),
(RM ),
..., and
(RM ).
.ENDASIS
Since is an RM-minimal z-tuple such that (P X1 ... Xz)=F,
we have:
.ASIS
(P d[&1,1,1] ... d[&1,1,z])/$m-1=F,
(P d[&1,2,1] ... d[&1,2,z])/$m-1=F,
..., and
(P d[&1,h{SUB "1"},1] ... d[&1,h{SUB "1"},z])/$m-1=F.
.ENDASIS
Hence, by the first induction
step, we derive (P X1 ... Xz)/$m-1=F, contradicting the assumption that
(P X1 ... Xz)=F. Q.E.D.
.SS |Shells|, SSNEWDATATYPES:
Thus far the theory is somewhat impoverished in that it does not
have any "interesting" objects. It would be convenient,
for example, if we could refer to the natural numbers 0, 1, 2, ...
and ordered pairs from within our theory (as we have several
times in discussions of our theory). We could invent appropriate
axioms for each individual "type" of object. However, we want to
ensure that no natural number is T, F, or an ordered pair.
In addition, we want to specify how the primitive functions behave
on "unexpected"
arguments (e.g., what does the successor function return when given T as an
argument?).{FNOTE |One way to make sure that T is not a number or to
. escape from asking what is the successor of T is
. to employ a typed syntax. Indeed, Aubin {REF AUBIN} and Cartwright {REF CARTWRIGHT}
. have implemented theorem provers for recursive functions that use typed syntax.
. However, we have grown so accustomed to the untyped
. syntax of predicate calculus, set theory, LISP, MACRO-10, and POP-2 that
. we simply do not like typed syntax.|}
Because of considerations such as these, we address the general problem of extending the theory
by adding a new "type" of object.
Among the most common objects in the applications of our theory
are what we will call "shells."{FNOTE |Our shells are inspired by the "structures" used by Burstall {REF BURSTALL}.
. Recently, Oppen {REF OPPEN} has established the decidability of a
. theory similar to our shell theory.|}
A shell can be thought of as
a colored n-tuple with restrictions on the colors of objects that
can occupy its components. For example, the natural numbers
can be thought of as shells:##a number is either a blue 0 or a
blue 1-tuple containing another blue object (namely, the predecessor of the
tuple). Ordered pairs can be red 2-tuples
containing arbitrary objects. The type consisting of lists of numbers
can be either the green, empty list of numbers or else green 2-tuples, , such
that x is a number (blue) and y is a list of numbers (green). The fact that
ordered pairs and
lists of numbers have different colors prevents an ordered pair consisting of
a
number and a list of numbers from being confused with a list of numbers.
Because it is useful to be able to extend the theory by
adding the axioms defining a new shell class and because the
required set of axioms can be represented schematically, we will
adopt a notational shorthand for adding new shells. We now specify informally
the properties of a shell. The basic
function for a shell class is one that "constructs" n-tuples of the appropriate
color (e.g., the successor function
or the pairing function). It is convenient if each shell class can (optionally) have
one object that is in the class but is not such an n-tuple (e.g., 0 and the empty
list of numbers). Because we will have many kinds of shells,
we will need a function, called the "recognizer" of the class that
returns T on objects of the class and F otherwise. We also require n "accessor" (or "destructor") functions associated with the class, that,
when given an n-tuple of the right color, return the corresponding
components of the n-tuple (e.g., the predecessor function is the "accessor"
corresponding to the shell for numbers). Finally, we posit that
any object in the class can be generated with a finite number of
"constructions" starting with the bottom object and objects not
in the class.
This is arranged by assuming a certain function to be a well-founded relation
(e.g., one under which the predecessor of a
nonzero number is smaller than the number itself).
Because we wish to have
restrictions on the types of objects that can be components of a shell n-tuple,
we must adopt some convention for specifying the restriction.
We also adopt conventions for specifying what a constructor returns when
one of its arguments fails to meet the required restriction and what
an accessor returns when given an object of the wrong type as an argument. We require
that there be associated with each argument position of each shell constructor
a "type restriction" that limits the colors of objects that may occupy
that component. The restriction is expressed in one of two ways:##(a)
that an object must have a color that is a member of an explicitly given set of
previously (or currently being) axiomatized colors, or (b) that an object
may __not_ have a color in such a set. The type restriction is written
as a propositional term (see condition (b) below). We also require
that each argument have a "default value" that is permitted by the
type restriction to occupy the corresponding component of the shell tuple.
When one of the arguments to a constructor does not satisfy the corresponding
type restriction, the default value for that argument position is used in its place.
Finally, we arrange that
the accessor for a position return the corresponding
default value when given either the bottom object or an object of the wrong
color.
.STARRS
.BEGIN
.CENTER
The Shell Principle
.END
.ASIS
To __add the shell_ const __of_ n __arguments_
__with_ (optionally, __bottom object_ (btm),)
__recognizer_ r,
__accessors_ ac[&1], ..., ac[&n],
__type restrictions_ tr[&1], ..., tr[&n],
__default values_ dv[&1], ..., dv[&n], __and_
__well-founded relation_ wfn,
where:
(a) const is a new function symbol of n arguments,
(btm is a new function symbol of no arguments,
if a bottom object is supplied),
r, ac[&1], ..., ac[&n] are new function symbols
of one argument,
wfn is a new function symbol of two arguments, and
all the above function symbols are distinct;
(b) each tr[&i] is a term that mentions no symbol
as variable besides Xi and mentions no symbol
as a function symbol besides IF, TRUE, FALSE,
previously introduced shell recognizers, and r; and
(c) if no bottom object is supplied, the dv[&i]
are bottom objects of previously introduced
shells, and for each i,
(IMPLIES (EQUAL Xi dv[&i]) tr[&i]) is a theorem;
if a bottom object is supplied, each dv[&i]
is either (btm) or a bottom object of some
previously introduced shell, and for each i,
(IMPLIES (AND (EQUAL Xi dv[&i])
(r (btm)))
tr[&i])
is a theorem,
means to extend the theory by doing the following (using
T for (r (btm)) and F for all terms of the form
(EQUAL x (btm)) if no bottom object is supplied):
(1) assume the following axioms:
(OR (EQUAL (r X) T) (EQUAL (r X) F)),
(r (const X1 ... Xn)),
(r (btm)),
(NOT (EQUAL (const X1 ... Xn) (btm))), and
(IMPLIES (AND (r X)
(NOT (EQUAL X (btm))))
(EQUAL (const (ac[&1] X) ... (ac[&n] X))
X));
(2) for each i from 1 to n, assume the following axiom:
(IMPLIES tr[&i]
(EQUAL (ac[&i] (const X1 ... Xn))
Xi));
(3) for each i from 1 to n, assume the following axiom:
(IMPLIES (OR (NOT (r X))
(EQUAL X (btm))
(AND (NOT tr[&i])
(EQUAL X (const X1 ... Xn))))
(EQUAL (ac[&i] X) dv[&i]));
(4) assume the axioms:
(NOT (r T)) and
(NOT (r F));
(5) for each recognizer, r', of a shell class previously
added to the theory, assume the following axiom:
(IMPLIES (r X) (NOT (r' X)));
(6) assume the axiom:
(wfn X Y) = (OR t
(AND (r Y)
(NOT (EQUAL Y (btm)))
(OR (EQUAL X (ac[&1] Y))
...
(EQUAL X (ac[&n] Y))))),
where t is the term (FALSE) if no shell has
been added previously, and otherwise is (wfn' X Y)
where wfn' is the well-founded relation name for
the last shell previously added; and
(7) assume wfn denotes a well-founded relation.
.ENDASIS
If the tr[&i] are not
specified, they should each be assumed to be T.
.STARRS
The n axioms in (3) specify what the values of the accessors
are when given "unexpected" arguments.
It is possible to prove the consistency of the theory resulting from
the addition of a finite number of shells by exhibiting a model.
A suitable model may be constructed by representing a (nonbottom)
member of a shell class having n accessors as an n+1-tuple
whose first component is an integer encoding the "color."
Note that merely because we
add a finite number of shells we are not assured that every object
in the world is in one of our shell classes. That is, we do not have
an axiom that says: for any x, x is either T, or x is F, or x satisfies one
of the shell recognizers. Indeed, this is an intended feature of the
shell principle; we desire that any extension produced by
adding shells can be further extended by additional shells without
giving rise to inconsistency.
From the point of view of modeling programming language constructs,
shells are valuable. They can play a role in
the semantics of the usual kinds of "records"
since records are often n-tuples with type restrictions on their
components. Shells can also be used to model
other kinds of common programming objects, such as the integers,
atomic objects (words, capabilities, characters, file names),
push down stacks, and character strings. In the next three
{SUBSECTIONORSECTION}s, we will use shells to add the natural numbers,
literal atoms, and ordered pairs to our theory.
.SS |Natural Numbers|
We now axiomatize the natural numbers, 0, 1, 2, etc. using
the shell principle:
.STARRS
.ASIS
Shell Definition.
Add the shell ADD1 of one argument
with bottom object (ZERO),
recognizer NUMBERP,
accessor SUB1,
type restriction (NUMBERP X1),
default value (ZERO), and
well-founded relation SUB1P.
.ENDASIS
.STARRS
This axiomatizes
a new type of object we will call the "numbers."
The numbers consist of the new object (ZERO) and all of the
objects returned by the new function ADD1.
We now informally repeat the axioms added by the shell principle.
The numbers in parentheses indicate the corresponding clause
of the definition of the shell addition principle.
(1) The function NUMBERP
(which recognizes numbers), always returns either T or F, and returns T on
(ADD1 X) and (ZERO). (ZERO) is never
returned by ADD1. If X is a non-(ZERO) number, then (ADD1 (SUB1 X))
is X. (2) If X is a number, then (SUB1 (ADD1 X)) is X. (3) SUB1 returns (ZERO)
if applied to a nonnumber, (ZERO), or (ADD1 X1) when X1 is a nonnumber.
(4) T and F are nonnumeric. (5) Because no other shells have been
added, clause (5) does not contribute any axioms.
(6) We define the function SUB1P so that (SUB1P X Y) is T if
Y is a number other than (ZERO) and X is (SUB1 Y), and (SUB1P X Y)
is F otherwise. (7) Finally, we assume that SUB1P is a well-founded relation.
Note the fundamental nature of the assumption that SUB1P is a well-founded relation:#
by virtue of this assumption (and our principle of
induction), (P X) can be proved, for all X, by proving (P X)
when X is not a number, proving (P (ZERO)), and proving that if X is
a number other than (ZERO), then (P (SUB1 X)) implies (P X).
Among the theorems that can be derived from the above axioms is
the theorem that if X and Y are numeric, then (ADD1 X) is equal to (ADD1 Y)
if and only if X is equal to Y. See {APP APPSHELL}.
We will abbreviate (ZERO) as 0, and any well-formed nest of ADD1's around a
0 as the decimal numeral expressing the number of ADD1 terms in the nest.
Thus, 1 is an abbreviation for (ADD1 0), 2 is an abbreviation
for (ADD1 (ADD1 0)), etc.
.SS |Literal Atoms|
We want to be able to prove theorems about functions that
manipulate symbols. For example, in {YONSEC SECCOMPILER}
we prove the correctness of a function that
translates from symbolic arithmetic expressions to sequences of instructions
for a hand-held calculator. We write symbols as sequences of characters
delimited by quotation marks (e.g., "X" and "ABC"). We could
adopt the convention that "X", for example, was an abbreviation for 24. Such
a convention is part of the logician's standard method for
representing terms, known as Goedelization.
However,
we want to arrange for the symbols to be different from the
integers. To this end
we add a new shell class called the "literal atoms," and we adopt
a syntactic convention that translates from quoted character sequences
to literal atoms.
The shell class is recognized by the
new Boolean function LITATOM. The new function PACK, of one argument,
takes an arbitrary object and returns a literal atom. (The name PACK
derives from the INTERLISP operation for constructing literal atoms by
concatenating sequences of characters.) (PACK x) is the same
literal atom as (PACK y) if and only if x
is the same object as y. The new function UNPACK, given a literal atom, returns the object
used to construct it.
.STARRS
.ASIS
Shell Definition.
Add the shell PACK of one argument
with bottom object (NIL),
recognizer LITATOM,
accessor UNPACK,
default value 0, and
well-founded relation UNPACKP.
.ENDASIS
.STARRS
Note that since ADD1 was the last shell added
and the well-founded relation for it was SUB1P, the new well-founded relation
UNPACKP holds between X and Y either if SUB1P holds between X and Y or
if X is the result of UNPACKing (the non-(NIL) literal atom) Y.
We now adopt a convention for abbreviating literal atoms as symbols.
We suppose an enumeration s[&1], s[&2], s[&3], ...
of all symbols (character sequences) except "NIL". When we write
"NIL" in a term position, it is an abbreviation for (NIL). When
we write s[&i] delimited by quotation marks in a term position,
it is an abbreviation for (PACK i).
.SS |Ordered Pairs|
We axiomatize ordered pairs as follows:
.STARRS
.ASIS
Shell Definition.
Add the shell CONS of two arguments
with recognizer LISTP,
accessors CAR and CDR,
default values "NIL" and "NIL", and
well-founded relation CAR.CDRP.
.ENDASIS
.STARRS
We sometimes think of ordered pairs as sequences, binary trees, or terms.
For example
.ASIS
(CONS 1 (CONS 2 (CONS 3 "NIL")))
.ENDASIS
may be thought of as the sequence 1, 2, 3.
(CONS (CONS 1 2) 3) may be thought of as the binary tree:
.ASIS
*
/ \
* 3
/ \
1 2
.ENDASIS
Finally,
.ASIS
(CONS "PLUS"
(CONS "X" (CONS 3 "NIL"))).
.ENDASIS
may be thought of as the term (PLUS X 3).
.STARRS
Because nests of CARs and CDRs are frequently used, we provide a definition
for each function symbol beginning with the letter C, ending with the letter
R, and containing only A's and D's in between. The body of the definition
is just the appropriate nest of C__A_Rs and C__D_Rs. For example,
.ASIS
Definition.
(CADDR X)
=
(CAR (CDR (CDR X))).
.ENDASIS
.STARRS
.SS |Definitions|
We have already defined certain
simple functions, such as AND, OR, NOT, and IMPLIES. For example,
.ASIS
Definition.
(AND P Q)
=
(IF P (IF Q T F) F).
.ENDASIS
Another simple function we define is ZEROP; it returns
T if its argument is virtually 0 (in the sense that ADD1 and
SUB1 treat it as 0) and F otherwise:
.ASIS
.STARRS
Definition.
(ZEROP X)
=
(OR (EQUAL X 0) (NOT (NUMBERP X)))
.STARRS
.ENDASIS
In general, if the function symbol f is new, if
x[&1], ..., x[&n] are distinct variables,
if the term body mentions no symbol as a variable other than these
x[&i], and if body does not mention f as a function symbol,
then adding the axiom:
.ASIS
(f x[&1] ... x[&n]) = body
.ENDASIS
is a proper way to define a new function.
Indeed, any use of the symbol f as a function symbol in a term, such
as (f t[&1] ... t[&n]), can be completely eliminated by replacing the term
with the result of substituting $a{, ..., }
into body.
However, one apparently mild generalization of the above scheme results
in our being able to define functions that are considerably more
interesting. This generalization allows the use of f as a
function symbol in the body of its own definition.
For example, to define a function that returns the integer sum of
its two arguments we could write:
.ASIS
Definition.
(SUM X Y)
=
(IF (ZEROP X)
Y
(ADD1 (SUM (SUB1 X) Y))).
.ENDASIS
Unlike our previous definitions, the body of SUM mentions the
function symbol being defined. That is, SUM is defined recursively.
Nevertheless, SUM is well-defined. For example, consider (SUM 3 4).
.ASIS
(SUM 3 4) = (ADD1 (SUM 2 4))
= (ADD1 (ADD1 (SUM 1 4)))
= (ADD1 (ADD1 (ADD1 (SUM 0 4))))
= (ADD1 (ADD1 (ADD1 4)))
= 7.
.ENDASIS
If we were to allow the new function symbol to occur arbitrarily
in the right-hand side, we could define all
"general recursive"
functions. However, we could also fall into inconsistency.
For example, were we to add the axiom:
.ASIS
(RUSSELL X) = (IF (RUSSELL X) F T),
.ENDASIS
our theory would be inconsistent. To sketch a proof:##(RUSSELL X) must be
equal to F or not equal to F. If the former, then by the definition of RUSSELL
it follows that (RUSSELL X) = T, a contradiction.
If the latter, it follows that
(RUSSELL X) = F, another contradiction.
Q.E.D.
We now present a principle of definition that allows
the introduction of recursive functions. The principle will not allow
us to introduce all "general recursive" functions or even all "recursive"
functions.{FNOTE |See Peter {REF PETER} for a thorough treatment
. of general recursive functions.|} However, it will permit the definition of
almost all the functions in which we are currently
interested. And we shall prove that every application of
the principle is sound (unlike the axiomatization of RUSSELL above).
.STARRS
.BEGIN
.CENTER
The Definition Principle
.END
In stating our principle of definition below, we say that
a term is f-__free_ if the symbol f does not occur in the term as
a function symbol.
We say that a term t __governs_ an occurrence of a term s
in a term b either if b contains a subterm of the form (IF t p q)
and the occurrence of s is in p, or if b contains a subterm of the form
(IF t' p q), where t is (NOT t')
and the occurrence of s is in q. Thus, P and (NOT Q) govern the first
occurrence of S in:
.ASIS
(IF P
(IF (IF Q F S)
S
R)
T).
.ENDASIS
Note that P and (IF Q F S) govern the second occurrence of S.
Our principle of definition is:
.ASIS
__To define_ f __of_ x[&1], ..., x[&n]
__to be_ body
(usually written "Definition. (f x[&1] ... x[&n]) = body"),
where:
(a) f is a new function symbol of n arguments;
(b) x[&1], ..., x[&n] are distinct variables;
(c) body is a term and mentions no symbol as a
variable other than x[&1], ..., x[&n]; and
(d) there is a well-founded relation denoted by
a function symbol r and a function symbol m
of n arguments, such that for each occurrence of a
subterm of the form (f y[&1] ... y[&n]) in body
and the f-free terms t[&1], ..., t[&k]
governing it, it is a theorem that:
(IMPLIES (AND t[&1] ... t[&k])
(r (m y[&1] ... y[&n]) (m x[&1] ... x[&n]))),
means to add as an axiom the defining equation:
(f x[&1] ... x[&n]) = body.
.ENDASIS
.STARRS
We now illustrate an application of the principle of definition.
Imagine that LESSP is well-founded and that the axioms CAR.LESSP
and CDR.LESSP have been added as in {YONSEC SECOVERVIEW}.
The defining equation for MC.FLATTEN is added to our theory
by the following instantiation of our principle of definition.
f is the function symbol MC.FLATTEN; n is 2; x[&1] is X and
x[&2] is ANS; body is the term:
.ASIS
(IF (LISTP X)
(MC.FLATTEN (CAR X)
(MC.FLATTEN (CDR X) ANS))
(CONS X ANS));
.ENDASIS
r is LESSP; m is the function symbol COUNT1, where (COUNT1 X Y)
is defined to be (COUNT X). The two theorems required by (d) are:
.ASIS
(IMPLIES (LISTP X)
(LESSP (COUNT1 (CDR X) ANS)
(COUNT1 X ANS))), and
(IMPLIES (LISTP X)
(LESSP (COUNT1 (CAR X)
(MC.FLATTEN (CDR X) ANS))
(COUNT1 X ANS))).
.ENDASIS
Both theorems are easily proved from CAR.LESSP, CDR.LESSP and the
definition of COUNT1. Note that the second theorem is
proved before any axiom about MC.FLATTEN has been posited,
even though MC.FLATTEN is used as a function symbol in the theorem.
If we have defined (f x[&1] ... x[&n]) to be body, then
we say that body is the __body_ of f and that x[&i] is
the i^^th^ __formal parameter_ of f. If body mentions
f as a function symbol, we say that f is __recursive_
and otherwise we say that f is __nonrecursive_.{FNOTE |This is potentially confusing, since in both cases the
. function is (general) recursive in the usual mathematical sense. No
. confusion should arise from our convention -- which is derived from everyday
. usage in computer programming -- since we will nowhere discuss in this
. book functions that are not general recursive in the mathematical
. sense. Our definition principle does not permit mutually recursive
. definitions. If f were defined in terms of a new function g,
. then after the definition, g would no longer be new, and
. hence g could not be defined.|}
If f has not been defined but has been mentioned as a function
symbol of n arguments in an axiom, we say that Xi is the
i^^th^ __formal parameter_ of f, for i from 1 to n.
We now offer a justification for admitting recursive definitions.
This justification will relieve the fears raised by RUSSELL.
Roughly speaking, we shall prove that for each correct
application of the definition principle, we can prove
that there exists a unique function f that satisfies the
defining equation (f x[&1] ... x[&n]) = body.
We shall construct the desired function using a standard set-theoretic
method of partial functions that "approximate" the desired
function. Unfortunately, different set theories supply different
answers to the question: what is the value of applying a
function to an object not in the function's domain. Instead
of adopting a particular theory of sets, we shall instead
make sure in the following proof not to apply any function
to an object not in the function's domain. Furthermore, we
shall assume the existence of some universal set D to be the
domain of discourse for all the functions that we axiomatize
in our theory. To be precise, we assume that:
.CROWN(8,8,0)
There exists a set D such that each function symbol f
mentioned as a function symbol in any axiom denotes a
function whose domain is D^n and whose range is a subset of
D, where n is the number of arguments of f.
.ENDCROWN
If G is a function whose domain is a subset of D^n, for some n, and whose
range is a subset of D, then the
__extension_ of G is the function on D^n to D that is
defined to be (G X1 ... Xn) if
is a member of the domain of g and is defined to be (TRUE) otherwise.
Suppose that we have in mind some specific f, x[&1], ..., x[&n],
body, r, and m and suppose they satisfy the conditions (a)
through (d) of the definition principle. Before we add the
defining axiom (f x[&1] ... x[&n]) = body, we wish to prove
that there exists a unique function f defined on D^n to D
satisfying the equation. Without loss of generality,
suppose
that f, x[&1], ..., x[&n], r, and m are the symbols FN, X1, ..., Xn, R, and M respectively.
Let us adopt the notational convention that b[s] is an
abbreviation for the term obtained by replacing every
occurrence of FN as a function symbol in the term b with the
symbol s. (For example, if term is (ADD1 (FN X1)), then
term[G] is an abbreviation for (ADD1 (G X1)).)
Let RM be the well-founded relation defined on n-tuples by
(RM ) = (R (M U1 ... Un) (M V1 ... Vn)).
Let us say that a subset S of D^n is RM-__closed_ if and only
if every member of D^n RM-smaller than a member of S is
itself a member of S.
Let us say that a function H is __partially correct_ if (a)
its domain is an RM-closed subset of D^n, (b) its range is a
subset of D, and (c) if H' is the extension of H, then for each
in the domain of H, (H X1 ... Xn) = body[H'].
We now prove a lemma that is used frequently below. Its proof
is quite tedious.
.ASIS
Lemma. Suppose:
F1 is a function whose domain is a subset of
of D^n and whose range is a subset of D,
F1' is the extension of F1,
G1 is partially correct,
G1' is the extension of G1,
is in D^n, and
F1 and G1 are defined and agree upon every
member of D^n that is RM-smaller than
.
Then body[F1'] = body[G1'].
.ENDASIS
Proof. Let subterm[&1], ..., subterm[&k] be an enumeration of the
occurrences of the subterms of body, and suppose that if the term
subterm[&i] is a proper subterm of the term subterm[&j] then i
is RM-smaller than and so is
.
But F1 and G1 are defined and agree on members of D^n RM-smaller
than . Thus, *1 follows from the hypothesis that
tests[&i] /$m-1= F and the *a. Q.E.D.
We now turn to the construction of the unique function satisfying
the defining equation (FN X1 ... Xn) = body.
Let F0 be the union of all partially correct functions. We will prove
that F0 is the desired function by demonstrating that (a) F0 is a function,
(b) F0 is partially correct, and (c) the domain of F0 is D^n.
The uniqueness of F0 follows from (a), (b), (c), and the fact
that any other function defined on D^n to D satisfying the defining
equation is partially correct and hence a subset of F0.
Proof that F0 is a function. If F0 is not a function it is
multiply defined somewhere. Let be an RM-minimal member
of D^n such that for some two distinct values, Z1 and Z2 say,
both <,Z1> and <,Z2> are members of F0.
Let F1 and G1 be partially correct functions that contributed
<,Z1> and <,Z2> to F0. Let F1' and G1'
be the extensions of F1 and G1. Both F1 and G1 are defined
upon all members of D^n RM-smaller than because both
are partially correct. F1 and G1 have the same values
on all members of D^n RM-smaller than because
is RM-minimal. Therefore, by the lemma, body[F1'] = body[G1'].
But Z1 = (F1 X1 ... Xn) = body[F1'] = body[G1'] = (G1 X1 ... Xn) = Z2
because both F1 and G1 are partially correct. Q.E.D.
Proof that F0 is partially correct. The domain of F0 is an RM-closed
subset of D^n because it is the union of RM-closed subsets of D^n.
The range of F0 is a subset of D. Let F0' be the extension of F0.
Let be any member of the domain of F0 such that
(F0 X1 ... Xn) /$m-1= body[F0']. Let G be a partially
correct function with in its domain such that
(G X1 ... Xn) = (F0 X1 ... Xn). Let G' be the extension of G.
By applying the lemma to F0, F0', G, G', and
we infer that body[F0'] = body[G']. But (F0 X1 ... Xn) =
(G X1 ... Xn) = body[G'] = body[F0']. Q.E.D.
Before proving that the domain of F0 is D^n we adopt the notational
convention that body' is an abbreviation for the result of substituting
Yi for Xi in body[F0']. For example, if body is the term
(IF (LISTP X1) (FN X1 X2) F), then body' is (IF (LISTP Y1) (F0' Y1 Y2) F).
Proof that the domain of F0 is D^n. Suppose that F0 is not defined on
every element of D^n. Let be an RM-minimal
element of D^n not in the domain of F0. Let F0' be the
extension of F0. Let G be the function that results from adding to
F0 the ordered pair <,body'>. If we can show that
G is partially correct a contradiction will arise because then G would
be a subset
of F0 by the definition of F0. The domain of G is an RM-closed subset of D^n
because it was formed by adding to an RM-closed subset of D^n
an RM-minimal element of D^n not in that subset.
Let G' be the extension of G.
We need to show that for every n-tuple in the domain of G that (G X1 ... Xn)
= body[G']. For every in the domain of G, we may apply the
lemma for G, G', F0, F0', and to infer that body[G'] =
body[F0']. If = , then (G X1 ... Xn) =
body[F0'] = body[G']. If /$m-1= then
(G X1 ... Xn) = (F0 X1 ... Xn) = body[F0'] = body[G'].
Q.E.D.
That concludes the proof that the definition
principle is sound. No constructivist would
be pleased by the foregoing justification of recursive
definition because of its freewheeling, set-theoretic
character. The truth is that induction and inductive
definition are more basic than the truths of
high-powered set theory, and it is slightly odd
to justify a fundamental concept such
as inductive definition with set theory.
We have presented this proof only to provide
the careful reader with some clear talk about our
definition principle. The only other kind
of discussion we might have presented would
have consisted of examples and the truly
hand-waving phrase "and so on." One of our
teachers, Paul Lorenzen, once proclaimed
that the correct way to introduce induction
to a student in an ideal society
was simply to draw strokes: |, ||, |||, ||||,
and so on until the student "caught on."
.SS |Lexicographic Relations|, SSLEX:
Our theory requires one more concept:##the
idea of lexicographic relations.
.STARRS
To define l to be the __lexicographic relation induced by_ r and s, where:
.ASIS
(a) l is a new function symbol of 2 arguments,
(b) r and s are function symbols of 2 arguments, and
(c) neither r nor s is l,
means to add as an axiom the following defining equation:
(l P1 P2) = (OR (r (CAR P1) (CAR P2))
(AND (EQUAL (CAR P1) (CAR P2))
(s (CDR P1) (CDR P2)))).
.ENDASIS
.STARRS
That is, l orders pairs of objects by first comparing
their CAR components using r, but using s on their CDR components
if the test with r fails and the CARs are equal.
(The name "lexicographic" is inspired by the alphabetic
order used by lexicographers.)
.STARRS
If r and s denote well-founded relations and l is defined to be
the lexicographic relation induced by r and s, then l denotes a well-founded
relation.
.STARRS
Proof. Suppose that x[&1], x[&2], ... were an
infinite sequence and that for all positive i, (l x[&i+1] x[&i]) /$m-1= F.
By the definition of l, (r (CAR x[&i+1]) (CAR x[&i])) /$m-1= F
or (CAR x[&i+1]) = (CAR x[&i]). But since r is well-founded,
the sequence (CAR x[&1]), (CAR x[&2]), ... cannot be infinitely descending
in r.
Hence, for some j, for all positive p, (CAR x[&j]) = (CAR x[&j+p]).
But the sequence (CDR x[&j]), (CDR x[&j+1]), ... must then be infinitely
descending in s, a contradiction. Q.E.D.
.SS |LESSP and COUNT|, SSLESSP:
We have now finished defining the formal theory that
we use as the logical basis of our theorem-proving system.
We now use the theory to define two functions, LESSP
and COUNT, that play central roles in our proofs (but have
no role in the formal definition of the theory).
LESSP and COUNT are the well-founded relation and measure function we
use most often in applying our principles of induction and definition.
(LESSP X Y) returns T if X is less than Y and F otherwise. LESSP
treats nonnumeric arguments as 0. LESSP determines whether X is less
than Y by counting them both down to 0, seeing which gets there first.
.STARRS
.ASIS
Definition.
(LESSP X Y)
=
(IF (ZEROP Y)
F
(IF (ZEROP X)
T
(LESSP (SUB1 X) (SUB1 Y)))).
.ENDASIS
.STARRS
Since (IMPLIES (NOT (ZEROP X)) (SUB1P (SUB1 X) X)) is a theorem,
the first argument of LESSP gets SUB1P smaller in the recursive call.
(In fact, so does the second argument.) Thus, LESSP
is admitted under the principle
of definition.
We claim that LESSP is a well-founded relation. That is, we claim
there is no infinite sequence x[&1], x[&2], ... such that x[&i+1]
is LESSP-smaller than x[&i]. It is easy to see how to
prove that LESSP is well-founded in a suitable theory of sets,
since SUB1P is well-founded,
and x is LESSP-smaller than y if and only if a finite number of SUB1s will
reduce y to x (when both are numbers). We cannot state or
prove the well-foundedness of LESSP within our theory.
.STARRS
We assume LESSP to be a well-founded relation.
.STARRS
By virtue of this assumption, it is permitted to make
induction arguments in which some measure
gets LESSP-smaller in the induction hypotheses.
Similarly, it is permitted to define recursive functions
in which some measure gets LESSP-smaller in the recursive calls.
A particularly useful measure is the "size" of a shell object
obtained by adding one to the sum of the sizes of its components.
We first define the addition function for the
nonnegative integers. We could use the function SUM
defined above.
However, SUM suffers from
the disadvantage of sometimes returning a nonnumber (it returns Y, whatever
that is, when X is 0). SUM is thus not commutative
(e.g., (SUM 0 T) = T, while (SUM T 0) = 0). We thus make the following definitions:
.STARRS
.ASIS
Definition.
(FIX X)
=
(IF (NUMBERP X) X 0)
Definition.
(PLUS X Y)
=
(IF (ZEROP X)
(FIX Y)
(ADD1 (PLUS (SUB1 X) Y)))
.ENDASIS
We adopt the notational convention of writing (PLUS a b c) for (PLUS a (PLUS b c)), etc.
Now assume we have added all the shells we will
use. We define the function COUNT to return 0 on
bottom objects, to return 1 plus the sum of the COUNTs
of the components of a nonbottom shell object, and to
return 0 on any nonshell object. For example, if the only
shells we were ever to add were ADD1, PACK, and CONS, we
would define COUNT as:
.ASIS
Definition.
(COUNT X)
=
(IF (NUMBERP X)
(IF (EQUAL X 0) 0
(ADD1 (COUNT (SUB1 X))))
(IF (LITATOM X)
(IF (EQUAL X "NIL")
0
(ADD1 (COUNT (UNPACK X))))
(IF (LISTP X)
(ADD1 (PLUS (COUNT (CAR X))
(COUNT (CDR X))))
0))).
.ENDASIS
.STARRS
The immediately preceding definition of COUNT would be admitted under the principle of
definition since at each stage the argument is
CAR.CDRP-smaller.
In general, the definition of COUNT is admitted under
the principle of definition, because at each stage the
argument is smaller according to the well-founded relation
of the last shell.
To permit the illusion that shells may be added at any time,
our theorem-proving program does not actually employ the
full definition of COUNT, but instead records (a) for
each shell const the theorems:
.ASIS
(EQUAL (COUNT (const X1 ... Xn))
(ADD1 (PLUS (IF tr[&1] (COUNT X1) 0)
...
(IF tr[&n] (COUNT Xn) 0)))) and
(EQUAL (COUNT (btm)) 0)
.ENDASIS
(omitting the latter if const has no bottom object),
and (b) for each i from 1 to n,
the theorem:
.ASIS
(IMPLIES (AND (r X) (NOT (EQUAL X (btm))))
(LESSP (COUNT (ac[&i] X)) (COUNT X)))
.ENDASIS
(using T for (NOT (EQUAL X (btm))) if const has no bottom object).
These theorems may be proved from the shell axioms
and the definition of COUNT.
.SS |Conclusion|
This concludes the discussion of our formal theory.
We recap the topics presented:
.CROWN(8,0,0)
We defined with axioms certain functions including IF and EQUAL.
We introduced the idea of well-founded relations.
We introduced a principle of induction.
We introduced a general mechanism for adding "new" types of
"colored" n-tuples called "shells."
We used the
shell principle to add axioms for the natural numbers,
literal atoms, and ordered pairs.
We introduced a principle of definition
which allows the introduction of recursive functions.
We introduced the concept of a lexicographic relation.
We used the principle of definition
to introduce the usual "less than" function, assumed it was well-founded,
and defined the measure function COUNT that computes the size of an object.
.ENDCROWN
.SEC |THE CORRECTNESS OF A TAUTOLOGY CHECKER|, SECTAUTOLOGYCHECKER:
Before we describe how we prove theorems in the theory
just presented, it is important that the reader be familiar
with the theory itself. In addition, it is useful to go through the proofs of
some difficult theorems, so that the reader gets a feel for what is
coming in subsequent {SECTIONORCHAPTER}s. Finally, readers unfamiliar
with mechanical theorem-proving may be curious about how one
proves theorems mechanically.
Since all three of these objectives should be
addressed before we begin to present our proof techniques, we have
chosen to illustrate them all in a rather novel example:
the mechanical proof of the correctness of
a simple mechanical theorem prover. In particular, we prove the
correctness of a decision procedure for the propositional calculus.
In the standard development of logic, the propositional calculus
is presented first. As in our theory, it often forms part of the
logical underpinnings of richer theories. In addition, it offers
a simple way of introducing certain important ideas such as soundness,
completeness, and decision procedures.
Because of its foundational role, discussions of
the propositional calculus are usually carried on in the informal
"metalanguage." For example, a common definition of the value of
the formula "p & q" is that it is "true if both p and q have the value
true, and false otherwise." In this {SECTIONORCHAPTER} we exercise
the expressive power of our theory, and clarify certain aspects of it,
by formalizing the semantics of a version of propositional calculus in our theory.
We then introduce certain very simple theorem-proving ideas (such as
how to apply a theorem as a rewrite rule, and how to
keep track of what assumptions govern a subformula of a formula) by
writing, as a recursive function in our theory, a decision procedure
for the propositional calculus. Finally, we illustrate some of our proof
techniques by proving that the decision procedure is well-defined,
recognizes only tautologies, and recognizes all tautologies.
The proofs described are actually carried out by our own mechanical theorem
prover, and the discussion of the proofs illustrates the role of the human
user in our automatic theorem-proving system.
.SS |Informal Development|
Throughout this {SECTIONORCHAPTER} we will be concerned with
the set of terms constructed entirely from variables, T, F,
and the function symbol IF. We call such terms "propositional
IF-expressions." Examples of propositional IF-expressions are:
.ASIS
(IF A B C),
(IF T F (IF A B C)), and
(IF (IF P Q F) (IF P T Q) T).
.ENDASIS
Note that the first of these expressions sometimes has the value F
(when A is T and B is F, for example) but sometimes does not have the value F
(when A is T and B is T, for example). On the other hand, the
second expression always has the value F, and the third expression
never has the value F. We call a propositional IF-expression that never
has the value F a "tautology." Note that any formula of the ordinary propositional calculus can
be converted to an equivalent propositional IF-expression
by using the definitions of AND, OR, NOT, and IMPLIES
presented in {YONSEC SECTHEFORMALTHEORY}.
(Throughout the remainder of this {SECTIONORCHAPTER}
we shall use "expression" as a shorthand for "propositional IF-expression.")
It is our aim in this {SECTIONORCHAPTER} to construct a procedure
for deciding whether an expression is a tautology.
Our first step is to indicate more precisely what we mean by "the value of
an expression." Informally, let us say that v
is an __assignment_ provided that v is a function,
its domain includes T, F, and the variables,
and v maps T to T and F to F.
If v is an assignment, then by "the assignment of x under v" we
mean v(x).
Then the __value of the expression_ x
__under the assignment_ v is defined recursively as:
.ASIS
if x has the form (IF p q r),
then if the value of p under v is F
then return the value of r under v,
else return the value of q under v;
else return the assignment of x under v.
.ENDASIS
We want to define a mechanical procedure that when given an expression x
returns non-F
if for every assignment v, the value of x under v is non-F, and returns F
if for some assignment v, the value of x under v is F. We will call
our procedure TAUTOLOGY.CHECKER.
There are many ways to write TAUTOLOGY.CHECKER. The question:
"What is the most efficient way to write TAUTOLOGY.CHECKER?" is actually one
of the most important unsolved problems in computer science.
One method, called the "truth table" method, considers all possible assignments of T and F to the variables
in the given expression. The truth table
method requires execution time exponential in the number of variables
in the expression. No one knows a method that
does not require exponential time in the worst case. Furthermore,
no one has yet proved that all algorithms require exponential time
in the worst case.
The version of TAUTOLOGY.CHECKER that we present is more
efficient than the truth-table method on one important class of
expressions, namely those in "IF-normal form."{FNOTE |"This
. nomenclature is an excellent example of the time-honored
. custom of referring to a problem we cannot handle as abnormal,
. irregular, improper, degenerate, inadmissible, and otherwise
. undesirable." From Kelley {REF KELLEY}, on "normal" spaces.|}
An expression x is said to be in __IF-normal form_ provided
that no subterm of x beginning with an IF has as its first argument
another term beginning with an IF.
Of the three example formulas above, the first two are in
IF-normal form and the last is not.
When a formula is in IF-normal form, we can decide whether
it is a tautology very easily: we consider each "branch"
through the expression and require either that the tests through
which we pass are contradictory or that the tests through which
we pass force the output to be something other than F. Consider, for example,
the expression:
.ASIS
(IF P (IF T T
F)
(IF Q (IF P F
Q)
T)).
.ENDASIS
There are five branches through this expression (one output per line). The first
branch returns T. The second branch returns F but can never be taken because the
second test, on T, never fails. The third branch can never be
taken because the first test on P must have returned F so the
second must also. The fourth branch returns Q, which is not
F because the earlier test on Q determined that Q was not F.
And the last branch returns T.
So the expression is a tautology.
Informally, then, we have a method for deciding which expressions
in IF-normal form are tautologies. To use the method on expressions in general (rather
that just those in IF-normal form),
we convert the given expression into an equivalent one
(that is, one that always has the same value) in
IF-normal form. We achieve this normalization by applying the
theorem
.ASIS
(EQUAL (IF (IF P Q R) LEFT RIGHT)
(IF P (IF Q LEFT RIGHT) (IF R LEFT RIGHT)))
.ENDASIS
repeatedly, as a rewrite rule from left to right. That is, whenever
we find an expression of the form (IF (IF p q r) left right), we
replace it with the equivalent (IF p (IF q left right) (IF r left right)).
Normalizing an expression may produce a
formula that is exponentially larger than the one with which
we started. So in the worst case, our procedure is
at least exponential.
The foregoing sketch of a decision procedure for the tautology
problem is very informal. Below we reconsider both the
problem and its solution very formally -- in fact we
formalize both the problem and its solution using the
theory presented in {YONSEC SECTHEFORMALTHEORY}.
One way to view the formal presentation
is as an interaction between four participants:##a "buyer" who
wants to purchase a recursive function satisfying his specification
of a tautology checker; an "implementor" who encodes his knowledge
of theorem-proving in a recursive function claimed to meet the
specifications; a "theorem prover" that proves that the implementor
did his job; and a "mathematician user" who aids the theorem prover
by suggesting that it prove certain lemmas.
.SS |Formal Specification of the Problem|
In this {SUBSECTIONORSECTION} we play the role of the buyer:##we specify our
requirements by formally defining what a propositional IF-expression is,
what the value of such an expression is, and what it means
for a function to be a decision procedure.
.SSS |Representing Expressions|
Since we want to define functions on IF-expressions, we
must represent IF-expressions as objects in our theory.
From the point of view of general-purpose theorem-proving programs, the most natural and convenient
way to represent
terms is to represent variables as literal atoms and to represent
the term (f x[&1] ... x[&n]) as the sequence whose CAR is the literal atom f and
whose CDR is the sequence of objects representing the terms x[&1] through
x[&n]. This is the representation we use in our theorem prover. However,
this representation makes it awkward to refer to subterms.
For example, if x represented
(IF test left right), then in order to refer to the third argument one
would write (CAR (CDR (CDR (CDR x)))).
With ease of reading in mind,
we represent IF-expressions in this {SECTIONORCHAPTER} by employing
a new shell class (the green triples, say), called the IF.EXPRPs,
which we introduced with
.ASIS
Shell Definition.
Add the shell CONS.IF of three arguments with
recognizer IF.EXPRP,
accessors TEST, LEFT.BRANCH, and RIGHT.BRANCH,
default values "NIL", "NIL", and "NIL", and
well-founded relation TEST.LEFT.BRANCH.RIGHT.BRANCHP.
.ENDASIS
Thus, we represent the term:
.ASIS
(IF x y z)
as
(CONS.IF x' y' z')
.ENDASIS
where x', y', and z' are the representations of x, y, and z respectively.
We use T and F to represent T and F respectively.
For the purposes of this example
we agree that any object other than T, F, or an
IF.EXPRP represents a variable.
.SSS |Formal Definitions of ASSIGNMENT and VALUE|
To represent assignments we use the standard "association list"
technique from LISP programming. An association list (or simply "alist") is a sequence of
pairs interpreted as
associating with the CAR of each pair the item of information in the CDR.
The recursive function ASSIGNMENT interprets
alists as assignments of values to terms.
ASSIGNMENT returns the value
assigned to a given term in
a given alist (or F if it is not explicitly assigned). ASSIGNMENT assigns T and F to themselves.
Here is the definition of ASSIGNMENT:
.ASIS
Definition.
(ASSIGNMENT VAR ALIST)
=
(IF (EQUAL VAR T)
T
(IF (EQUAL VAR F)
F
(IF (NLISTP ALIST)
F
(IF (EQUAL VAR (CAAR ALIST))
(CDAR ALIST)
(ASSIGNMENT VAR (CDR ALIST)))))).
.ENDASIS
(NLISTP x) is defined to be (NOT (LISTP x)).
The formal definition of the value of the expression X under the
assignment ALIST is:
.ASIS
Definition.
(VALUE X ALIST)
=
(IF (IF.EXPRP X)
(IF (VALUE (TEST X) ALIST)
(VALUE (LEFT.BRANCH X) ALIST)
(VALUE (RIGHT.BRANCH X) ALIST))
(ASSIGNMENT X ALIST)).
.ENDASIS
.SSS |The Formal Correctness Specifications|
As the buyer we want a decision procedure for the propositional
calculus. We now specify what we require of a decision procedure.
First of all, we require that the decision procedure be introduced as a
function. Let us call it TAUTOLOGY.CHECKER.
Second, we require that if TAUTOLOGY.CHECKER recognizes an expression
(in the sense that TAUTOLOGY.CHECKER returns something other than F
when given the expression), then the expression must have a value
other than F under all assignments{FNOTE |The purist may note that in a freewheeling set theoretic approach
. to validity, one would consider all assignments rather
. than merely the finite assignments to which we limit ourselves
. when we represent assignments as finite alists. Of course,
. no real damage is done, because (in a suitable theory of sets)
. one can prove that it is sufficient to restrict one's attention to
. assignments that assign a meaning to the finite number of variables
. in the term in which one is interested.|}.
Stated formally, this requirement is:
.ASIS
Theorem. TAUTOLOGY.CHECKER.IS.SOUND:
(IMPLIES (TAUTOLOGY.CHECKER X)
(VALUE X A)).
.ENDASIS
When specifying requirements, one must be
very careful to say enough. The careless buyer might think that we have
fully specified TAUTOLOGY.CHECKER. However, a function that always returned
F (i.e., recognized nothing) would satisfy the above specification.
We require more than that of
TAUTOLOGY.CHECKER. In fact, we require that it
recognize all tautologies; when TAUTOLOGY.CHECKER fails to recognize an expression
there must exist an
assignment for which the VALUE of the expression is F.
Since we do not use existential quantification, how can
we express the proposition that when TAUTOLOGY.CHECKER fails
to recognize an expression there exists a falsifying assignment?
The answer is that we require that somebody define a recursive
function that explicitly constructs a falsifying assignment for a nontautological expression.
We call the function FALSIFY. Then the statement that the tautology checker
recognizes all tautologies is:
.ASIS
Theorem. TAUTOLOGY.CHECKER.IS.COMPLETE:
(IMPLIES (NOT (TAUTOLOGY.CHECKER X))
(EQUAL (VALUE X (FALSIFY X)) F)).
.ENDASIS
That is, if the tautology checker fails to recognize an expression, then
there is an assignment (namely (FALSIFY X))
for which the value of the expression is F.
From our perspective as the buyer,
the definition of FALSIFY is irrelevant. That is, if somebody were to supply us with a legal definition of
TAUTOLOGY.CHECKER (and also one of FALSIFY) such that the above
two conjectures were theorems, then we would believe that TAUTOLOGY.CHECKER
was a decision procedure.
.SS |The Formal Definition of TAUTOLOGY.CHECKER|
We now take on the role of the implementor.
The buyer's definitions and conjectures in the last {SUBSECTIONORSECTION} specify what
is required of TAUTOLOGY.CHECKER. As the implementor, we now define a function we claim
has the desired properties. Since the specified task is to write a simple
mechanical theorem prover, it happens (in this example) that the
implementor must appeal to some of the basic ideas in mechanical
theorem-proving.
.SSS |TAUTOLOGY.CHECKER|
The definition of TAUTOLOGY.CHECKER requires two subsidiary concepts:
.CROWN(8,0,0)
NORMALIZE, which given an expression returns an equivalent expression
in IF-normal form and
TAUTOLOGYP, which given an expression in IF-normal form
and a list of assumptions determines if the expression is
never F under those assumptions.
.ENDCROWN
Given NORMALIZE and TAUTOLOGYP we define
TAUTOLOGY.CHECKER as:
.ASIS
Definition.
(TAUTOLOGY.CHECKER X)
=
(TAUTOLOGYP (NORMALIZE X) "NIL").
.ENDASIS
.SSSS |NORMALIZE|
Recall that the basic idea behind NORMALIZE is to apply the
theorem
.ASIS
(EQUAL (IF (IF P Q R) LEFT RIGHT)
(IF P (IF Q LEFT RIGHT) (IF R LEFT RIGHT)))
.ENDASIS
as a rewrite rule until we have removed all IFs from the tests
of other IFs. Thus, to
normalize an expression x we proceed as follows:
.ASIS
If x is not an IF.EXPRP, we return x.
If x is of the form (IF test left right), then we ask
whether test is of the form (IF p q r).
If so, we return the result of normalizing the
expression (IF p (IF q left right)
(IF r left right)).
If not, we return the expression
(IF test left' right'), where left' and right'
are the results of normalizing left and right.
.ENDASIS
The formal definition of this process is:
.ASIS
Definition.
(NORMALIZE X)
=
(IF
(IF.EXPRP X)
(IF
(IF.EXPRP (TEST X))
(NORMALIZE (CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))))
(CONS.IF (TEST X)
(NORMALIZE (LEFT.BRANCH X))
(NORMALIZE (RIGHT.BRANCH X))))
X).
.ENDASIS
.SSSS |TAUTOLOGYP|
Now that we can put an expression into normal form, we
consider TAUTOLOGYP, which
determines whether an expression, x, in IF-normal form, is never F.
Recall that the basic idea is to explore
every branch through the IF-expression and check that either
the tests along the branch are contradictory or else that the output
of the branch is forced by the tests to be non-F. Our definition
requires that TAUTOLOGYP have a second argument, alist,
used to remember the tests that have been seen and whether
they are being assumed true or false on the current branch.
Since all the tests in a normalized IF-expression are variables (or else
the constants T or F) the alist of assumptions can also be thought of as an assignment to some
of the variables in x.
Here is how TAUTOLOGYP determines that x is never F under the assumptions in alist:
.CROWN(8,0,0)
If x is not an IF.EXPRP, then it is either T, F, or a variable.
.CROWN(8,0,0)
If x is T, then it is never F.
If x is F, then clearly it is "sometimes" F.
If x is neither T nor F, then it is a variable. If x is currently
assumed non-F, then x is never F under alist;
otherwise x is sometimes F.
.ENDCROWN
If x is an IF.EXPRP, say representing (IF test left right), then there
are three possibilities:
.CROWN(8,0,0)
If test (which must be a variable, T, or F) is T or assumed non-F in
alist, then x is never F under alist if and
only if left never is.
If test is F or assumed F in alist, then x is never F under
alist if and only if right never is.
Otherwise, x is never F under alist if and only
if both:
.CROWN(8,0,0)
left is never F under the assumptions in alist plus the additional
assumption that test is non-F, and
right is never F under the assumptions in alist plus the additional
assumption that test is F.
.ENDCROWN
.ENDCROWN
.ENDCROWN
To define TAUTOLOGYP formally we use four auxiliary functions:
.CROWN(8,0,0)
ASSIGNEDP, which determines whether a given variable is explicitly
assumed F or non-F in a given alist,
ASSIGNMENT (defined above), which returns the assumed value
of a variable in an alist,
ASSUME.TRUE, which adds to an alist the pair that indicates that
a given variable is being assumed non-F, and
ASSUME.FALSE, which adds to an alist the pair that indicates that
a given variable is being assumed F.
.ENDCROWN
The definitions of these functions are in {APP APPTHMS}. ASSIGNEDP is
very similar to ASSIGNMENT. ASSUME.TRUE and ASSUME.FALSE simply
CONS the appropriate pair onto the alist.
The formal definition of TAUTOLOGYP is:
.ASIS
Definition.
(TAUTOLOGYP X ALIST)
=
(IF
(IF.EXPRP X)
(IF (ASSIGNEDP (TEST X) ALIST)
(IF (ASSIGNMENT (TEST X) ALIST)
(TAUTOLOGYP (LEFT.BRANCH X) ALIST)
(TAUTOLOGYP (RIGHT.BRANCH X) ALIST))
(AND (TAUTOLOGYP (LEFT.BRANCH X)
(ASSUME.TRUE (TEST X) ALIST))
(TAUTOLOGYP (RIGHT.BRANCH X)
(ASSUME.FALSE (TEST X) ALIST))))
(ASSIGNMENT X ALIST)).
.ENDASIS
.SSS |Summary of the Simple Theorem-proving Ideas|
As implementor of the buyer's specifications, we claim that our
job is done:##TAUTOLOGY.CHECKER is a decision procedure
for the propositional calculus. Before discussing the proof of this assertion we review the
simple theorem-proving techniques illustrated:
.CROWN(8,0,0)
Terms can (and must) be represented as objects. In our case, we
used the shell facility to define a new class of objects, called
the IF-expressions.
Both NORMALIZE and TAUTOLOGYP illustrate how terms can be explored
mechanically.
The function NORMALIZE shows how a theorem can be exhaustively
applied as a rewrite rule in a mechanical way.
TAUTOLOGYP illustrates the use of alists of assumptions (manipulated
by the functions ASSUME.TRUE, ASSUME.FALSE, ASSIGNEDP, and ASSIGNMENT)
to remember one's context while exploring a formula.
The use of NORMALIZE to produce an equivalent
expression that is amenable to exploration by TAUTOLOGYP illustrates the
value of "simplification" even when it produces a larger expression.
.ENDCROWN
Our own proof techniques (in contrast to those of an implementor
concerned only with the propositional calculus), involve ideas such as those
above, but usually in much more elaborate
form. In fact, the next five {SECTIONORCHAPTER}s of this book
are concerned entirely with how we represent formulas, how we remember the assumptions governing
the subexpressions in an expression, and how we use rewrite
rules to simplify expressions.
.SS |The Mechanical Proofs|
We now describe the proofs of TAUTOLOGY.CHECKER.IS.SOUND
and TAUTOLOGY.CHECKER.IS.COMPLETE. The proofs are constructed entirely by our
mechanical theorem prover. However, the mathematician user of the system
plays an important role by suggesting that the theorem prover prove
certain lemmas first, thus making the system cognizant of truths that were not
evident to it previously. It is important to understand from the outset
that an incompetent human user may not be able to get the theorem prover
to admit that a valid conjecture is a theorem. On the other hand, the
user does not have to be trusted:##if a monkey were to cause the theorem prover
to announce that a conjecture were a theorem, the conjecture would indeed
be a theorem.
In this {SUBSECTIONORSECTION} we primarily play the role of the mathematician user.
However, occasionally we take
the role of the theorem prover to illustrate how the proofs
go. The precise user commands to
our theorem prover can be found in {APP APPTHMS}. Events CONS.IF through
TAUTOLOGY.CHECKER.IS.SOUND are what the user had to type
to define the necessary concepts and cause the theorem prover to prove the desired results.
.SSS |Complying with the Principle of Definition|
Before anything can be proved, the necessary concepts must be introduced. In particular, we
must introduce the CONS.IF shell class and the functions derived above.
Furthermore, the system must confirm that the shell principle and
the definition principle admit the definitions.
The introduction of CONS.IF is trivial. The only restrictions are syntactic
in nature and the system immediately adds the axioms indicated in
{YONSEC SECTHEFORMALTHEORY}.
As for the function definitions, the system must confirm that in each definition some
measure of the arguments is decreasing according to a well-founded
relation in every recursive call.
All but one of the functions
easily pass the test because either they have no
recursive calls (e.g., ASSUME.TRUE) or they do simple recursion on components of LISTPs or IF.EXPRPs
(e.g., ASSIGNMENT and TAUTOLOGYP) so that the COUNT of some
argument is always decreasing.
However, one function, namely NORMALIZE, provides a nontrivial challenge
because in one of its recursive calls the COUNT of its only argument
increases. Before the theorem prover will accept the
definition of NORMALIZE, we must lay a certain amount
of groundwork.
If the reader has not yet discovered a measure and well-founded relation
that decrease when NORMALIZE recurses, he is encouraged to do so before
reading further.
We know of several measures and well-founded relations justifying the definition of
NORMALIZE. We discuss only one of them, namely the first one we
discovered.
In general one has to justify all the recursive calls simultaneously.
That is, it will not do to find one measure
that goes down in one call and a different one that goes down in another
unless they can be lexicographically combined to account for all the
recursions. We will eventually exhibit such a lexicographic combination.
To derive it, we will start with the first recursive call in NORMALIZE, the
one in which the COUNT of its argument increases as a result of
transforming (IF (IF p q r) left right) to (IF p (IF q left right) (IF r left right)).
Consider the function IF.DEPTH:
.ASIS
Definition.
(IF.DEPTH X)
=
(IF (IF.EXPRP X)
(ADD1 (IF.DEPTH (TEST X)))
0).
.ENDASIS
IF.DEPTH is admitted under the principle of definition since it recurses
on components of IF.EXPRPs. In particular, the lemma
.ASIS
(IMPLIES (IF.EXPRP X)
(LESSP (COUNT (TEST X)) (COUNT X)))
.ENDASIS
(added by the shell mechanism when the CONS.IF shell
was axiomatized) is precisely the theorem required by the definition
principle.
Now that IF.DEPTH has been admitted, consider what it does:##it counts the
depth of IF-nesting in the TEST component of a propositional
IF-expression. Thus, when a function (such as NORMALIZE)
recurses by changing (IF (IF p q r) left right) to (IF p (IF q left right) (IF r left right)),
it drives down the IF.DEPTH of its argument, according to the well-founded
relation LESSP. Thus, the lemma
.ASIS
Theorem. IF.DEPTH.GOES.DOWN:
(IMPLIES
(AND (IF.EXPRP X) (IF.EXPRP (TEST X)))
(LESSP (IF.DEPTH (CONS.IF (TEST (TEST X)) Y Z))
(IF.DEPTH X)))
.ENDASIS
suggests a justification of NORMALIZE. The system proves IF.DEPTH.GOES.DOWN
using the definitions of LESSP and IF.DEPTH.
But now let us consider the other two recursive calls in NORMALIZE,
those that recurse on the LEFT.BRANCH and RIGHT.BRANCH of
IF.EXPRPs. If IF.DEPTH decreased according to LESSP in those recursions,
we would be finished:##IF.DEPTH would be a measure that got
LESSP-smaller in all recursions, and LESSP is well-founded.
But IF.DEPTH does not necessarily decrease in the last two recursions.
For example, the IF.DEPTH of the expression:
.ASIS
(IF X (IF (IF A B C) D E) Y)
.ENDASIS
is 1, while the IF.DEPTH of its LEFT.BRANCH is 2. In general, the IF.DEPTH
of a branch of an IF.EXPRP is unrelated to that of the expression itself
and might be arbitrarily bigger.
We remedy the situation by defining a second measure, called IF.COMPLEXITY,
and by proving that it gets LESSP-smaller on the latter two recursive
calls while not changing on the first recursive call. Given such results
it is clear that the measure:
.ASIS
(CONS (IF.COMPLEXITY X) (IF.DEPTH X))
.ENDASIS
gets lexicographically smaller on each call (using the well-founded
relation induced by LESSP and LESSP).
Defining IF.COMPLEXITY so that it that decreases on the branches of IF.EXPRPs is easy.
(For example, COUNT goes down.) But defining IF.COMPLEXITY so that it also stays
unchanged when (IF (IF p q r) left right) is transformed to
(IF p (IF q left right) (IF r left right)) is more difficult. The
definition of IF.COMPLEXITY that we use is:
.ASIS
Definition.
(IF.COMPLEXITY X)
=
(IF (IF.EXPRP X)
(TIMES (IF.COMPLEXITY (TEST X))
(PLUS (IF.COMPLEXITY (LEFT.BRANCH X))
(IF.COMPLEXITY (RIGHT.BRANCH X))))
1).
.ENDASIS
The three theorems:
.ASIS
Theorem. IF.COMPLEXITY.GOES.DOWN1:
(IMPLIES (IF.EXPRP X)
(LESSP (IF.COMPLEXITY (LEFT.BRANCH X))
(IF.COMPLEXITY X))),
Theorem. IF.COMPLEXITY.GOES.DOWN2:
(IMPLIES (IF.EXPRP X)
(LESSP (IF.COMPLEXITY (RIGHT.BRANCH X))
(IF.COMPLEXITY X))),
Theorem. IF.COMPLEXITY.STAYS.EVEN:
(IMPLIES
(AND (IF.EXPRP X) (IF.EXPRP (TEST X)))
(EQUAL
(IF.COMPLEXITY
(CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))))
(IF.COMPLEXITY X)))
.ENDASIS
establish that IF.COMPLEXITY has the desired properties. The system proves these
theorems using the definitions of LESSP and IF.COMPLEXITY,
together with the inductively proved lemma that IF.COMPLEXITY is never 0
and about 20 well-known lemmas about PLUS, TIMES,
and LESSP and the relations between them.
The user must have the theorem prover prove these 20 arithmetic
lemmas before it proves the IF.COMPLEXITY lemmas. We do not descend into
the proofs here. The statements of the lemmas are among those preceding
the tautology theorems in {APP APPTHMS}. (In fact, we had the system
prove these elementary arithmetic lemmas long before we even considered
the tautology problem; the system recalled them automatically during
the IF.COMPLEXITY proofs.)
Once the IF.COMPLEXITY theorems have been proved by the theorem prover (and thus
brought to its attention), the theorem prover accepts the definition
of NORMALIZE under our principle of definition and responds with:
.ASIS8
The lemmas IF.COMPLEXITY.GOES.DOWN1,
IF.COMPLEXITY.GOES.DOWN2, IF.COMPLEXITY.STAYS.EVEN and
IF.DEPTH.GOES.DOWN can be used to prove that:
(CONS (IF.COMPLEXITY X) (IF.DEPTH X))
decreases according to the well-founded lexicographic relation
induced by LESSP and LESSP in each recursive call. Hence,
NORMALIZE is accepted under the principle of definition.
Observe that:
(OR (IF.EXPRP (NORMALIZE X))
(EQUAL (NORMALIZE X) X))
is a theorem.
CPU time (devoted to theorem-proving):##1.388 seconds
.ENDASIS
It is important to note that the admissibility of NORMALIZE has been
__proved_ and in no way assumed. In particular, we defined certain
functions (IF.DEPTH and IF.COMPLEXITY) that were admitted to the theory
because of shell axioms. Then we proved certain theorems about those
functions, namely that the IF.DEPTHs (or IF.COMPLEXITYs) of certain
expressions were LESSP-smaller than those of others. Some of these
theorems required induction to prove -- inductions justified by shell
axioms. Finally, invoking the theorems just proved, the
well-foundedness of LESSP, and the principle of lexicographic relations, we
exhibited a measure and well-founded relation justifying the definition
of NORMALIZE. Note
further that the newly invented measure and well-founded relation
permit an induction not permitted by the shell axioms alone -- an induction
in which we may assume an instance about (IF p (IF q left right) (IF r left right)) while trying to prove a conjecture about (IF (IF p q r) left right).
.SSS |Mechanical Proof of TAUTOLOGY.CHECKER.IS.SOUND|
Now we turn our attention to the proofs of our main theorems.
To enable the theorem prover to prove TAUTOLOGY.CHECKER.IS.SOUND we decompose the problem
into three main lemmas establishing properties of NORMALIZE and TAUTOLOGYP,
the two "subroutines" of TAUTOLOGY.CHECKER. To prove one of these main lemmas
the theorem prover needs several subsidiary lemmas about assignments. Below we present the
decomposition, the subsidiary
lemmas, and the proofs of the main lemmas. Finally, we combine
the main lemmas to prove TAUTOLOGY.CHECKER.IS.SOUND.
.SSSS |Decomposition|
We can establish that TAUTOLOGY.CHECKER recognizes only tautologies by proving that:
.CROWN(8,0,0)
When TAUTOLOGYP returns non-F on an expression in
IF-normal form, the value of the expression is non-F under all assignments,
NORMALIZE produces expressions in IF-normal form, and
NORMALIZE produces an expression with the same VALUE
as its input (so that if one is a tautology, the other is also).
.ENDCROWN
Note that this was exactly the decomposition of the problem employed
when we, in the role of the implementor, defined TAUTOLOGY.CHECKER.
We define NORMALIZED.IF.EXPRP to be the recursive function that determines
whether or not an expression is in IF-normal form (see {APP APPTHMS}).
The formal statements of the three main lemmas are:
.ASIS
Theorem. TAUTOLOGYP.IS.SOUND:
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X A1))
(VALUE X (APPEND A1 A2))),
Theorem. NORMALIZE.NORMALIZES:
(NORMALIZED.IF.EXPRP (NORMALIZE X)),
Theorem. NORMALIZE.IS.SOUND:
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A)).
.ENDASIS
Note that the first lemma is more general than required by the decomposition.
The decomposition calls for:
.ASIS
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X "NIL"))
(VALUE X A)).
.ENDASIS
That is, if X is in IF-normal form and (TAUTOLOGYP X "NIL")
is non-F, then the VALUE of X is non-F under all assignments.
The more general
TAUTOLOGYP.IS.SOUND, which can be proved by induction, says that if X is in IF-normal form and
(TAUTOLOGYP X A1) is non-F, then the VALUE of X is
non-F under any assignment having A1 as an initial segment. TAUTOLOGYP.IS.SOUND
reduces to the desired lemma when A1 is "NIL", since (APPEND "NIL" A2) is A2.
.SSSS |Subsidiary Lemmas|
Before proving the three main lemmas, we make explicit four facts
about assignments and VALUE.
First, since ASSIGNMENT returns F if the variable in question is not explicitly
assigned in A, we conclude that when (ASSIGNMENT X A) is non-F,
X must be explicitly assigned:
.ASIS
Theorem. ASSIGNMENT.IMPLIES.ASSIGNEDP:
(IMPLIES (ASSIGNMENT X A)
(ASSIGNEDP X A)).
.ENDASIS
Second, since ASSIGNMENT returns the first assignment it finds for
X in an alist, the assignment of X in the alist (APPEND A B) is either the
assignment of X in A (if X is explicitly assigned in A) or
else is the assignment of X in B:
.ASIS
Theorem. ASSIGNMENT.APPEND:
(EQUAL (ASSIGNMENT X (APPEND A B))
(IF (ASSIGNEDP X A)
(ASSIGNMENT X A)
(ASSIGNMENT X B))).
.ENDASIS
Third, if an alist contains a pair that can be deleted without changing
the assignment of the variable involved, then the value of any
expression under the original alist is equal to that under the shorter
alist. In particular, if VAR already has value VAL in A, then
the value of any given expression under (CONS (CONS VAR VAL) A) is the same as its value
under A.
Since we are interested only in whether VALUEs of expressions
are F or non-F, we can generalize the theorem to:
.ASIS
(IMPLIES (IFF VAL (ASSIGNMENT VAR A))
(IFF (VALUE X (CONS (CONS VAR VAL) A))
(VALUE X A))),
.ENDASIS
where (IFF X Y) is T if X and Y are both F or both non-F and F otherwise.
In order to make the lemma useful as a rewrite rule, we actually express
it as two implications:
.ASIS
Theorem. VALUE.CAN.IGNORE.REDUNDANT.ASSIGNMENTS:
(AND
(IMPLIES (AND (IFF VAL (ASSIGNMENT VAR A))
(VALUE X A))
(VALUE X (CONS (CONS VAR VAL) A)))
(IMPLIES (AND (IFF VAL (ASSIGNMENT VAR A))
(NOT (VALUE X A)))
(NOT (VALUE X (CONS (CONS VAR VAL) A))))).
.ENDASIS
Fourth, and finally, if X is an IF.EXPRP and is in IF-normal form,
then the VALUE of (TEST X) under A is just the assignment of (TEST X) in
A:
.ASIS
Theorem. VALUE.SHORT.CUT:
(IMPLIES (AND (IF.EXPRP X)
(NORMALIZED.IF.EXPRP X))
(EQUAL (VALUE (TEST X) A)
(ASSIGNMENT (TEST X) A))).
.ENDASIS
The proofs of these four lemmas are all straightforward. The first three
are proved by induction and the fourth is immediate from the definitions
of NORMALIZED.IF.EXPRP and VALUE. We do not discuss the proofs.
.SSSS |Main Lemmas|
We now return to the main lemmas in the
decomposition of TAUTOLOGY.CHECKER.IS.SOUND. The hardest of these lemmas is
the first:
.ASIS
Theorem. TAUTOLOGYP.IS.SOUND:
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X A1))
(VALUE X (APPEND A1 A2))).
.ENDASIS
We now sketch the machine's proof. Let (p X A1 A2) be a schematic
representation of the above conjecture. The machine describes
its induction analysis as follows:
.ASIS8
Let us appeal to the induction principle. The
recursive terms in the conjecture suggest four inductions.
They merge into three likely candidate inductions, none of
which is unflawed. However, one is more likely than the
others. We will induct according to the following scheme:
(AND (IMPLIES (NOT (IF.EXPRP X))
(p X A1 A2))
(IMPLIES (AND (IF.EXPRP X)
(p (RIGHT.BRANCH X)
(CONS (CONS (TEST X) F) A1)
A2)
(p (LEFT.BRANCH X)
(CONS (CONS (TEST X) T) A1)
A2)
(p (RIGHT.BRANCH X) A1 A2)
(p (LEFT.BRANCH X) A1 A2))
(p X A1 A2))).
The inequalities LEFT.BRANCH.LESSP and RIGHT.BRANCH.LESSP
establish that the measure (COUNT X) decreases according
to the well-founded relation LESSP in the induction step
of the scheme. Note, however, the inductive instances
chosen for A1.
.ENDASIS
(The inequalities LEFT.BRANCH.LESSP and RIGHT.BRANCH.LESSP
are axioms added by the addition of the CONS.IF shell.)
The base case (in which X is not an IF.EXPRP) can be simplified to:
.ASIS
(IMPLIES (AND (NOT (IF.EXPRP X))
(ASSIGNMENT X A1))
(ASSIGNMENT X (APPEND A1 A2)))
.ENDASIS
by applying the definitions of NORMALIZED.IF.EXPRP, TAUTOLOGYP, and VALUE,
and further reduces to T using ASSIGNMENT.APPEND and ASSIGNMENT.IMPLIES.ASSIGNEDP.
The induction step is considerably more complicated. We break our analysis
of it into two cases according to the VALUE of (TEST X) under (APPEND A1 A2),
which, by VALUE.SHORT.CUT and ASSIGNMENT.APPEND, gives rise to
many cases depending on whether (TEST X) is assigned in A1 or A2 and what
the assignment is. We sketch just one of these cases to indicate
how the proof goes.
Suppose that (TEST X) is unassigned in A1 and has a non-F assignment
in A2. The conclusion, (p X A1 A2), of the induction step
simplifies to:
.ASIS
~concl (IMPLIES (AND (NOT (IF.EXPRP (TEST X)))
(NORMALIZED.IF.EXPRP (LEFT.BRANCH X))
(NORMALIZED.IF.EXPRP (RIGHT.BRANCH X))
(TAUTOLOGYP (LEFT.BRANCH X)
(CONS (CONS (TEST X) T) A1))
(TAUTOLOGYP (RIGHT.BRANCH X)
(CONS (CONS (TEST X) F) A1)))
(VALUE (LEFT.BRANCH X) (APPEND A1 A2)))
.ENDASIS
using the definitions of NORMALIZED.IF.EXPRP, TAUTOLOGYP, and VALUE,
the lemmas ASSIGNMENT.APPEND and ASSIGNMENT.IMPLIES.ASSIGNEDP,
and the case assumptions about the assignment of (TEST X).
Consider the second induction hypothesis
.ASIS
(p (LEFT.BRANCH X) (CONS (CONS (TEST X) T) A1) A2),
.ENDASIS
which, after applying the definition of APPEND, is:
.ASIS
~hyp (IMPLIES (AND (NORMALIZED.IF.EXPRP (LEFT.BRANCH X))
(TAUTOLOGYP (LEFT.BRANCH X)
(CONS (CONS (TEST X) T) A1)))
(VALUE (LEFT.BRANCH X)
(CONS (CONS (TEST X) T) (APPEND A1 A2)))).
.ENDASIS
By virtue of ASSIGNMENT.APPEND and our case analysis, we know that
(TEST X) is already assigned non-F in (APPEND A1 A2). Thus, by VALUE.CAN.IGNORE.REDUNDANT.ASSIGNMENTS,
the pair
(CONS (TEST X) T) can be deleted from the alist (CONS (CONS (TEST X) T) (APPEND A1 A2))
(occurring in the conclusion of ~hyp above)
without changing the truth-value of any expression.
That is, we know that ~hyp is equivalent to
.ASIS
~hyp' (IMPLIES (AND (NORMALIZED.IF.EXPRP (LEFT.BRANCH X))
(TAUTOLOGYP (LEFT.BRANCH X)
(CONS (CONS (TEST X) T) A1)))
(VALUE (LEFT.BRANCH X)
(APPEND A1 A2))).
.ENDASIS
Since ~hyp' propositionally implies the induction conclusion, ~concl, we have
completed the proof of the case in which (TEST X) is unassigned in A1 and
assigned non-F in A2.
The remaining cases of the induction step are similar.
The proofs of the two NORMALIZE lemmas, namely that NORMALIZE produces expressions
in IF-normal form while preserving their values, are straightforward by
induction. However, the inductions are interesting
because of the unusual recursion in NORMALIZE. To illustrate the induction, we exhibit the
machine's proof of NORMALIZE.IS.SOUND. The proof of NORMALIZE.NORMALIZES is similar.
.ASIS
Theorem. NORMALIZE.IS.SOUND:
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A))
.ENDASIS
.ASIS8
Give the conjecture the name *1.
Perhaps we can prove it by induction. The recursive
terms in the conjecture suggest two inductions, neither of
which is unflawed, and both of which appear equally likely.
So we will choose the one that will probably lead to
eliminating the nastiest expression. We will induct
according to the following scheme:
(AND
(IMPLIES (NOT (IF.EXPRP X)) (p X A))
(IMPLIES
(AND (IF.EXPRP X)
(IF.EXPRP (TEST X))
(p (CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X)))
A))
(p X A))
(IMPLIES (AND (IF.EXPRP X)
(NOT (IF.EXPRP (TEST X)))
(p (RIGHT.BRANCH X) A)
(p (LEFT.BRANCH X) A))
(p X A))).
The inequalities IF.COMPLEXITY.GOES.DOWN1,
IF.COMPLEXITY.GOES.DOWN2, IF.COMPLEXITY.STAYS.EVEN and
IF.DEPTH.GOES.DOWN establish that the measure:
(CONS (IF.COMPLEXITY X) (IF.DEPTH X))
decreases according to the well-founded lexicographic relation
induced by LESSP and LESSP in each induction step of the
scheme. The above induction scheme generates three new
conjectures:
Case 1. (IMPLIES (NOT (IF.EXPRP X))
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A))).
This simplifies, unfolding NORMALIZE and VALUE, to:
(TRUE).
Case 2. (IMPLIES
(AND
(IF.EXPRP X)
(IF.EXPRP (TEST X))
(EQUAL
(VALUE
(NORMALIZE
(CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))))
A)
(VALUE (CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X)))
A)))
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A))),
which we simplify, applying RIGHT.BRANCH.CONS.IF,
LEFT.BRANCH.CONS.IF and TEST.CONS.IF, and expanding the
definitions of VALUE and NORMALIZE, to:
(TRUE).
Case 3. (IMPLIES
(AND (IF.EXPRP X)
(NOT (IF.EXPRP (TEST X)))
(EQUAL (VALUE (NORMALIZE (RIGHT.BRANCH X)) A)
(VALUE (RIGHT.BRANCH X) A))
(EQUAL (VALUE (NORMALIZE (LEFT.BRANCH X)) A)
(VALUE (LEFT.BRANCH X) A)))
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A))).
This simplifies, appealing to the lemmas
RIGHT.BRANCH.CONS.IF, LEFT.BRANCH.CONS.IF and
TEST.CONS.IF, and unfolding the functions NORMALIZE and
VALUE, to:
(TRUE).
That finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##8.853 seconds
.ENDASIS
The induction performed above is analogous to the recursion in NORMALIZE.
There is a base case for the possibility that X is not a CONS.IF and
there are two induction steps. In the first, X is assumed to be of the
form (IF (IF p q r) left right) and a single inductive instance is provided, in which X is replaced by
(IF p (IF q left right) (IF r left right)). In the second, X is assumed to be of the
form (IF p left right), where p is not an IF-expression, and two inductive instances are
provided, one in which X is replaced by left and the other in which X is replaced by right.
The induction is justified by the measure and well-founded relation
justifying NORMALIZE. The simplifications of the three cases of the induction
rely upon definitions and the axioms of the CONS.IF shell.
.SSSS |TAUTOLOGY.CHECKER.IS.SOUND|
The proof of TAUTOLOGY.CHECKER.IS.SOUND
follows immediately from our three main lemmas, given the following
"bridge" lemma:
.ASIS
Theorem. TAUTOLOGY.CHECKER.SOUNDNESS.BRIDGE:
(IMPLIES (AND (TAUTOLOGYP Y A1)
(NORMALIZED.IF.EXPRP Y)
(EQUAL (VALUE X A2)
(VALUE Y (APPEND A1 A2))))
(VALUE X A2)).
.ENDASIS
The bridge lemma tells the mechanical theorem prover that to prove
that (VALUE X A2) is true it is sufficient to show that it is
equal to (VALUE Y (APPEND A1 A2)), where Y is in IF-normal form
and a TAUTOLOGYP under A1. The bridge lemma is trivial to prove:
the result of substituting (VALUE Y (APPEND A1 A2)) for (VALUE X A2) in the bridge lemma is
an instance of TAUTOLOGYP.IS.SOUND.
Without the bridge lemma, the mechanical theorem prover would not
consider "reducing" a problem about (VALUE X A) to one about
(VALUE (NORMALIZE X) (APPEND "NIL" A)), which is a necessary step in our
decomposition of the problem.
Given the bridge, the proof of
.ASIS
Theorem. TAUTOLOGY.CHECKER.IS.SOUND:
(IMPLIES (TAUTOLOGY.CHECKER X)
(VALUE X A))
.ENDASIS
is trivial. After replacing TAUTOLOGY.CHECKER by its definition,
the theorem prover obtains:
.ASIS
(IMPLIES (TAUTOLOGYP (NORMALIZE X) "NIL")
(VALUE X A)).
.ENDASIS
But the theorem prover can derive the above conjecture
from the bridge lemma as follows.
It instantiates the bridge lemma, replacing Y by (NORMALIZE X),
A1 by "NIL" and A2 by A:
.ASIS
(IMPLIES (AND (TAUTOLOGYP (NORMALIZE X) "NIL")
(NORMALIZED.IF.EXPRP (NORMALIZE X))
(EQUAL (VALUE X A)
(VALUE (NORMALIZE X)
(APPEND "NIL" A))))
(VALUE X A)).
.ENDASIS
The second hypothesis reduces to T by NORMALIZE.NORMALIZES and the
third reduces to T by NORMALIZE.IS.SOUND and the definition of APPEND.
After thus removing these true hypotheses the theorem prover obtains:
.ASIS
(IMPLIES (TAUTOLOGYP (NORMALIZE X) "NIL")
(VALUE X A)).
.ENDASIS
Q.E.D.
.SSS |Mechanical Proof of TAUTOLOGY.CHECKER.IS.COMPLETE|
All of the above proof steps were described from the theorem prover's
point of view. We now turn our attention to the proof of:
.ASIS
Theorem. TAUTOLOGY.CHECKER.IS.COMPLETE:
(IMPLIES (NOT (TAUTOLOGY.CHECKER X))
(EQUAL (VALUE X (FALSIFY X)) F)),
.ENDASIS
and describe it from the user's point of view.
.SSSS |FALSIFY|
In our scenario, neither the buyer nor the implementor were
required to define FALSIFY. However, before the theorem prover can prove
TAUTOLOGY.CHECKER.IS.COMPLETE the
mathematician user must define FALSIFY.
Recall that FALSIFY must return an assignment that falsifies any expression
not recognized by our tautology checker.
The definition of FALSIFY is extremely similar to that of TAUTOLOGY.CHECKER. FALSIFY
puts the expression into IF-normal form with NORMALIZE and
tries to construct a falsifying assignment for that equivalent
expression, using a function called FALSIFY1 that is
very similar to TAUTOLOGYP.
FALSIFY1 walks through a normalized IF-expression with an alist that
assigns values to some variables. The function
tries to extend that alist to one that falsifies the current expression.
FALSIFY1 returns F if it
fails to find such an alist, and otherwise returns the
extended alist. The following two observations
are basic to how FALSIFY1 works:
.CROWN(8,0,0)
An unassigned variable can be falsified by assuming it false.
(IF test left right), where test is an unassigned variable,
can be falsified by assuming test true and falsifying left (if possible)
or by assuming test false and falsifying right (if possible).
.ENDCROWN
Of course, FALSIFY1 must respect its current assignments (e.g., if the
test of an IF is already assigned, FALSIFY1 must try to falsify the appropriate
branch).
The definitions of FALSIFY1 and FALSIFY are:
.ASIS
Definition.
(FALSIFY1 X ALIST)
=
(IF (IF.EXPRP X)
(IF (ASSIGNEDP (TEST X) ALIST)
(IF (ASSIGNMENT (TEST X) ALIST)
(FALSIFY1 (LEFT.BRANCH X) ALIST)
(FALSIFY1 (RIGHT.BRANCH X) ALIST))
(IF (FALSIFY1 (LEFT.BRANCH X)
(ASSUME.TRUE (TEST X) ALIST))
(FALSIFY1 (LEFT.BRANCH X)
(ASSUME.TRUE (TEST X) ALIST))
(FALSIFY1 (RIGHT.BRANCH X)
(ASSUME.FALSE (TEST X) ALIST))))
(IF (ASSIGNEDP X ALIST)
(IF (ASSIGNMENT X ALIST) F ALIST)
(CONS (CONS X F) ALIST))).
Definition.
(FALSIFY X)
=
(FALSIFY1 (NORMALIZE X) "NIL").
.ENDASIS
Both definitions are accepted immediately by the theorem prover.
.SSSS |Sketch of the Proof of TAUTOLOGY.CHECKER.IS.COMPLETE|
We prove that if TAUTOLOGY.CHECKER returns F then there exists
a falsifying assignment by proving that:
.CROWN(8,0,0)
when TAUTOLOGYP fails to recognize a normalized IF-expression,
FALSIFY1 returns an assignment (rather than F) on the expression, and
if FALSIFY1 returns an assignment (rather than F) for a normalized IF-expression,
then the value of the expression under the assignment is F.
.ENDCROWN
The formal statements of these lemmas are:
.ASIS
Theorem. TAUTOLOGYP.FAILS.MEANS.FALSIFY1.WINS:
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(NOT (TAUTOLOGYP X A))
A)
(FALSIFY1 X A)),
Theorem. FALSIFY1.FALSIFIES:
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(FALSIFY1 X A))
(EQUAL (VALUE X (FALSIFY1 X A)) F)).
.ENDASIS
TAUTOLOGY.CHECKER.IS.COMPLETE follows from the above two
lemmas and NORMALIZE.NORMALIZES and NORMALIZE.IS.SOUND. To get
the theorem prover to put them together in the desired way,
a "bridge" version of FALSIFY1.FALSIFIES is required:
.ASIS
Theorem. TAUTOLOGY.CHECKER.COMPLETENESS.BRIDGE:
(IMPLIES (AND (EQUAL (VALUE Y (FALSIFY1 X A))
(VALUE X (FALSIFY1 X A)))
(FALSIFY1 X A)
(NORMALIZED.IF.EXPRP X))
(EQUAL (VALUE Y (FALSIFY1 X A)) F)).
.ENDASIS
The proof of the bridge is trivial using FALSIFY1.FALSIFIES.
All that remains is to prove FALSIFY1.FALSIFIES
and TAUTOLOGYP.FAILS.MEANS.FALSIFY1.WINS. These two theorems
yield immediately to the correct induction provided the previously
proved ASSIGNMENT.IMPLIES.ASSIGNEDP and VALUE.SHORT.CUT are used and
the following property of FALSIFY1 is known by the theorem prover:##if VAR is explicitly assigned in A, then the
assignment of VAR in (FALSIFY1 X A) is the assignment of VAR in
A if (FALSIFY1 X A) is non-F.
The formal statement of the relationship between FALSIFY1 and ASSIGNMENT
is:
.ASIS
Theorem. FALSIFY1.EXTENDS.MODELS:
(IMPLIES (ASSIGNEDP X A)
(EQUAL (ASSIGNMENT X (FALSIFY1 Y A))
(IF (FALSIFY1 Y A)
(ASSIGNMENT X A)
(EQUAL X T)))).
.ENDASIS
This property of FALSIFY1 is a crucial aspect of the process of
falsification:##it is illegal to change the assignment of a
variable in midstream. FALSIFY1.EXTENDS.MODELS is proved by induction.
The proof appeals to the previously proved ASSIGNMENT.IMPLIES.ASSIGNEDP.
.SS |Summary|
The theorem prover (with some guidance from the user) has
thus established that TAUTOLOGY.CHECKER is well-defined, only recognizes
tautologies, and recognizes all tautologies.
It is worthwhile to summarize our objectives in this {SECTIONORCHAPTER}.
Hopefully, the reader better understands our theory and
its expressive power. The utility and power of IF
and the convenience of T and F as objects was demonstrated.
The shell principle was used to introduce IF-expressions as objects. The use of measures
and well-founded relations to justify recursive definitions was illustrated.
In addition, we demonstrated how we could justify definitions by introducing
new measures and proving theorems establishing that the measures decrease.
We also illustrated the induction principle in use.
Finally, FALSIFY illustrated
how we use recursive functions to express existential quantification.
Advocates of quantification may feel that our lack of quantification makes
it difficult for us to state certain conjectures. We agree; but we
observe that the use of explicit existential quantification
makes it more difficult to find constructive proofs. Any constructive
proof of a conjecture involving existential quantification (such as the
proposition that when TAUTOLOGY.CHECKER returns F on an
expression there exists a falsifying assignment)
must exhibit a method (such as FALSIFY)
for obtaining the objects alleged to exist.
The second objective of this {SECTIONORCHAPTER} was to expose the
reader to our proof techniques and to indicate the role of the user in the
theorem-proving process. Perhaps the easiest way to summarize
the description of the proofs is to note that
the proof of TAUTOLOGY.CHECKER.IS.COMPLETE
is in many ways harder than the proof of TAUTOLOGY.CHECKER.IS.SOUND
but that our discussion of it was much more brief. The reason is that we
presented a good deal of the proof of TAUTOLOGY.CHECKER.IS.SOUND
from the theorem prover's
point of view:##we talked about such things as induction schemes,
case splitting, and use of function definitions and previously proved theorems.
The discussion of TAUTOLOGY.CHECKER.IS.COMPLETE, on the other hand, was almost
entirely from the user's point of view:##we talked about the concepts
and "obvious" relationships that hold between them, and left the proofs to
the theorem prover.
The third objective of this {SECTIONORCHAPTER} was to
illustrate briefly some simple theorem-proving ideas. We illustrated how to
represent and manipulate terms mechanically, how to use theorems to rewrite
expressions, and how to maintain a representation of one's knowledge about
the context of a term in an expression.
Finally, let us note one unstated objective: illustrating the value of definitions
and proofs. Consider what the mathematician user of the theorem
prover must tell the buyer when the final proof is completed.
He can say, simply, "Here is the function you ordered.
Your two conjectures are theorems. Go in peace." The mathematician
does not have to mention the decomposition of the problem, because all
the lemmas were proved. Furthermore, he does not have to mention
NORMALIZED.IF.EXPRP or any of the other functions not written
by the buyer, because those functions were all
introduced under the principle of definition. In contrast, consider
the mathematician's duty to the buyer had the proofs required adding
nondefinitional axioms about concepts (even concepts, such as NORMALIZED.IF.EXPRP,
not involved in the statement of the main results but just in their proofs);
he would have had to say "I'm afraid we did not
prove your conjectures. However, I have managed to shift the burden of proof
back to you. If you will just accept these few axioms..."
.SS |Notes|
Church, on pages 129 to 132 of
{REF CHURCH}, discusses a formulation of the propositional
calculus very similar to ours. He uses [B, A, C] to
denote what we denote by (IF A B C). Interestingly, he
suggests the oral reading: "[p, q, r]" is "p or r according as
q or not q." Church's version of propositional calculus differs
from ours principally because our IF may return arbitrary
objects, not merely truth values. It is odd that logicians
have not sufficiently seen the utility of IF to include
it in their formal theories. To our knowledge, McCarthy {REF MCCARTHYBASIS}
first introduced the IF we use.
We are grateful to Greg Nelson, of Stanford University, who first
suggested that we try to prove TAUTOLOGYP.IS.SOUND. We tried to do so
several months before beginning to write this book and failed, primarily
because, as users of the system, we failed to see the importance of
VALUE.CAN.IGNORE.REDUNDANT.ASSIGNMENTS. After beginning the book we
realized it would be beneficial to take advantage of the
theory's expressive power to exhibit a simple theorem prover in it.
Thus, we returned to the TAUTOLOGYP example with the results reported above.
We then elaborated it by introducing NORMALIZE and TAUTOLOGY.CHECKER,
and proving that TAUTOLOGY.CHECKER is a decision procedure.
The entire effort required
about 12 hours of real time by one of the authors playing the role of
the buyer, implementor, and user. Most of that time was spent
watching the theorem prover failing to prove theorems, figuring out the facts
that were "obvious" to the user but unknown to the system, and instructing
the system to prove those facts as lemmas.
The total amount of computer
time expended to check all the definitions and prove all the theorems
in the final sequence
is about 10 minutes.
.SEC |AN OVERVIEW OF HOW WE PROVE THEOREMS|, SECPROVE:
In this and the next ten {SECTIONORCHAPTER}s, we describe some techniques
for proving theorems in our theory. In fact, we describe how
our mechanical theorem-proving program works. The reader familiar with mechanical
theorem-proving should be able to reconstruct our theorem prover from these
discussions. However, the reader
not familiar with mechanical theorem-proving will be able to follow our
presentation without difficulty.
No knowledge of computer programming is required, but we describe
our proof techniques in complete detail and leave no important
decisions to the reader's imagination.
.SS |The Role of the User|
Suppose that someone, whom we shall call "the user," has
conjectures that he wants proved by a very
careful but unimaginative device that we shall call "the
theorem prover."
The user typically intuits a theorem and perhaps
even sketches a proof on paper.
We assume the user is willing to help
the theorem prover by formulating the conjectures in the most general
way and by laying appropriate groundwork.
We require that when the user brings a conjecture
to the theorem prover's attention (by asking it to prove it or assume it as an axiom), he give
the theorem prover
hints regarding how the theorem should be used subsequently.
A theorem may be used in any of four ways:
as a rewrite, elimination, generalization, or induction lemma.
Rewrite lemmas are used to simplify conjectures by replacing terms with other
terms. Elimination lemmas are used to remove certain "undesirable"
expressions from conjectures. Generalization lemmas point out properties
of terms that are good to keep in mind when generalizing formulas.
Induction lemmas point out that a given operation drives a given
measure down according to some well-founded relation.
The precise meaning of these lemma types will be
provided when we describe our heuristics for proving theorems.
When the user suggests the types for a lemma, he is not merely suggesting
that the lemma can be used in the ways indicated
(that can be checked mechanically),
but that he wants the lemma to be used in the ways indicated.
.SS |Clausal Representation of Conjectures|
We now present the concept of clause as used in our
theorem prover. Through the remainder of this
work,
a __clause_ is a list of terms. The meaning that we attach to
a clause is the disjunction of its members.
Following Robinson {REF ROBINSON}, we sometimes delimit
clauses with set brackets.
For example, if p, q, and r are terms, the clause $a{p, q, r}
is the list of the three terms p, q, and r and means p=$m-1/F,
q=$m-1/F, or r=$m-1/F.
Sometimes we display clauses as terms to make them easier
to read. We may display the clause $a{p, (NOT q), r} as
(IMPLIES (AND (NOT p) q) r), we may display the clause
$a{p, q} as (IMPLIES (NOT p) q), and we may display the
clause $a{p} as p.
In the remainder of this book, whenever we refer to a conjecture,
theorem, or formula being manipulated by the theorem-proving program,
the reader should understand that a clause is being processed.
The
members of a clause are called __literals_.
If a literal p has the form (NOT atm), then the __atom_ of p is atm, and
otherwise the __atom_ of p is p.
Because our earlier work {REF JACM} did not use clauses and because many
researchers in mechanical theorem-proving have come to believe
that using clauses is counterproductive, we now explain
why we choose to use them.
The basic propositional connective in our theory is IF.
Consider how we might represent a term such as (IF p T q),
where p and q are Boolean (i.e., always
return T or F).
(IF p T q) is
the term representing (OR p q). When we recursively explore (IF p T q)
with a process such as TAUTOLOGYP, we naturally have assumed
that p is false when we encounter q. But when we encounter p, we have assumed
nothing about q, because we have not yet seen q. But (IF p T q)
is equal to (IF q T p), and thus, when we encounter p, we could assume
q false. The asymmetry is magnified if the q in (IF p T q) is itself
an IF-expression, such as (IF r s t), for then when we encounter p we
should actually note that either (a) r is true and s is false, or
(b) r is false and t is false.
To avoid this asymmetry, we reduce
a term containing an IF to an IF-free conjunction of clauses.
It is easy to put an expression into this form by using
the fact that (IF p q r) is a theorem if and only if the two
clauses $a{(NOT p) q} and $A{p r} are theorems.
The clauses for an IF-expression
correspond to the branches through the IF-normal form of the expression.
If we are trying to prove a clause, then when we consider any
given literal of it, we assume the remaining literals false.
Furthermore, if we ever manage to reduce a literal to T (or any other non-F
expression), the clause is true, and if we ever manage to reduce a literal
to F, we remove that literal from the clause.
.SS |The Organization of Our Heuristics|
When should induction be used? We believe that induction should
only be used as a last resort when all other methods of
proof have failed. Furthermore, we believe that
induction should be applied only to the most simple
and generally stated propositions possible.
To this end we have developed a series of heuristics for
preparing formulas for induction:
.CROWN(8,8,0)
Simplify the conjecture by applying axioms, rewrite lemmas, and
function definitions and by converting the conjecture to a
conjunction of IF-free clauses. Sometimes simplification will prove
the conjecture. When it does not, at least it will reduce
the complexity of the conjecture.
When possible, reformulate the conjecture to eliminate "undesirable"
concepts.
Use equalities and then throw them away.
Generalize the conjecture by introducing variables for terms that
have "played their role."
Eliminate irrelevant terms from the conjecture.
.ENDCROWN
We apply first the safest operations (those, such as simplification,
that always convert a conjecture into an equivalent one)
before trying more daring operations (such as generalization).
Induction is applied last for two reasons:##It is difficult
to invent the right induction argument for anything but the
simplest, strongest conjecture available, and induction
increases the size and complexity of the conjecture.
Given a conjecture to prove,
we apply the above heuristics in the order listed. Each of these heuristics can be
regarded as taking a clause as input and returning a set of clauses as
output. If each of the output clauses is a theorem, the input clause is a theorem. Thus,
each of the output clauses is to be proved instead of the input. To get the process
started on a user-supplied term, p, we start with the unit clause
$a{p$a}.
Sometimes a clause is proved by one of these heuristics,
in which case the empty set of clauses is returned. If a heuristic
cannot prove or improve its input clause, it
returns the singleton set containing
the input, and then the next heuristic is tried. But if a heuristic changes
its input, then we recursively start the whole sequence of heuristics
over again on each of the output clauses.
A clause only emerges from this sequence of heuristics when it
can no longer be changed by any of them.
A good metaphor for the organization of these heuristics is
an initially dry waterfall. One pours out a clause at the top.
It trickles down and is split into pieces. Some pieces evaporate as
they are proved. Others are further split up and simplified. Eventually
at the bottom a pool of clauses forms whose
conjunction suffices to prove the original formula.{FNOTE |The only thing wrong with
. this analogy is that our waterfall is recursive:##every time a
. clause splits up, no matter how far down the waterfall, the pieces spill
. over the top of the fall.|}
We clean up this pool by removing any
clause that is a substitution instance of another (i.e.,
we delete subsumed clauses).
Having thus obtained the simplest and most
general set of clauses we know how, we attempt to prove
each by induction.{FNOTE |There are theorems that seem to require induction
. on a conjunction of formulas to permit sufficiently strong induction
. hypotheses. A classic example is the theorem that (GCD X Y) divides both
. X and Y (rather than just one of them). We do not know mechanical ways of recognizing this
. situation. Thus, if the user has stated a conjecture
. that, by the time it first reaches the induction stage, has been split into
. two or more formulas, we abandon the work we did to split the
. conjecture up and go into induction on the
. original formula, assuming the user would not have suggested
. that we prove a conjunction of two conjectures, each of which
. required an inductive proof, unless induction on their
. conjunction is necessary. After the first induction, this restriction is no
. longer applied.|}
We choose a clause, remove it from the pool,
invent an induction scheme for it,
and generate a conjunction of new clauses to prove (the base case
and the induction steps).
We then try to prove each of the new clauses by pouring each of them
over the waterfall. Descendants of these clauses may
also eventually trickle into the
same pool from which we drew the one upon which
we inducted. If we are successful, then eventually no
clause will be in the pool or trickling over the waterfall.
We will have proved the original conjecture.
.SS |The Organization of Our Presentation|
In the next ten {SECTIONORCHAPTER}s, we present the details of the
various heuristics we have developed.
We begin the presentation with a general discussion of how we extract
from an expression certain information about the type of its value and how
such information is used to help us keep track of what we know
in any given context.
Then we discuss how rewrite axioms and theorems are used to
rewrite terms. Following that, we explain how we use
function definitions. After these three topics have been discussed,
we describe how they are used to simplify clauses.
We thus devote four chapters to simplification.
Recall that simplification is the first
of the heuristics
we apply when trying to prove a theorem. After simplification, there follow the elimination
of "undesirables," utilization of equalities, generalization, and the elimination
of irrelevant terms. A {SECTIONORCHAPTER} is devoted to each of
these heuristics.
Finally comes induction. We have devoted two {SECTIONORCHAPTER}s
to that topic. The first deals with observations about recursive functions
that enable the recognition of appropriate induction schemes.
The second
describes how we choose
an induction scheme for a conjecture, given the previously computed information
about how the functions in it recurse.
We illustrate each heuristic with particularly appropriate examples.
We touch upon a great many theorems and problem domains
during this discussion. To tie all the heuristics together, we have also
chosen one simple example about list processing.
At the end of the discussion on simplification ({YONSEC SECREWRITESIMPLIFY}) and
at the end of each subsequent {SECTIONORCHAPTER}, we advance the
proof of this simple theorem.
When we have completed our presentation of our heuristics, we
discuss several much more complicated examples.
.SEC |USING TYPE INFORMATION TO SIMPLIFY FORMULAS|, SECTYPESET:
The ability to simplify formulas is central to the
ability to prove theorems by induction; a
principal activity during an inductive proof is transforming the
induction conclusion into an expression resembling the induction
hypothesis so that the induction hypothesis can be used.
To simplify a formula, we simplify its subterms
under the assumptions we can glean from the context of
the subterms in the formula. In this chapter, we
describe how we represent such assumptions so that they
can be readily used.
We also explain how we derive from an expression or a
recursive function definition a superset of the types of
objects the expression or function returns. The ability to look
at a term and immediately see that it may return certain
types of objects is used in almost all our theorem-proving
heuristics.
.SS |Type Sets|
In the chapter on the tautology checker
we arranged to remember assumptions that certain terms
were F or non-F by maintaining a sequence of pairs. As we explored
an expression to determine whether it was a tautology under such
a sequence (alist) of assumptions,
we both added new assumptions and searched through the
current assumptions to determine whether any
had been made about a certain term. In the simplification
techniques of our theorem-proving system,
we use a refinement of the idea of alists of assumptions.
Instead of simply pairing terms with
T or F, we pair terms with "type sets,"
which indicate that the terms have certain "types."
In this chapter, we define type set, and we
describe an algorithm that computes a type set
for an expression. The algorithm can itself be viewed as a
refinement of the function TAUTOLOGYP, which determined whether
an expression (in IF-normal form) never returned
F. The type set algorithm recursively explores
an expression, sometimes adding new assumptions
about the types of certain terms and often asking
whether an assumption has been made about a given term.
While TAUTOLOGYP only made use of knowledge about
the functions IF, TRUE, and FALSE, the type set
algorithm also uses knowledge of EQUAL, knowledge of
shell constructor, accessor, and recognizer functions, and
knowledge of defined functions.
Assume that 3+n shells have been added to our
theory, with the recognizers NUMBERP, LITATOM,
LISTP, and r[&1], ..., r[&n].
Let __F_ be the set $A{F}, let __T_ be the
set $A{T}, let __NUMBERP_ be the set of all
objects for which NUMBERP returns T, let
__LITATOM_ be the set of all objects for which
LITATOM returns T, and so on for the sets __LISTP_,
__r_[&1], ..., __r_[&n]. Let __OTHERS_ be the
set of all objects not in any of __T_, __F_, __NUMBERP_,
__LITATOM_, __LISTP_, __r_[&1], ..., __r_[&n].
The __types_ are the sets __T_, __F_, __NUMBERP_,
__LITATOM_, __LISTP_, __r_[&1], ..., __r_[&n], and __OTHERS_.
A __type set_ is a set of types. Let __UNIVERSE_
be the set of all types. A term t is said to
__have type set_ s provided s is a type set and
the value of t under any interpretation of the variables
of t is a member of some member of s. For example,
the following terms have the corresponding type sets.
.ASIS
term type set
X __UNIVERSE_
(ZERO) $A{__NUMBERP_$a}
(ADD1 X) $A{__NUMBERP_$a}
(EQUAL X Y) $A{__T F_$a}
(IF P (ADD1 X) (CONS X Y)) $A{__NUMBERP LISTP_$a}
(IF P X 0) __UNIVERSE_
(IF (NUMBERP X) X 0) $A{__NUMBERP_$a}
(IF (NUMBERP X) T X) __UNIVERSE_ - $A{__NUMBERP_}
.ENDASIS
To say that t has type set $A{__NUMBERP LISTP_$A} is just
to say that t is a number or a list. To say that t has type
set __UNIVERSE_ - $A{__NUMBERP_$A} is to say that t is anything
but a number.
Our algorithm for computing a type set for an expression
actually computes a type set for the expression under
some assumptions that certain terms have certain
type sets.
Our algorithm does not always return the
smallest type set for the given expression; any
algorithm that did so would be able to decide for
any formula p whether it was a theorem by determining
whether __F_ was not in the computed type set of p.
Instead of computing
the smallest type set, our algorithm always returns
a superset of the smallest type set.
Before describing how we determine a type set for an expression, we first illustrate with a
few examples the kind of reasoning employed in computing
and using type sets.
Suppose we knew that x had type set s. What could we
infer if we encountered the term (NUMBERP x), while simplifying a formula,
say? If s contained __NUMBERP_ and no other element,
then we would know that (NUMBERP x) were true. If s
did not contain __NUMBERP_, then we would know that
(NUMBERP x) were false. If s contained both __NUMBERP_
and another element, then if we were asked to suppose that
(NUMBERP x) were true, we could assume that x had type set $A{__NUMBERP_$A},
and if we were asked to
suppose that (NUMBERP x) were false, we could assume
that x had type set s - $a{__NUMBERP_}.
As another example, suppose that we knew that x had
type set $a{__NUMBERP_} and y had type set
$a{__LISTP_}. Then if we encountered the
term (EQUAL x y), we would know that it
was false because the two type sets had
an empty intersection.
Our type set algorithm utilizes an auxiliary algorithm
for adding to a set of assumptions
a new assumption that a given expression is true or false.
More precisely, the auxiliary algorithm accepts an
expression together with a collection of assumptions
(that certain terms have certain type sets), and
returns one of three possible answers. The first possible answer
is that the expression must be true (i.e., non-F) under the
assumptions given. The second possible answer is that
the expression must be false (i.e., F) under the assumptions given.
The third possible answer has two parts. The first
part is a set of assumptions (that certain terms have
certain type sets) equivalent to the conjunction of the input assumptions
and the new assumption that the input expression
is true. The second part is a set of assumptions
equivalent to the conjunction of the input assumptions and the new assumption that
the input expression is false.
The algorithm for making assumptions is mutually
recursive with the type set algorithm. In the
next two sections, we present first the details of the
assumption algorithm and then the details of the
type set algorithm.
.SS |Assuming Expressions True or False|
To assume an expression
p true or false in the context of certain assumptions
about type sets of some terms, we consider the
form of p.
.SSS |Assuming an EQUAL-Expression True or False|
If p has the form (EQUAL t[&1] t[&2]), then
we first compute type sets for t[&1] and t[&2], say s[&1] and s[&2].
If s[&1] and s[&2] have an empty intersection, then p
must be false. If s[&1] and s[&2] are equal,
s[&1] has only one member, and that member has only one member,
we conclude that p
must be true. Examples of such singleton-singleton type sets are
$a{__T_}, $A{__F_}, and the singleton of the type
for a shell
of no components and no bottom object. Otherwise, we return two
sets of assumptions.
To assume p true, we add
to our current assumptions that p has type set $A{__T_$a}.
"Add" means that the
assumption overrides any previous assumption about the type set of p.
We also add the assumption that the commuted version of p, (EQUAL t[&2] t[&1]),
has type set $a{__T_$a}. Finally, we add the two assumptions that t[&1] and t[&2] each
have as type sets the intersection of
s[&1] and s[&2]. Thus, if t[&1] were known to be a list or a literal atom,
and t[&2] were known to be a nonlist, then in assuming (EQUAL t[&1] t[&2])
true we would assume that both t[&1] and t[&2] were literal atoms.
To assume p false, we add
the assumption that p has type set $A{__F_$a}.
We also add the assumption that (EQUAL t[&2] t[&1]) has type
set $a{__F_$a}. If s[&1] is a singleton-singleton, we add
the assumption that t[&2] has
type set s[&2]-s[&1]. We perform the symmetric addition
if s[&2] is a singleton-singleton.
.SSS |Assuming a Recognizer Expression True or False|
If p has the form (r t), where r is a shell recognizer,
we first compute the type set, s, of t. If s is $A{__r_$a}, then
p must be true. If s does not contain __r_, then p must be false.
Otherwise, to assume p true we add the assumption
that t has type set $A{__r_$a}, and to assume p false we add the assumption
that t has type set s-$A{__r_$a}.
.SSS |Assuming Other Expressions True or False|
If p is not an equality or recognizer expression, we first
compute the type set, s, of p. If s is $A{__F_$a},
then p must be false. If s does not contain __F_, then p must be true.
Otherwise, to assume p true we add the assumption that the type set of
p is s-$A{__F_$a}, and to assume p false we add the assumption that the type
set of p is $A{__F_$a}.
.SS |Computing Type Sets|
Given the ability to determine that a term must be true, must be false,
or to assume it true or false, we now describe how we determine a type
set of an expression
under a set of assumptions that certain terms have
certain type sets.
If the expression is among those terms
with an assumed type set, then that type set is the answer. Otherwise, we
consider the form of the expression.
.SSS |The Type Set of a Variable|
If the expression is a variable, then we return __UNIVERSE_.
.SSS |Fixed Type Sets|
If the expression is not a variable, we consider the function
symbol of the expression.
If the function symbol is TRUE or FALSE, we return $A{__T_$a} or $A{__F_$a}, respectively.
If the function symbol is EQUAL or a shell recognizer,
we return $a{__T F_}. (If a type set of a term is a subset of $A{__T F_$A}, we say
the term is __Boolean_.)
If the function is a shell constructor or the function symbol
of a bottom object, we return $a{__r_$a},
where r is the corresponding recognizer.
For each shell accessor, we return the type set determined by the
type restrictions on the corresponding shell component (e.g., all SUB1
expressions have type set $a{__NUMBERP_$a} by virtue of the type restriction
(NUMBERP X1)
on the ADD1 shell, and similarly, all CAR expressions have type set __UNIVERSE_
by virtue of the default type restriction T on the types of arguments to CONS).
.SSS |The Type Set of IF-Expressions|
The case for IF is more interesting. If we can determine that the test of the IF must be true
or must be false under our current assumptions, then we
merely return the type set of the appropriate branch of the IF.
Otherwise we obtain the
type sets of the two branches -- assuming the test true on the one and
false on the other -- and return the union of those two type sets.
.SSS |The Type Set of Other Functions|
To explain how we compute a type set for other function symbols,
we first define:
.CROWN(8,0,0)
The pair is a __type prescription for the function symbol_ f
provided (1) ts is a type set, (2) args is a subset of the set of formal
parameters of f, and (3) whenever terms t[&1], ..., t[&n] have type sets
s[&1], ..., s[&n], then (f t[&1] ... t[&n]) has as a type set the union of ts
with the union of those s[&i] such that the i^^th^ formal parameter of f is in args.
.ENDCROWN
In the next {SUBSECTIONORSECTION}, we explain how we determine a particular
type prescription for a function symbol, given its definitional equation
or a theorem about the type of the function.
However, given a previously determined type prescription, , for f,
it is easy to compute a type set for (f t[&1] ... t[&n]). In particular,
we return the union of ts with the type sets of those t[&i] indicated by args
(under the current list of type assumptions).
.SS |Type Prescriptions|
We now turn to the problem of computing a type prescription for a newly introduced
function. Aside from the primitives and shell functions (whose type sets
are described explicitly above), a function symbol can be introduced into our theory
in one of two ways. The function symbol can be "declared" to take a given number of arguments
and forever remain undefined, or else it can be defined under
the principle of definition. In the former case we associate the type prescription
<__UNIVERSE_,$A{$A}> with the function symbol. In the latter case,
we compute a type prescription from the definition.
If the user adds a rewrite type axiom or proves a rewrite type theorem
that is equivalent to a certain function's having a particular type
prescription, then we store that axiom or theorem as the type prescription
for the function.
For example, in {YONSEC SECCOMPILER} we add the rewrite type axiom:
.ASIS
Axiom. NUMBERP.APPLY:
(NUMBERP (APPLY FN X Y)),
.ENDASIS
where APPLY is an undefined (and otherwise unaxiomatized) function
symbol. The axiom is stored as the type prescription <$A{__NUMBERP_$A},$A{$A}>
for APPLY.
.SSS |Examples of Type Prescriptions|
Before describing how we compute the type prescription
for a defined function, we first consider a few examples.
Given the definition of APPEND:
.ASIS
Definition.
(APPEND X Y)
=
(IF (LISTP X)
(CONS (CAR X) (APPEND (CDR X) Y))
Y),
.ENDASIS
we conclude that APPEND returns either
a LISTP object (due to the CONS expression) or the second argument, Y.
That is, it is a theorem that:
.ASIS
(OR (LISTP (APPEND X Y))
(EQUAL (APPEND X Y) Y)).
.ENDASIS
The type prescription for APPEND is thus <$A{__LISTP_$A},$A{Y$A}>.
Some examples of type sets computed for APPEND-expressions
are:
.ASIS
expression type set
(APPEND X Y) __UNIVERSE_
(APPEND X (CONS A B)) $a{__LISTP_$a}
(APPEND X "NIL") $a{__LISTP LITATOM_$a}
.ENDASIS
Given the definition of REVERSE:
.ASIS
Definition.
(REVERSE X)
=
(IF (LISTP X)
(APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL"))
"NIL"),
.ENDASIS
we observe that REVERSE either returns a LISTP (because
we have already observed that (APPEND r (CONS c n)) is always a LISTP) or else
returns a LITATOM (because "NIL" is a LITATOM). Thus any term
beginning with the function symbol REVERSE has type set $a{__LISTP LITATOM_$a}.
Given the definition of SUM:
.ASIS
Definition.
(SUM X Y)
=
(IF (ZEROP X) Y (ADD1 (SUM (SUB1 X) Y))),
.ENDASIS
we observe that SUM returns either a NUMBERP or its second
argument. Thus, if y is known to be a number, then
(SUM x y) has type set $a{__NUMBERP_$a}.
If we were to define TIMES in terms of SUM {FNOTE |We actually define TIMES
. in terms of the numeric function PLUS.|}:
.ASIS
Definition.
(TIMES I J)
=
(IF (ZEROP I)
0
(SUM J (TIMES (SUB1 I) J))),
.ENDASIS
we could observe that TIMES would always return a number.
For, when TIMES returned the 0 it would be returning
a number. When it returned the value of the SUM expression it either
would be returning a number (because SUM may return a number) or it
would be returning
the second argument to the SUM expression (because SUM may
return its second argument). But the second argument to the SUM
expression would be a recursive call of TIMES. Thus, it could be nothing but
a number. The computation of the type prescription of a recursive function
involves such an inductive argument.
.SSS |Computing the Type Prescription|
To compute the type prescription for a function, we use
a generalized version of the idea of type set. A __definition
type set_ is a pair consisting of a type set and a
finite set of variables. A term
__has definition type set_ , provided ts is a
type set, s is a set of variables, every variable in s
occurs in the term, and the value of the term
under any interpretation of the variables in the term either
is a member of a member of ts or is the value of some
member of s under the same interpretation.
For example, a definition type set for the term
.ASIS
(IF (LISTP X)
(CONS (CAR X) (APPEND (CDR X) Y))
Y)
.ENDASIS
is <$A{__LISTP_$A},$A{Y$A}>. Given accurate type prescriptions for
the functions concerned, the computation of a definition type set
for an expression (under some assumptions about the definition type sets
of certain terms) is closely analogous to the computation of a type
set for the expression. Because of the similarity, we do not
further discuss the definition type set computation. Instead,
we describe how we use it to discover a type prescription for a newly
defined function.
Note that one way to confirm that is a type prescription for a
newly defined function symbol, f, is to assume that is such
a type prescription, to compute a definition type set, for the body
of f (under the assumption that each formal parameter x of f has definition
type set <$a{$a},$a{x$a}>), and to check that ts' is a subset of
ts and that s' is a subset of args. If so, the definition type
set computation above constitutes an
inductive proof that f does have type prescription
.
The type prescription
<__UNIVERSE_, formals>, where formals is the set of formal
parameters of f, is a type prescription for any function f.
However, we prefer to find
a more restrictive type prescription. Instead of
searching exhaustively through all possible
type prescriptions, we adopt the following
search strategy. First we assume that
f has the type prescription <$a{}, $a{}>.
Then we compute the definition type set
of the body of f. We next assume that f has
as its type prescription the
pairwise union of the previously assumed type prescription and the newly computed
definition type set. We iterate until
the computed definition type set is
a pairwise subset of the type prescription just previously assumed.
We then use the type prescription just previously assumed
as the final type prescription for f.
The iteration always stops because on each
iteration the type prescription "grows," but
there are only a finite number of type prescriptions.
The type prescription computation is performed only after the
definition has been accepted by the definition principle, for
otherwise the inductive argument inherent in the computation
may be invalid.
.SS |Summary|
In this {SECTIONORCHAPTER} we explained:
.CROWN(8,0,0)
What information we glean from assuming a term true or false,
How we store that information as type sets,
How we compute type sets for terms, and
How we compute type prescriptions for recursive functions from
their definitions.
.ENDASIS
The definition-time discovery of a type set for a function
is an important and sometimes surprising aspect of our mechanical
theorem prover. Recall, for example, in {YONSEC SECOVERVIEW}, that when
FLATTEN was defined as:
.ASIS
Definition.
(FLATTEN X)
=
(IF (LISTP X)
(APPEND (FLATTEN (CAR X))
(FLATTEN (CDR X)))
(CONS X "NIL")),
.ENDASIS
the theorem prover announced "Observe that (LISTP (FLATTEN X)) is a
theorem." The fact that FLATTEN always returns a list is nonobvious, but
it is important in proofs about FLATTEN. By following the recipe
given above, the reader should be able to "discover" the theorem
(LISTP (FLATTEN X)) for himself.
.SS |Notes|
Since type sets are finite sets, we implement them as bit strings.
For example, we obtain the union of two type sets by computing
their "logical or."
Because type set information is used so extensively by all our heuristics,
our theorem-proving program never reports the use of a type set axiom
or lemma. The reader may assume that if a proof involved a function
symbol f, then the proof may have tacitly employed type set lemmas about f.
.SEC |USING AXIOMS AND LEMMAS AS REWRITE RULES|, SECREWRITERULES:
We have been discussing the handling of type information and how
it can be used to represent our current set of assumptions as we
walk through a formula.
Let us now move on to the second major aspect of the simplification
of expressions:##how one can use axioms and lemmas as rewrite rules.
.SS |Directed Equalities|
If one has a lemma of the form:
.ASIS
(EQUAL lhs rhs),
.ENDASIS
it is sound to use it to replace any instance of lhs with the
corresponding instance of rhs.
(Term t __is an instance of_ term lhs provided t is the result of
substituting some substitution into lhs.)
For example, in {YONSEC SECTAUTOLOGYCHECKER} we saw how the theorem:
.ASIS
(EQUAL (IF (IF P Q R) X Y)
(IF P (IF Q X Y) (IF R X Y)))
.ENDASIS
could be used as a rewrite rule.
In general, we want to use arbitrary user-supplied theorems
as rewrite rules.
For example, if we proved (and have been instructed to
use as a rewrite rule):
.ASIS
(EQUAL (APPEND (APPEND X Y) Z)
(APPEND X (APPEND Y Z))),
.ENDASIS
then whenever we encounter a term of the form
(APPEND (APPEND a b) c) we replace it by (APPEND a (APPEND b c)).
Treating equalities in this directed way is arbitrary.
Given that equality is symmetric, it is just as reasonable to replace
(APPEND a (APPEND b c)) with (APPEND (APPEND a b) c)
as vice versa.
(Indeed, it is
just as reasonable to rewrite neither term and merely to note
that they are equal.) We do not know how to
decide mechanically in which direction
to use a rewrite rule.{FNOTE |But see Knuth and Bendix {REF KNUTHBENDIX} and
. Lankford and Ballantyne {REF BALLANTYNE} for interesting work
. on such questions.|} We leave it to the user to declare what
theorems are to be used as rewrite rules and to recognize that we
use equalities in this asymmetric, left-to-right fashion when he
formulates theorems.
.SS |Infinite Looping|
Even with the proviso that the supplier of theorems be cognizant of our
conventions, many useful equality theorems could lead us around in circles.
A simple example is the commutativity of PLUS:
.ASIS
~CP1 (EQUAL (PLUS X Y) (PLUS Y X)).
.ENDASIS
It is definitely advantageous to know that PLUS is commutative. However,
using the above lemma as a simple rewrite rule would cause the following
sequence of rewrites to occur on (PLUS A B):
.ASIS
(PLUS A B) rewrites to
(PLUS B A), which rewrites to
(PLUS A B), which rewrites to
....
.ENDASIS
To prevent such loops, one can observe the following simple
(indeed, almost mindless) rule:##if a rewrite rule is __permutative_
(i.e., the left- and right-hand sides are instances of one another),
then do not apply the rewrite rule when the application
would move a term to the left into a position previously occupied
by an alphabetically smaller term.
Thus, while the rule would permit the use of the commutativity of
PLUS to rewrite (PLUS B A) to (PLUS A B), it would not permit the
use of the rule to rewrite (PLUS A B) to (PLUS B A). While this may seem
a capricious way to prevent loops, it does have a certain
normalizing effect on terms. For example, let us consider another
permutative rewrite about PLUS:
.ASIS
~CP2 (EQUAL (PLUS X (PLUS Y Z))
(PLUS Y (PLUS X Z))).
.ENDASIS
Given the term (PLUS (PLUS A B) C), the following is the only
allowed sequence of rewrites involving ~CP1 and ~CP2:
.ASIS
(PLUS (PLUS A B) C) rewrites to
(PLUS C (PLUS A B)), using ~CP1, which rewrites to
(PLUS A (PLUS C B)), using ~CP2, which rewrites to
(PLUS A (PLUS B C)), using ~CP1.
.ENDASIS
Note that at each stage the term is getting alphabetically smaller.
Furthermore, after the third rewrite neither ~CP1 nor ~CP2 can be legally
applied.
Finally, note that we just proved that PLUS is associative.
In fact, using
~CP1, ~CP2, and the
associativity of PLUS (stated to right-associate PLUS), we can rewrite any nest of PLUS
expressions to the nest that is right-associated
with the arguments in ascending alphabetic order. Thus
any two nests of PLUS expressions with the same "bag" of arguments
can be rewritten to identical expressions. Moreover,
the analogous lemmas about any other function symbol
(such as TIMES or GCD) allow us to normalize nests of that function symbol.
.SS |More General Rewrite Rules|
Up to now we have considered only rewrite rules of the form
(EQUAL lhs rhs). The idea of using a theorem to rewrite expressions can be
generalized considerably. In the first place, any literal can be
interpreted as an equality in our theory. For example, (NOT p)
can be regarded as (EQUAL p F). If p is Boolean, then the literal p
can be interpreted as (EQUAL p T). If p is not Boolean, then, although
the literal p cannot be interpreted as (EQUAL p T), it is sound, knowing
that p is nonfalse, to replace p by T in any position of a formula in
which only the "truth value" and not the identity of p is of concern.
For example, knowing that p is nonfalse is as good as knowing that it is
explicitly T in the test of an IF.
Thus,
requiring a rewrite rule to be of the form (EQUAL lhs rhs) is actually no restriction.
A more substantial generalization is the idea of using multi-literal
formulas as rewrite rules. Consider a formula of the form:
.ASIS
(IMPLIES (AND h[&1] ... h[&n])
(EQUAL lhs rhs)).
.ENDASIS
A "natural" interpretation of this is that any instance of lhs
can be replaced by the corresponding instance of rhs, provided the
corresponding instances of the h[&i] are true.
A good example of such a rule is:
.ASIS
(IMPLIES (NOT (LISTP X))
(EQUAL (CAR X) "NIL")).
.ENDASIS
A natural way to interpret this as a rewrite rule is to observe that
we can rewrite any expression of the form (CAR x) to "NIL", provided
we can establish that (LISTP x) is false (in the context in which
the expression occurs).
Once again we see an element of arbitrariness.
The above lemma can just as easily be interpreted as a way
to establish that (LISTP x) is true:##establish that (CAR x) is not "NIL".
Rather than try to develop heuristics for guessing the ways the lemma
should be used (or, worse, using it in all possible ways), we
obtain this information implicitly from the statement
of the lemma. In particular, if the user states a lemma as an
implication, we take it to mean that the conclusion is to be used
as a rewrite rule when the hypotheses are established.
How can we establish the hypotheses? The answer is simple:##rewrite them
recursively and if each is reduced to true, then the conclusion may be
applied. By recursively rewriting hypotheses
we are enabling our knowledge of type sets, lemmas,
and recursive functions to be applied to them.
Thus, the following scheme for using rewrite lemmas suggests itself.
Suppose we have a term (f t[&1] ... t[&n]) and we have recursively
rewritten the arguments, t[&i], and now wish to apply our known
lemmas to the term. Then we look for a lemma with a conclusion
of the form (EQUAL lhs rhs), where (f t[&1] ... t[&n]) is an instance of lhs
under some substitution s.
If one is found, we instantiate the hypotheses of the lemma with s.
Then we recursively rewrite each hypothesis. (Note that,
like the tests of IFs and the literals of a clause, only the
truth-value of a hypothesis matters. Thus, if we know p is not false, we rewrite it to T
when it appears as a hypothesis.) If each of the hypotheses
rewrites to nonfalse, then we replace (f t[&1] ... t[&n]) by
the instantiated rhs and then recursively rewrite that. Of course,
the application of the rewrite rule is subject to our
rule about infinite looping due to permutative lemmas.
.SS |An Example of Using Rewrite Rules|
Suppose we
have proved as rewrite lemmas the following theorems from
{YONSEC SECTAUTOLOGYCHECKER}:
.ASIS
~T1 (EQUAL (VALUE (NORMALIZE X) A) (VALUE X A)),
~T2 (NORMALIZED.IF.EXPRP (NORMALIZE X)),
~T3 (IMPLIES (AND (NOT (TAUTOLOGYP X A))
(NORMALIZED.IF.EXPRP X)
A)
(FALSIFY1 X A)), and
~T4 (IMPLIES (AND (EQUAL (VALUE Y (FALSIFY1 X A))
(VALUE X (FALSIFY1 X A)))
(NORMALIZED.IF.EXPRP X)
(FALSIFY1 X A))
(NOT (VALUE Y (FALSIFY1 X A)))).
.ENDASIS
The first three are lemmas discussed carefully in {YONSEC SECTAUTOLOGYCHECKER}.
We have used shorter names here.
The fourth theorem, ~T4, is the "bridge" lemma mentioned.
It is FALSIFY1.FALSIFIES phrased in a way that makes it a
more powerful rewrite rule in our system. FALSIFY1.FALSIFIES says that under some conditions
we can conclude a certain thing about (VALUE X (FALSIFY1 X A)).
~T4 says that under identical conditions we can conclude the same
thing about the more general term (VALUE Y (FALSIFY1 X A)) -- provided
we can prove those two VALUE-expressions equal.
Let us see how our rewrite scheme would prove TAUTOLOGY.CHECKER.IS.COMPLETE. After expanding the definitions of TAUTOLOGY.CHECKER and
FALSIFY, we obtain:
.ASIS
~T5 (IMPLIES (NOT (TAUTOLOGYP (NORMALIZE P) "NIL"))
(NOT (VALUE P (FALSIFY1 (NORMALIZE P) "NIL")))).
.ENDASIS
We cannot rewrite the hypothesis of ~T5. Thus, we start to
rewrite the conclusion of ~T5. However, in the process we can
assume the hypothesis true. That is, we can assume:
.ASIS
~A1 (TAUTOLOGYP (NORMALIZE P) "NIL") has type set $a{__F_$a}.
.ENDASIS
Under this assumption we rewrite the atom of the conclusion of ~T5:
.ASIS
~T5.2 (VALUE P (FALSIFY1 (NORMALIZE P) "NIL")).
.ENDASIS
We can use ~T4 to rewrite this to F (and thus reduce ~T5 to a
tautology since ~T5.2 is negated in ~T5) if we can only
establish the three hypotheses of ~T4 after instantiating them
by replacing X by (NORMALIZE P), Y by P, and A by "NIL".
The first instantiated hypothesis of ~T4 is:
.ASIS
~T4.1 (EQUAL (VALUE P (FALSIFY1 (NORMALIZE P) "NIL"))
(VALUE (NORMALIZE P) (FALSIFY1 (NORMALIZE P) "NIL"))).
.ENDASIS
But, using ~T1, we rewrite the right-hand side of this equality
to precisely the left-hand side (since the VALUE of (NORMALIZE P)
is the VALUE of P). Thus, we have established the first
hypothesis of ~T4.
The second hypothesis of ~T4 is:
.ASIS
~T4.2 (NORMALIZED.IF.EXPRP (NORMALIZE P)).
.ENDASIS
But we recursively rewrite this to T using ~T2.
The third hypothesis of ~T4 is:
.ASIS
~T4.3 (FALSIFY1 (NORMALIZE P) "NIL").
.ENDASIS
We can rewrite this to T (since it is in a hypothesis position) using ~T3, if
we can establish the three hypotheses of ~T3.
The first hypothesis of ~T3 is:
.ASIS
~T3.1 (NOT (TAUTOLOGYP (NORMALIZE P) "NIL")).
.ENDASIS
But according to ~A1, the type set of the atom of this
literal is $a{__F_$a}. Thus, the negation of it is T and we have
established ~T3.1.
The second hypothesis of ~T3 is:
.ASIS
~T3.2 (NORMALIZED.IF.EXPRP (NORMALIZE P)),
.ENDASIS
which once again rewrites to T using ~T2.
The third and final hypothesis of ~T3 is just:
.ASIS
~T3.3 "NIL",
.ENDASIS
which is non-F (by type set reasoning, for example).
Therefore, we apply ~T3 to rewrite ~T4.3 to T, and hence,
apply ~T4 to rewrite ~T5.2 to F, and have thus proved ~T5.
Of course, we did not have to cite such a complicated example to
illustrate the use of rewrite lemmas. In particular, the reader
should keep in mind that virtually everything our implementation
knows about arithmetic, lists, etc., is represented with rewrite lemmas.
Below are some simple rewrite lemmas added by our implementation of
the shell principle (see {APP APPSHELL}):
.ASIS
(EQUAL (CAR (CONS X1 X2)) X1),
(IMPLIES (NOT (LISTP X))
(EQUAL (CAR X) "NIL")),
(EQUAL (EQUAL (CONS X1 X2)
(CONS Y1 Y2))
(AND (EQUAL X1 Y1)
(EQUAL X2 Y2))), and
(EQUAL (SUB1 (ADD1 X1))
(IF (NUMBERP X1) X1 0)).
.ENDASIS
Note that the last two examples illustrate the very useful idea
of stating a lemma, when possible, as an unconditional rewrite (by using
an IF or other propositional construct in the right-hand side)
rather than as a collection of multiliteral rewrite rules.
.SS |Infinite Backwards Chaining|
The idea of recursively appealing to lemmas to establish the hypotheses
of other lemmas is called "backwards chaining." Implementing it mechanically
requires addressing one major problem:##it is possible to backwards chain
indefinitely.
For example, consider the rewrite lemma:
.ASIS
(IMPLIES (LESSP X (SUB1 Y))
(LESSP X Y)),
.ENDASIS
which says that we can rewrite (LESSP X Y) to T if we can establish
that X is less than Y-1. Note how we might be tempted to
use this theorem to establish that (LESSP I J) is true:
.ASIS
Using the lemma we can prove (LESSP I J),
if only we could prove (LESSP I (SUB1 J)).
Ah ha! We can prove (LESSP I (SUB1 J)),
if only we could prove (LESSP I (SUB1 (SUB1 J))).
Ah ha! We can prove (LESSP I (SUB1 (SUB1 J))),
if only ...
.ENDASIS
To prevent this from occurring, we
remember what we are trying to do and we give up when certain contraindications
arise.
In particular, we keep a list of the
negations of the hypotheses we are currently trying to establish.
Here is how we use the list. Suppose we are trying to apply a rewrite
rule r, one of whose hypotheses is the term new.
If we find new on the list, then it is sound to assume new
true and spend no further time trying to establish it. (That is,
because new is on the list, we know that we are in the process of trying to
establish its negation. But it is permitted to assume p while trying
to establish (NOT p).) If we find
new's negation on the list, then we are looping, and we abandon the attempt
to apply r.
We also decide we are looping (but in a much more insidious way)
when we find that the atom of new is an "elaboration of"
the atom of one of the hypotheses we are
already trying to establish. If none of these contraindications are present, we
store the negation of new on the list, and then recursively rewrite new.
The basic idea of "elaboration" is suggested by the example
above. We say that new is an __elaboration of_ old
if either (1) new is identical to old or (2) the
number of occurrences of function symbols in new is greater than
or equal to the number in old and new is "worse than" old.
We say that new is __worse than_ old if (1) old is a variable
and properly occurs in new, or (2) neither old nor new is
a variable and either (2.a) new and old have different
function symbols and some subterm of new is worse than
or identical to old, or (2.b) some argument of new is worse than
the corresponding argument of old but no argument of
new is a variable or an "explicit value" unless
the corresponding argument of old is, and furthermore
no argument of old is worse than the corresponding argument of new.
The definition of "explicit value" is given in
{YONSEC SECDEFINITIONS}.
Thus, (LESSP I (SUB1 (SUB1 J))) is worse than (LESSP I (SUB1 J)).
(LESSP I (SUB1 (SUB1 J))) is not considered worse than (LESSP (F I) (SUB1 J)) because
I is a variable and (F I) is not.
.SS |Free Variables in Hypotheses|
The discussion of how we establish the hypotheses of rewrite lemmas
ignored an important point. We said that after discovering
that the
term to be rewritten is an instance of the left-hand side of the rewrite lemma's
conclusion, we instantiate the hypotheses
and rewrite them recursively. However, it is possible that not all the
variables in the hypotheses are mentioned in the left-hand side
of the conclusion, and hence, some variable may not be instantiated.
We refer to such a variable as a "free" variable.
An example of a useful rewrite lemma with free variables in it is:
.ASIS
(IMPLIES (AND (LESSP X Y)
(LESSP Y Z))
(LESSP X Z)).
.ENDASIS
That is, we can rewrite (LESSP X Z) to T if we can establish that
X is less than Y and Y is less than Z.
The correct way to use such a lemma is to try to find
an instantiation for Y that makes one of the two hypotheses true and then
to rewrite the appropriate instance
of the other hypothesis to establish it.
We try to find an instantiation y for Y by searching
through the current type set assumptions, looking for a term
(LESSP x y) assumed to be true, where x is the instantiation of X picked up
when (LESSP X Z) was initially instantiated.
If such a y is found, we use it for Y while trying to establish the
remaining hypothesis.
Our approach to handling free-variables is very weak. In particular,
our system cannot establish a hypothesis with a free-variable in it unless
an instance of
the
hypothesis has previously been assumed true.
Here is an example of the inadequacy of our handling of free-variables.
Assume we have proved the two lemmas:
.ASIS
(IMPLIES (NOT (ZEROP X))
(LESSP (SUB1 X) X)),
(IMPLIES (NOT (ZEROP Y))
(LESSP X (PLUS X Y))).
.ENDASIS
and suppose we wish to prove:
.ASIS
(IMPLIES (AND (NOT (ZEROP I))
(NOT (ZEROP J)))
(LESSP (SUB1 I)
(PLUS I J))).
.ENDASIS
All that is required is a single application of the transitivity of LESSP,
using I as the choice for Y and the two previously mentioned
lemmas to establish the hypotheses. Our system is not able to do this.
The system can prove this lemma (and hundreds like it)
by induction. But it is painful to the
user to state explicitly a theorem that is
an easy consequence of substitutions and __modus ponens_.
.SEC |USING DEFINITIONS|, SECDEFINITIONS:
We now move on to the third (and last) fundamental activity involved in
simplifying expressions:##the use of function definitions.
Suppose we have a function definition of the form:
.ASIS
(f v[&1] ... v[&n]) = body.
.ENDASIS
By the axioms of equality we can replace a call of f, (f t[&1] ... t[&n]),
by the body of f, after substituting the t[&i] for the corresponding
formals in the body. We call this "opening up" or "expanding" the
function call.
Since a function definition is just
an equation, there is in principle no difference between using function
definitions and using other equality theorems. However, following the rules
sketched above, we might expand recursive definitions indefinitely,
since the recursive calls in the instantiated body could also
be expanded.
Making intelligent decisions about whether to use a definition
is crucial to proving theorems in a theory with a definition
principle (be it a recursive one or not). Unnecessary expansion of definitions
will swamp a theorem prover (mechanical or otherwise) with irrelevant
detail. Failure to expand a
definition can prevent a proof from being found at all.
In studying many hand proofs we have learned three heuristics that
are useful to know when considering whether to expand a recursive definition.
We discuss each of these in turn.
.SS |Nonrecursive Functions|
If one encounters a function call of f, and f is nonrecursive,
it is clear that expanding its definition is safe in the sense that
it will not lead to infinite loops.
In general, it is not necessarily wise to open up a function
simply because it is safe. For example, if P is defined nonrecursively
but the definition requires several pages to write down, then the
theorem (IMPLIES (P X) (P X)) will take longer to prove if P is opened up.
Nevertheless, our theorem prover opens up every nonrecursive call
it encounters.
This heuristic is tolerable only because most of
the nonrecursive functions with which
our theorem prover deals have small bodies. Recall the definitions
of such typical nonrecursive functions as NOT, AND, ZEROP, and FALSIFY.
.SS |Computing Values|
It is sometimes possible to open up recursive functions and not introduce
new recursive calls. For example, recall the definition of APPEND:
.ASIS
Definition.
(APPEND X Y)
=
(IF (LISTP X)
(CONS (CAR X) (APPEND (CDR X) Y))
Y)
.ENDASIS
and consider the term:
.ASIS
(APPEND (CONS 1 (CONS 2 "NIL")) (CONS 3 "NIL")).
.ENDASIS
If we open up APPEND repeatedly and simplify the result
we obtain:
.ASIS
(CONS 1 (CONS 2 (CONS 3 "NIL"))),
.ENDASIS
completely eliminating APPEND.
The key to this particular example is the use of "explicit values" as
arguments. Examples of explicit values are "NIL", 0, 1 (i.e., (ADD1 0)) and
(CONS 1 "NIL"). An __explicit value_ is defined to be either T, F, a
bottom object of some shell, or else the constructor of some shell
applied to explicit values satisfying the type restrictions
for the constructor. Thus, while T and (ADD1 0) are
explicit values, (ADD1 T) is not.
(We will later need the concept of an __explicit value template_,
to wit: a nonvariable term composed entirely of
shell constructors, bottom objects,
and variables. Examples of explicit value templates
are (CONS X "NIL") and (ADD1 I).)
The reason explicit values are mathematically interesting is that they
constitute a normal form for a certain class of expressions. It can
be proved inductively that two explicit values are equal if and only if
they are identical terms. If we did not require that each component
of an explicit value be of the right type, then
the theorem just mentioned would have counter examples
(ADD1 T) and (ADD1 0). For (ADD1 T) and
(ADD1 0) are equal but not identical.
We call a function f __explicit value preserving_ if and only if f is
TRUE, FALSE, IF, EQUAL, one of the functions introduced by the
shell principle, or f was defined under our principle of definition
and the body of f calls only f or explicit value preserving functions.
Most of the functions with which we deal are explicit value preserving.
The function EVAL, used in {YONSEC SECCOMPILER}, is an example of a
function in our theory that is not explicit value preserving because
it uses the undefined function APPLY.
If f is explicit value preserving and
t[&1], ..., t[&n] are explicit values, then
(f t[&1] ... t[&n]) can be rewritten to a unique equivalent explicit value
by literally computing it from the axioms and definitions.
Thus, we know we can open up (APPEND "NIL" (CONS 3 "NIL")), for example,
without even worrying that we will indefinitely expand the recursion
in the body.
In fact, we do not require that all the arguments be explicit values.
Recall that when we define a recursive function, the definition principle
requires that we find a measure and well-founded relation justifying the
function's definition. In APPEND, we see that the function is accepted because
(COUNT X) gets LESSP-smaller on each (i.e., the) recursive call.
We say that $a{X$a} is a "measured subset" of the formals of APPEND
since a measure of that subset decreases on every recursive call in the definition
of APPEND (we will define "measured subset" in {YONSEC SECRECURSION}).
If some subset of the arguments to a call (f t[&1] ... t[&n]) of a function are
explicit values, and that subset "covers" a measured subset of the function
(in the sense that t[&i] is an explicit value when the i^^th^ formal
parameter of f is in the subset),
then we open up the call.
For example, we open up:
.ASIS
(APPEND (CONS 1 (CONS 2 "NIL")) y),
.ENDASIS
regardless of what y is, and eventually get something that does not
involve APPEND at all (except where it might occur in y), namely:
.ASIS
(CONS 1 (CONS 2 y)).
.ENDASIS
Of course, in general there may be more than one measured subset.
For example, in LESSP:
.ASIS
Definition.
(LESSP X Y)
=
(IF (ZEROP Y)
F
(IF (ZEROP X)
T
(LESSP (SUB1 X) (SUB1 Y))))
.ENDASIS
there are two measured subsets, $a{X$a} and $a{Y$a}. Thus,
we could open up (LESSP x 2) and eventually get (after simplification):
.ASIS
(OR (NOT (NUMBERP x))
(EQUAL x 0)
(EQUAL (SUB1 x) 0)).
.ENDASIS
That is, opening up (LESSP x 2) forces us to
consider the cases:##x is not a number, is 0, or is 1.
.SS |Diving in to See|
The above two heuristics only scratch the surface and would not
allow us to prove many theorems by themselves, because they
attempt to answer the question "Should I open up (f t[&1] ... t[&n])?"
without considering the subterms of f's body.
In general, the only way an intelligent decision can be made is to
explore the body of f and see whether it has anything to
contribute. This can be done by rewriting the body recursively,
remembering that when a formal parameter, v[&i], of f is encountered
it should be replaced by the already simplified t[&i].
The result will be a new term, val, and we
must then decide whether we would prefer to keep (f t[&1] ... t[&n])
or val.
One must be careful, when rewriting the body of f recursively,
not to give similar consideration to the recursive
calls of f, since that would lead to nonterminating recursion.
We have found that a suitable rule to
follow is to keep a list of the function names
being tentatively opened up, and to refuse to consider
opening recursive calls of those functions.
Note that because we rewrite the bodies of functions recursively before
deciding whether to introduce those expressions into the conjecture, we bring
all our knowledge about type sets, previously
proved results, and recursive functions to bear on the definition.
Sometimes the result of rewriting a body is just an
instantiated copy of the body. For example, tentatively opening up
(APPEND a b)
may lead to:
.ASIS
(IF (LISTP a) (CONS (CAR a) (APPEND (CDR a) b)) b).
.ENDASIS
But, for example, if our type set or lemma reasoning could conclude that
(LISTP a) were false, the result would be simply b. If a were of
the form (CONS u v), then the result would be (CONS u (APPEND v b)),
since axioms inform us of such things as (LISTP (CONS u v)) and
(EQUAL (CAR (CONS u v)) u).
Sometimes the result is less trivial. For example, the
recursive call in the definition of (QUOTIENT I J) is (QUOTIENT (DIFFERENCE I J) J). Had we previously proved the lemmas:
.ASIS
(IMPLIES (NUMBERP I)
(EQUAL (DIFFERENCE (PLUS J I) J) I)) and
(NOT (LESSP (PLUS I J) J)),
.ENDASIS
and if we knew that j were non-ZEROP and i were a number,
then the result of tentatively opening up (QUOTIENT (PLUS j i) j)
would be (ADD1 (QUOTIENT i j)).
Thus, on complicated function bodies, we might do a considerable amount of
simplification before even beginning to decide whether we want to
keep the expanded body.
We have found that more economical methods of deciding whether to
use a definition (such as preprocessing it, or exploring it without
actually simplifying it) are inadequate
because they do not take into account all that we know at the moment
about the concepts involved. Since failure to open a definition at
the right time will hide information from the proof and thus prevent a
proof, it is crucial to bring one's full knowledge
(both global and contextual) to the problem.
Thus, having obtained the simplified function body, val, we must decide
if it is "better" than the call it would replace, (f t[&1] ... t[&n]).
.SSS |Keeping Nonrecursive Expansions|
If val does not mention f as a function symbol, then we consider val to be
better than (f t[&1] ... t[&n]).
This happens frequently.
For example, the function may be directed down a nonrecursive branch (as by
the base case of an induction), or the recursive calls might be reduced
to nonrecursive expressions by contextual information or lemmas.
As an example of the latter, consider expanding (MEMBER a b)
under the assumption that (MEMBER a (CDR b)) is non-F (as might be
supplied by an induction hypothesis), where MEMBER is defined thus:
.ASIS
Definition.
(MEMBER X L)
=
(IF (LISTP L)
(IF (EQUAL X (CAR L))
T
(MEMBER X (CDR L)))
F).
.ENDASIS
In this case,
type set reasoning will allow us to replace (MEMBER a (CDR b)) in the
body by T. Then (IF (EQUAL a (CAR b)) T T) will reduce to T, and then
(IF (LISTP b) T F) will reduce to (LISTP b) as the final result.
As another example,
consider (QUOTIENT I I). The recursive call is (QUOTIENT (DIFFERENCE I I) I),
which, if we know the obvious facts about DIFFERENCE, will reduce to
(QUOTIENT 0 I), which can be expanded again to eliminate QUOTIENT altogether
by the previously mentioned heuristic involving explicit values in measured
subsets.
.SSS |Keeping Recursive Expansions|
If the tentative result, val, involves recursive calls, then we are
forced to choose between those calls and (f t[&1] ... t[&n]).
We have found that it is usually a good idea to expand (f t[&1] ... t[&n])
(i.e., replace it by val) if each of the calls of f in val has one of
three "good" properties compared to (f t[&1] ... t[&n]).
.SSSS |No New Terms|
The first "good" property is simple and yet the most fundamental:
If each of the arguments of a call of f in val already appears
in the conjecture being proved, then the call is good.
For example, if the conjecture already involves
(CDR a) and b, then (APPEND a b) is best expressed in terms of (APPEND (CDR a) b).
This heuristic has a strong normalizing effect on the conjecture;
terms are expressed in common terms when possible. Of course,
soon the conjecture "settles down" to those common terms.
How is it that we ever open up anything again? The answer is induction.
For example, suppose we are proving some fact about (APPEND A B).
We simplify it as much as possible. But if (CDR A) is not
mentioned in the conjecture, we will not
expand (APPEND A B) to introduce (APPEND (CDR A) B). But if induction
supplies us with an induction hypothesis about (CDR A), it suddenly
becomes a good idea to express (APPEND A B) in terms of (APPEND (CDR A) B).
This first "good" property accounts for
the vast majority of openings performed by our program. As indicated, however, we have
found two other useful properties.
.SSSS |More Explicit Values as Arguments|
The second "good" property of a recursive call is that it contains
more explicit values as arguments than (f t[&1] ... t[&n]). Introducing
an explicit value where before we had an arbitrary term is a good idea,
since we can usually further simplify matters.
.SSSS |Less Complex Controllers|
The third "good" property of a recursive call in the tentative expansion
is motivated by the example (LESSP I (ADD1 J)). We have
found in our hand proofs that it is usually more convenient to express
this as (LESSP (SUB1 I) J) -- that is, to allow the recursive call to introduce
(SUB1 I) where no (SUB1 I) appeared before, in order to get rid of (ADD1 J).
As we will see in {YONSEC SECELIMINATINGDESTRUCTORS},
we can usually eliminate expressions like (SUB1 I) in other ways. Thus,
the third "good" property of recursive calls is that the symbolic complexity
of some measured subset is smaller than the complexity of that subset in
the original (f t[&1] ... t[&n]) call. A heuristically adequate measure
of symbolic complexity is the number of occurrences of
function symbols. In
computing the symbolic complexity of (IF x y z), however, we just take the
maximum of the complexities of y and z, since after the IF is distributed on the
far outside of the conjecture, only y and z will be arguments to the recursive
call.
.SEC |REWRITING TERMS AND SIMPLIFYING CLAUSES|, SECREWRITESIMPLIFY:
.SS |Rewriting Terms|
The three preceding {SECTIONORCHAPTER}s have presented the major ideas
involved in rewriting terms. In the next paragraph we explain the
context in which we do the rewriting. Then, we describe how we
put the various ideas together to rewrite terms.
When we rewrite a term, we do so in the context specified by two lists of
assumptions. The first list, called the __type set alist_,
is an alist of assumptions about the type sets
of certain terms. The second list,
called the __variable alist_, is
an alist associating terms with variables
and is used to avoid carrying out explicit substitutions. For example,
when we explore the definition of APPEND while trying to expand
(APPEND (CONS A B) C), we use the variable alist to remember that the first
argument is (CONS A B) and the second is C, by associating (CONS A B) with
the first formal parameter of APPEND, X, and associating C with the
second formal parameter, Y. If the pair is on the variable alist, we
say v __is bound_, and that t __is the binding of_ v.
If v is bound to t, then v is assumed to be equal to t.
We proceed as follows to rewrite x under a type set alist and a variable alist.
.SSS |Rewriting a Variable|
If x is a variable, we ask if x is bound.
If so, let t be its binding. Because we will have previously rewritten t,
we return t as the result of rewriting x.{FNOTE |Actually, t would have been rewritten
. under the assumptions available when it was bound to x. It is possible
. that by rewriting t again, under the current set of assumptions, we could
. further simplify it. In one of many heuristic compromises between
. power and efficiency, we do not resimplify t before returning it.|}
If x is not bound, we return x.
If x is not a variable, we consider the cases on the form of x.
.SSS |Rewriting Explicit Values|
If x is an explicit value, we return x.
.SSS |Rewriting IF-Expressions|
If x is of the form (IF test left right), then we recursively rewrite
test and obtain some new term, test'. If test' must be true or must
be false under the assumptions in the type set alist, we recursively rewrite and return left or right, as appropriate.
If test' can apparently be either true or false,
we recursively rewrite left using the type set alist obtained
by assuming test'
true, and we recursively rewrite right using the type set alist obtained
by assuming test'
false. Suppose this produces left' and right'.
We then try to apply each of the following rewrite rules for IF-expressions
to (IF test' left' right'). We return the result of the first applicable
rule (if any), or else we return (IF test' left' right'):
.ASIS
(EQUAL (IF X Y Y) Y),
(EQUAL (IF X X F) X), and
(EQUAL (IF X T F) X), applied only if X is Boolean.
.ENDASIS
.SSS |Rewriting EQUAL-Expressions|
If x is of the form (EQUAL t s), then we first obtain t' and s' by recursively
rewriting t and s.
If t' and s' are identical,
we return T.
If t' and s' could not possibly be equal, we return F.
We know four ways to decide that two terms are definitely unequal:
(a) their type sets do not intersect, (b) they are distinct
explicit values, (c) one term is a bottom object and the other is
a call of a shell constructor, or (d) one term is a call of a shell constructor and
the other term occurs as a component (of the right type) in the first.
If none of the above rules apply, we next try rewriting
(EQUAL t' s') with each of the following rewrite rules:
.ASIS
(EQUAL (EQUAL X T) X), applied only if x is Boolean,
(EQUAL (EQUAL X (EQUAL Y Z))
(IF (EQUAL Y Z)
(EQUAL X T)
(EQUAL X F))),
(EQUAL (EQUAL X F) (IF X F T)).
.ENDASIS
Let val be the result of the first
applicable rewrite, or (EQUAL t' s') if none applies.
We return the result of rewriting val with all known
rewrite lemmas.
To __rewrite a term_ val __with lemmas_, we consider all
known rewrite lemmas in the reverse order in which
they were introduced and "apply" the first "applicable"
lemma. If no lemma is applicable, we return val.
A rewrite lemma:
.ASIS
(IMPLIES (AND h[&1] ... h[&n])
(EQUAL lhs rhs))
.ENDASIS
is applicable to val if val is an instance of lhs (under
some substitution s on the variables of lhs), s does not violate the alphabetic
ordering restriction if (EQUAL lhs rhs) is permutative,
and we can establish the h[&i].
To establish a hypothesis containing no free variables,
we rewrite the hypothesis, using s as the alist
specifying the values of variables.
To establish a hypothesis containing free variables,
we try to extend s so that under the extended substitution
the hypothesis is one of the terms currently assumed
true.
If the lemma is applicable, then we return the result of
rewriting rhs (under the alist s plus any additional
substitution pairs obtained in relieving hypotheses
containing free-variables).
Note that this scheme allows us to use lemmas that rewrite equalities.
For an example of such a lemma, consider:
.ASIS
(EQUAL (EQUAL (PLUS X Y) (PLUS X Z))
(EQUAL (FIX Y) (FIX Z))),
.ENDASIS
which allows us to "cancel" the identical first arguments of two
equated PLUS-expressions.
.SSS |Rewriting Recognizer Expressions|
If x is of the form (r t), where r is a shell recognizer, we
recursively rewrite t to obtain t'.
Then, if the type set of t' is $a{__r_$a}, we return T.
If the type set of t' does not include __r_ as an element, we return F.
Otherwise, we rewrite (r t') with lemmas (as above).
.SSS |Rewriting Other Expressions|
Otherwise, x is of the form (f t[&1] ... t[&n]). We first rewrite each
t[&i] to t[&i]'.
If f is nonrecursive
or a measured subset of the t[&i]' are explicit values, we
rewrite the body of f under
a variable alist that associates each formal with the corresponding
t[&i]' and return the result. If f is on the list of function
names being tentatively expanded, we return (f t[&1]' ... t[&n]').
Otherwise, we rewrite (f t[&1]' ... t[&n]') with lemmas
(as above).
If no rewrite rule is applicable, we determine whether f has a definition.
If so, we
add f to the list of functions being tentatively expanded,
we rewrite the body of f under a variable alist
associating the formals of f with the corresponding
t[&i]', and then we compare its rewritten body with
(f t[&1]' ... t[&n]') as in {YONSEC SECDEFINITIONS}
to see which
we should keep.
If f is not a defined function, we return (f t[&1]' ... t[&n]').
.SSS |Caveats|
There are three discrepancies between the above
description and our actual implementation.
First, as noted in {YONSEC SECREWRITERULES}, we distinguish between when
we are concerned with maintaining the equality of the term being rewritten
and when we are concerned only with
maintaining its "truth-value." In particular, we know that we are interested only
in truth-values when we
are rewriting the atom of a literal in a clause, the test of an IF, or
a hypothesis to a rewrite lemma. At all other times we must maintain
strict equality (including, of course, when rewriting subterms of
tests, etc.).
A second discrepancy is that we
keep track of whether we are "hoping" the term we are rewriting will be
rewritten to T or F (or be rewritten arbitrarily). In general, we do not
care how the term rewrites. However, when we try to establish
a hypothesis of a lemma, we do not waste time trying
to rewrite the hypothesis to false.
Thus, when we rewrite the hypotheses of lemmas, we actually
rewrite the atom of the literal in the hypothesis. If the literal is
positive, we "hope" the atom will be rewritten to T. If the literal is
negative, we "hope" the atom will be rewritten to F.
If we hope a term will be rewritten to
T (or actually, non-F), we apply a rewrite rule only
when the right-hand side of the conclusion is not F.
The analogous statement holds when we hope the term
will be rewritten to F. If we do not care how the term rewrites, we apply all rules
as described.
Thus, if we were trying to establish that (VALUE x a) were true so
that we could make a rewrite, we would not even consider applying a
lemma with conclusion (NOT (VALUE x a)).
The third discrepancy is that before we return from rewriting, we
ask if the assumed type set of the answer is $a{__T_$a} or $a{__F_$a} (or, in the case where we are interested only
in the "truth value" rather than the identity, we ask if the type set
does not include __F_), and if so, return
instead T or F as appropriate.
.SS |Simplifying Clauses|
Given the ability to rewrite terms under a set of assumptions,
it is easy to simplify clauses by sequentially rewriting the literals.
The only interesting
thing about simplifying clauses is how
one can convert IF-expressions to clausal form "on-the-fly."
.SSS |Converting IF-Expressions to Clausal Form|
Suppose we are in the process of simplifying a clause:
.ASIS
$A{new[&1] ... new[&n] old[&1] old[&2] ... old[&k]$a},
.ENDASIS
by rewriting each of the literals in it. Suppose we have already
rewritten those to the left of old[&1] and are now ready to rewrite
old[&1] itself.
Then we assume all the literals except old[&1] to be false. (Actually,
if a literal has the form (NOT atm) we assume atm true.)
Then we rewrite the atom of old[&1] using the type set
alist obtained from the foregoing assumptions and the empty
variable alist. We thus obtain some
value which we negate if old[&1] was a negative literal. Let val be the result.
If val is T, we have established that the clause is true.
If val is F, we delete old[&1] from the clause and continue with
old[&2].
Otherwise, we can replace old[&1] by val and move on
to old[&2].
However, if val contains IF-expressions, we first
split the clause into as many new clauses as necessary to remove all
IFs from val. To do this, we
first move all the IFs in val to the top, by repeatedly
applying the rewrite rule:
.ASIS
(EQUAL (f X1 ... (IF P Q R) ... Xn)
(IF P
(f X1 ... Q ... Xn)
(f X1 ... R ... Xn))),
.ENDASIS
where f is any function symbol,
to val until all the IFs are outside all other
function symbols.
Then we repeatedly apply the rule:
.ASIS
$a{new (IF p q r) old} <->
$a{new (NOT p) q old} & $a{new p r old}
.ENDASIS
until none of the IFs introduced by val remain.
This results in a conjunction of clauses which we continue to
simplify recursively. We continue the rewriting process in each of these clauses, starting with old[&2].
The resulting set of
clauses is returned as the value of simplifying our input clause.
Of course, if we changed anything (i.e., the resulting set of clauses
is different from the singleton set containing our input clause), then
each of the resulting clauses is poured over the waterfall again to
be resimplified.
Thus, we will get the opportunity to resimplify p, say, in the context of assuming
the rewritten old[&2] false.
.SSS |Caveats|
There are three discrepancies between this description and our
actual implementation.
First, before we begin simplifying the literals of a clause,
we check whether any literal has the form (NOT (EQUAL x t)),
where x is a variable and t is a term not containing x as a variable. If
so, we replace every occurrence of x in the clause with t
and delete the literal.
The second discrepancy is that when we remove all of
the IFs from val by splitting the clause into a set of clauses, we
actually remove from the set any clause that is subsumed by any other clause.{FNOTE |We use a subsumption algorithm of J.A. Robinson (private
. communication) combining backtracking with the delicate
. treatment of unification in {REF ROBINSON2}.|}
The third discrepancy is that we implement
Robinson's "replacement principle" {REF ROBINSON} here. In particular, if
the splitting process produces two clauses one of whose ground resolvents subsumes either
of them, we throw out the subsumed clause(s) and keep the resolvent.
For example, the description above would transform the clause:
.ASIS
$a{(IF P
(IF Q R S)
(IF Q R V))}
.ENDASIS
into the following four clauses:
.ASIS
$a{(NOT P) (NOT Q) R$A}
$A{(NOT P) Q S$A}
$A{P (NOT Q) R$A}
$A{P Q V$A},
.ENDASIS
while our implementation would produce just three clauses:
.ASIS
$A{(NOT Q) R$A}
$A{(NOT P) Q S$A}.
$A{P Q V$A}
.ENDASIS
In particular,
we must prove $A{(NOT Q) R$A}
given P and $A{(NOT Q) R$A} given (NOT P). Thus, we decide to prove
$A{(NOT Q) R$A}.
.SS |The REVERSE Example|
Let us now look at an example theorem. We have picked a
simple one so that we can explain each "move" carefully.
Consider the idea of reversing a list. The reverse of the empty list
is the empty list. The reverse of the list x[&1], x[&2], ..., x[&n] is
x[&n], ..., x[&2], x[&1]. It can be recursively obtained
by reversing x[&2], ..., x[&n] to get x[&n], ..., x[&2] and then
adding x[&1] to the right-hand end.
.ASIS
Definition.
(REVERSE X)
=
(IF (LISTP X)
(APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL"))
"NIL").
.ENDASIS
If X is a "proper list" then (REVERSE (REVERSE X))
is just X. A "proper list" is one that terminates in "NIL" rather
than some other non-LISTP object. Its definition is:
.ASIS
Definition.
(PLISTP X)
=
(IF (LISTP X)
(PLISTP (CDR X))
(EQUAL X "NIL")).
.ENDASIS
That is, if X is a LISTP it must have a proper CDR, and if X is not a LISTP
it must be "NIL".
Let us prove:
.ASIS
~RR (IMPLIES (PLISTP X)
(EQUAL (REVERSE (REVERSE X)) X)),
.ENDASIS
using only the axioms of our theory of {YONSEC SECTHEFORMALTHEORY}
and the definitions of APPEND, REVERSE, and PLISTP.
.SS |Simplification in the REVERSE Example|
A careful inspection of ~RR (considered as a clause of two
literals) will show that we can do nothing to
simplify it further. In particular, we have no lemmas to apply to it,
and none of the recursive functions will expand without violating our
guidelines. Perhaps we can prove it by
induction. We will discuss how induction analysis
is handled in {YONSEC SECINDUCTION}.
At the moment, suffice it to say that
we are led to the following three new conjectures to prove:
.ASIS
~RR1 (IMPLIES (AND (NOT (LISTP X))
(PLISTP X))
(EQUAL (REVERSE (REVERSE X)) X)),
~RR2 (IMPLIES (AND (LISTP X)
(NOT (PLISTP (CDR X)))
(PLISTP X))
(EQUAL (REVERSE (REVERSE X)) X)),
and
~RR3 (IMPLIES (AND (LISTP X)
(PLISTP X)
(EQUAL (REVERSE (REVERSE (CDR X)))
(CDR X)))
(EQUAL (REVERSE (REVERSE X)) X)).
.ENDASIS
(The conjunction of ~RR2 and ~RR3 is propositionally equivalent to
the induction step.)
Let us now try to prove each of these by simplification.
That means we try to rewrite each of the literals in the clausal form
of the formulas, assuming the other literals to be false.
We begin with ~RR1. The intuitive reason ~RR1 is true is that
if X is not a LISTP but is a proper list, it must be "NIL",
and if it is "NIL" then we can confirm with computation that (REVERSE (REVERSE X))
is X. To show how our mechanical process follows this line of reasoning,
we proceed to simplify each literal in turn.
~RR1 is the three-literal clause:
.ASIS
$a{(LISTP X)
(NOT (PLISTP X))
(EQUAL (REVERSE (REVERSE X)) X)$A}.
.ENDASIS
Assuming the second and third literals false, we first try to rewrite
the first literal, (LISTP X). However, it cannot be simplified
because the type set of X is __UNIVERSE_ and we have no known rewrite lemmas
for LISTP.
Next, assuming the first and third literals false, we rewrite the atom
of the second literal, (PLISTP X). When we assume (LISTP X)
false, we note that X has type set
__UNIVERSE_ - $A{__LISTP_}. Thus, when we explore the definition of PLISTP
while trying to expand (PLISTP X), we rewrite the test (LISTP X) to
F and thus rewrite (PLISTP X) to (EQUAL X "NIL"). Thus, the intermediate
clause obtained after rewriting the first two literals of ~RR1 is:
.ASIS
$a{(LISTP X)
(NOT (EQUAL X "NIL"))
(EQUAL (REVERSE (REVERSE X)) X)$A}.
.ENDASIS
Finally, we explore the third literal, assuming (LISTP X) false and
(EQUAL X "NIL") true. The inner REVERSE term in the third
literal
simplifies to "NIL" (because X is now known to have type set
$a{__LITATOM_}) and so the outer REVERSE term opens up
to "NIL". Thus, the value of the third literal is (EQUAL "NIL" X),
which has type set $A{__T_} and hence is T.
Having reduced a literal of
~RR1 to T, we have proved it.
Goal ~RR2 is also easy. Reasoning informally, we can see that if X is a LISTP and its CDR
is not proper, then X cannot be a proper list. But this contradicts the third
literal of ~RR2. Our simplification heuristic proceeds as follows.
The first literal in the clausal form of ~RR2, (NOT (LISTP X)), cannot be simplified at all. The second, (PLISTP (CDR X)), is also
in simplest form. Of course, we consider opening PLISTP up, but find that
such a move would introduce (CDR (CDR X)), which is not currently involved
in ~RR2. But when we simplify the atom, (PLISTP X), of the third literal,
(NOT (PLISTP X)), in the clausal representation of ~RR2,
we assume X has type set $A{__LISTP_$A} and (PLISTP (CDR X)) has type set $A{__F_$A}
(i.e., is false). Thus, (PLISTP X) opens up to F (because
its recursive call, (PLISTP (CDR X)), has been assumed false), and
the third literal of ~RR2 is thus rewritten to (NOT F) or T.
Consequently, we are done with ~RR2.
Goal ~RR3 is the interesting one. The first hypothesis, (LISTP X), cannot
be simplified. The second, (PLISTP X), can be replaced by (PLISTP (CDR X)),
since when we tentatively open up PLISTP assuming (LISTP X) is false, we
obtain (PLISTP (CDR X)), and (CDR X) is mentioned in the conjecture already.
The third hypothesis, (EQUAL (REVERSE (REVERSE (CDR X))) (CDR X)), cannot be simplified
without introducing recursive calls (such as (REVERSE (CDR (CDR X)))) that
violate our guidelines. Finally, in the conclusion, (EQUAL (REVERSE (REVERSE X)) X),
we can open up (REVERSE X) to:
.ASIS
(APPEND (REVERSE (CDR X)) (CONS (CAR X) "NIL")),
.ENDASIS
since (CDR X) is already involved in the conjecture. None of our rules allow the resulting conjecture to be further
simplified and we are left with:
.ASIS
~RR4 (IMPLIES (AND (LISTP X)
(PLISTP (CDR X))
(EQUAL (REVERSE (REVERSE (CDR X)))
(CDR X)))
(EQUAL (REVERSE (APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL")))
X)).
.ENDASIS
To prove this, we must do something besides the kind of simplification we
have been discussing. In fact, the proof will ultimately require many of our heuristics
and we will advance the proof in each of the subsequent {SECTIONORCHAPTER}s
on proof techniques.
.SEC |ELIMINATING DESTRUCTORS|, SECELIMINATINGDESTRUCTORS:
.SS |Trading Bad Terms for Good Terms|
A standard trick when trying to prove a theorem involving
X-1, where the variable X is known to be a number other than 0,
is to replace X everywhere by Y+1. This means that the formula
now mentions Y and Y+1 where before it mentioned X-1 and X.
This trading of SUB1 for ADD1 makes
the relation between X-1 and X more obvious:
representing X as (ADD1 Y) makes it clear that X is a number,
that it is not 0, and that (SUB1 X) (i.e., Y) literally occurs within its
structure.
Consider another example. A formula about (QUOTIENT X Y) and (REMAINDER X Y)
(i.e., the integer quotient and remainder of X divided
by Y) can be reformulated by representing X as I+Y*J, where I is a number less
than Y. This trades the terms (QUOTIENT X Y), (REMAINDER X Y), and X, for
J, I, and I+Y*J. In particular, it eliminates QUOTIENT and REMAINDER
at the expense of introducing PLUS and TIMES. This is usually a
good trade because it makes clear that the quotient and remainder can
have arbitrary values (within certain constraints). For example, we
could induct on J, the number of times Y divides X. Furthermore,
PLUS and TIMES are simpler functions than QUOTIENT and REMAINDER, and it happens
that we know a lot of theorems about them. Once we have proved that
any number can be represented as I+Y*J, where I is less than Y, we
can deduce things about the quotient and remainder using our
already established knowledge of addition and multiplication.
What justifies this elimination of some terms in favor of others?
Let's look at the elimination of SUB1 in favor of ADD1 more
carefully and explain it in terms of axioms about arithmetic.
Suppose we have a formula of the form:
.ASIS
~1 (p (SUB1 x) x),{FNOTE |We now loosen our notational conventions
. by permitting lower case words in function symbol positions to represent
. schemas. For example, we think of (p (SUB1 x) x) as standing for
. a term such as (EQUAL (PLUS V Y) (TIMES (SUB1 X) Z)). If (p (SUB1 x) x)
. was understood to denote the above example, then when we refer to
. (p A B) we would have in mind (EQUAL (PLUS V Y) (TIMES A Z)).
. It is possible to abuse notational conventions; however, since
. we are now engaged in explaining heuristics and assume that the
. reader is mathematically competent, we feel that our occasional use
. of this convention does not warrant the complexity that precision here
. would entail. In sections "precisely" describing how
. our theorem prover works, we revert to using lower case
. words in function symbol positions to represent
. only function symbols, not schemas.|}
.ENDASIS
where x is a variable and (SUB1 x) actually occurs in the formula.
If x is not a number, or else is 0, then the (SUB1 x) term is
degenerate and it is useful to consider that case separately.
But if x is known to be a number and not 0, then we can soundly
replace x by (ADD1 y), where y is a new variable known to be numeric.
The result is that instead of proving ~1 we try to prove
both of the following:
.ASIS
~2 (IMPLIES (OR (NOT (NUMBERP x))
(EQUAL x 0))
(p (SUB1 x) x)) and
~3 (IMPLIES (NUMBERP y)
(p y (ADD1 y))).
.ENDASIS
Why is this move sound? That is, why does the conjunction of ~2
and ~3 suffice to prove ~1? Clearly, if x is nonnumeric or is 0,
then ~2 implies ~1. On the other hand, if x is numeric and non-0,
then we can derive ~1 from ~3 as follows. Instantiate ~3,
replacing y by (SUB1 x), to obtain:
.ASIS
(IMPLIES (NUMBERP (SUB1 x))
(p (SUB1 x) (ADD1 (SUB1 x)))).
.ENDASIS
Then use the axiom:
.ASIS
~A1 (IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0)))
(EQUAL (ADD1 (SUB1 X))
X))
.ENDASIS
to rewrite (ADD1 (SUB1 x)) to x (since we are assuming x is a non-0 number).
This produces:
.ASIS
(IMPLIES (NUMBERP (SUB1 x))
(p (SUB1 x) x)).
.ENDASIS
Finally, use the axiom:
.ASIS
~A2 (NUMBERP (SUB1 X))
.ENDASIS
to remove the hypothesis. The result is (p (SUB1 x) x), which is ~1.
Given that we believe it is easier to prove something about y and (ADD1 y)
than about (SUB1 x) and x, the problem for a theorem prover is to take note of ~A1 and ~A2
and generate ~2 and ~3 as goals when asked to prove ~1. The process
is exactly the reverse of the justification. Given ~1, split it into
two parts according to whether the hypotheses of ~A1 hold. ~2 is
the case that they do not. In the case where they hold replace certain of
the x's by (ADD1 (SUB1 x)), as allowed by ~A1. Then generalize the result
by replacing (SUB1 x) by y. The process of generalizing a conjecture
is discussed in detail in {YONSEC SECGENERALIZATION}. As we shall see then,
when (SUB1 x) is generalized to some new variable y, it is usually a
good idea to restrict the new variable to having some of the properties
of (SUB1 x). In particular, we can take note of ~A2 to restrict y to
being numeric. The result is ~3. The precise description of how we use
~A1 and ~A2 to generate ~2 and ~3 from ~1 is given later in this {SECTIONORCHAPTER}.
The really difficult question is where we get the
idea that REMAINDER and QUOTIENT are "bad"
and PLUS and TIMES are "good." Merely
knowing that we can eliminate REMAINDER and QUOTIENT because we
have proved some facts analogous to ~A1 and ~A2 is not reason enough
to eliminate them. For example, the following two axioms
are exactly analogous to
~A1 and ~A2 above, and allow us to eliminate ADD1
in favor of SUB1:
.ASIS
(IMPLIES (NUMBERP X)
(EQUAL (SUB1 (ADD1 X)) X)) and
(NUMBERP (ADD1 X)).
.ENDASIS
In general, we let the user tell us which functions should be eliminated
by allowing him to label certain theorems as "elimination"
type theorems. For example, ~A1 is an elimination theorem.
As for ~A2, it
is to be explicitly labeled as a "generalization" lemma if it
should be noted when (SUB1 x) is generalized.{FNOTE |In the special case of shells, over which we have complete control,
. it is the implementation of the shell principle that declares how an axiom should be
. used. When the ADD1 shell is added, ~A1 and ~A2 are
. classed as "elimination" and "generalization" theorems.|}
.SS |The Form of Elimination Lemmas|
An elimination theorem must have the form:
.ASIS
~ELIM
(IMPLIES hyp (EQUAL lhs var)),
.ENDASIS
where (1) var is a variable, (2) there is at least one proper subterm of lhs
of the form (d v[&1] ... v[&n]), where d is a function symbol
and the v[&i] are distinct
variables and are the only variables in the theorem,
and (3) var occurs in lhs only in such (d v[&1] ... v[&n]).
Examples of elimination lemmas are:
.ASIS
Axiom. SUB1.ELIM:
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0)))
(EQUAL (ADD1 (SUB1 X))
X))
Axiom. CAR/CDR.ELIM:
(IMPLIES (LISTP X)
(EQUAL (CONS (CAR X) (CDR X))
X))
Theorem. DIFFERENCE.ELIM:
(IMPLIES (AND (NUMBERP Y)
(LESSEQP X Y))
(EQUAL (PLUS X (DIFFERENCE Y X)) Y))
.ENDASIS
We call the (d v[&1] ... v[&n]) terms in the left-hand side of the
conclusion "destructor terms." In the above examples, the destructor
terms are (SUB1 X), (CAR X), (CDR X), and (DIFFERENCE Y X).
The name "destructor" refers to the fact that these functions can be
viewed as decomposing one of their arguments into its components in some
representation.
.SS |The Precise Use of Elimination Lemmas|
An elimination lemma can be used to eliminate any instance of
a destructor term by following the scenario sketched above for SUB1.
However, we have found that it is usually a mistake to eliminate
an instance in which the v[&i] are bound to nonvariables, or
when several of the v[&i] are bound to the same variable.
For example, eliminating (SUB1 (PLUS X Y)), while sound, usually
produces something that is more general than the original conjecture
and often a nontheorem, because the connection between the new variable
introduced, and other uses of X and Y, is lost. Similarly, while
(REMAINDER X X) could be eliminated as sketched, it would be a
heuristic mistake (since (REMAINDER X X) is in fact 0).
Suppose we are trying to prove some conjecture p,
involving a term (d x[&1] ... x[&j] ... x[&n]), where
x[&1], ..., x[&j], ..., x[&n] are distinct variables
and (d x[&1] ... x[&j] ... x[&n]) is an instance of a
destructor term (d v[&1] ... v[&j] ... v[&n]) in
an elimination lemma:
.ASIS
~ELIM (IMPLIES hyp (EQUAL lhs v[&j])).
.ENDASIS
We will eliminate (d x[&1] ... x[&j] ... x[&n])
from p by using ~ELIM to re-represent x[&j].
The result will be two new clauses, which are
sufficient to establish p.
Let ~ELIM' be the formula obtained by simultaneously
replacing each v[&i] in ~ELIM by x[&i]:
.ASIS
~ELIM' (IMPLIES hyp' (EQUAL lhs' x[&j])).
.ENDASIS
Since ~ELIM' is a theorem, our goal p is equivalent
to the conjunction of:
.ASIS
~ELIM1 (IMPLIES (NOT hyp') p) and
~ELIM2 (IMPLIES (AND hyp' (EQUAL lhs' x[&j]))
p).
.ENDASIS
~ELIM1 is one of the two formulas produced by eliminating
(d x[&1] ... x[&j] ... x[&n]) from p. ~ELIM1 is the
degenerate case. We derive the second output formula
from ~ELIM2 as follows.
We generalize ~ELIM2 in two steps. The first step
is to add to ~ELIM2 an additional hypothesis
gen known to be a theorem:
.ASIS
~ELIM3 (IMPLIES (AND gen hyp' (EQUAL lhs' x[&j]))
p).
.ENDASIS
Intuitively, gen is a theorem about the destructor
terms in lhs' and serves to restrict the coming generalization.
The selection of gen is described in {YONSEC SECGENERALIZATION}.
The second generalization step is to uniformly replace
throughout ~ELIM3 each of the destructor terms in lhs'
by some distinct variable not already occurring in
~ELIM3:
.ASIS
~ELIM4 (IMPLIES (AND gen' hyp'' (EQUAL lhs'' x[&j]))
p').
.ENDASIS
Note that ~ELIM4 is sufficient to prove ~ELIM2:#
instantiate the new variables in ~ELIM4 to produce
~ELIM3 and then use the theorem gen to derive
~ELIM2. (Actually, the generalization heuristic
described in {YONSEC SECGENERALIZATION} is used to produce
~ELIM4 from ~ELIM2 given the destructor terms
in lhs.)
The final step in eliminating (d x[&1] ... x[&j] ... x[&n])
from p is to use the equality hypothesis (EQUAL lhs'' x[&j])
in ~ELIM4 by uniformly replacing x[&j] throughout ~ELIM4 by lhs''
and deleting the hypothesis:
.ASIS
~ELIM5 (IMPLIES (AND gen'' hyp''') p'').
.ENDASIS
~ELIM1 and ~ELIM5 are the results of eliminating (d x[&1] ... x[&j] ... x[&n]) from p.
.SS |A Nontrivial Example|
This may seem like a very complicated way to replace X by (ADD1 Y).
However, the idea of rerepresenting terms is important in many
difficult proofs. Let us consider a nontrivial example. We will
carry it out in the same step-by-step fashion we described above.
Suppose we have proved the following two theorems:
.ASIS
~T1 (IMPLIES (AND (NOT (ZEROP Y)) (NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X))
and
~T2 (EQUAL (LESSP (REMAINDER X Y) Y)
(NOT (ZEROP Y))).
.ENDASIS
These are probably the two most important properties of REMAINDER
and QUOTIENT. The first says that by adding the remainder to the
product of the quotient and the divisor one obtains the dividend.
The second says that the remainder is less than the divisor.{FNOTE |This
. particular statement is stronger and more useful as a rewrite
. rule. It says that (REMAINDER X Y) is less than Y if and only if
. Y is non-ZEROP.|}
Our mechanical theorem prover proves these two theorems by induction,
using the recursive definitions of REMAINDER and QUOTIENT and
previously proved theorems about PLUS, TIMES, LESSP, and DIFFERENCE.
The theorem prover's proof of ~T1 is the last proof exhibited in
{YONSEC SECELEMENTARY}. Let
us suppose ~T1 and ~T2 have been proved and that
~T1 is available as an elimination theorem and ~T2
as a generalization theorem (they are both useful as rewrite rules as well).
Let us now prove:
.ASIS
(IMPLIES (DIVIDES A B) (DIVIDES A (TIMES B C)))
.ENDASIS
where the definition of (DIVIDES A B) is (EQUAL (REMAINDER B A) 0).
This is usually proved with the following argument. If (DIVIDES A B), then we can
write B as (TIMES A J), making a factor of A in (TIMES B C) manifest.
Of course, one has to consider the possibility that B cannot be represented
as (TIMES A J). For example, what if B is nonnumeric or A is 0?
Let us now go through the mechanical proof and see how this reasoning is
done formally and completely.
By opening up the definition of (DIVIDES A B) we obtain:
.ASIS
~4 (IMPLIES (EQUAL (REMAINDER B A) 0)
(EQUAL (REMAINDER (TIMES B C) A)
0)).
.ENDASIS
Noting that (REMAINDER B A) is an instance of a destructor term in ~T1
and that the arguments are all distinct variables, we can use ~T1 to
eliminate (REMAINDER B A). First we split ~4 into two parts:
.ASIS
~5 (IMPLIES (AND (OR (NOT (NUMBERP B))
(ZEROP A))
(EQUAL (REMAINDER B A) 0))
(EQUAL (REMAINDER (TIMES B C) A) 0)) and
~6 (IMPLIES (AND (NUMBERP B)
(NOT (ZEROP A))
(EQUAL (PLUS (REMAINDER B A)
(TIMES A (QUOTIENT B A)))
B)
(EQUAL (REMAINDER B A) 0))
(EQUAL (REMAINDER (TIMES B C) A)
0)).
.ENDASIS
Formula ~5 corresponds to formula ~ELIM1 in the schematic description
of elimination, above. We do not further manipulate it as part
of eliminating (REMAINDER B A).
Formula ~6 corresponds to formula ~ELIM2 above, and we want to remove the
destructor terms. First we generalize those terms away, replacing
(REMAINDER B A) by the new variable I and (QUOTIENT B A) by the new
variable J. The generalization heuristic will take note of ~T2 as a
generalization lemma and will also note that both REMAINDER and QUOTIENT
are always numerically valued (by computing the type sets of
the expressions generalized). The result of generalizing ~6 is:
.ASIS
(IMPLIES (AND (NUMBERP I)
(NUMBERP J)
(EQUAL (LESSP I A) (NOT (ZEROP A)))
(NUMBERP B)
(NOT (ZEROP A))
(EQUAL (PLUS I (TIMES A J)) B)
(EQUAL I 0))
(EQUAL (REMAINDER (TIMES B C) A)
0)).
.ENDASIS
(The first three hypotheses are the restrictions placed on the new
variables by the generalization. The rest of the
formula is just ~6 with the destructor terms replaced by I and J.)
Now we use the hypotheses, (EQUAL (PLUS I (TIMES A J)) B), to
replace B everywhere in the formula. Afterwards, we throw away the
hypothesis. The result is:
.ASIS
~7 (IMPLIES (AND (NUMBERP I)
(NUMBERP J)
(EQUAL (LESSP I A) (NOT (ZEROP A)))
(NUMBERP (PLUS I (TIMES A J)))
(NOT (ZEROP A))
(EQUAL I 0))
(EQUAL (REMAINDER (TIMES (PLUS I (TIMES A J))
C)
A)
0)).
.ENDASIS
This formula corresponds to ~ELIM5 in the schematic presentation
of elimination, above. ~5 and ~7 together are the result of eliminating
(REMAINDER B A) from ~4.
At first sight things appear worse than they
were.
However, ~5 is the degenerate case in which B is nonnumeric or
A is ZEROP. Quoting from our sketch of the proof:##"Of course, one has to consider the possibility that B cannot be represented
as (TIMES A J). For example, what if B is nonnumeric or A is 0?"
In fact, ~5 can be simplified to true using only
our definitions of TIMES and REMAINDER.
As for ~7, it too can be simplified drastically. For example,
since PLUS is always numeric, the (NUMBERP (PLUS I (TIMES A J)))
term simplifies to T. But the really important observation is that our
hypothesis (DIVIDES A B) has been transformed into (EQUAL I 0).
Simplification will substitute 0 for I everywhere. After
routine simplification the result is:
.ASIS
(IMPLIES (AND (NUMBERP J)
(NUMBERP A)
(NOT (EQUAL A 0)))
(EQUAL (REMAINDER (TIMES A (TIMES C J))
A)
0)).
.ENDASIS
Once again quoting from our earlier sketch:##
"If (DIVIDES A B), then we can
write B as (TIMES A J), making a factor of A in (TIMES B C) manifest."
The actual process was:##"If (EQUAL (REMAINDER B A) 0) then we
can represent B as (PLUS I (TIMES A J)), where (EQUAL I 0)."
In the informal proof sketch, the word "manifest" assumed that the
reader was familiar with the
theorem (DIVIDES J (TIMES J I)), or, opening DIVIDES up, (EQUAL (REMAINDER (TIMES J I) J) 0).
If we had previously proved this as a rewrite rule, then ~7 would
simplify to true (i.e., we would have gotten something out of the
observation that indeed a factor of A was manifest). If we had not proved the above
theorem then we would have to prove the simplified version of ~7
by induction.
.SS |Multiple Destructors and Infinite Looping|
Two final aspects of destructor elimination should be mentioned.
Occasionally one has the opportunity of eliminating several destructors.
For example, SUB1, DIFFERENCE, and REMAINDER are all destructors and
frequently occur in the same conjectures (since they are defined
in terms of one another). We have found that when one has a choice
of what terms to eliminate it is best to eliminate the simplest first.
Thus we would eliminate SUB1 (with ADD1) before eliminating
DIFFERENCE (with PLUS), and eliminate DIFFERENCE before we eliminated
REMAINDER (with PLUS and TIMES). We define "simplest"
here by considering the order in which the functions
were introduced into the theory,
since "subroutines" must be introduced before the functions using
them.
When a conjecture contains several eliminable destructors, we eliminate
the simplest first. Then we repeatedly eliminate destructor
terms introduced by the previous elimination. The resulting
set of clauses is returned to the top of the waterfall.
For example, if a conjecture contained (SUB1 (SUB1 X)) and
(REMAINDER U V), we would first eliminate
(SUB1 X) by replacing X with (ADD1 J). This would transform (SUB1 (SUB1 X))
to (SUB1 J). Then we would eliminate (SUB1 J).
Then we would return to simplification and not eliminate
(REMAINDER U V) until after simplification.
(The result in this case is just
what we would have obtained by initially eliminating (SUB1 (SUB1 X)) by
letting X be I+2.)
In tandem
with simplification, destructor elimination could cause infinite loops.
An example is the term (LESSP (SUB1 I) I). Here we
would "eliminate" (SUB1 I) by replacing it with (ADD1 J) to obtain
(LESSP J (ADD1 J)). Then simplification would expand LESSP once to
produce (LESSP (SUB1 J) J), and we would begin again. To avoid looping,
we
never eliminate a term that involves a
variable that was introduced by a previous elimination pass
unless there has been an intervening induction.
.SS |When Elimination is Risky|, SSECWHENELIMINATIONISRISKY:
As presented, and as implemented, the elimination of destructors
can be heuristically risky, because it
can result in a conjecture more general than the initial one.
Elimination of destructors is always sound, because
by construction, if ~ELIM1 and ~ELIM5 are theorems, then p is a theorem.
However, it is possible for p to be a theorem but for ~ELIM5
to be a nontheorem. For example, if we
transformed:
.ASIS
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0)))
(p (SUB1 X) X))
.ENDASIS
to:
.ASIS
(p Y (ADD1 Y)),
.ENDASIS
instead of:
.ASIS
(IMPLIES (NUMBERP Y)
(p Y (ADD1 Y))),
.ENDASIS
the result might not be a theorem.
We now present sufficient conditions under which
elimination is not risky. In the following
proof we suppose that our elimination lemma has
two destructor terms and that each destructor
term has two arguments; a proof for the
general case can be constructed in strict
analogy with the following.
Suppose we are trying to prove:
.ASIS
~GOAL (p (d x y) (e x y) x y),
.ENDASIS
where x and y are distinct variables. Suppose
further that we have an elimination lemma
.ASIS
~ELIM (IMPLIES (hyp u v)
(EQUAL (lhs (d u v) (e u v) v)
u)).
.ENDASIS
Next suppose that we have the generalization lemma:
.ASIS
~GEN (g (d w z) (e w z) w z),
.ENDASIS
where w and z are distinct variables.
The results of using the elimination lemma ~ELIM
(together with the generalization lemma ~GEN)
upon ~GOAL are the two formulas:
.ASIS
~ELIM1 (IMPLIES (NOT (hyp x y))
(p (d x y) (e x y) x y)) and
~ELIM5 (IMPLIES (AND (hyp (lhs r s y) y)
(g r s (lhs r s y) y))
(p r s (lhs r s y) y)),
.ENDASIS
where r and s are new variables. Our no-risk insurance is:#
If ~GOAL is a theorem, then ~ELIM1 and ~ELIM5
are theorems if:
.ASIS
~COND (IMPLIES (g r s (lhs r s y) y)
(AND (EQUAL (d (lhs r s y) y) r)
(EQUAL (e (lhs r s y) y) s)))
.ENDASIS
is a theorem. ~ELIM1 follows immediately from ~GOAL. To prove
~ELIM5, choose r, s, and y and assume the hypothesis
(g r s (lhs r s y) y). Instantiate ~GOAL to obtain:
.ASIS
(p (d (lhs r s y) y)
(e (lhs r s y) y)
(lhs r s y)
y).
.ENDASIS
From ~COND, our assumptions, and the last formula, we
conclude:
.ASIS
(p r s (lhs r s y) y).
.ENDASIS
Q.E.D.
Given this theorem, we can check that the elimination
of SUB1 by the introduction of ADD1 is not risky since
we have:
.ASIS
(IMPLIES (NUMBERP U)
(EQUAL (SUB1 (ADD1 U))
U)).
.ENDASIS
Similarly, we can check that the elimination of
REMAINDER and QUOTIENT is not risky. The basic
idea is that for any numeric U less than Y and any numeric
V, U+Y*V has remainder U when divided by Y
and quotient V when divided by Y.
Our implementation does not check that
an elimination lemma is risk free, since it
is not necessary to the soundness of the system.
As users, we have never employed risky elimination
theorems.
.SS |Destructor Elimination in the REVERSE Example|
Let us now return to the proof of the theorem about (REVERSE (REVERSE X)).
Recall that after induction we had three cases. Simplification reduced
the first two to true and the third one to:
.ASIS
~RR4 (IMPLIES (AND (LISTP X)
(PLISTP (CDR X))
(EQUAL (REVERSE (REVERSE (CDR X))) (CDR X)))
(EQUAL (REVERSE (APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL")))
X)).
.ENDASIS
We can eliminate (CAR X) by using the elimination lemma
for it added by our implementation of the shell principle:
.ASIS
Axiom. CAR/CDR.ELIM:
(IMPLIES (LISTP X)
(EQUAL (CONS (CAR X) (CDR X))
X)).
.ENDASIS
In a conjecture of the form (p (CAR X) (CDR X) X), destructor elimination
would produce two cases:
.ASIS
(IMPLIES (NOT (LISTP X))
(p (CAR X) (CDR X) X))
.ENDASIS
and
.ASIS
(IMPLIES (LISTP (CONS A B))
(p A B (CONS A B))).
.ENDASIS
Since our current conjecture, ~RR4, has a (LISTP X) hypothesis, the first
case produced by destructor elimination is trivial.{FNOTE |It is a propositional
. tautology and would not in fact be produced by the implementation for
. that reason.|} The second case, after simplification, is:
.ASIS
~RR5 (IMPLIES (AND (PLISTP B)
(EQUAL (REVERSE (REVERSE B)) B))
(EQUAL (REVERSE (APPEND (REVERSE B) (CONS A "NIL")))
(CONS A B))).
.ENDASIS
Note that in ~RR5 the equality hypothesis about B can be used in
the conclusion about (CONS A B) in a way that the equality
hypothesis in ~RR4 cannot. In particular, we see that there is an occurrence of B
in the right-hand side of the conclusion, where none was obvious before.
We continue the proof of the REVERSE example in the
next chapter.
The use of elimination in the REVERSE example illustrates an important aspect of destructor elimination
not mentioned elsewhere. Note that ~RR5 is exactly what we would have
had, had we initially used an induction step such as (IMPLIES (p B) (p (CONS A B))),
instead of (IMPLIES (AND (LISTP X) (p (CDR X))) (p X)). Similarly, an elimination
of (SUB1 X) would convert an induction step such as:
.ASIS
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(p (SUB1 X)))
(p X))
.ENDASIS
to the more conventional:
.ASIS
(IMPLIES (AND (NUMBERP I)
(p I))
(p (ADD1 I))).
.ENDASIS
The latter induction is usually nicer for the same reasons that
elimination of destructors is desirable at all.
One might ask why we did not do such an induction in the first place.
The reason is that in general it is impossible because not all operations
have inverses.
For example, consider the function DELETE:
.ASIS
Definition.
(DELETE X Y)
=
(IF (NLISTP Y)
Y
(IF (EQUAL X (CAR Y))
(CDR Y)
(CONS (CAR X) (DELETE X (CDR Y))))),
.ENDASIS
which returns the result of deleting the first occurrence
of X in Y. There is no function PUT.BACK such that
(IMPLIES (PLISTP Y) (EQUAL (PUT.BACK X (DELETE X Y)) Y)).
In the function DSORT, we use DELETE as the destructor
function in the recursive call. In proving the correctness of
DSORT in the theorem DSORT.SORT2, we perform an induction with
the scheme:
.ASIS
(AND (IMPLIES (NOT (LISTP X)) (p X))
(IMPLIES (AND (LISTP X)
(p (DELETE (MAXIMUM X) X)))
(p X))).
.ENDASIS
This induction is appropriate, and in the
absence of an elimination lemma for DELETE, it is
difficult to imagine the "constructive" (as
opposed to "destructive") version of this induction.
Thus induction must, in general, operate by supplying hypotheses about
the "destructors" actually employed by the recursive functions in the theorem,
rather than conclusions about "constructors." Since
some destructors are eliminable and the need to eliminate them arises
outside of induction as well as inside it, we decided to formulate the
destructor elimination heuristic in the general way described.
.SEC |USING EQUALITIES|, SECFERTILIZE:
.SS |Using and Throwing Away Equalities|
When a formula has been maximally simplified and has had all the
eligible destructor terms eliminated, we next try to use any
equality hypotheses that may exist in the formula.
We try to use an equality hypothesis such as (EQUAL s' t') by substituting s' for t'
elsewhere in the formula and deleting the equality.
This procedure sometimes results in conjectures that can
then be proved by simplification. For example, after the substitution
it might become possible to open up a recursive function under our guidelines.
But the motivation behind our handling of
equality is far more heuristic:##if a conjecture has not yielded to
simplification and elimination of destructors, we will probably
resort to induction to prove it. If so, it is best
to clean up the conjecture as much as possible.
Furthermore, if we have already applied induction, it is best to use
the available induction hypotheses before resorting to induction again.
To explain our handling of equality we have to talk briefly about induction.
The fundamental induction heuristic is to try to arrange things so
that in an induction step of the form (IMPLIES (p t') (p t)),{FNOTE |Here and elsewhere
. in this {SECTIONORCHAPTER}, we have ignored many of
. the details of induction, such as the case analysis responsible for
. making the induction hypotheses legal, so that we can concentrate on
. giving the reader our intuitions about the problems rather than the
. details.|} simplification
will be able to reduce the conclusion, (p t), to some expression involving t', so
that the induction hypothesis can be used. Now suppose the theorem to
be proved is of the form (EQUAL s t) (or merely concludes with such a literal).
Then if the induction heuristic succeeds we will, after simplification,
have a conjecture of the form:
.ASIS
(IMPLIES (EQUAL s' t')
(EQUAL s (h t'))).
.ENDASIS
In particular, t'
will occur in the conclusion because we inducted in a way to make it do so.
If the implication above survives simplification we will probably have
to prove it by induction. But proving something of the
form (IMPLIES p q) by induction, where p is an equality, is often difficult. If we
analyze the propositional calculus in the induction step for (IMPLIES p q):
.ASIS
(IMPLIES (IMPLIES p' q')
(IMPLIES p q)),
.ENDASIS
we see that one of the cases is to prove (IMPLIES p q), given that p' does not
hold. Since p' is an equality, its negation is not very strong, and since
we have already failed to prove (IMPLIES p q), we do not have much with which to work.
From a purely heuristic standpoint it is better not to try to prove
(IMPLIES p q) by induction but rather to try to use the
hypothesis, p, and throw it away, before we go into induction again.
Bledsoe noted the importance of "using up" a hypothesis
and throwing it away in the "forcing principle" of {REF BLEDSOELIMIT}.
In the resolution tradition of automatic theorem-proving,
the idea of using up and throwing away hypotheses has received scant
attention. One reason is that it is never actually
necessary to throw away a clause in order to find a refutation of
a set of clauses. However, when one is using a principle of induction,
one has to select a particular formula
upon which to do the induction. We believe
that the "cleaning up" effect of fertilization, the simplifications
performed by rewriting, and the generalizations to be described
are essential to the performance of any theorem-proving system that
handles proof by induction.
.SS |Cross-Fertilization|
In order to use (EQUAL s' t') in:
.ASIS
(IMPLIES (EQUAL s' t')
(EQUAL s (h t'))),
.ENDASIS
we can substitute s' for t' in the other literals of the clause and
delete the hypothesis. But rather than substitute for all occurrences
of t' in (EQUAL s (h t')), we prefer to substitute just for those in (h t').
That is, if we have decided to use (EQUAL s' t') by substituting the left-hand side
for the right, and one of the places into which we substitute is itself an
equality, (EQUAL s (h t')), related to (EQUAL s' t') by induction, then we substitute
only into the right-hand side. We call this "cross-fertilization."
To justify the plausibility of this heuristic, we must again discuss induction. If (EQUAL s t)
is not proved by one induction, it is often because
we managed to get t to simplify to t' but failed to get s to simplify to s',
usually because s requires a different induction
than t, e.g., induction on a different set of variables or with different
hypotheses. By substituting s' for t' on t's side of the conjecture we
can eliminate t from the problem and at the same time cast the problem
entirely in terms of s and its descendants. In particular, by transforming:
.ASIS
(IMPLIES (EQUAL s' t')
(EQUAL s (h t')))
.ENDASIS
to:
.ASIS
(EQUAL s (h s')),
.ENDASIS
we may be able to do an induction that lets both sides of the equality
step through induction together.
.SS |A Simple Example of Cross-Fertilization|
Let us now illustrate why we throw away the equality
hypothesis after it has been used and how cross-fertilization
often constructs theorems that go through induction cleanly.
While we
could cite complicated proofs in which cross-fertilization plays a role,
we will deal here with a simple theorem, for pedagogical reasons.
Let us prove that PLUS is commutative:
.ASIS
(EQUAL (PLUS X Y) (PLUS Y X)).
.ENDASIS
Note that the roles of X and Y are symmetric. Thus there is nothing
to distinguish an induction on X from one on Y. An induction on X will
let (PLUS X Y) step cleanly through the induction (in the sense that
the (PLUS X Y) term in the induction conclusion will simplify
to a term involving its counterpart in the induction hypothesis).
Similarly, an induction on Y would "favor" (PLUS Y X). Neither
induction is well-suited to both terms. Let us do the induction
on Y. Then the induction step is:
.ASIS
(IMPLIES (AND (NOT (ZEROP Y))
(EQUAL (PLUS X (SUB1 Y))
(PLUS (SUB1 Y) X)))
(EQUAL (PLUS X Y) (PLUS Y X))).
.ENDASIS
After simplification and the elimination of (SUB1 Y) by replacing Y with
(ADD1 Y), we get:
.ASIS
(IMPLIES (EQUAL (PLUS X Y) (PLUS Y X))
(EQUAL (PLUS X (ADD1 Y)) (ADD1 (PLUS Y X)))).
.ENDASIS
Note that, as expected, the (PLUS Y X) term appears both in the hypothesis
and the conclusion. Thus, we can use the equality by substituting
(PLUS X Y) for (PLUS Y X) in the right-hand side of the conclusion and,
after deleting the equality, get:
.ASIS
(EQUAL (PLUS X (ADD1 Y)) (ADD1 (PLUS X Y))).
.ENDASIS
(Note that this equation is the "recursive" clause
of a definition of PLUS that decomposes Y instead of X.)
We have to prove this equation by induction, but now the theorem involves only
(PLUS X Y) and its descendants. In particular, the commuted PLUS expression "favoring" Y
has been eliminated (precisely because we inducted in the way we did and threw
away the equality).
Because all the PLUS terms descend from (PLUS X Y) there is a single,
clear-cut induction we can perform to make them all step through
induction, namely, induction on X. If we now
perform an induction in which the induction step is:
.ASIS
(IMPLIES (EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y)))
(EQUAL (PLUS (ADD1 X) (ADD1 Y))
(ADD1 (PLUS (ADD1 X) Y)))),
.ENDASIS
the conclusion
simplifies, first to:
.ASIS
(EQUAL (ADD1 (PLUS X (ADD1 Y)))
(ADD1 (ADD1 (PLUS X Y)))),
.ENDASIS
and then to:
.ASIS
(EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y))),
.ENDASIS
which is precisely our induction hypothesis.
Had we not performed the cross-fertilization, or had we done the
substitution but not deleted the equality hypothesis, the
conjecture would still have involved (PLUS Y X) terms and a subsequent
induction on X would not have gone through (because our hypothesis would
concern (PLUS Y X) and the conclusion (PLUS Y (ADD1 X))).
.SS |The Precise Use of Equalities|
Here is the precise way we use equalities.
Given a clause, we look for an equality hypothesis, (EQUAL s' t') (i.e.,
a literal of the clause of the form (NOT (EQUAL s' t'))), where t' (or s')
occurs in another literal of the clause and is not an explicit value template.
Suppose we find such an (EQUAL s' t'), and that t' has the property described
above. Then we will substitute s' for t' in a way described below.
If we are working on an induction step and there is an equality literal in
the clause that mentions t' on the right-hand side,
we decide to cross-fertilize (unless s' is an explicit value).
Then we substitute s' for t' in each literal of the clause, except the
(EQUAL s' t') hypothesis. If we decided to cross-fertilize
then when we encounter an equality literal we substitute s' uniformly for t' on
the right-hand side. Otherwise we substitute s' uniformly for t' throughout the literal.
Finally, if we are working on an induction step and s' was
not an explicit value, we delete the (EQUAL s' t') hypothesis.
Of course, the resulting formula is then poured over the
waterfall to be simplified again.
If there are multiple equality hypotheses that can be so used, we
use only the first one we find. The others will be used on subsequent
passes, after we have simplified the new formula and
eliminated any destructor terms now eligible.
By throwing away the equality hypothesis, we are generalizing
the clause and are thus risking the adoption of a nontheorem as our
goal. (For example, under the hypotheses elsewhere in the formula,
the equality with which we substitute might be false. The input formula
would thus be a theorem, but after eliminating the "reason" it was
a theorem, it might not be.)
As noted earlier, we prefer to do the safest things first,
and both simplification and elimination of destructors are safe and
can possibly simplify the formula before we have to resort to
another substitution.
.SS |Cross-Fertilization in the REVERSE Example|
Let us now return to the (REVERSE (REVERSE X)) example.
Recall that after elimination of the (CAR X) and (CDR X) expressions
we were left with:
.ASIS
~RR5 (IMPLIES (AND (PLISTP B)
(EQUAL (REVERSE (REVERSE B)) B))
(EQUAL (REVERSE (APPEND (REVERSE B)
(CONS A "NIL")))
(CONS A B))).
.ENDASIS
Note that we can use the hypothesis (EQUAL (REVERSE (REVERSE B)) B) by
substituting (REVERSE (REVERSE B)) for B in the conclusion. However,
we will ignore the occurrences of B in the left-hand side of
the conclusion, and will cross-fertilize for B in the right-hand side.
Observe that we can cross-fertilize only because the elimination of destructors
made it manifest that (CDR X) occurs in X when X is a list (i.e., B occurs
in (CONS A B)). After deleting the equality hypothesis we are
left with:
.ASIS
~RR6 (IMPLIES (PLISTP B)
(EQUAL (REVERSE (APPEND (REVERSE B)
(CONS A "NIL")))
(CONS A (REVERSE (REVERSE B))))).
.ENDASIS
We have thus managed to use our induction hypothesis, and we have
produced a "balanced" equality with REVERSE and its descendants on
both sides. In addition, since a subterm of s, namely the innermost
REVERSE expression, did reappear in s' because of our induction, we
will be able to generalize it as described in the next {SECTIONORCHAPTER}.
.SEC |GENERALIZATION|, SECGENERALIZATION:
.SS |A Simple Generalization Heuristic|
In proofs by induction, it is often easier to prove a theorem that is
stronger than the one needed by some particular application. We have already seen
several instances of this. For example, it arose in the TAUTOLOGYP
proofs, where we proved:
.ASIS
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X A1))
(VALUE X (APPEND A1 A2)))
.ENDASIS
rather than the more obvious:
.ASIS
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X "NIL"))
(VALUE X A2)).
.ENDASIS
Another example arose in {YONSEC SECOVERVIEW}
when we proved:
.ASIS
(EQUAL (MC.FLATTEN X ANS) (APPEND (FLATTEN X) ANS))
.ENDASIS
rather than the more obvious:
.ASIS
(EQUAL (MC.FLATTEN X "NIL") (FLATTEN X)).
.ENDASIS
Of course, the reason that induction on stronger theorems is easier is
that the main tools one has when proving a formula by induction
are instances of the formula itself.
There has been some work on trying to generate mechanically
the kind of generalizations performed in the MC.FLATTEN
problem above {REF IEEE}, {REF AUBIN}. However,
such major generalizations require "creative" insight into the
problem.{FNOTE |That is, until someone produces a mechanization of the
. process, we say the process requires creativity.|}
We do not attempt to make such generalizations mechanically and
leave such leaps to the user; he can always formulate and prove the desired theorem as a rewrite
rule, so that instances of
the theorem will be simplified to true and we will never have to guess the appropriate generalization.
However, if one inspects many inductive proofs, one discerns a common phenomenon
involving generalization.
Suppose we are trying to prove that some recursive function, f,
always computes a value satisfying proposition p. That is, we are trying to
prove (p (f x[&1] ... x[&n])). Suppose further that under some condition we know that
(f x[&1] ... x[&n]) computes its value by computing (f x[&1]' ... x[&n]') recursively, and then
applying h. Thus, a reasonable induction step{FNOTE |We will here ignore the finer points of induction, such as the case
. analysis, just as we did in the last
. {SECTIONORCHAPTER}, and for the same reasons.|}
to provide is:
.ASIS
(IMPLIES (p (f x[&1]' ... x[&n]'))
(p (f x[&1] ... x[&n]))),
.ENDASIS
for then, when we simplify (f x[&1] ... x[&n]) in the conclusion, we
get:
.ASIS
~1 (IMPLIES (p (f x[&1]' ... x[&n]'))
(p (h (f x[&1]' ... x[&n]')))),
.ENDASIS
where, as planned, we managed to cause (f x[&1]' ... x[&n]') to appear in
both the
hypothesis and the conclusion.
Now suppose that we are not able to prove this formula
by the previously presented heuristics. Then we will
probably have to appeal to induction again. We have found
that in such a situation, it is fruitful to
try instead to prove the more general:
.ASIS
~2 (IMPLIES (p z) (p (h z))),
.ENDASIS
where z is a new variable. That is, if we were to prove ~2, we could derive ~1 from it
by instantiating the z in ~2 to be (f x[&1]' ... x[&n]').
Another way to look at it is that by replacing
(f x[&1]' ... x[&n]') in ~1 by the new variable z,
we can "guess" ~2 as a possible way
of proving ~1.
We thus have another heuristic:##if in the result
of simplifying an induction step we find subterms occurring in two or
more literals, then we assume that those terms
stepped through induction cleanly, have introduced their subsidiary
functions and tests, and now merely represent "place-holders" for
arbitrary objects with the properties described by the hypotheses.
Thus, those common subterms can be replaced by new variables.
If we were initially trying to prove an equality then it often happens
that our hypothesis gets "used" (by fertilization) because one side
of the equality comes through the induction cleanly. However, the
other side of both the hypothesis and conclusion equalities may
have common subterms as above. After cross-fertilizing, those common
subterms are on opposite sides of the conclusion equality.
Thus, we expand our heuristic to apply to
common subterms on opposite sides of an equality literal.
.SS |Restricting Generalizations|
The heuristic of generalizing common subterms on either side of an
equality or implication was first implemented in the theorem prover
described in {REF JACM}. We found it worked very well in simple
examples. But it suffers from a tendency to produce
overly general statements (i.e., nontheorems). In justifying the
idea of generalizing the common subterm (f x[&1]' ... x[&n]'), we said that perhaps it
was a "place holder" for any object with the properties
described by the induction hypotheses and case analysis.
But suppose that (f x[&1]' ... x[&n]') has "intrinsic"
properties that are relevant to the proof but not mentioned.
For example, if (f x[&1]' ... x[&n]') was known to be numeric, then it might be good
to require that the new variable be numeric. Similarly, if
we ever generalize (SORT X), where SORT is a function that sorts
the elements of its list argument into ascending order, it might
be good to require that the new variable be an ordered list.
We do not know how to recognize mechanically what
properties of the term being generalized to require
of the new variable. So we permit the user to bring to
our attention "generalization" lemmas that inform us of facts
that are good to keep in mind when generalizing.
Suppose we have previously proved and noted as a generalization lemma a
theorem such as:
.ASIS
~3 (r (f t[&1] ... t[&n])),
.ENDASIS
where r is a schema.
Suppose further that the term to be generalized, (f x[&1]' ... x[&n]'), is an
instance of (f t[&1] ... t[&n]).
The generalization of ~1 above proceeds as follows.
We notice that (f x[&1]' ... x[&n]') is a common subterm and that
it occurs in an instance of ~3:
.ASIS
~3' (r (f x[&1]' ... x[&n]')).
.ENDASIS
Consider the conjecture obtained by adding ~3' as a
hypothesis to ~1:
.ASIS
~4 (IMPLIES (AND (r (f x[&1]' ... x[&n]'))
(p (f x[&1]' ... x[&n]')))
(p (h (f x[&1]' ... x[&n]')))).
.ENDASIS
Since ~3' is a theorem, ~1 is a theorem if ~4 is
a theorem. We then choose to try to prove ~4 by trying
to prove the more
general conjecture obtained by replacing throughout
~4 (f x[&1]' ... x[&n]') with a new variable z:
.ASIS
(IMPLIES (AND (r z) (p z))
(p (h z))).
.ENDASIS
If we know that the term being generalized always
returns an object of a single shell type (that is, if we can observe
that the type set of the term is a singleton), then we have found it
useful to restrict the new variable to being in that class.
For example, if (f x[&1]' ... x[&n]') is numeric,
then it is both sound and generally useful to add as an additional
hypothesis (NUMBERP z). However, if the type set of
(f x[&1]' ... x[&n]') contains more than one type,
the corresponding restriction would be a disjunction
(e.g., z would be required
to satisfy either NUMBERP or LISTP).
We have found, empirically, that such weak constraints usually contribute little
and split the theorem into several parts. In this case we
simply ignore the type set information we have about (f x[&1]' ... x[&n]').
.SS |Examples of Generalizations|
We will describe the whole generalization procedure precisely in a moment.
But first we look more closely at two example generalizations that
were mentioned earlier. The first
was in the MC.FLATTEN proof in {YONSEC SECOVERVIEW}. There, in
proving:
.ASIS
(EQUAL (MC.FLATTEN X ANS) (APPEND (FLATTEN X) ANS)),
.ENDASIS
we inducted on X, simplified, eliminated the destructors CAR and CDR,
performed two cross-fertilizations and were left with:
.ASIS
~5 (EQUAL (APPEND (FLATTEN Z) (APPEND (FLATTEN V) ANS))
(APPEND (APPEND (FLATTEN Z) (FLATTEN V)) ANS)).
.ENDASIS
Let us now proceed to justify and carry out the generalization step
done automatically in {YONSEC SECOVERVIEW}.
Note that (FLATTEN Z) and (FLATTEN V) occur on both sides
of the equality. Assuming that FLATTEN has played its role and that
the conjecture is true because of the relationships introduced by expanding functions and
using the induction hypotheses, we now replace the two
FLATTEN expressions by Y and A respectively.
However, since we know that FLATTEN
always returns a list, we restrict the two variables to be LISTPs.
The result is:
.ASIS
~6 (IMPLIES (AND (LISTP Y)
(LISTP A))
(EQUAL (APPEND Y (APPEND A ANS))
(APPEND (APPEND Y A) ANS))).
.ENDASIS
This is just a weak version of the associativity of APPEND and can now be proved
by induction on the new variable, Y. In fact, ~5
does not yield to induction
(without a generalization somewhere along the line) because
induction on the variables inside the FLATTEN expressions will simply
produce deeper and deeper nests of APPENDs. It is thus
crucial to guess that FLATTEN has played its role and to eliminate it.
We discussed a second example of generalization
in connection with the elimination of destructors in {YONSEC SECELIMINATINGDESTRUCTORS}. When
we generalize destructor terms, we do not bother to look for
common subterms:##we know exactly which terms we want to replace
with variables.
However, since we are performing
a generalization, we do take advantage of our type set knowledge and
available generalization lemmas.
For example,
if, for any reason, we generalize (REMAINDER B A) by replacing it with I
(as we did in {YONSEC SECELIMINATINGDESTRUCTORS}), then we
add the additional restriction (NUMBERP I) because we know from its type set
that
REMAINDER always returns a number. Furthermore, if we
know:
.ASIS
(EQUAL (LESSP (REMAINDER X Y) Y) (NOT (ZEROP Y)))
.ENDASIS
as a generalization lemma, we add the additional restriction:
.ASIS
(EQUAL (LESSP I A) (NOT (ZEROP A))).
.ENDASIS
Thus, the result of generalizing the REMAINDER expression in:
.ASIS
(p (REMAINDER B A) A B)
.ENDASIS
is:
.ASIS
(IMPLIES (AND (NUMBERP I)
(EQUAL (LESSP I A) (NOT (ZEROP A))))
(p I A B)).
.ENDASIS
This would be split into two conjectures when simplified,
and we would consider the case that A was ZEROP on one branch
and that A was non-ZEROP and I less than A on the other one.
.SS |The Precise Statement of the Generalization Heuristic|
There are
two parts to the generalization heuristic, the choice of terms to generalize and the actual
generalization and use of known facts about the terms. The elimination of
destructors relies only upon the second phase of the generalization heuristic.
We say a term is __generalizable_ unless it is a variable,
an explicit value template, or its function symbol
is EQUAL or a destructor.
We first collect all the generalizable terms t such that either
t occurs in two or more literals or there occurs
a literal with atom (EQUAL x y) and t occurs in both x and y.
After collecting such common terms, we delete from further
consideration any term that properly contains another that
we are considering. The remaining terms collected
will be generalized away.
By working our way outwards from the minimal
common subterms in single generalization steps we are
able to use our generalization lemmas to catch relations between the new
and old variables that might be lost if we replaced the largest
common subterms in one pass.
We have found it inappropriate to generalize explicit values (such as 5)
or even terms that are explicit value templates
because they contain
too much information. We do not generalize destructor
terms; if the destructor elimination heuristic has not
eliminated them, they should probably not be eliminated.
Note that after generalizing the minimal terms,
it may be possible to eliminate destructor terms that
could not have been eliminated earlier.
Having obtained a set of minimal common subterms (or having been
supplied them by the destructor elimination heuristic) we then proceed
to carry out the actual generalization. For each term, t,
being generalized we search through all known generalization lemmas, looking
for all lemmas that contain a subterm of which t is
an instance under some substitution s.
Whenever we find such a lemma, we instantiate
it with s and add it as a hypothesis to the formula
we are generalizing (i.e., we add the negation of the instantiated lemma
as a literal to the clause being generalized). In addition, we obtain the
type set of t (in the context of assuming all the literals in
the clause false), and if that set contains only one
type, __r_, we add (r t) as a hypothesis.
When we have so considered each of the terms being generalized we will have
produced a new, expanded formula equivalent to the original one.
We then generalize this expanded formula by uniformly
substituting distinct
new variables (i.e., ones not occurring in the formula) for
each of the terms being generalized. This more general formula is then poured over the
waterfall again (or, in the case of a generalization for the elimination of
destructors, given back to that heuristic).
We have found it inappropriate to use a generalization lemma
to restrict the generalization of a term if the
generalization of the added hypothesis
still mentions the function symbol of the term we were generalizing.
Thus, a lemma such as:
.ASIS
(EQUAL (FLATTEN (GOPHER X))
(FLATTEN X)).
.ENDASIS
might be a good generalization lemma when (GOPHER x) is generalized to Z
(because it effectively adds the restriction that Z
has the same fringe as x). But that lemma is not
a good lemma to use when (FLATTEN x) is generalized to Z.
Such a use of the lemma would add the hypothesis
that (EQUAL (FLATTEN (GOPHER x)) Z), so we would not only fail to eliminate FLATTEN but
would actually complicate matters by transforming (FLATTEN x) to
(FLATTEN (GOPHER x)).
.SS |Generalization in the REVERSE Example|
We now return to our ongoing proof that when a
proper list is reversed twice the result is the list itself.
Recall that after cross-fertilizing we had:
.ASIS
~RR6 (IMPLIES (PLISTP B)
(EQUAL (REVERSE (APPEND (REVERSE B) (CONS A "NIL")))
(CONS A (REVERSE (REVERSE B))))).
.ENDASIS
Note that (REVERSE B) occurs on both sides of the equality.
It came through the induction cleanly and was involved
in the left-hand side of our induction hypothesis and the left-hand side
of our simplified induction conclusion. After using the hypothesis we
find it on opposite sides of the equality. We thus generalize it
to Z.
Since we have no generalization lemmas about REVERSE and
since (REVERSE B) is not always in a single shell class, we do not
restrict the generalization. We thus obtain:
.ASIS
~RR7 (IMPLIES (PLISTP B)
(EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z)))).
.ENDASIS
We can interpret the conclusion of this new conjecture in
the following way.
Suppose we have any list Z and we insert A as its last element.
Then reversing the resulting list is equivalent to reversing Z
and adding A as the first element. Note however that the hypothesis
of ~RR7 is not relevant to the truth of the conjecture.
.SEC |ELIMINATING IRRELEVANCE|, SECIRRELEVANCE:
.SS |Two Simple Checks for Irrelevance|
Eliminating irrelevant hypotheses in a formula before trying to
prove it by induction is just another way
of obtaining a stronger conjecture to prove.
Furthermore, eliminating irrelevant
terms from a clause simplifies the task of
finding an appropriate induction.
In general, recognizing that a hypothesis is irrelevant
to the truth of a formula takes a deep understanding of the problem
at hand. However, there are simple cases where it is clear that
a hypothesis is irrelevant.
The most obvious place to look for irrelevance is
in hypotheses that are completely disconnected from the rest of
the formula. Thus, the first thing we do when looking for
irrelevance is to partition the literals
of the clause according to shared variables, putting two literals
in the same partition if they share
variables. Then we try to decide which partitions are probably falsifiable
and we delete any such partition from the clause.
If a partition is falsifiable, then the result
of deleting the partition from the clause is a theorem
if and only if the original clause is a theorem.
We have two simple heuristics for deciding that a partition
is "probably" falsifiable. But even when these
heuristics fail us (by guessing incorrectly
that a partition is falsifiable), we are assured
that if the result of deleting the partition (or indeed any
set) from the clause is a theorem, then
the original clause is a theorem.
The first heuristic tests whether the partition mentions any recursive
function. If not, then it is composed entirely of EQUAL, shell recognizers,
constructors, bottom objects, etc. But if such a partition were
always true we should have proved this clause with simplification.
Since we did not, we can reasonably
assume the partition can be falsified.
We give an example of such a partition in a moment.
The second heuristic tests whether the partition contains exactly one term
and that term has the form (f v[&1] ... v[&n]), where f is a recursive
function and the v[&i] are distinct variables.
The only way such a partition can be a theorem is if the function
f always returns true. But to have survived simplification it would
have to appear sometimes to return F or else we would have simplified
the literal to true by type set considerations. While it is certainly
easy to write recursive functions that always return T
but for which we compute the type set $A{__T_ __F_},
we have never had occasion to use them.
Thus, we feel justified in assuming we could find values for the v[&i]
that would falsify the literal, since the v[&i] are completely
unconstrained. An analogous treatment eliminates
any singleton partition whose member is a term
of the form (NOT (f v[&1] ... v[&n])).
.SS |The Reason for Eliminating Isolated Hypotheses|
One might wonder why we bother to advocate any mechanical irrelevance
checking, given that our two ideas are so trivial.
Generally, isolated hypotheses do not prevent the correct induction from
succeeding, since they survive the induction step untouched.
However, they do obscure the choice of the correct induction.
In particular, irrelevant recursive hypotheses
compete with the other terms in the conjecture for
our attention when we are trying to choose the correct induction. Without recognizing
that they are irrelevant, we may decide to induct "for" them rather than for the important terms.
The elimination of irrelevance is valuable as well in
detecting that we are trying to prove a nontheorem.
It is frequently the case, when our current conjecture is in fact
not a theorem, that we are led to consider demonstrably falsifiable
goals.
For example, suppose we tried to prove (EQUAL (REVERSE (REVERSE X)) X)
without bothering to require that X be a proper list.
The mechanical proof attempt goes as follows:
.ASIS8
Give the conjecture the name *1.
We will try to prove it by induction. There is only
one plausible induction. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (LISTP X)) (p X))
(IMPLIES (AND (LISTP X) (p (CDR X)))
(p X))).
The inequality CDR.LESSP establishes that the measure
(COUNT X) decreases according to the well-founded relation
LESSP in the induction step of the scheme. The above
induction scheme leads to two new goals:
Case 1. (IMPLIES (NOT (LISTP X))
(EQUAL (REVERSE (REVERSE X)) X)).
This simplifies, opening up the definition of REVERSE, to
the goal:
(IMPLIES (NOT (LISTP X))
(EQUAL "NIL" X)),
which has two irrelevant terms in it. By eliminating
these terms we get:
F.
Why say more?
****************************************************
*** ***
*** F A I L E D ! ***
*** ***
****************************************************
CPU time (devoted to theorem-proving): .465 seconds
.ENDASIS
Note that in the base case we ended up having to prove that
if X is not a list, then it is "NIL". Since this partition contains no recursive
function we should have been able to simplify it to true were it a theorem.
Since we could not simplify it, we eliminated those two literals,
leaving us, in this case, with the empty clause.
In general, one cannot conclude anything about the input conjecture
if our heuristics lead to the empty clause. In particular, one cannot
conclude that the input conjecture was not a theorem, since we might have
generalized it in one of many different ways, and succeeded in generalizing
it "too much." Nevertheless, it is usually worthwhile for the user to
construct a counterexample to the conjecture that led to the empty clause
and see whether that falsifies the input. In the above example,
the user need only identify a nonlist other than "NIL".
.SS |Elimination of Irrelevance in the REVERSE Example|
The example REVERSE proof we have been conducting illustrates
how irrelevance can crop up in the proof of a well-stated theorem.
Recall that after generalizing (REVERSE B) to Z we were left with:
.ASIS
~RR7 (IMPLIES (PLISTP B)
(EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z)))).
.ENDASIS
The hypothesis, (PLISTP B), was important at the beginning of the
proof. Indeed, the above attempt at proving the theorem
without the proper list hypothesis led us to a counterexample.
(The reader should recall that our proofs of the first
two induction cases,
~RR1 and ~RR2, of the correct statement of the theorem, ~RR,
in {YONSEC SECREWRITESIMPLIFY}
were based largely
on reasoning about PLISTP.) However, after the generalization
step, (PLISTP B) is disconnected from the rest of the conjecture.
If ~RR7 were true because (PLISTP B) were always false, then PLISTP
would have to return F on every input, since there are no restrictions on B.
Because the type set of (PLISTP B) is $A{__T_ __F_},
we can reasonably suppose (PLISTP B) is sometimes T
and hence is truly irrelevant to ~RR7. We produce:
.ASIS
~RR8 (EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z))).
.ENDASIS
Our heuristics have thus led us to
a natural lemma about APPEND and REVERSE. We must
prove it by induction.
.SEC |INDUCTION AND THE ANALYSIS OF RECURSIVE DEFINITIONS|, SECRECURSION:
If the steps described above do not prove the conjecture, we will
have reduced it to a conjunction of formulas, each of which
is as simple as we can make it. Having nothing else left in our arsenal,
we must prove each of these formulas by induction. Therefore, we
choose one of them, formulate an induction scheme that seems
appropriate for it, and then apply the scheme to the formula
to obtain a new set of formulas to prove. We use the
methods we have already discussed (and additional inductions, of
course) to prove each of the formulas produced by the induction
scheme.
Thus, the only outstanding question is the major one:##how do
we invent an induction scheme appropriate for a formula?
The answer lies in the similarity of recursion and induction.
The reader may have noticed the similarity between our statements
of the induction principle and the definition principle.
Very roughly speaking,
the induction principle lets us
prove (p x[&1] ... x[&n]), where the x[&i] are distinct variables,
assuming (p y[&1] ... y[&n]), provided that for some
measure m and well-founded relation r, it is the case that
(m y[&1] ... y[&n]) is r-smaller than (m x[&1] ... x[&n]), under the assumptions
of the case analysis.
Very roughly speaking,
the definition principle lets us define
(f x[&1] ... x[&n]), where the x[&i] are distinct variables,
in terms of (f y[&1] ... y[&n]), provided that for some
measure m and well-founded relation r, it is the case that
(m y[&1] ... y[&n]) is r-smaller than (m x[&1] ... x[&n]), under the assumptions
of the case analysis in the body of the function.
We
exploit this similarity (or, rather, contrived this similarity)
to determine a reasonable induction to
perform when confronted with a conjecture involving recursive functions.
In particular, suppose we were trying to prove a conjecture that
contained some call of a recursive function f, and suppose that we
knew that in its recursion, f drove down some measure of certain
of its arguments. Then if the call of f in question contains
variables in those argument positions, that call "suggests" a plausible
induction, namely, under the conditions that ensure that the measure
is driven down, assume the instances of the conjecture obtained by replacing
those variables by
what they will be when that call opens up. Such an induction is sound because we know
that the measure of the indicated arguments is being decreased.
Such an induction is heuristically plausible because it gives us induction assumptions
about terms that would occur in the induction conclusion
were we only to open up the appropriate call.
Thus, to set up an induction for a conjecture we must have a good
understanding of how the functions in it recurse. In particular, we
want to be able to look at a term in the formula and see
immediately the inductions it suggests. In the remainder of this
{SECTIONORCHAPTER} we discuss how we analyze each recursive function
when it is first introduced to check the
requirements of the definition principle and to note the inductions
the function suggests. In the next {SECTIONORCHAPTER} we will discuss how we
refine these suggested inductions to form one
appropriate for the formula as a whole.
Even considered in isolation from the proof-time induction analysis,
the definition-time analysis of functions is complicated.
Two distinct problems are intertwined in the
actual processing:##we must establish that the function is well-defined and
we must analyze its recursion to determine all the possible inductions it
suggests. We do these two tasks simultaneously.
However, we start out by describing roughly how we
prove that functions are well-defined, and then we describe the kind of information
we want to have by the time we actually try formulating
inductions. Once both tasks have been sketched and the important
heuristic components identified, we give a more precise statement of
the actual process.
.SS |Satisfying the Principle of Definition|
The definition principle puts several restrictions on the form of
definitions. Most of these are trivial syntactic requirements. However, the
requirement of a well-founded relation and measure justifying the definition
is nontrivial. If (f x[&1] ... x[&n]) is
defined to be some term, body, then the following must hold (according
to {YONSEC SECTHEFORMALTHEORY}):
.ASIS
(d) there is a well-founded relation denoted by
a function symbol r, and a function symbol, m,
of n arguments, such that for each occurrence of a
subterm of the form (f y[&1] ... y[&n]) in body
and the f-free terms t[&1], ..., t[&k]
governing it, it is a theorem that:
(IMPLIES (AND t[&1] ... t[&k])
(r (m y[&1] ... y[&n]) (m x[&1] ... x[&n]))).
.ENDASIS
Note that we must establish that the tests governing each recursive
call imply that some measure (fixed for all recursive calls) of the
arguments is getting smaller according to a well-founded relation
(fixed for all recursive calls). But we are not permitted to use the tests
that involve the function symbol f, which has not yet been admitted into
the theory. We describe below how we find a measure that is decreasing
in each recursive call.
.SSS |Machines|
We start by flattening the
nested structure of the body into a table that enumerates the branches through the
definition that lead to recursions, and lists the governing tests and the recursive calls on
each branch.
We call this table the "machine" of the function definition and it is useful both in
applying the definition principle and in formulating the case analysis of an induction.
To build a machine for a function body we first normalize the function
body (in the spirit of NORMALIZE of {YONSEC SECTAUTOLOGYCHECKER}). We then walk through the body collecting
the tests governing the current expression (in the spirit of TAUTOLOGYP). We
stop as soon as the current expression
is
either not an IF, or is an IF but a recursive call occurs in the test, or
the set of recursive calls on one branch is a nonempty subset of
those on the other. Each time we stop, we add an entry to the emerging table
if the current expression contains a recursive call. The entry
contains the tests collected and all the recursive
calls in the current expression.
For example, the machine for Peter's version of Ackermann's function {REF PETER}:
.ASIS
Definition.
(ACK M N)
=
(IF (ZEROP M)
(ADD1 N)
(IF (ZEROP N)
(ACK (SUB1 M) 1)
(ACK (SUB1 M) (ACK M (SUB1 N))))).
.ENDASIS
is:
.ASIS
case tests recursive calls
(1) (AND (NOT (ZEROP M)) (ACK (SUB1 M) 1)
(ZEROP N))
(2) (AND (NOT (ZEROP M)) (ACK (SUB1 M) (ACK M (SUB1 N)))
(NOT (ZEROP N))) (ACK M (SUB1 N))
.ENDASIS
For a second example, consider the function that returns T if X is a
subtree of Y and F otherwise:
.ASIS
Definition.
(OCCUR X Y)
=
(IF (EQUAL X Y)
T
(IF (LISTP Y)
(IF (OCCUR X (CAR Y))
T
(OCCUR X (CDR Y)))
F)).
.ENDASIS
The machine for OCCUR is:
.ASIS
case tests recursive calls
(1) (AND (NOT (EQUAL X Y)) (OCCUR X (CAR Y))
(LISTP Y)) (OCCUR X (CDR Y))
.ENDASIS
To satisfy restriction (d), given the machine for a definition,
we need a measure and well-founded
relation such that for each case in the machine and for each recursive call in the case,
we can prove that the tests in the case imply that the measure of
the arguments in the recursive call is smaller than the measure of the
formals.
.SSS |The Form of Induction Lemmas|
To select an appropriate measure and well-founded relation, we rely
upon axioms and previously proved theorems labeled by the user with the
hint "induction."
An induction theorem
points out that some operation drives some measure down according to
some well-founded relation. The general form of an
induction lemma is:
.ASIS
(IMPLIES h
(r (m y[&1] ... y[&j]) (m x[&1] ... x[&j]))),
.ENDASIS
where the x[&i] are distinct variables, all the variables in
h occur in the conclusion, r and m are function symbols, and r is known to be
well-founded.{FNOTE |In our current implementation, r must be
. LESSP. The theorem prover constructs lexicographic combinations automatically,
. as will be described. The only other function we have been tempted
. to assume to be well-founded is Gentzen's {REF GENTZEN} well-founded
. relation on epsilon naught.|}
Note that our
definition of an induction lemma requires that
the same explicit measure function, m, be the outermost function
symbol of both arguments to the well-founded relation in the conclusion.
Thus, certain useful
rewrite lemmas, such as one with the conclusion
(LESSP (DIFFERENCE I N) I),
would not be allowed to double as induction lemmas. Instead, slightly
reformulated versions would have to be proved for use as induction lemmas.
However, note that if y is a numerically valued term,
then (LESSP y x) implies
(LESSP (COUNT y) (COUNT x)), because (COUNT y) is y and (COUNT x) is
greater than or equal to x. Our implementation thus contains the following
feature: if the conclusion of a lemma
has the form (LESSP y x), where y
has type set $a{__NUMBERP_$a}, then if the lemma is to be processed as an induction
lemma, the conclusion is treated as though it were
(LESSP (COUNT y) (COUNT x)).
Note that if one of the hypotheses is of the form (NOT (EQUAL (m y[&1] ... y[&j])
(m x[&1] ... x[&j]))), the lemma tells us that the measure is either decreasing
or stays fixed. The knowledge that a measure
does not increase -- even though it may not decrease --
is important when trying to establish that a lexicographic measure is
decreasing.
Here are three examples of induction lemmas:
.ASIS
(IMPLIES (NOT (ZEROP X))
(LESSP (COUNT (SUB1 X)) (COUNT X))),
(IMPLIES (LISTP X)
(LESSP (COUNT (CDR X)) (COUNT X))), and
(IMPLIES (LESSP X Y)
(LESSP (DIFFERENCE Y (ADD1 X))
(DIFFERENCE Y X))).
.ENDASIS
The first two are intrinsic to the axiomatization of the ADD1 and
CONS shells. The third one is the theorem COUNTING.UP.BY.1, which informs us that the
measure DIFFERENCE of X and Y decreases if X is replaced by (ADD1 X) and
Y is held constant, provided X is less than Y. Other
examples of induction theorems can be found in {APP APPTHMS}.
The basic idea behind the use of induction theorems is simple:
consider the machine for some function f whose formal
parameters are x[&1], ..., x[&n], and consider a particular recursive
call (f y[&1] ... y[&n]) in some case of the machine.
We look for an induction lemma with
a conclusion that says that some measure of our y[&i] is
smaller than the same measure of our x[&i]. If we find such
a lemma we then try to prove that the tests in the machine imply the
hypothesis of the induction lemma.
Thus, the theorems we
try to prove while applying the principle of definition
are usually quite simple since they
involve showing only that the tests in the machine imply the
hypothesis of the induction lemma, and not the usually more difficult fact that
the measure is decreasing according to a well-founded relation.
Of course, that more difficult fact was established once and for all
when the induction lemma was proved.
.SSS |A Simple Example|
Now let us consider an example of using induction
lemmas. Suppose PRED and FN have been previously defined.
Consider the function WHILELOOP:
.ASIS
Definition.
(WHILELOOP I MAX X)
=
(IF (LESSP I MAX)
(IF (PRED I X)
T
(WHILELOOP (ADD1 I) MAX (FN X)))
F).
.ENDASIS
We have contrived this function to have several interesting properties
and will discuss it many times in this and the next {SECTIONORCHAPTER}.
WHILELOOP is the obvious recursive expression
of a simple loop that counts I up to MAX by 1. If it reaches or
exceeds MAX, it returns F. If ever (PRED I X) holds, it stops and returns T.
Otherwise, WHILELOOP resets X to (FN X) and iterates.
The machine for WHILELOOP is:
.ASIS
case tests recursive calls
(1) (AND (LESSP I MAX) (WHILELOOP (ADD1 I) MAX (FN X))
(NOT (PRED I X)))
.ENDASIS
Note that the recursive call changes I to (ADD1 I) and holds MAX fixed.
(It also happens to change X to (FN X), but that is not important at the
moment.) Recall the example induction lemma COUNTING.UP.BY.1 about DIFFERENCE
(now instantiated with the variables used in WHILELOOP in one of nine possible ways):
.ASIS
(IMPLIES (LESSP I MAX)
(LESSP (DIFFERENCE MAX (ADD1 I))
(DIFFERENCE MAX I))).
.ENDASIS
The conclusion of this lemma informs us that the DIFFERENCE between MAX and I may be
decreasing in WHILELOOP. To guarantee it, we must prove only that the tests
in the machine for this case imply the hypothesis of the induction
lemma. That is, we must prove:
.ASIS
(IMPLIES (AND (LESSP I MAX)
(NOT (PRED I MAX)))
(LESSP I MAX)).
.ENDASIS
This is trivial.
Thus, to satisfy requirement (d)
of the definition principle for WHILELOOP, we let the well-founded relation, r, be
LESSP, and we let m be M, where:
.ASIS
(M I MAX X) = (DIFFERENCE MAX I).
.ENDASIS
Thus, WHILELOOP is accepted under the definition principle as a well-defined
function (and would be accepted by our implementation if it were cognizant
of the induction lemma used).
.SSS |Lexicographic Measures and Relations|
Let us illustrate one further aspect of finding a measure and well-founded relation that
explain a function. Consider Ackermann's function as defined
above.
Note that the first argument, M, sometimes goes down in recursion and sometimes
stays fixed. The second argument, N, sometimes goes up (quite rapidly) and
sometimes goes down. The function is well-defined because
a lexicographic measure is going down. That is, in each recursive
call, (ACK m n), the pair is lexicographically smaller than
the pair .
To say it another way, the ordinal omega*m+n is less than omega*M+N.
We can say this in our theory easily since we have ordered pairs.{FNOTE |Indeed, it is quite easy to
. write functions for doing ordinal arithmetic.|} In particular,
the measure (CONS (COUNT M) (COUNT N)) gets LEX-smaller on every recursive call, where
LEX is the lexicographic relation induced by LESSP and LESSP:
.ASIS
Definition.
(LEX P1 P2)
=
(IF (LESSP (CAR P1) (CAR P2))
T
(IF (EQUAL (CAR P1) (CAR P2))
(LESSP (CDR P1) (CDR P2))
F)).
.ENDASIS
If one knows enough to try lexicographic measures,
the justification of ACK can be derived from the previously
mentioned induction axiom intrinsic to the ADD1 shell:
.ASIS
(IMPLIES (NOT (ZEROP X))
(LESSP (COUNT (SUB1 X)) (COUNT X))).
.ENDASIS
It is easy, and useful, to be able to formulate such lexicographic
measures and well-founded relations from arbitrarily many other measures
and well-founded relations.
For example, consider the function GCD:
.ASIS
Definition.
(GCD X Y)
=
(IF (ZEROP X)
(FIX Y)
(IF (ZEROP Y)
X
(IF (LESSP X Y)
(GCD X (DIFFERENCE Y X))
(GCD (DIFFERENCE X Y) Y)))).
.ENDASIS
One explanation of why GCD is well-defined
is that the measure (CONS (COUNT X) (COUNT Y)) decreases according
to the relation LEX above.{FNOTE |When we, as users of our program,
. introduced the definition of GCD, we had previously proved as
. an induction lemma that (DIFFERENCE X Y) is smaller than X when X and Y are non-ZEROP.
. We proved this so that we could introduce REMAINDER and QUOTIENT,
. both of which recurse by subtracting the second argument from the first.
. It had not occurred to us that GCD could be explained lexicographically
. until the definitional mechanism used the measure and relation
. above to explain it.|}
.SS |Induction Schemes Suggested by Recursive Functions|
We will be more precise later about how we use a function's machine
and known induction theorems to find a measure and well-founded relation
justifying the function's definition.
We delay that discussion because we want to get more
from a recursive definition than
the assurance that it is well-defined. We want to be able to look at a
call of a recursive function and see inductions that are
appropriate. So we will now turn our attention to induction.
To apply the principle of induction to a conjecture we must invent
a case analysis, together with some
substitutions, a variable n-tuple, a measure,
and a well-founded relation. We must prove the conjecture under each
of the cases. In all but the base case we may assume instances
of the conjecture obtained by uniformly replacing some of its variables
by terms. However, we must also establish that in each such case the
substitutions decrease the measure of the variable n-tuple according to the
well-founded relation. Inventing an induction scheme that actually makes it
possible to prove a given conjecture, while satisfying all the foregoing
constraints, is sometimes quite difficult.
But the recursive definitions
of functions in the conjecture "suggest" appropriate inductions.
In particular, suppose the conjecture mentions the call
(f x[&1] ... x[&n]) of a recursively defined function, suppose further that
when we defined f we found a measured subset of the function's arguments,
a measure on that subset, and well-founded
relation justifying the definition of f, and finally suppose that all the x[&i]
in those measured positions are distinct variables.
Then the sense in which (f x[&1] ... x[&n]) suggests an induction is
as follows. By opening up (f x[&1] ... x[&n]) we could reexpress the
conjecture in terms of the recursive calls, (f y[&1] ... y[&n]), in
the definition of f. But, we can obtain inductive hypotheses
about (f y[&1] ... y[&n]) -- at least
for those y[&i] in the measured subset -- by using the substitutions that
replace the measured x[&i] by y[&i] and replace other variables arbitrarily.
By using a case analysis similar to the one in the definition of f, we
know that our previously discovered measure on the subset
decreases under these substitutions. Thus, it is easy to
justify the induction scheme.
.SSS |Why We Use Measures and Relations|
The key to the above induction heuristic is that under certain
conditions recursive definitions
allow us to rewrite some function calls in the induction
conclusion to terms involving instances of those calls -- namely the recursive
calls in the body of the definitions -- and that
those instances can also be provided in inductive hypotheses.
This reasoning can be expressed in a way in which no explicit
mention is made of measures and well-founded relations:
having accepted a function definition we can induct according
to it (e.g., the "subgoal induction" scheme
of Morris and Wegbreit {REF MORRIS}.)
Let us consider a simple example. Suppose we wished to
prove a conjecture of the form (p (WHILELOOP I MAX X)). One appropriate
induction for it is closely analogous to the definition of WHILELOOP.
The induction step provides the induction hypothesis
(p (WHILELOOP (ADD1 I) MAX (FN X))), under the conditions (LESSP I MAX)
and (PRED I X). Two base cases are necessary, namely those obtained
by negating the conditions defining the induction step.
The induction scheme can be justified by any measure
and well-founded relation justifying the definition of WHILELOOP.
More generally, if f is a recursive function, then the term (f A B C)
suggests an induction scheme which,
under exactly the case analysis
in the body of f, supplies induction hypotheses obtained by instantiating
A, B, and C exactly as they are instantiated in the recursive calls
in (f A B C). The suggested induction is justified by the
same measure and well-founded relation justifying the definition of f.
Thus, at first sight there is no apparent need for us to consider
measures and well-founded relations explicitly for induction.
However, we want the terms in the conjecture being proved to suggest
inductions to perform. For example, suppose the term (f A B term),
where term is not a variable, is mentioned in the conjecture.
If f is a well-defined recursive function, but no measure
analysis is available, no legal induction is suggested by (f A B term).
In particular, we are not free to obtain our induction hypotheses by
instantiating A, B, and term as they are instantiated by recursive calls in f,
because term is not a variable, and we have no reason to believe that the
measure justifying f decreases under a substitution instantiating
only A and B.
But (WHILELOOP I MAX term) nevertheless suggests an induction, namely
the one in which we have the induction assumption
for (ADD1 I) and MAX in the case (LESSP I MAX).
We can look at (WHILELOOP I MAX term) and see
an induction because we know that only the first two arguments
of WHILELOOP are critical to the justification of the definition of WHILELOOP.
Because we want terms in the conjecture to suggest inductions,
it is to our advantage to analyze each recursive definition carefully, so as
to discover all the measures and well-founded relations that explain
it.
.SSS |Measured Subsets|
The key to seeing an induction in (WHILELOOP I MAX term) is
knowing that I and MAX, and just those two, are crucial in the measure
justifying the definition. Our definition principle requires that
the measure m justifying a definition of a function f, with
formal parameters x[&1], ..., x[&n], be a function of n arguments.
But it is often the case that there exists a measure m' and a subset
s = $a{x'[&1], ... , x'[&j]} of $a{x[&1], ..., x[&n]} such that the
requirements of the definition principle are met when (m x[&1] ... x[&n])
is defined to be (m' x'[&1] ... x'[&j]). If such an m' and s
exist, we call s a __measured subset_ for f.
Thus, a precise statement of the fact that only I and MAX
are crucial to the measure justifying WHILELOOP is that $a{I MAX}
is a measured subset of WHILELOOP.
The only measured subset for ACK is $a{M N$a}. The
fact that we explained ACK lexicographically, piecing
together measures on M and measures on N, is not relevant
here.
The ability to spot when a term suggests an induction
is strengthened if we know all the possible justifications of
the function's definition.
Consider WHILELOOP. It is possible, for example, that (FN X) drives X down if (PRED I X) is false.
If that were known, then $a{X} would also be a measured subset of WHILELOOP
and we would be able to spot a potentially useful
induction in a term such as (WHILELOOP term[&1] term[&2] X).
It is not unusual for a function to have more than one measured
subset. Consider the definition of DIFFERENCE:
.ASIS
Definition.
(DIFFERENCE I J)
=
(IF (ZEROP I)
0
(IF (ZEROP J)
I
(DIFFERENCE (SUB1 I) (SUB1 J)))).
.ENDASIS
Note that there
are two explanations of this definition:##the COUNT of the first argument
decreases in every call, and the COUNT of the second argument decreases in every call.
Consequently, both $a{X} and $a{Y} are measured subsets of DIFFERENCE
and both (DIFFERENCE X term) and (DIFFERENCE term Y) suggest
legal inductions.
When we enforce the requirements of the principle of definition, we consider all the
different combinations of arguments (that is, all the subsets of
the formals), measured in all possible ways by known measures and
lexicographic combinations of known measures.
We even consider the possibility that unchanged arguments
are contributing to the justification; for example, $a{I MAX$a} is a measured subset for WHILELOOP,
even though MAX is unchanged in the recursion. Should we find
any subset, measure, and well-founded relation decreasing in every
recursive call, then we accept the definition under our principle
of definition.
To satisfy our need to spot inductions we find every nontrivial
explanation.{FNOTE |We
. do not bother to look for measures on supersets of identified
. measured subsets. In addition, we do not consider a lexicographic
. combination of two measures if either measure alone is always decreasing.|}
.SSS |Specifying an Induction Schema|
It is not enough to know that some given measure of some subset of
a function's arguments is decreased in recursion.
That is enough to let us spot that an induction is suggested, but not
to tell us what the induction is. We would also like to know, for each
explanation found, the case analysis for the induction and the inductive
instances we can (and supposedly should) assume for each case.
Recall that when we induct we are free to pick an
arbitrary case analysis (together with a well-founded relation, measure,
and n-tuple of variables). If we can show that a certain instantiation
decreases the measure of our n-tuple of variables under the hypotheses of
the case analysis, then we can legally assume that instance of the
conjecture being proved. Thus, a typical inductive step
is an implication in which we have the conditions defining the
case and a set of instances of the conjecture as our hypotheses, and
the conjecture itself as our conclusion.
It should be fairly clear that the case analysis for any induction for
a function should be somewhat along the lines of the machine for the
function. To illustrate this, consider Ackermann's function again and recall
its machine:
.ASIS
case tests recursive calls
(1) (AND (NOT (ZEROP M)) (ACK (SUB1 M) 1)
(ZEROP N))
(2) (AND (NOT (ZEROP M)) (ACK (SUB1 M) (ACK M (SUB1 N)))
(NOT (ZEROP N))) (ACK M (SUB1 N))
.ENDASIS
If we were trying to prove a proposition about (ACK M N) we would
clearly want to have two separate induction steps. One, governed
by the tests in case (1), would supply as an inductive assumption
the conjecture with M replaced by (SUB1 M) and N replaced by 1,
because in that case the term (ACK M N) in the conclusion will open up
to (ACK (SUB1 M) 1). The second inductive step, governed by the
tests in case (2), would supply two inductive assumptions:
one in which M is replaced by (SUB1 M) and N is replaced by (ACK M (SUB1 N)),
and one in which M is replaced by M, and N is replaced by (SUB1 N). This choice
of instances is motivated by the observation that
the (ACK M N) term in the conclusion will open up to involve both of
the two ACK terms we will obtain in the hypothesis under these
instantiations. The base case of our induction would be obtained by negating the disjunction
of the tests in cases (1) and (2).
So in general the machine for a function suggests the
case analysis and the induction hypotheses. We now describe the
selection of the case analysis and induction hypotheses more carefully.
.SSSS |Defining the Cases|
How shall we define the cases of the induction argument? As we noted, we could
in principle use the tests in the machine. We know that if we are free to
instantiate all the arguments in any measured subset, then the
associated measure will be decreased under the case analysis of the machine.
This will give us n+1 cases in an induction argument about a
machine with n entries. The extra case is the base case obtained
by negating the tests leading to induction steps.
We have found that using the machine in this way, while ideal if we
are considering only a single term in the conjecture, leads to trouble if
there are interesting interactions between the various recursive functions
involved in the formula being proved.
.SSSSS |Irrelevant Tests and Weak Base Cases|
Let us look at another example. Consider the definition of LESSP:
.ASIS
Definition.
(LESSP X Y)
=
(IF (ZEROP Y)
F
(IF (ZEROP X)
T
(LESSP (SUB1 X) (SUB1 Y)))).
.ENDASIS
The machine for LESSP is:
.ASIS
case tests recursive calls
(1) (AND (NOT (ZEROP Y)) (LESSP (SUB1 X) (SUB1 Y))
(NOT (ZEROP X)))
.ENDASIS
$a{X$a} and $a{Y$a} are both measured subsets of LESSP.
Consider the term (LESSP term I), where term is a nonvariable.
This term suggests an induction on I, in which we have one induction
step, providing one inductive hypothesis, namely that obtained
by replacing I by (SUB1 I). But what exactly should be the conditions
governing the step? Note that two tests govern the recursion,
(NOT (ZEROP I)) and (NOT (ZEROP term)). The question is, do we
want these two tests to define our induction step as well?
While the second test is important in making LESSP compute the
desired value, it is completely irrelevant to the recursion on I.
Consider the consequences of using both tests to define our induction
step. We would be obliged to prove the weak base case in which I was
assumed to be non-ZEROP but term was assumed to be ZEROP. While this
may be a natural base case for (LESSP term I), it may not be a
natural base case for other expressions in the conjecture. For example,
suppose (PLUS I J) were also involved in the conjecture. Then, in the case
in which I is assumed non-ZEROP, we have to use recursion to determine the
value of (PLUS I J) and thus would naturally want the case
to be an induction step, not a base case.
For example, consider proving the theorem:
.ASIS
(NOT (LESSP (PLUS I J) I)).
.ENDASIS
If we do not treat the second test in the machine for LESSP as
irrelevant, the (LESSP term I) subterm suggests an induction in which
the induction step is governed by (NOT (ZEROP I)) and (NOT (ZEROP (PLUS I J))).
Thus, we are obliged to prove the base case:
.ASIS
(IMPLIES (AND (NOT (ZEROP I))
(ZEROP (PLUS I J)))
(NOT (LESSP (PLUS I J) I))),
.ENDASIS
which reduces to:
.ASIS
(IMPLIES (ZEROP (PLUS I J)) (ZEROP I)).
.ENDASIS
The proof of the above formula requires expanding the definition of
PLUS, which we would do by performing a second induction on I.
On the other hand, if we recognize that the second test in the machine
for LESSP is irrelevant here, the (LESSP term I) subterm suggests
an induction in which the induction step is governed by (NOT (ZEROP I)),
giving rise to the "natural" base case (ZEROP I). Both the induction
step and the base case of the suggested induction simplify to true.
Recognizing certain tests to be irrelevant has another important
effect on the analysis of appropriate inductions.
Note that in (NOT (LESSP (PLUS I J) I)) there are two suggested
inductions, the one suggested by (LESSP term I) and the one
suggested by (PLUS I J). If we recognize the second test in the
machine for LESSP to be irrelevant to an induction on the
second argument, then the induction suggested by (LESSP term I)
is precisely the induction suggested by (PLUS I J). If, on the
other hand, we use the irrelevant test to define the induction
step, the (LESSP term I) induction is different from the (PLUS I J)
induction and we must choose between them.
Eliminating irrelevant tests from induction schemes thus
has two advantageous effects: we eliminate weak base cases and
we can arrange for different terms to suggest identical inductions.
The latter effect is important because it permits us to focus our
attention on a smaller number of candidate inductions, each
"satisfying" a larger number of terms in the conjecture.
In the foregoing example, it is easy to spot that the test (NOT (ZEROP X))
is irrelevant to the measured subset $a{Y$a}. But in general, the
situation is more subtle. For example, consider the function MEMBER:
.ASIS
Definition.
(MEMBER X L)
=
(IF (LISTP L)
(IF (EQUAL X (CAR L))
T
(MEMBER X (CDR L)))
F).
.ENDASIS
MEMBER returns T if X is an element of the list Y, and F otherwise.
The machine for the function is:
.ASIS
cases tests recursive calls
(1) (AND (MEMBER X (CDR Y))
(LISTP Y)
(NOT(EQUAL X (CAR Y))))
.ENDASIS
Note that the second test, while important in making MEMBER compute
the desired value, is completely irrelevant to the justification of the
recursion. Recognizing the irrelevancy of the second test in MEMBER
permits us to spot that (MEMBER A X), (APPEND X Y), and (REVERSE X)
all suggest identical inductions.
.SSSSS |Weeding Out Irrelevant Tests|
So how do we weed out the irrelevant tests in a function definition?
The answer is fairly simple:##we consider the induction lemmas that
explain recursive calls,
and we use the hypotheses of the lemmas,
rather than the tests in the machine,
to determine the cases.
That is, if a machine tests t[&1], ..., and t[&j] and then recurses
with (f y[&1] ... y[&n]) and we know the induction lemma:
.ASIS
(IMPLIES h
(r (m y[&1] ... y[&n]) (m x[&1] ... x[&n])))
.ENDASIS
and can establish:
.ASIS
(IMPLIES (AND t[&1] ... t[&j]) h),
.ENDASIS
then we know m goes down in that recursive call. Regardless of what
terms actually govern the recursion, h is sufficient to guarantee
that m decreases. In the
case analysis for the induction, we will use h rather than the t[&i],
as the test for this case of the induction.
.SSSSS |An Example of Weeding Out Irrelevant Tests|
For example, in processing MEMBER at definition-time, we try $a{Y$a} as a
possible measured subset. We see that in the only recursion, Y is
being changed to (CDR Y). In our list of
known induction lemmas we find the following lemma added by our
implementation of the shell principle:
.ASIS
(IMPLIES (LISTP X)
(LESSP (COUNT (CDR X)) (COUNT X))).
.ENDASIS
Instantiating the lemma by matching the (CDR X) in its conclusion
with the (CDR Y) in the recursive call, we learn that the
COUNT of Y decreases if the tests in the machine imply
the instantiated hypothesis of the lemma, (LISTP Y).
We thus try to prove the trivial implication:
.ASIS
(IMPLIES (AND (LISTP Y)
(NOT (EQUAL X (CAR Y))))
(LISTP Y)).
.ENDASIS
Since this succeeds (and there is only one recursive call), we
have positively identified $a{Y$a} as a measured subset.
For the purposes of induction according to this measured subset,
we associate with $a{Y$a} a revised version of the machine for MEMBER:
.ASIS
case tests recursive calls
(1) (LISTP Y) (MEMBER X (CDR Y))
.ENDASIS
where the test is that from the induction lemma, not the function body.
Note that this use of the hypotheses of induction lemmas is most effective
when the user states induction lemmas with the
cleanest hypotheses available.
.SSSS |Selecting the Induction Hypotheses|
The second part of specifying an induction scheme is to decide, for
each case in the revised machine for a measured subset, what the
legal and supposedly appropriate induction instances are.
From the point of view of any given term (f x[&1] ... x[&n])
in a conjecture to be proved by induction, we know exactly which instances
we would like in a given case of the analysis:##those instances
(f y[&1] ... y[&n]) that arise when the recursive definition of f is expanded
under that case. If some subset of the x[&i] consists of distinct
variables, and that same subset is measured,
then we know that instantiating those x[&i]
in accordance with the recursion is sound. But what of the other x[&i]?
Clearly, if x[&i] is not in the measured subset, then we can ignore it
if we wish (from the soundness point of view), but (from the heuristic
point of view) we should do our
best to get induction hypotheses in which the terms occupying x[&i]'s
position are those that arise when (f x[&1] ... x[&n]) is
expanded.
The induction principle allows us to substitute arbitrarily for variables
not in the measured subset.
Thus, in the ideal case, when all the x[&i] are distinct variables, we will
substitute as directed by the recursion regardless of which measure
we use to justify the induction. At definition time we cannot
anticipate which argument positions might be occupied by nonvariables and which
by variables, so we just note the "ideal" hypotheses in which we
substitute for all the positions. We can represent a hypothesis
as a substitution scheme on the formals of the function -- a substitution
that, for each recursive call, maps each formal to the corresponding term in the
recursive call. At induction time we substitute
the actual values of the formals into the substitution scheme to obtain
the substitution used to produce an induction hypothesis.
At that time we must throw out any substitution pair that
would have us substitute for a nonvariable. Of course, not any
pair can be thrown out if the resulting induction is to be sound. In the next {SECTIONORCHAPTER},
we specify which pairs may be deleted.
.SS |The Details of the Definition-Time Analysis|
We now summarize what we observe about a function's definition
when it is introduced.
We first compute the machine for the function.
Then, we consider all possible subsets of the formal parameters.
For each subset of cardinality j we produce the j-tuples containing exactly the variables of the subset
but in all possible permutations.
For each such variable j-tuple we
look at every known j-ary measure and well-founded relation in
an induction lemma and note, for every recursive call in the machine, whether the measure goes down or does
not increase on the j-tuple.
When we find an induction lemma whose conclusion
suggests that a measure decreases or is at least nonincreasing,
we use our simplification heuristics to try to prove that the tests
in the machine governing that recursion imply the hypothesis of the
lemma.
In searching for an appropriate induction lemma, we elaborate the set of
user supplied lemmas by exploiting the fact that LESSP is transitive.
This is useful when the recursion involves nests of function symbols.
For example, consider the definition of HALF:
.ASIS
Definition.
(HALF I)
=
(IF (ZEROP I)
0
(IF (ZEROP (SUB1 I))
0
(ADD1 (HALF (SUB1 (SUB1 I)))))).
.ENDASIS
Note that in the recursive call, I is replaced by (SUB1 (SUB1 I)).
We can use the following induction lemma to establish that a measure of
the variable 1-tuple * is
decreasing:
.ASIS
Theorem. SUB1.LESSP:
(IMPLIES (NOT (ZEROP X))
(LESSP (COUNT (SUB1 X)) (COUNT X))).
.ENDASIS
We use the lemma as follows.
We match (SUB1 (SUB1 I)) with the (SUB1 X) in the conclusion of the
lemma. Instantiating the lemma with the resulting substitution we get:
.ASIS
(IMPLIES (NOT (ZEROP (SUB1 I)))
(LESSP (COUNT (SUB1 (SUB1 I))) (COUNT (SUB1 I)))).
.ENDASIS
Had the right-hand side of the instantiated conclusion been (COUNT I)
(i.e., the measure applied to our variable 1-tuple), we would be
done. Since it is (COUNT (SUB1 I)) instead, we recursively try to establish
that (COUNT (SUB1 I)) is no bigger than (COUNT I) according to the same measure and
LESSP.
Thus, we again appeal to SUB1.LESSP, matching (SUB1 I) with (SUB1 X), and
obtain:
.ASIS
(IMPLIES (NOT (ZEROP I))
(LESSP (COUNT (SUB1 I)) (COUNT I))).
.ENDASIS
This time the right-hand side is (COUNT I), so, provided the hypotheses
hold, we have a transitivity argument that (COUNT (SUB1 (SUB1 I))) is smaller than
than (COUNT I). To complete the argument we must show
that the tests in the machine governing the recursion imply
the conjunction of the tests we have accumulated: (NOT (ZEROP (SUB1 I)))
and (NOT (ZEROP I)). That is, (COUNT (SUB1 (SUB1 I))) is
smaller than (COUNT I) if I
is a number, not 0, and not 1.
In some cases we might find more than one way to establish that
(SUB1 I) is no bigger than I. For example, we might know the
induction lemma:
.ASIS
(IMPLIES (NOT (EQUAL (COUNT (SUB1 X)) (COUNT X)))
(LESSP (COUNT (SUB1 X)) (COUNT X))).
.ENDASIS
Recall that such a lemma means that (COUNT (SUB1 X)) is less than or
equal to (COUNT X). Thus, if our implementation were aware
of the above lemma, HALF would be an acceptable definition even if it
only tested (ZEROP I). That is, the above lemma allows the implementation
to deduce that (COUNT (SUB1 (SUB1 I))) is smaller than (COUNT I) if I is a number and not 0.
The foregoing procedure for unravelling nests of function symbols
such as (SUB1 (SUB1 I)) is not limited to induction lemmas about
COUNT and LESSP. The procedure may be generalized and applied
to any measure and any well-founded relation that is known to
be transitive. In fact, any well-founded relation may be extended
to a transitive well-founded relation by taking its transitive
closure.
Any time we find that a measure goes down or is nonincreasing on a
particular call, we remember the variable j-tuple, measure, well-founded
relation, recursive call, and the hypotheses of the induction
lemma(s) used.
Having observed the behavior of every known measure and well-founded
relation on every variable j-tuple and recursive call, we then try
to find a way to piece this information together to find a
lexicographic relation on m-tuples of the variable j-tuples.
We proceed to find all possible lexicographic combinations justifying
the definition. Of course, we do not construct trivial combinations
in which, say, the first component by itself is always decreasing.
We now illustrate how we piece measures together lexicographically. Suppose
we have found that some measure m[&1] on the variable j-tuple
gets r[&1]-smaller on some recursive calls
and is merely nonincreasing on others. Also, suppose that
on these other recursive calls we have found that another measure, m[&2] , on
the variable k-tuple
gets r[&2]-smaller. Then we construct
a measure that produces pairs of the form (CONS (m[&1] x[&1] ... x[&j]) (m[&2] y[&1] ... y[&k]))
and we form the lexicographic well-founded relation induced by r[&1] and r[&2].
Either r[&1] or r[&2] may itself
be lexicographic in nature.
If we ever find a measure and relation that is always decreasing, we can easily
use the induction lemma hypotheses to reconstruct a revised version of the machine
with the lemma hypotheses, rather than the tests from the function body,
defining the cases. We conjoin all the hypotheses
involved in explaining all the recursions in a given case and use that
conjunction as the tests for the case. In addition, we convert each recursive
call in each case into a substitution by pairing each
formal with the term occupying the corresponding argument
position in the recursive call.
When we have finished, we will have found all the measured subsets
we could identify. For each measured subset we will have noted
the measure and well-founded relation associated with it,
and the revised machine.
We call this information associated with a measured subset
an __induction template_ because it describes one of the inductions
suggested by the function.
As an example of an induction template, let us consider the
function WHILELOOP:##it has a measured subset $A{I MAX$A}, the measure
is (DIFFERENCE MAX I), and the measure decreases according to the well-founded
relation LESSP. The case analysis contains just one case,
namely that to prove (p I MAX X) one may inductively assume (p (ADD1 I) MAX (FN X))
under the condition that (LESSP I MAX). This induction step is
encoded as the substitution that replaces I by (ADD1 I),
MAX by MAX, and X by (FN X). Note that the definition of the case
does not mention (PRED I X). In general, a case may have
more than one such substitution (e.g., FLATTEN, ACK, and
NORMALIZE), there may be more than one case (e.g., ACK and NORMALIZE),
and there may be more than one induction template (e.g., LESSP and DIFFERENCE).
.SS |Recursion in the REVERSE Example|
Recall that we are in the process of proving the theorem:
.ASIS
(IMPLIES (PLISTP X)
(EQUAL (REVERSE (REVERSE X))
X)).
.ENDASIS
There are three recursive functions involved in the proof of this
theorem, PLISTP, REVERSE, and APPEND (which, recall, is a "subroutine" of
REVERSE).
Given the single induction lemma:
.ASIS
(IMPLIES (LISTP X)
(LESSP (COUNT (CDR X)) (COUNT X))),
.ENDASIS
we make
the following straightforward observations about those three functions.
(PLISTP X) has one measured subset, $A{X$A}, which is measured with COUNT
and is getting LESSP-smaller. The appropriate case analysis contains
one case, namely that to prove (p X) one may inductively assume (p (CDR X)),
under the condition (LISTP X).
(REVERSE X) has exactly the same analysis as PLISTP.
(APPEND X Y) also has exactly the same analysis as PLISTP, except
we note that to prove (p X Y) one should assume (p (CDR X) Y) under the
condition (LISTP X). In particular, we note that in this, the only induction case,
APPEND holds its second argument, Y, fixed while changing X to (CDR X).
Although Y is not essential to the measure (it is not in the
measured subset), our inductions for APPEND should try to keep
the second argument fixed.
.SEC |FORMULATING AN INDUCTION SCHEME FOR A CONJECTURE|, SECINDUCTION:
We now return to the problem of setting up an induction for a particular
formula. The basic idea is to look at the terms in the formula
and to note the inductions suggested by each of them. Then, after expanding
each scheme to account for as many terms as
possible, we pick the "best" according to various heuristics.
.SS |Collecting the Induction Candidates|
Suppose that the term (f t[&1] ... t[&n]) occurs in the formula
and we know an induction template for the recursive function f. Then
there are two obvious questions:##does the template apply
(e.g., are enough of the t[&i] terms distinct variables to permit a sound induction)
and what is the induction suggested?
.SSS |Deciding That a Template Applies|
If the t[&i] occupying the argument positions measured by the
induction template we have in mind
are all distinct variables, then we can use the template
to construct a sound induction scheme.
And in general, if any of the measured t[&i] is not a variable,
or is the same variable as another measured t[&i], we
cannot. However, there is an important exception to the rule.
If t[&j] is a nonvariable term in a measured position, and if the j^^th^ argument of f is never
changed in any of the substitutions in the cases (i.e., in any of
the recursive calls of f), then we can get
induction hypotheses that force the measure down by not
changing any of the variables occurring in t[&j]. (The second
argument of WHILELOOP is an example of a t[&j] in a
measured position not changed in any substitution; the second
argument of APPEND is not.)
We now make this precise. Let the __changeables_ be those t[&i] that occur
in measured positions that are also sometimes changed in the recursion.
Let the __unchangeables_ be the variables occurring in those t[&i]
occupying measured positions that never change in the recursion.
A template __applies_ to a term if the changeables are all distinct variables and none of
them is among the unchangeables.
For example, the template of WHILELOOP applies to (WHILELOOP X Y (H Z))
because X is the only changeable (and is a variable) and Y is the only
unchangeable (and is different from X). The template does not apply to
(WHILELOOP (G I) MAX X), because (G I) is a changeable that is not a variable.
The template does not apply to (WHILELOOP I (G I) X), because I is both a
changeable and an unchangeable.
We justify the definition of "applies" after explaining how it is used.
.SSS |Obtaining the Induction Scheme Suggested|
Given a template that applies to a term,
we can produce an induction scheme. An induction scheme is
a case analysis together with a set of substitutions giving
the induction hypotheses for each case, exactly analogous to
the revised machine in the template. The only problem is
that the template is expressed in terms of the formals of
the function. We must instantiate it with the actual
arguments of the term in the formula.
For example, the template for WHILELOOP (which was defined
using the formals I, MAX, and X) tells us that under the
condition (LESSP I MAX) we should assume the formula with I
replaced by (ADD1 I), MAX replaced by MAX, and X replaced by
(FN X). Consider the term (WHILELOOP K (PLUS X Y) V). K is
the only changeable and X and Y are both unchangeables.
Thus, the template applies. The induction suggested by
(WHILELOOP K (PLUS X Y) V) is to assume the formula with K
replaced by (ADD1 K), X and Y unchanged, and V replaced by
(FN V), under the condition (LESSP K (PLUS X Y)). This is
an appropriate induction because when (WHILELOOP K (PLUS X
Y) V), in the induction conclusion, is opened up under the
case (LESSP K (PLUS X Y)), the resulting WHILELOOP
expression is identical to that provided in the induction
hypothesis. But note that in instantiating the substitution
scheme we had to throw out the pair that would have
instructed us to replace (PLUS X Y) by (PLUS X Y). In
general, when we instantiate the substitution schemes in the
template with the actual arguments, we must then go through
the substitutions and delete certain illegal substitution
pairs. There are three kinds of pairs that must be deleted
(and can be deleted without affecting the soundness of the
resulting induction scheme, provided the induction template
indeed applies to the term in question).
As noted above, we must throw out any pair that would have us
substitute for a nonvariable.
The second kind of pair we must throw out is any that requires that
we substitute for an unchangeable. For example, in (WHILELOOP K (G X) X),
we know we must keep X unchanged because it occurs in the second argument.
However, it also occurs in the third argument, and the substitution scheme
in the template would have us replace X by (FN X). This would violate the
need to keep X fixed. Hence we must throw that pair out.
The third criterion for deleting a pair applies to an ambiguous
"substitution," one that would have us substitute twice for the same
variable. For example, the term (WHILELOOP I MAX I) would suggest we
substitute (ADD1 I) for I (because it occurs in the first argument) and
(FN I) for I (because it occurs in the last argument). If we find such
duplicate pairs we must keep the one that substitutes for a measured
variable (if either does). If neither variable is measured, we
can choose arbitrarily which to delete. (Given that the template applies, we know that both are not
measured since we have already determined that no two changeables are identical.)
Thus, we obtain the induction scheme, if any, suggested by a template and
a term, in two steps. We first decide whether the template applies.
If so, we then instantiate the case analysis and substitution schemes in the template
and delete any illegal pairs from the resulting "substitutions."
Both steps are trivial.
We now give some example induction schemes suggested by certain terms.
The term (WHILELOOP K (PLUS X Y) K) suggests the scheme in which, under
the condition (LESSP K (PLUS X Y)), we provide an inductive assumption
for K replaced by (ADD1 K), and X and Y unchanged.
The term (LESSP I (G I J)) suggests the induction scheme in which, under the
condition (NOT (ZEROP I)), we provide an inductive assumption for I replaced
by (SUB1 I).
Finally, (LESSP I J) suggests two schemes since there are two templates that
apply. The first provides an inductive assumption for I replaced by (SUB1 I)
and J replaced by (SUB1 J), under the condition (NOT (ZEROP I)). The
second is the symmetric one for J.
.SSS |Proof that the Inductions Suggested Are Sound|
We claim that if given a template and a term (f t[&1] ... t[&k]) to
which the template applies, the above process produces a case analysis
and some substitutions satisfying the requirements of the induction
principle.
Recall that we must exhibit some conditions q[&i], and some substitutions s[&i,j],
together with a well-founded relation r, variable n-tuple x[&1], ..., x[&n], and
measure m such that, for each i and j:
.ASIS
~goal (IMPLIES q[&i]
(r (m x[&1] ... x[&n])/s[&i,j] (m x[&1] ... x[&n]))).
.ENDASIS
Let s be the substitution mapping the formals of f to the corresponding
t[&i]. Let v[&1], ..., v[&a] be the formals of f in the measured
subset of the template. Suppose the condition defining the i^^th^ case
in the template is q[&i]'. Then the q[&i] we use in the induction
principle is q[&i]'/s, as described. The s[&i,j] are the substitutions
obtained by instantiating the substitution schemes of the template with
s and deleting illegal pairs, as described.
The proof that the s[&i,j] are indeed substitutions (as opposed
to arbitrary sets of pairs) follows trivially from the definition of "applies"
and the first and third deletion criteria. The hard part still remains:
what r, x[&1], ..., x[&n], and m do we use?
The well-founded relation, r, is that of the induction template.
The x[&i] are the union of the changeables and the unchangeables
defined above (in any order). Observe that the x[&i] include every
variable mentioned in any term in a measured position of (f t[&1] ... t[&k]).
We now construct a measure function, m, satisfying ~goal. Let m'
be the measure function associated with the induction template. Consider
the i^^th^ case and the i,j^^th^ recursive call in the template (i.e.,
the j^^th^ call in the i^^th^ case).
By construction, m' applied to the terms y[&1], ..., y[&a] occupying
the measured positions in the i,j^^th^ recursive call is r-smaller
than m' applied to the measured subset itself:
.ASIS
(IMPLIES q[&i]'
(r (m' y[&1] ... y[&a]) (m' v[&1] ... v[&a]))).
.ENDASIS
Thus, the above theorem holds if we instantiate it with s:
.ASIS
~thm (IMPLIES q[&i]'/s
(r (m' y[&1] ... y[&a])/s
(m' v[&1] ... v[&a])/s)).
.ENDASIS
We define m, the required measure function, with the equation:
.ASIS
(m x[&1] ... x[&n])
=
(m' v[&1] ... v[&a])/s.
.ENDASIS
That such a nonrecursive definition is well-formed (i.e., that the body
mentions no variable except the x[&i]) follows from the definition
of the x[&i] and that the v[&i] are the measured subset.
We now show that ~goal holds under the foregoing definitions.
Note that the hypothesis, q[&i]'/s of ~thm, is, by definition,
q[&i], and that the right-hand side of the conclusion, (m' v[&1] ... v[&a])/s,
is equal to (m x[&1] ... x[&n]) by the definition of m.
Hence, ~goal is equivalent to ~thm
if (m' y[&1] ... y[&a])/s is equal to (m x[&1] ... x[&n])/s[&i,j],
or, equivalently, if (m' y[&1]/s ... y[&a]/s) is
(m' (v[&1]/s)/s[&i,j] ... (v[&a]/s)/s[&i,j]). In fact, it is
the case that for each c from 1 to a, y[&c]/s is (v[&c]/s)/s[&i,j].
The reasoning is as follows:##y[&c]/s is the term in the c^^th^ measured
position of the i,j^^th^ recursive call introduced by expanding (f t[&1] ... t[&n]).
But (v[&c]/s) is the t[&i] in the c^^th^ measured position.
Let us call it t[&c]. Either t[&c] is one of the changeables or else it is a
term all whose variables are unchangeables. If it is a changeable, s[&i,j] maps it to
y[&c]/s by construction of the induction template substitution
schemes and the instantiation and pair-deletion process. If t[&c] is a term
all whose variables are unchangeables, then s[&i,j] will not effect it, by the
second pair-deletion criterion. Thus, t[&c]/s[&i,j] is t[&c]. But
by definition of an unchangeable, t[&c] is y[&c]/s. Q.E.D.
Thus, the simple definition of "applies" and the instantiation and deletion
process produce sound induction schemes.
.SS |The Heuristic Manipulation of Induction Schemes|
Once we have noted each induction scheme (i.e., case analysis and
substitutions) suggested
by any term in the formula, we begin the mainly heuristic phase of
manipulating induction schemes and choosing the best one we
can formulate. We have discovered many heuristics for
obtaining new schemes from old ones and for choosing among the various
candidate inductions.
To facilitate the discussion of these heuristics,
we associate with each scheme
.CROWN(8,0,0)
The term for which it was produced,
The set of all variables
that are substituted for (whether measured or unmeasured), henceforth
called the __changing variables_,
The set consisting of all the unchangeables (as defined previously)
and all the variables occurring in arguments to the term that
are changed by no substitution (that is,
the variables that must stay
fixed for the induction to be sound plus those we are keeping fixed
because the function merely "wants" them that way), henceforth
called the __unchanging_ variables, and
A __score_ that reflects our estimation of how good a match this induction scheme
is for the term for which it accounts.
.ENDCROWN
Initially, the score
is the rational quotient of the number of formals for which we substituted,
divided by the number of formals of the function symbol of
the term that suggested the induction template. Thus, initially, the score
reflects how many of the arguments of the function we expect to "pick up" by our
induction hypotheses when the function opens up.
.SSS |Subsumption of Induction Schemes|
Our first step in cleaning up the set of possible
induction schemes is to throw away any "subsumed" by another.
Suppose that some
scheme s[&1] has only the single case that says "under the
assumption (LISTP X) assume the conjecture with X replaced with (CDR X)."
Further, suppose that scheme s[&2] has a richer case structure, but one of
its cases is "under the assumption (LISTP X) and (LISTP (CDR X))
assume the conjecture with X replaced with (CDR (CDR X))." Then from a
heuristic point of view, s[&2] "subsumes" s[&1] because the s[&2] case above
will essentially give the term by which s[&1] was suggested permission
to recurse twice, once to (CDR X) and then again to (CDR (CDR X)).
We throw out the s[&1] induction in favor of the s[&2]
induction.
In order for s[&2] to __subsume_ s[&1] we require three things. First, the
changing variables of s[&1] must be a subset of those of s[&2].
Second, the unchanging variables of s[&1] must be a subset of those of s[&2].
Finally we require that every case of s[&1] be subsumed by a case of s[&2],
in the sense that the tests of the s[&1] case are a subset of those of the s[&2] case,
and that for every substitution in the s[&1] case there be a substitution in
the s[&2] case such that for each component in the s[&1] substitution, there
is a component in the s[&2] substitution with the same variable and a term
that mentions the term of the s[&1] component. Further, no s[&2] case
is permitted to subsume two s[&1] cases, and no s[&2] substitution is
permitted to subsume two s[&1] substitutions.
When we throw out s[&1] because s[&2] subsumes it, we add s[&1]'s score to that of
s[&2], and we consider that s[&2] accounts for
all the terms for which it used to account plus all those for which s[&1] was accounting.
Note that if two induction schemes are identical, then one subsumes
the other. Hence, if several terms in the formula suggest the same
induction, as we saw happen with (PLISTP X) and (REVERSE X), we
will have eliminated duplicate suggestions after the subsumption check.
We will have noted also that the suggested induction accounts for
several terms.
As an example of an induction scheme being subsumed by a nonidentical
one, consider the theorem that (HALF I) is less than or equal to I:
.ASIS
(NOT (LESSP I (HALF I))).
.ENDASIS
The LESSP-expression suggests inducting on I, assuming the theorem for
(SUB1 I) under the case (NOT (ZEROP I)). The HALF-expression suggests
induction on I, assuming the theorem for (SUB1 (SUB1 I)) under the
case (NOT (ZEROP I)) and (NOT (ZEROP (SUB1 I))). The induction for LESSP
is subsumed by the induction for HALF.
At the conclusion of this {SECTIONORCHAPTER} we present several thoroughly
described example inductions involving subsumption and our other heuristics.
.SSS |Merging of Induction Schemes|
To see the need for the next heuristic, let us look at an
example. Suppose we are trying to prove the transitivity of LESSP:
.ASIS
(IMPLIES (AND (LESSP X Y)
(LESSP Y Z))
(LESSP X Z)).
.ENDASIS
Since LESSP changes both of its arguments, and a measure of either is sufficient to
justify the definition, we start out with six suggested schemes.
They are (grouping them by two's in correspondence with the
LESSP terms above):
.ASIS
Under the condition (NOT (ZEROP X)), assume the
conjecture with X replaced with (SUB1 X) and Y with (SUB1 Y).
Under the condition (NOT (ZEROP Y)), assume the
conjecture with X replaced with (SUB1 X) and Y with (SUB1 Y).
Under the condition (NOT (ZEROP Y)), assume the
conjecture with Y replaced with (SUB1 Y) and Z with (SUB1 Z).
Under the condition (NOT (ZEROP Z)), assume the
conjecture with Y replaced with (SUB1 Y) and Z with (SUB1 Z).
Under the condition (NOT (ZEROP X)), assume the
conjecture with X replaced with (SUB1 X) and Z with (SUB1 Z).
Under the condition (NOT (ZEROP Z)), assume the
conjecture with X replaced with (SUB1 X) and Z with (SUB1 Z).
.ENDASIS
Suppose we were to induct according to any one of these -- for
example, the first. Then our hypothesis would be obtained by replacing
X and Y by (SUB1 X) and (SUB1 Y) respectively. But consider
the term (LESSP X Z) in the conclusion. Note that its counterpart in the
induction hypothesis (i.e., the term obtained by instantiating
it as above) is (LESSP (SUB1 X) Z). If we open up the (LESSP X Z) in the conclusion
we will obtain (LESSP (SUB1 X) (SUB1 Z)), which is not in the hypothesis
because in the hypothesis we did not replace Z by (SUB1 Z). But if we do not open
it up, and leave it (LESSP X Z), it is not in the hypothesis because in the hypothesis we
did replace X by (SUB1 X).
Clearly, if the changing variables of two
schemes overlap, then doing either induction by itself will throw the
terms associated with the other induction "out of sync" by replacing some
but not all the variables they need to reoccur.
That is the heuristic motivation of "merging."
We __merge_ scheme s[&1] into s[&2] provided their changing variables have a nonempty intersection,
the unchanging variables of each has an empty intersection with the changing variables of
the other, and we can merge each case of s[&1] into a case of s[&2]
in the following sense:##for every substitution in the s[&1] case we can
find a substitution in the s[&2] case such that the two substitutions
substitute for some common variable, the two substitutions substitute
identically on all common variables, and there is at least one common
variable, v, such that the term replacing it is not v itself.
Further, no two s[&1] cases may merge
into the same s[&2] case, and no two s[&1] substitutions may merge
into the same s[&2] substitution.
The __result of such a merge_ is like s[&2], except that for each case
in s[&2] that absorbed an s[&1] case we add the tests from the s[&1] case
to those of the s[&2] case, and we extend each substitution in the s[&2]
case by adding any new pairs from an s[&1] substitution with which it overlapped (if any).
In addition, we merge each s[&1] case into as many other s[&2] cases
as we can. We add the changing variables of s[&1] to the changing variables of
s[&2], and we add the unchanging variables of s[&1] to the unchanging variables of
s[&2]. The new scheme's score is
the sum of the scores of s[&1] and s[&2], and the new scheme
accounts for all the terms of the two older schemes. We throw out s[&1] and
retain the modified s[&2].
To see how merging works, we return to the example of
the transitivity of LESSP. The six schemes noted above merge into one:
.ASIS
Under the conditions (NOT (ZEROP X)), (NOT (ZEROP Y)),
and (NOT (ZEROP Z)), assume the conjecture with
X replaced with (SUB1 X), Y with (SUB1 Y), and Z with (SUB1 Z).
.ENDASIS
If we let (p X Y Z) be the statement of the transitivity of LESSP, then
the above induction scheme produces three base cases, one each for
X, Y, or Z being ZEROP. The induction step is:
.ASIS
(IMPLIES (AND (NOT (ZEROP X))
(NOT (ZEROP Y))
(NOT (ZEROP Z))
(p (SUB1 X) (SUB1 Y) (SUB1 Z)))
(p X Y Z)).
.ENDASIS
Note that if the LESSP expressions in the conclusion, (p X Y Z), are
expanded under the conditions given, the result is precisely the induction
hypothesis.
The result of merging is sound for the same reasons that s[&2] was sound.
For example, if we merged the last five LESSP induction schemes above
into the first scheme,
then the new scheme is sound because the first induction was
sound. In particular, we still replace X with (SUB1 X) under the hypothesis
that (NOT (ZEROP X)) is true, so that the same measure and well-founded
relation explain the new induction scheme.
In general, merging
adds additional tests to the induction cases
and instantiates some variables not involved in the justification.
The additional tests in the induction cases
will cause additional base cases to be generated (when we negate the
conditions of the induction steps to obtain the base cases), but
that is a heuristic problem, not a logical one.
We feel it is reasonable to add the extra tests (for example, the
tests on (NOT (ZEROP Y)) and (NOT (ZEROP Z)) above) to the induction steps
since those steps introduce instances (involving (SUB1 Y) and (SUB1 Z) in
our example) that generally do not make sense without such tests.
.SSS |Flawed Induction Schemes|
Once we have done all the possible subsumptions and merges we analyze the
schemes to decide whether some of the recursions in the conjecture
are getting in the way of others. Let us consider the
associativity of APPEND:
.ASIS
(EQUAL (APPEND (APPEND A B) C)
(APPEND A (APPEND B C))).
.ENDASIS
Recall that (APPEND X Y) recursively changes X and leaves
Y fixed. We thus observe three suggested induction schemes,
namely one for each of the terms above in which APPEND has a variable
in its first argument. Two of the suggested inductions merge
and we must thus consider the two alternative schemes:
.ASIS
Under the condition (LISTP A), assume the
conjecture with A replaced with (CDR A) and
B and C unchanged.
Under the condition (LISTP B), assume the
conjecture with B replaced with (CDR B) and
C unchanged.
.ENDASIS
Now consider what would happen if we inducted according to the second
scheme. The induction step would be:
.ASIS
(IMPLIES (AND (LISTP B)
(EQUAL (APPEND (APPEND A (CDR B)) C)
(APPEND A (APPEND (CDR B) C))))
(EQUAL (APPEND (APPEND A B) C)
(APPEND A (APPEND B C)))).
.ENDASIS
The term (APPEND B C) in the conclusion would open up to involve
(APPEND (CDR B) C), as planned. However, the term (APPEND A B) in the
conclusion, whether we open it or not, will not look like its counter-part
in the hypothesis because there we replaced B with (CDR B) in an
argument of APPEND that does not change.
On the other hand, if we induct according to the first scheme,
then all the terms mentioning A in the conclusion
will recurse once to give rise to the terms mentioning A in the hypothesis
(since A is never used by any term other than the ones the scheme
accounts for), and furthermore, by holding all the other variables
fixed, the induction on A guarantees that terms mentioning only those
variables will reappear in the hypothesis simply because they will not
change. Thus, the first scheme is virtually perfect while the
second is worthless. In this case we say that the first scheme is "unflawed."
We consider any scheme, s[&1], __flawed_ if there is another scheme, s[&2],
such that some changing or unchanging variable of s[&2] is an "induction"
variable of s[&1]. We say that v is an __induction_ variable of s[&1]
provided there is a term t for which s[&1] accounts and a template temp
for the function symbol of t such that v is a changeable with respect to
t and temp.
The example
just given illustrates why no induction variable of s[&1] should be an unchanging
variable of s[&2]. We consider s[&1] flawed if one of its induction
variables is a changing variable
of s[&2] because the two schemes must disagree on some variables since they
did not merge. We do not care whether s[&1]'s unchanging variables
overlap other schemes since s[&1] may account for the terms suggesting those schemes
by not touching those variables.
If some scheme is unflawed, we throw out all flawed schemes. If all
schemes are flawed, we simply throw out none
and proceed (but usually with some trepidation).{FNOTE |We have
. seen a few examples where the merging heuristic flaws the "right" induction scheme,
. by introducing into it a variable over which there is
. competition. As users we tend to rephrase the theorem to avoid the problem.
. See the footnote about ID in {YONSEC SECPRIMEFACTORIZATION}.|}
.SSS |Tie Breaking Rules|
It is surprising how often, in well-stated theorems, only one
suggested induction scheme survives the foregoing heuristics.
The most common exception arises when the conjecture is symmetric in several
variables, in which case it usually does not matter which induction
is chosen. However, if after all the above we are still left
with more than one candidate scheme, we consider the one with the
highest score as being the most likely to succeed (if there is exactly
one with the highest score).
If at this point two or more schemes are tied with the highest
score, we have one useful tie-breaking rule. It is most likely that the
terms we induct "for" will occur in both the hypothesis and the conclusion
after simplification. Therefore, these terms are most likely
to be eliminated by fertilization and generalization. Consequently,
by inducting on the "nastiest" functions in the conjecture we may
well eliminate them now and have something better to work on
next time. We use a simple measure of "nastiness":##a function is nasty
if it is not primitive-recursive (in that its arguments are either held fixed
or decremented by shell accessors).
Thus, to break ties we choose the scheme that is credited with the
largest number terms that are not primitive-recursive. If we still have a tie,
we choose arbitrarily. It is interesting to note that in proving
the several hundred theorems in {APP APPTHMS}, we choose arbitrarily only in symmetric cases.
.SSS |Superimposing the Machine|
Finally, having chosen a scheme, we perform one last operation
on it. If the scheme is credited with exactly one term, then
it just represents the induction for that term. Consequently, we
can ensure that the term in the induction conclusion opens up to
precisely the terms in the induction hypothesis (at least
on the measured subset) by superimposing
on the case structure of the scheme the case structure of
the machine for that function. Since the two case structures have
exactly the same number of cases (we originally created the
case analysis for the scheme by replacing the tests in the
case analysis of the machine), this amounts to going
over the scheme's cases and adding in the tests from the
corresponding cases of the instantiated machine.
If, on the other hand, we have merged other schemes into the
winner, then the case structure of any particular machine probably will
not account for all the terms credited to the scheme. (Recall
the discussion of Irrelevant Tests and Weak Base Cases in {YONSEC SECRECURSION}.) If we have merged,
we simply check that each of the cases of the scheme is
different (in the sense that each set of tests is different), and if we
find any two that are identical we add the substitutions of one case into those of
the other and throw out the first case. This is sound since the new case has
the same tests, and all the induction hypotheses drive the same
measure down under those tests. It is heuristically necessary since,
if we were to leave the two identical cases, with two different induction hypotheses,
then when the two conclusions opened up there would be nothing to force them
down the branch of the machine handled by their respective hypothesis (since the tests
are equivalent). Thus, we cover our bets by providing one induction step
with all the relevant hypotheses.
.SSS |Producing the Induction Formula|
Having finally obtained the x[&i], q[&i], and s[&i,j] from the
selected induction scheme for the clause in question, we apply the
induction principle to the term corresponding to the disjunction of
its literals, producing k+1 terms. We then convert those terms
into a propositionally equivalent set of IF-free clauses after expanding all
calls of AND, OR, NOT, and IMPLIES. The resulting set of clauses is then
poured over the waterfall.
.SS |Examples of Induction|
We now consider three example inductions. There are many
other induction examples elsewhere in this book.
The first example comes from the proof that a fast string searching
algorithm is correct. The ideas behind the algorithm and the
proofs are discussed in {YONSEC SECFSTRPOS}. The intuitive
statement of one of the main lemmas is that if PAT is a nonempty
character sequence, if I is a legal character position in another sequence, STR,
and if the right end of the leftmost occurrence of PAT in STR
is beyond position I, then it is also beyond position (PLUS I (DELTA1 (NTHCHAR I STR) PAT)).
Stated formally this is:
.ASIS
(IMPLIES (AND (LISTP PAT)
(LESSP I (LENGTH STR))
(LESSP I
(PLUS (LENGTH PAT) (STRPOS PAT STR))))
(LESSP (PLUS I (DELTA1 (NTHCHAR I STR) PAT))
(PLUS (LENGTH PAT) (STRPOS PAT STR)))).
.ENDASIS
This simplifies, by opening up the nonrecursive functions, to:
.ASIS
(IMPLIES
(AND (LISTP PAT)
(LESSP I (LENGTH STR))
(LESSP I
(PLUS (LENGTH PAT) (STRPOS PAT STR))))
(LESSP (PLUS I
(STRPOS (CONS (CAR (NTH STR I)) "NIL")
(REVERSE PAT)))
(PLUS (LENGTH PAT) (STRPOS PAT STR)))).
.ENDASIS
In order to understand how we set up an induction for this formula,
it is not necessary to understand what these functions
do, only how they do it. Their definitions are in {APP APPTHMS}. However,
below we give a brief sketch of the recursive structure of the
functions:
.ASIS
(LESSP X Y) Decrements X and Y with SUB1, under
non-ZEROP tests.
(LENGTH X) Decrements X with CDR under a
(LISTP X) test.
(PLUS X Y) Decrements X with SUB1 and leaves Y
unchanged, under a non-ZEROP test
on X.
(STRPOS X Y) Decrements Y with CDR and leaves
X unchanged, under (among
other things) a (LISTP Y) test.
(REVERSE X) Decrements X with CDR under a
(LISTP X) test.
(NTH X Y) Decrements X with CDR and Y with
SUB1, under a non-ZEROP test on Y.
.ENDASIS
When presented with the above simplified formula, our induction
heuristics lead to the following analysis (the following is
the output generated by the implementation):
.ASIS8
We will appeal to induction. The recursive terms in
the conjecture suggest ten inductions. They merge into two
likely candidate inductions. However, only one is unflawed.
We will induct according to the following scheme:
(AND (IMPLIES (NOT (LISTP STR))
(p I STR PAT))
(IMPLIES (NOT (NUMBERP I))
(p I STR PAT))
(IMPLIES (EQUAL I 0) (p I STR PAT))
(IMPLIES (AND (LISTP STR)
(NUMBERP I)
(NOT (EQUAL I 0))
(p (SUB1 I) (CDR STR) PAT))
(p I STR PAT))).
The inequality SUB1.LESSP establishes that the measure
(COUNT I) decreases according to the well-founded relation
LESSP in the induction step of the scheme. Note, however,
the inductive instance chosen for STR. The above
induction scheme produces six new conjectures.
.ENDASIS
The ten plausible inductions should be evident. All of them involve
instantiating either STR with (CDR STR),
I with (SUB1 I), or PAT with (CDR PAT). But the I and STR inductions
are linked by the (NTH STR I) term and they all merge into
one scheme. The three schemes
involving PAT are all identical and merge. Thus, we are left
with two schemes:##induction on I and STR together, or on PAT by itself. But we can see that
the PAT induction is flawed because the (STRPOS PAT STR) terms mention
PAT in an unchanging argument position. Hence, the heuristics have left us
with only one induction:##simultaneous induction on I (decomposed by SUB1s) and STR (decomposed
by CDRs). We thus have three base cases, one for STR being non-LISTP, one for
I being nonnumeric, and one for I being 0. The single induction step
supposes STR is a list and I is a positive integer, and inductively
assumes the theorem for (SUB1 I) and (CDR STR). It should be noted that no function in the theorem actually
recurses in exactly this way (in particular, NTH, the function
that linked the I and STR inductions, does not bother to test STR
before applying CDR because NTH happens to be controlled entirely
by its numeric argument).
This reduction in the number of plausible inductions, from ten
to two to one in this case, is the rule rather than the
exception. Out of about 400 inductions involved in our standard library
of proofs, we have found that about 90% of the time the field of
possible schemes is narrowed to one by subsumption, merging,
and the elimination of flawed schemes.
About half the time the remaining 10% are symmetric in several
variables and there is no "right" induction. In the remaining 5%
of the cases, our tie breaking rules apply. To illustrate these
(as well as the contributions of our other heuristics), we consider
two proofs from {YONSEC SECTAUTOLOGYCHECKER}.
To illustrate how scores occasionally enter, consider the
theorem TAUTOLOGYP.IS.SOUND.
The opening "move" in this proof is as follows:
.ASIS8
Theorem. TAUTOLOGYP.IS.SOUND:
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X A1))
(VALUE X (APPEND A1 A2)))
Give the conjecture the name *1.
Let us appeal to the induction principle. The
recursive terms in the conjecture suggest four inductions.
They merge into three likely candidate inductions, none of
which is unflawed. However, one is more likely than the
others. We will induct according to the following scheme:
(AND (IMPLIES (NOT (IF.EXPRP X))
(p X A1 A2))
(IMPLIES (AND (IF.EXPRP X)
(p (RIGHT.BRANCH X)
(CONS (CONS (TEST X) F) A1)
A2)
(p (LEFT.BRANCH X)
(CONS (CONS (TEST X) T) A1)
A2)
(p (RIGHT.BRANCH X) A1 A2)
(p (LEFT.BRANCH X) A1 A2))
(p X A1 A2))).
The inequalities LEFT.BRANCH.LESSP and RIGHT.BRANCH.LESSP
establish that the measure (COUNT X) decreases according
to the well-founded relation LESSP in the induction step
of the scheme. Note, however, the inductive instances
chosen for A1. The above induction scheme generates the
following 26 new conjectures.
.ENDASIS
The four initial schemes were those suggested by NORMALIZED.IF.EXPRP,
TAUTOLOGYP, VALUE, and APPEND. The first is subsumed
by the second because NORMALIZED.IF.EXPRP and TAUTOLOGYP
both recurse on the LEFT.BRANCH and RIGHT.BRANCH of
IF-expressions and nowhere else. (In describing its
proofs, our theorem-proving program does not distinguish
subsumption from merging.)
The VALUE induction is different
because it recurses on the TEST of IF-expressions as well. Of course,
the APPEND expression is altogether different, since it recurses down
the CDRs of its first argument. After the subsumption we are left with
three possibilities and all are flawed. The two possible induction schemes
on X are flawed by one another, and the scheme on A1 is flawed by the
TAUTOLOGYP induction. But since we have two "votes" in favor of the TAUTOLOGYP
induction while we have only one in favor of each of the other two,
we go with that induction. (Note that had the votes been tied we
would have chosen this induction anyway, because it accounts for
the TAUTOLOGYP-expression, and TAUTOLOGYP is the only nonprimitive-recursive
function in the conjecture.) Since the induction scheme accounts
for two terms, we do not superimpose the machine for TAUTOLOGYP
but since the revised machine for TAUTOLOGYP has several
different cases, all governed by the same test, (IF.EXPRP X),
we "cover our bets" by grouping them all together in a
single case with four different induction hypotheses.
It happens that as often as not, scores are tied (because there
are just two obvious inductions that "perfectly"
satisfy their terms but do not merge). This is where our
final tie breaking rule enters.
Consider the statement that NORMALIZE preserves the
VALUE of its argument:
.ASIS8
Theorem. NORMALIZE.IS.SOUND:
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A))
Give the conjecture the name *1.
Perhaps we can prove it by induction. The recursive
terms in the conjecture suggest two inductions, neither of
which is unflawed, and both of which appear equally likely.
So we will choose the one that will probably lead to
eliminating the nastiest expression. We will induct
according to the following scheme:
(AND
(IMPLIES (NOT (IF.EXPRP X)) (p X A))
(IMPLIES
(AND (IF.EXPRP X)
(IF.EXPRP (TEST X))
(p (CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X)))
A))
(p X A))
(IMPLIES (AND (IF.EXPRP X)
(NOT (IF.EXPRP (TEST X)))
(p (RIGHT.BRANCH X) A)
(p (LEFT.BRANCH X) A))
(p X A))).
The inequalities IF.COMPLEXITY.GOES.DOWN1,
IF.COMPLEXITY.GOES.DOWN2, IF.COMPLEXITY.STAYS.EVEN and
IF.DEPTH.GOES.DOWN establish that the measure:
(CONS (IF.COMPLEXITY X) (IF.DEPTH X))
decreases according to the well-founded lexicographic relation
induced by LESSP and LESSP in each induction step of the
scheme. The above induction scheme generates three new
conjectures:
.ENDASIS
Here we have only two choices: induction on X as suggested by
NORMALIZE or induction on X
as suggested by VALUE. They do not merge and each flaws
the other. We thus choose to eliminate
NORMALIZE because it is not primitive-recursive.
.SS |The Entire REVERSE Example|
Recall the example theorem that has been used to tie together all the foregoing proof techniques:
.ASIS
Theorem. REVERSE.REVERSE:
(IMPLIES (PLISTP X)
(EQUAL (REVERSE (REVERSE X)) X)).
.ENDASIS
We reproduce below the theorem prover's output
in response to the four user-commands to define APPEND, REVERSE,
and PLISTP and to prove the above theorem.
In addition to recalling the definition-time analysis of the recursive
functions and the previous steps in the proof, the reader
should note the induction used on the original theorem, the induction
used on the subgoal generated (formula *1.1 below), and the proof of
each of the formulas produced by the second induction.
.ASIS8
Definition.
(APPEND X Y)
=
(IF (LISTP X)
(CONS (CAR X) (APPEND (CDR X) Y))
Y)
The lemma CDR.LESSP informs us that (COUNT X) goes
down according to the well-founded relation LESSP in each
recursive call. Hence, APPEND is accepted under the
definition principle. Observe that:
(OR (LISTP (APPEND X Y))
(EQUAL (APPEND X Y) Y))
is a theorem.
CPU time (devoted to theorem-proving):##.281 seconds
Definition.
(REVERSE X)
=
(IF (LISTP X)
(APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL"))
"NIL")
The lemma CDR.LESSP can be used to show that (COUNT X)
goes down according to the well-founded relation LESSP in
each recursive call. Hence, REVERSE is accepted under the
definition principle. Observe that:
(OR (LITATOM (REVERSE X))
(LISTP (REVERSE X)))
is a theorem.
CPU time (devoted to theorem-proving):##.34 seconds
Definition.
(PLISTP X)
=
(IF (LISTP X)
(PLISTP (CDR X))
(EQUAL X "NIL"))
The lemma CDR.LESSP informs us that (COUNT X) goes
down according to the well-founded relation LESSP in each
recursive call. Hence, PLISTP is accepted under the
definition principle. From the definition we can conclude
that:
(OR (EQUAL F (PLISTP X))
(EQUAL T (PLISTP X)))
is a theorem.
CPU time (devoted to theorem-proving):##.317 seconds
Theorem. REVERSE.REVERSE:
(IMPLIES (PLISTP X)
(EQUAL (REVERSE (REVERSE X)) X))
Name the conjecture *1.
Perhaps we can prove it by induction. There are two
plausible inductions. However, they merge into one likely
candidate induction. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (LISTP X)) (p X))
(IMPLIES (AND (LISTP X) (p (CDR X)))
(p X))).
The inequality CDR.LESSP establishes that the measure
(COUNT X) decreases according to the well-founded relation
LESSP in the induction step of the scheme. The above
induction scheme leads to the following three new
conjectures:
Case 1. (IMPLIES (AND (NOT (LISTP X)) (PLISTP X))
(EQUAL (REVERSE (REVERSE X)) X)),
which we simplify, expanding the definitions of PLISTP
and REVERSE, to:
(TRUE).
Case 2. (IMPLIES (AND (LISTP X)
(NOT (PLISTP (CDR X)))
(PLISTP X))
(EQUAL (REVERSE (REVERSE X)) X)),
which we simplify, unfolding PLISTP, to:
(TRUE).
Case 3. (IMPLIES (AND (LISTP X)
(EQUAL (REVERSE (REVERSE (CDR X)))
(CDR X))
(PLISTP X))
(EQUAL (REVERSE (REVERSE X)) X)),
which we simplify, expanding PLISTP and REVERSE, to:
(IMPLIES
(AND (LISTP X)
(EQUAL (REVERSE (REVERSE (CDR X)))
(CDR X))
(PLISTP (CDR X)))
(EQUAL (REVERSE (APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL")))
X)).
Appealing to the lemma CAR/CDR.ELIM, we now replace X by
(CONS A B) to eliminate (CDR X) and (CAR X). This
generates:
(IMPLIES
(AND (LISTP (CONS A B))
(EQUAL (REVERSE (REVERSE B)) B)
(PLISTP B))
(EQUAL
(REVERSE (APPEND (REVERSE B) (CONS A "NIL")))
(CONS A B))),
which further simplifies, obviously, to the conjecture:
(IMPLIES
(AND (EQUAL (REVERSE (REVERSE B)) B)
(PLISTP B))
(EQUAL
(REVERSE (APPEND (REVERSE B) (CONS A "NIL")))
(CONS A B))).
We now use the above equality hypothesis by
cross-fertilizing (REVERSE (REVERSE B)) for B and
throwing away the equality. This produces:
(IMPLIES
(PLISTP B)
(EQUAL
(REVERSE (APPEND (REVERSE B) (CONS A "NIL")))
(CONS A (REVERSE (REVERSE B))))),
which we generalize by replacing (REVERSE B) by Z. The
result is the conjecture:
(IMPLIES (PLISTP B)
(EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z)))),
which has an irrelevant term in it. By eliminating this
term we get:
(EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z))),
which we will finally name *1.1.
Let us appeal to the induction principle. There are
two plausible inductions. However, they merge into one
likely candidate induction. We will induct according to
the following scheme:
(AND (IMPLIES (NOT (LISTP Z)) (p Z A))
(IMPLIES (AND (LISTP Z) (p (CDR Z) A))
(p Z A))).
The inequality CDR.LESSP establishes that the measure
(COUNT Z) decreases according to the well-founded
relation LESSP in the induction step of the scheme. The
above induction scheme produces the following two new
goals:
Case 1. (IMPLIES
(NOT (LISTP Z))
(EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z)))),
which simplifies, applying the lemmas CAR.CONS and
CDR.CONS, and expanding the definitions of APPEND and
REVERSE, to:
(TRUE).
Case 2. (IMPLIES
(AND
(LISTP Z)
(EQUAL
(REVERSE (APPEND (CDR Z) (CONS A "NIL")))
(CONS A (REVERSE (CDR Z)))))
(EQUAL (REVERSE (APPEND Z (CONS A "NIL")))
(CONS A (REVERSE Z)))),
which simplifies, using the lemmas CAR.CONS and
CDR.CONS, and expanding the functions APPEND and
REVERSE, to:
(IMPLIES
(AND
(LISTP Z)
(EQUAL
(REVERSE (APPEND (CDR Z) (CONS A "NIL")))
(CONS A (REVERSE (CDR Z)))))
(EQUAL
(APPEND
(REVERSE (APPEND (CDR Z) (CONS A "NIL")))
(CONS (CAR Z) "NIL"))
(CONS A
(APPEND (REVERSE (CDR Z))
(CONS (CAR Z) "NIL"))))).
Appealing to the lemma CAR/CDR.ELIM, we now replace Z
by (CONS B X) to eliminate (CDR Z) and (CAR Z).
This generates:
(IMPLIES
(AND (LISTP (CONS B X))
(EQUAL (REVERSE (APPEND X (CONS A "NIL")))
(CONS A (REVERSE X))))
(EQUAL
(APPEND (REVERSE (APPEND X (CONS A "NIL")))
(CONS B "NIL"))
(CONS A
(APPEND (REVERSE X)
(CONS B "NIL"))))),
which we further simplify, trivially, to:
(IMPLIES
(EQUAL (REVERSE (APPEND X (CONS A "NIL")))
(CONS A (REVERSE X)))
(EQUAL
(APPEND (REVERSE (APPEND X (CONS A "NIL")))
(CONS B "NIL"))
(CONS A
(APPEND (REVERSE X)
(CONS B "NIL"))))).
We use the above equality hypothesis by
cross-fertilizing (CONS A (REVERSE X)) for:
(REVERSE (APPEND X (CONS A "NIL")))
and throwing away the equality. This generates:
(EQUAL (APPEND (CONS A (REVERSE X))
(CONS B "NIL"))
(CONS A
(APPEND (REVERSE X)
(CONS B "NIL")))).
However this simplifies further, applying the lemmas
CDR.CONS and CAR.CONS, and unfolding the definition of
APPEND, to:
(TRUE).
That finishes the proof of *1.1, which, consequently,
also finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##5.037 seconds
.ENDASIS
.SEC |ILLUSTRATIONS OF OUR TECHNIQUES VIA ELEMENTARY NUMBER THEORY|, SECELEMENTARY:
In this {SECTIONORCHAPTER} we illustrate the foregoing proof
techniques on several theorems in elementary number theory.
Assuming only the axioms, lemmas, and definitions
in {YONSEC SECTHEFORMALTHEORY}, our theorem
prover establishes a sequence of definitions and
theorems leading to the basic theorem:
If Y is nonzero and X is a number, then X = R+Q*Y,
where R is the remainder of X by Y and Q is the quotient of
X by Y.
The following points are worth noting.
.CROWN(8,0,0)
Although we explicitly request the theorem prover to prove a few simple
arithmetic theorems, many other such propositions
are raised as subgoals by our heuristics
and proved inductively. The reader should note carefully
each of the subgoals proved by induction.
The induction lemma RECURSION.BY.DIFFERENCE is proved in order to admit
the definitions of REMAINDER and QUOTIENT.
.ENDCROWN
The remainder of this {SECTIONORCHAPTER} was produced by our automatic
theorem prover in response to the user-commands supplying
function definitions and statements of theorems to prove.
.SS |PLUS.RIGHT.ID|
.ASIS
Theorem. PLUS.RIGHT.ID (rewrite):
(EQUAL (PLUS X 0) (FIX X))
This simplifies, unfolding the functions FIX and PLUS, to the
conjecture:
(IMPLIES (NUMBERP X)
(EQUAL (PLUS X 0) X)),
which we will name *1.
Let us appeal to the induction principle. There is only one
plausible induction. We will induct according to the following
scheme:
(AND (IMPLIES (EQUAL X 0) (p X))
(IMPLIES (NOT (NUMBERP X)) (p X))
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(p (SUB1 X)))
(p X))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme generates
the following three new conjectures:
Case 1. (IMPLIES (AND (EQUAL X 0) (NUMBERP X))
(EQUAL (PLUS X 0) X)).
This simplifies, expanding PLUS, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL X 0))
(NOT (NUMBERP (SUB1 X)))
(NUMBERP X))
(EQUAL (PLUS X 0) X)).
Of course, this simplifies, clearly, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL X 0))
(EQUAL (PLUS (SUB1 X) 0) (SUB1 X))
(NUMBERP X))
(EQUAL (PLUS X 0) X)),
which we simplify, opening up the function PLUS, to:
(IMPLIES (AND (NOT (EQUAL X 0))
(EQUAL (PLUS (SUB1 X) 0) (SUB1 X))
(NUMBERP X))
(EQUAL (ADD1 (PLUS (SUB1 X) 0)) X)).
Appealing to the lemma SUB1.ELIM, we now replace X by (ADD1 Z) to
eliminate (SUB1 X). We rely the type restriction lemma noted when
SUB1 was introduced to restrict the new variable. We must thus
prove:
(IMPLIES (AND (NUMBERP Z)
(NOT (EQUAL (ADD1 Z) 0))
(EQUAL (PLUS Z 0) Z)
(NUMBERP (ADD1 Z)))
(EQUAL (ADD1 (PLUS Z 0)) (ADD1 Z))).
This further simplifies, rewriting with ADD1.EQUAL, to:
(TRUE).
That finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##1.425 seconds
.ENDASIS
.SS |COMMUTATIVITY2.OF.PLUS|
.ASIS
Theorem. COMMUTATIVITY2.OF.PLUS (rewrite):
(EQUAL (PLUS X (PLUS Y Z))
(PLUS Y (PLUS X Z)))
Call the conjecture *1.
Perhaps we can prove it by induction. There are four plausible
inductions. They merge into two likely candidate inductions, both of
which are unflawed, and both of which appear equally likely. So we
will choose arbitrarily. We will induct according to the following
scheme:
(AND (IMPLIES (NOT (NUMBERP Y)) (p X Y Z))
(IMPLIES (EQUAL Y 0) (p X Y Z))
(IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(p X (SUB1 Y) Z))
(p X Y Z))).
The inequality SUB1.LESSP establishes that the measure (COUNT Y)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme generates
the following three new conjectures:
Case 1. (IMPLIES (NOT (NUMBERP Y))
(EQUAL (PLUS X (PLUS Y Z))
(PLUS Y (PLUS X Z)))),
which simplifies, applying PLUS.RIGHT.ID, and opening up PLUS, to:
(IMPLIES (AND (NOT (NUMBERP Y))
(NOT (NUMBERP Z))
(NUMBERP X))
(EQUAL X (PLUS X Z))).
Eliminate the irrelevant term. This produces:
(IMPLIES (AND (NOT (NUMBERP Z)) (NUMBERP X))
(EQUAL X (PLUS X Z))),
which we will name *1.1.
Case 2. (IMPLIES (EQUAL Y 0)
(EQUAL (PLUS X (PLUS Y Z))
(PLUS Y (PLUS X Z)))),
which we simplify, applying the lemma PLUS.RIGHT.ID, and opening up
PLUS, to the conjecture:
(IMPLIES (AND (NOT (NUMBERP Z)) (NUMBERP X))
(EQUAL X (PLUS X Z))).
Name the above subgoal *1.2.
Case 3. (IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(EQUAL (PLUS X (PLUS (SUB1 Y) Z))
(PLUS (SUB1 Y) (PLUS X Z))))
(EQUAL (PLUS X (PLUS Y Z))
(PLUS Y (PLUS X Z)))),
which simplifies, expanding the function PLUS, to the new
conjecture:
(IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(EQUAL (PLUS X (PLUS (SUB1 Y) Z))
(PLUS (SUB1 Y) (PLUS X Z))))
(EQUAL (PLUS X (ADD1 (PLUS (SUB1 Y) Z)))
(ADD1 (PLUS (SUB1 Y) (PLUS X Z))))).
Appealing to the lemma SUB1.ELIM, we now replace Y by (ADD1 V) to
eliminate (SUB1 Y). We use the type restriction lemma noted when
SUB1 was introduced to constrain the new variable. We thus obtain:
(IMPLIES (AND (NUMBERP V)
(NUMBERP (ADD1 V))
(NOT (EQUAL (ADD1 V) 0))
(EQUAL (PLUS X (PLUS V Z))
(PLUS V (PLUS X Z))))
(EQUAL (PLUS X (ADD1 (PLUS V Z)))
(ADD1 (PLUS V (PLUS X Z))))).
Of course, this simplifies further, trivially, to:
(IMPLIES (AND (NUMBERP V)
(EQUAL (PLUS X (PLUS V Z))
(PLUS V (PLUS X Z))))
(EQUAL (PLUS X (ADD1 (PLUS V Z)))
(ADD1 (PLUS V (PLUS X Z))))).
We use the above equality hypothesis by cross-fertilizing
(PLUS X (PLUS V Z)) for (PLUS V (PLUS X Z)) and throwing away the
equality. This generates the new conjecture:
(IMPLIES (NUMBERP V)
(EQUAL (PLUS X (ADD1 (PLUS V Z)))
(ADD1 (PLUS X (PLUS V Z))))),
which we generalize by replacing (PLUS V Z) by Y. We restrict
the new variable by appealing to the type restriction lemma noted
when PLUS was introduced. This generates:
(IMPLIES (AND (NUMBERP Y) (NUMBERP V))
(EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y)))).
Eliminate the irrelevant term. We would thus like to prove:
(IMPLIES (NUMBERP Y)
(EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y)))).
Finally name the above subgoal *1.3.
Let us appeal to the induction principle. There are two
plausible inductions. However, they merge into one likely
candidate induction. We will induct according to the following
scheme:
(AND (IMPLIES (NOT (NUMBERP X)) (p X Y))
(IMPLIES (EQUAL X 0) (p X Y))
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(p (SUB1 X) Y))
(p X Y))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme generates
three new formulas:
Case 1. (IMPLIES (AND (NOT (NUMBERP X)) (NUMBERP Y))
(EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y)))),
which we simplify, unfolding PLUS, to:
(TRUE).
Case 2. (IMPLIES (AND (EQUAL X 0) (NUMBERP Y))
(EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y)))).
This simplifies, expanding the definition of PLUS, to:
(TRUE).
Case 3. (IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(EQUAL (PLUS (SUB1 X) (ADD1 Y))
(ADD1 (PLUS (SUB1 X) Y)))
(NUMBERP Y))
(EQUAL (PLUS X (ADD1 Y))
(ADD1 (PLUS X Y)))),
which simplifies, appealing to the lemma ADD1.EQUAL, and
unfolding PLUS, to:
(TRUE).
That finishes the proof of *1.3.
So let us turn our attention to:
(IMPLIES (AND (NOT (NUMBERP Z)) (NUMBERP X))
(EQUAL X (PLUS X Z))),
which is formula *1.2 above. But this conjecture is subsumed by
formula *1.1 above.
So we now return to:
(IMPLIES (AND (NOT (NUMBERP Z)) (NUMBERP X))
(EQUAL X (PLUS X Z))),
named *1.1 above. Perhaps we can prove it by induction. There is
only one plausible induction. We will induct according to the
following scheme:
(AND (IMPLIES (EQUAL X 0) (p X Z))
(IMPLIES (NOT (NUMBERP X)) (p X Z))
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(p (SUB1 X) Z))
(p X Z))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme produces
the following three new conjectures:
Case 1. (IMPLIES (AND (EQUAL X 0)
(NOT (NUMBERP Z))
(NUMBERP X))
(EQUAL X (PLUS X Z))).
This simplifies, unfolding the definition of PLUS, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL X 0))
(NOT (NUMBERP (SUB1 X)))
(NOT (NUMBERP Z))
(NUMBERP X))
(EQUAL X (PLUS X Z))),
which we simplify, trivially, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL X 0))
(EQUAL (SUB1 X) (PLUS (SUB1 X) Z))
(NOT (NUMBERP Z))
(NUMBERP X))
(EQUAL X (PLUS X Z))),
which we simplify, unfolding the function PLUS, to:
(IMPLIES (AND (NOT (EQUAL X 0))
(EQUAL (SUB1 X) (PLUS (SUB1 X) Z))
(NOT (NUMBERP Z))
(NUMBERP X))
(EQUAL X (ADD1 (PLUS (SUB1 X) Z)))).
Applying the lemma SUB1.ELIM, replace X by (ADD1 V) to eliminate
(SUB1 X). We rely the type restriction lemma noted when SUB1 was
introduced to constrain the new variable. This generates:
(IMPLIES (AND (NUMBERP V)
(NOT (EQUAL (ADD1 V) 0))
(EQUAL V (PLUS V Z))
(NOT (NUMBERP Z))
(NUMBERP (ADD1 V)))
(EQUAL (ADD1 V) (ADD1 (PLUS V Z)))),
which we further simplify, using the lemma ADD1.EQUAL, to:
(TRUE).
That finishes the proof of *1.1, which finishes the proof of *1.
Q.E.D.
CPU time (devoted to theorem-proving):##5.861 seconds
.ENDASIS
.SS |COMMUTATIVITY.OF.PLUS|
.ASIS
Theorem. COMMUTATIVITY.OF.PLUS (rewrite):
(EQUAL (PLUS X Y) (PLUS Y X))
Call the conjecture *1.
Let us appeal to the induction principle. Two inductions are
suggested by terms in the conjecture, neither of which is unflawed,
and both of which appear equally likely. So we will choose
arbitrarily. We will induct according to the following scheme:
(AND (IMPLIES (EQUAL X 0) (p X Y))
(IMPLIES (NOT (NUMBERP X)) (p X Y))
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(p (SUB1 X) Y))
(p X Y))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme generates
three new formulas:
Case 1. (IMPLIES (EQUAL X 0)
(EQUAL (PLUS X Y) (PLUS Y X))).
This simplifies, appealing to the lemma PLUS.RIGHT.ID, and opening
up the definition of PLUS, to:
(TRUE).
Case 2. (IMPLIES (NOT (NUMBERP X))
(EQUAL (PLUS X Y) (PLUS Y X))).
This simplifies, unfolding the function PLUS, to:
(IMPLIES (AND (NOT (NUMBERP X)) (NUMBERP Y))
(EQUAL Y (PLUS Y X))).
Call the above conjecture *1.1.
Case 3. (IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(EQUAL (PLUS (SUB1 X) Y)
(PLUS Y (SUB1 X))))
(EQUAL (PLUS X Y) (PLUS Y X))),
which we simplify, expanding the function PLUS, to:
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(EQUAL (PLUS (SUB1 X) Y)
(PLUS Y (SUB1 X))))
(EQUAL (ADD1 (PLUS (SUB1 X) Y))
(PLUS Y X))).
Appealing to the lemma SUB1.ELIM, we now replace X by (ADD1 Z) to
eliminate (SUB1 X). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. We thus
obtain:
(IMPLIES (AND (NUMBERP Z)
(NOT (EQUAL (ADD1 Z) 0))
(NUMBERP (ADD1 Z))
(EQUAL (PLUS Z Y) (PLUS Y Z)))
(EQUAL (ADD1 (PLUS Z Y))
(PLUS Y (ADD1 Z)))).
Of course, this simplifies further, clearly, to:
(IMPLIES (AND (NUMBERP Z)
(EQUAL (PLUS Z Y) (PLUS Y Z)))
(EQUAL (ADD1 (PLUS Z Y))
(PLUS Y (ADD1 Z)))).
We use the above equality hypothesis by cross-fertilizing
(PLUS Y Z) for (PLUS Z Y) and throwing away the equality. We
would thus like to prove:
(IMPLIES (NUMBERP Z)
(EQUAL (ADD1 (PLUS Y Z))
(PLUS Y (ADD1 Z)))),
which we will name *1.2.
We will try to prove it by induction. Two inductions are
suggested by terms in the conjecture. However, they merge into one
likely candidate induction. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (NUMBERP Y)) (p Y Z))
(IMPLIES (EQUAL Y 0) (p Y Z))
(IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(p (SUB1 Y) Z))
(p Y Z))).
The inequality SUB1.LESSP establishes that the measure (COUNT Y)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme generates
three new conjectures:
Case 1. (IMPLIES (AND (NOT (NUMBERP Y)) (NUMBERP Z))
(EQUAL (ADD1 (PLUS Y Z))
(PLUS Y (ADD1 Z)))),
which we simplify, expanding the definition of PLUS, to:
(TRUE).
Case 2. (IMPLIES (AND (EQUAL Y 0) (NUMBERP Z))
(EQUAL (ADD1 (PLUS Y Z))
(PLUS Y (ADD1 Z)))).
This simplifies, expanding the definition of PLUS, to:
(TRUE).
Case 3. (IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(EQUAL (ADD1 (PLUS (SUB1 Y) Z))
(PLUS (SUB1 Y) (ADD1 Z)))
(NUMBERP Z))
(EQUAL (ADD1 (PLUS Y Z))
(PLUS Y (ADD1 Z)))).
This simplifies, using the lemma ADD1.EQUAL, and opening up the
function PLUS, to:
(TRUE).
That finishes the proof of *1.2.
So next consider:
(IMPLIES (AND (NOT (NUMBERP X)) (NUMBERP Y))
(EQUAL Y (PLUS Y X))),
which we named *1.1 above. Let us appeal to the induction principle.
There is only one suggested induction. We will induct according to
the following scheme:
(AND (IMPLIES (EQUAL Y 0) (p Y X))
(IMPLIES (NOT (NUMBERP Y)) (p Y X))
(IMPLIES (AND (NOT (EQUAL Y 0))
(NUMBERP Y)
(p (SUB1 Y) X))
(p Y X))).
The inequality SUB1.LESSP establishes that the measure (COUNT Y)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme produces
three new goals:
Case 1. (IMPLIES (AND (EQUAL Y 0)
(NOT (NUMBERP X))
(NUMBERP Y))
(EQUAL Y (PLUS Y X))).
This simplifies, unfolding the definition of PLUS, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL Y 0))
(NOT (NUMBERP (SUB1 Y)))
(NOT (NUMBERP X))
(NUMBERP Y))
(EQUAL Y (PLUS Y X))).
Of course, this simplifies, clearly, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL Y 0))
(EQUAL (SUB1 Y) (PLUS (SUB1 Y) X))
(NOT (NUMBERP X))
(NUMBERP Y))
(EQUAL Y (PLUS Y X))),
which we simplify, expanding the function PLUS, to the new
conjecture:
(IMPLIES (AND (NOT (EQUAL Y 0))
(EQUAL (SUB1 Y) (PLUS (SUB1 Y) X))
(NOT (NUMBERP X))
(NUMBERP Y))
(EQUAL Y (ADD1 (PLUS (SUB1 Y) X)))).
Appealing to the lemma SUB1.ELIM, replace Y by (ADD1 Z) to
eliminate (SUB1 Y). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. This
produces:
(IMPLIES (AND (NUMBERP Z)
(NOT (EQUAL (ADD1 Z) 0))
(EQUAL Z (PLUS Z X))
(NOT (NUMBERP X))
(NUMBERP (ADD1 Z)))
(EQUAL (ADD1 Z) (ADD1 (PLUS Z X)))).
However this simplifies further, applying the lemma ADD1.EQUAL, to:
(TRUE).
That finishes the proof of *1.1, which finishes the proof of *1.
Q.E.D.
CPU time (devoted to theorem-proving):##4.002 seconds
.ENDASIS
.SS |ASSOCIATIVITY.OF.PLUS|
.ASIS
Theorem. ASSOCIATIVITY.OF.PLUS (rewrite):
(EQUAL (PLUS (PLUS X Y) Z)
(PLUS X (PLUS Y Z)))
This formula simplifies, appealing to the lemmas
COMMUTATIVITY.OF.PLUS and COMMUTATIVITY2.OF.PLUS, to:
(TRUE).
Q.E.D.
CPU time (devoted to theorem-proving):##.229 seconds
.ENDASIS
.SS |TIMES|
.ASIS
Definition.
(TIMES I J)
=
(IF (ZEROP I)
0
(PLUS J (TIMES (SUB1 I) J)))
The lemma SUB1.LESSP establishes that (COUNT I) goes down
according to the well-founded relation LESSP in each recursive call.
Hence, TIMES is accepted under the principle of definition. Note
that (NUMBERP (TIMES I J)) is a theorem.
CPU time (devoted to theorem-proving):##.611 seconds
.ENDASIS
.SS |TIMES.ZERO|
.ASIS
Theorem. TIMES.ZERO (rewrite):
(EQUAL (TIMES X 0) 0)
Name the conjecture *1.
Let us appeal to the induction principle. There is only one
suggested induction. We will induct according to the following
scheme:
(AND (IMPLIES (EQUAL X 0) (p X))
(IMPLIES (NOT (NUMBERP X)) (p X))
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(p (SUB1 X)))
(p X))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme produces
three new conjectures:
Case 1. (IMPLIES (EQUAL X 0)
(EQUAL (TIMES X 0) 0)),
which we simplify, expanding the definition of TIMES, to:
(TRUE).
Case 2. (IMPLIES (NOT (NUMBERP X))
(EQUAL (TIMES X 0) 0)).
This simplifies, expanding the definition of TIMES, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(EQUAL (TIMES (SUB1 X) 0) 0))
(EQUAL (TIMES X 0) 0)).
This simplifies, unfolding PLUS and TIMES, to:
(TRUE).
That finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##.543 seconds
.ENDASIS
.SS |TIMES.ADD1|
.ASIS
Theorem. TIMES.ADD1 (rewrite):
(EQUAL (TIMES X (ADD1 Y))
(IF (NUMBERP Y)
(PLUS X (TIMES X Y))
(FIX X)))
This formula simplifies, using the lemma SUB1.TYPE.RESTRICTION, and
unfolding the definitions of FIX and TIMES, to two new conjectures:
Case 1. (IMPLIES (NUMBERP Y)
(EQUAL (TIMES X (ADD1 Y))
(PLUS X (TIMES X Y)))),
which we will name *1.
Case 2. (IMPLIES (AND (NOT (NUMBERP Y)) (NUMBERP X))
(EQUAL (TIMES X 1) X)).
Eliminate the irrelevant term. The result is the new formula:
(IMPLIES (NUMBERP X)
(EQUAL (TIMES X 1) X)),
which we would usually push and work on later by induction. But
since we have already pushed one goal split off of the original
input we will disregard all that we have previously done, give the
name *1 to the original input, and work on it.
So now let's consider:
(EQUAL (TIMES X (ADD1 Y))
(IF (NUMBERP Y)
(PLUS X (TIMES X Y))
(FIX X))).
We named this *1. We will appeal to induction. Three inductions are
suggested by terms in the conjecture. However, they merge into one
likely candidate induction. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (NUMBERP X)) (p X Y))
(IMPLIES (EQUAL X 0) (p X Y))
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(p (SUB1 X) Y))
(p X Y))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme leads to
the following three new conjectures:
Case 1. (IMPLIES (NOT (NUMBERP X))
(EQUAL (TIMES X (ADD1 Y))
(IF (NUMBERP Y)
(PLUS X (TIMES X Y))
(FIX X)))).
This simplifies, applying PLUS.RIGHT.ID, and unfolding the
definitions of TIMES and FIX, to:
(TRUE).
Case 2. (IMPLIES (EQUAL X 0)
(EQUAL (TIMES X (ADD1 Y))
(IF (NUMBERP Y)
(PLUS X (TIMES X Y))
(FIX X)))),
which simplifies, expanding the definitions of TIMES, PLUS and FIX,
to:
(TRUE).
Case 3. (IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(EQUAL (TIMES (SUB1 X) (ADD1 Y))
(IF (NUMBERP Y)
(PLUS (SUB1 X) (TIMES (SUB1 X) Y))
(FIX (SUB1 X)))))
(EQUAL (TIMES X (ADD1 Y))
(IF (NUMBERP Y)
(PLUS X (TIMES X Y))
(FIX X)))),
which simplifies, applying SUB1.ADD1 and SUB1.TYPE.RESTRICTION, and
opening up the definitions of FIX, PLUS and TIMES, to the following
two new goals:
Case 1. (IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(NUMBERP Y)
(EQUAL (TIMES (SUB1 X) (ADD1 Y))
(PLUS (SUB1 X) (TIMES (SUB1 X) Y))))
(EQUAL (ADD1 (PLUS Y (TIMES (SUB1 X) (ADD1 Y))))
(PLUS X
(PLUS Y (TIMES (SUB1 X) Y))))).
But this simplifies again, applying ADD1.EQUAL, and opening up
PLUS, to:
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(NUMBERP Y)
(EQUAL (TIMES (SUB1 X) (ADD1 Y))
(PLUS (SUB1 X) (TIMES (SUB1 X) Y))))
(EQUAL (PLUS Y (TIMES (SUB1 X) (ADD1 Y)))
(PLUS (SUB1 X)
(PLUS Y (TIMES (SUB1 X) Y))))).
But this again simplifies, applying the lemma
COMMUTATIVITY2.OF.PLUS, to:
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(NUMBERP Y)
(EQUAL (TIMES (SUB1 X) (ADD1 Y))
(PLUS (SUB1 X) (TIMES (SUB1 X) Y))))
(EQUAL (PLUS Y (TIMES (SUB1 X) (ADD1 Y)))
(PLUS Y
(PLUS (SUB1 X) (TIMES (SUB1 X) Y))))).
Applying the lemma SUB1.ELIM, replace X by (ADD1 Z) to
eliminate (SUB1 X). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. This
produces:
(IMPLIES (AND (NUMBERP Z)
(NUMBERP (ADD1 Z))
(NOT (EQUAL (ADD1 Z) 0))
(NUMBERP Y)
(EQUAL (TIMES Z (ADD1 Y))
(PLUS Z (TIMES Z Y))))
(EQUAL (PLUS Y (TIMES Z (ADD1 Y)))
(PLUS Y (PLUS Z (TIMES Z Y))))).
This simplifies further, clearly, to the goal:
(IMPLIES (AND (NUMBERP Z)
(NUMBERP Y)
(EQUAL (TIMES Z (ADD1 Y))
(PLUS Z (TIMES Z Y))))
(EQUAL (PLUS Y (TIMES Z (ADD1 Y)))
(PLUS Y (PLUS Z (TIMES Z Y))))).
We now use the above equality hypothesis by cross-fertilizing
(TIMES Z (ADD1 Y)) for (PLUS Z (TIMES Z Y)) and throwing away
the equality. We must thus prove:
(IMPLIES (AND (NUMBERP Z) (NUMBERP Y))
(EQUAL (PLUS Y (TIMES Z (ADD1 Y)))
(PLUS Y (TIMES Z (ADD1 Y))))).
Of course, this finally simplifies, obviously, to:
(TRUE).
Case 2. (IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(NOT (NUMBERP Y))
(EQUAL (TIMES (SUB1 X) 1) (SUB1 X)))
(EQUAL (TIMES X 1) X)).
This simplifies again, rewriting with SUB1.ADD1, and unfolding
the functions PLUS and TIMES, to:
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(NOT (NUMBERP Y))
(EQUAL (TIMES (SUB1 X) 1) (SUB1 X)))
(EQUAL (ADD1 (TIMES (SUB1 X) 1)) X)).
Appealing to the lemma SUB1.ELIM, replace X by (ADD1 Z) to
eliminate (SUB1 X). We rely the type restriction lemma noted
when SUB1 was introduced to constrain the new variable. We thus
obtain:
(IMPLIES (AND (NUMBERP Z)
(NUMBERP (ADD1 Z))
(NOT (EQUAL (ADD1 Z) 0))
(NOT (NUMBERP Y))
(EQUAL (TIMES Z 1) Z))
(EQUAL (ADD1 (TIMES Z 1)) (ADD1 Z))),
which we further simplify, using the lemma ADD1.EQUAL, to:
(TRUE).
That finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##7.086 seconds
.ENDASIS
.SS |ASSOCIATIVITY.OF.TIMES|
.ASIS
Theorem. ASSOCIATIVITY.OF.TIMES (rewrite):
(EQUAL (TIMES (TIMES X Y) Z)
(TIMES X (TIMES Y Z)))
Name the conjecture *1.
Let us appeal to the induction principle. The recursive terms
in the conjecture suggest three inductions. They merge into two
likely candidate inductions. However, only one is unflawed. We will
induct according to the following scheme:
(AND (IMPLIES (NOT (NUMBERP X)) (p X Y Z))
(IMPLIES (EQUAL X 0) (p X Y Z))
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(p (SUB1 X) Y Z))
(p X Y Z))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme produces
the following three new conjectures:
Case 1. (IMPLIES (NOT (NUMBERP X))
(EQUAL (TIMES (TIMES X Y) Z)
(TIMES X (TIMES Y Z)))),
which simplifies, expanding the definition of TIMES, to:
(TRUE).
Case 2. (IMPLIES (EQUAL X 0)
(EQUAL (TIMES (TIMES X Y) Z)
(TIMES X (TIMES Y Z)))),
which simplifies, opening up TIMES, to:
(TRUE).
Case 3. (IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(EQUAL (TIMES (TIMES (SUB1 X) Y) Z)
(TIMES (SUB1 X) (TIMES Y Z))))
(EQUAL (TIMES (TIMES X Y) Z)
(TIMES X (TIMES Y Z)))).
This simplifies, expanding TIMES, to:
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(EQUAL (TIMES (TIMES (SUB1 X) Y) Z)
(TIMES (SUB1 X) (TIMES Y Z))))
(EQUAL (TIMES (PLUS Y (TIMES (SUB1 X) Y)) Z)
(PLUS (TIMES Y Z)
(TIMES (SUB1 X) (TIMES Y Z))))).
Applying the lemma SUB1.ELIM, replace X by (ADD1 V) to eliminate
(SUB1 X). We use the type restriction lemma noted when SUB1 was
introduced to constrain the new variable. The result is:
(IMPLIES (AND (NUMBERP V)
(NUMBERP (ADD1 V))
(NOT (EQUAL (ADD1 V) 0))
(EQUAL (TIMES (TIMES V Y) Z)
(TIMES V (TIMES Y Z))))
(EQUAL (TIMES (PLUS Y (TIMES V Y)) Z)
(PLUS (TIMES Y Z)
(TIMES V (TIMES Y Z))))).
Of course, this simplifies further, trivially, to:
(IMPLIES (AND (NUMBERP V)
(EQUAL (TIMES (TIMES V Y) Z)
(TIMES V (TIMES Y Z))))
(EQUAL (TIMES (PLUS Y (TIMES V Y)) Z)
(PLUS (TIMES Y Z)
(TIMES V (TIMES Y Z))))).
We use the above equality hypothesis by cross-fertilizing
(TIMES (TIMES V Y) Z) for (TIMES V (TIMES Y Z)) and throwing away
the equality. We would thus like to prove the conjecture:
(IMPLIES (NUMBERP V)
(EQUAL (TIMES (PLUS Y (TIMES V Y)) Z)
(PLUS (TIMES Y Z)
(TIMES (TIMES V Y) Z)))),
which we generalize by replacing (TIMES V Y) by A. We restrict
the new variable by recalling the type restriction lemma noted when
TIMES was introduced. We would thus like to prove the new goal:
(IMPLIES (AND (NUMBERP A) (NUMBERP V))
(EQUAL (TIMES (PLUS Y A) Z)
(PLUS (TIMES Y Z) (TIMES A Z)))).
However this simplifies further, using the lemma
COMMUTATIVITY.OF.PLUS, to the conjecture:
(IMPLIES (AND (NUMBERP A) (NUMBERP V))
(EQUAL (TIMES (PLUS A Y) Z)
(PLUS (TIMES A Z) (TIMES Y Z)))),
which has an irrelevant term in it. By eliminating this term we
get:
(IMPLIES (NUMBERP A)
(EQUAL (TIMES (PLUS A Y) Z)
(PLUS (TIMES A Z) (TIMES Y Z)))),
which we will finally name *1.1.
Let us appeal to the induction principle. There are three
plausible inductions. They merge into two likely candidate
inductions. However, only one is unflawed. We will induct
according to the following scheme:
(AND (IMPLIES (NOT (NUMBERP A)) (p A Y Z))
(IMPLIES (EQUAL A 0) (p A Y Z))
(IMPLIES (AND (NUMBERP A)
(NOT (EQUAL A 0))
(p (SUB1 A) Y Z))
(p A Y Z))).
The inequality SUB1.LESSP establishes that the measure (COUNT A)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme produces
the following three new conjectures:
Case 1. (IMPLIES (AND (EQUAL A 0) (NUMBERP A))
(EQUAL (TIMES (PLUS A Y) Z)
(PLUS (TIMES A Z) (TIMES Y Z)))).
This simplifies, expanding the functions PLUS and TIMES, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL A 0))
(NOT (NUMBERP (SUB1 A)))
(NUMBERP A))
(EQUAL (TIMES (PLUS A Y) Z)
(PLUS (TIMES A Z) (TIMES Y Z)))),
which we simplify, obviously, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL A 0))
(EQUAL (TIMES (PLUS (SUB1 A) Y) Z)
(PLUS (TIMES (SUB1 A) Z) (TIMES Y Z)))
(NUMBERP A))
(EQUAL (TIMES (PLUS A Y) Z)
(PLUS (TIMES A Z) (TIMES Y Z)))),
which we simplify, rewriting with COMMUTATIVITY.OF.PLUS,
SUB1.ADD1 and ASSOCIATIVITY.OF.PLUS, and unfolding the functions
PLUS and TIMES, to:
(IMPLIES (AND (NOT (EQUAL A 0))
(EQUAL (TIMES (PLUS Y (SUB1 A)) Z)
(PLUS (TIMES Y Z) (TIMES (SUB1 A) Z)))
(NUMBERP A))
(EQUAL (PLUS Z (TIMES (PLUS (SUB1 A) Y) Z))
(PLUS Z
(PLUS (TIMES Y Z)
(TIMES (SUB1 A) Z))))),
which we again simplify, rewriting with COMMUTATIVITY.OF.PLUS, to:
(IMPLIES (AND (NOT (EQUAL A 0))
(EQUAL (TIMES (PLUS Y (SUB1 A)) Z)
(PLUS (TIMES Y Z) (TIMES (SUB1 A) Z)))
(NUMBERP A))
(EQUAL (PLUS Z (TIMES (PLUS Y (SUB1 A)) Z))
(PLUS Z
(PLUS (TIMES Y Z)
(TIMES (SUB1 A) Z))))).
Applying the lemma SUB1.ELIM, we now replace A by (ADD1 X) to
eliminate (SUB1 A). We rely the type restriction lemma noted
when SUB1 was introduced to constrain the new variable. We thus
obtain:
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL (ADD1 X) 0))
(EQUAL (TIMES (PLUS Y X) Z)
(PLUS (TIMES Y Z) (TIMES X Z)))
(NUMBERP (ADD1 X)))
(EQUAL (PLUS Z (TIMES (PLUS Y X) Z))
(PLUS Z
(PLUS (TIMES Y Z) (TIMES X Z))))).
This further simplifies, applying COMMUTATIVITY.OF.PLUS, to:
(IMPLIES (AND (NUMBERP X)
(EQUAL (TIMES (PLUS X Y) Z)
(PLUS (TIMES X Z) (TIMES Y Z))))
(EQUAL (PLUS Z (TIMES (PLUS X Y) Z))
(PLUS Z
(PLUS (TIMES X Z) (TIMES Y Z))))).
We use the above equality hypothesis by cross-fertilizing:
(PLUS (TIMES X Z) (TIMES Y Z))
for (TIMES (PLUS X Y) Z) and throwing away the equality. We
thus obtain:
(IMPLIES (NUMBERP X)
(EQUAL (PLUS Z
(PLUS (TIMES X Z) (TIMES Y Z)))
(PLUS Z
(PLUS (TIMES X Z) (TIMES Y Z))))),
which we further simplify, clearly, to:
(TRUE).
That finishes the proof of *1.1, which, consequently, finishes
the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##10.277 seconds
.ENDASIS
.SS |DIFFERENCE|
.ASIS
Definition.
(DIFFERENCE I J)
=
(IF (ZEROP I)
0
(IF (ZEROP J)
I
(DIFFERENCE (SUB1 I) (SUB1 J))))
The lemma SUB1.LESSP can be used to show that (COUNT I)
decreases according to the well-founded relation LESSP in each
recursive call. Hence, DIFFERENCE is accepted under the
definition principle. The definition of DIFFERENCE can be
justified in another way. The lemma SUB1.LESSP informs us that
(COUNT J) decreases according to the well-founded relation
LESSP in each recursive call. Note that:
(NUMBERP (DIFFERENCE I J))
is a theorem.
CPU time (devoted to theorem-proving):##1.594 seconds
.ENDASIS
.SS |RECURSION.BY.DIFFERENCE|
.ASIS
Theorem. RECURSION.BY.DIFFERENCE (induction):
(IMPLIES (AND (NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I))
Name the conjecture *1.
Perhaps we can prove it by induction. Three inductions are
suggested by terms in the conjecture. However, they merge into one
likely candidate induction. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (NUMBERP N)) (p I N))
(IMPLIES (EQUAL N 0) (p I N))
(IMPLIES (NOT (NUMBERP I)) (p I N))
(IMPLIES (EQUAL I 0) (p I N))
(IMPLIES (AND (NUMBERP N)
(NOT (EQUAL N 0))
(NUMBERP I)
(NOT (EQUAL I 0))
(p (SUB1 I) (SUB1 N)))
(p I N))).
The inequality SUB1.LESSP establishes that the measure (COUNT I)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. Note, however, the inductive instance
chosen for N. The above induction scheme generates five new
conjectures:
Case 1. (IMPLIES (AND (NOT (NUMBERP (SUB1 I)))
(NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I)).
This simplifies, clearly, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (NUMBERP (SUB1 N)))
(NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I)),
which simplifies, clearly, to:
(TRUE).
Case 3. (IMPLIES (AND (EQUAL (SUB1 I) 0)
(NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I)).
Applying the lemma SUB1.ELIM, replace I by (ADD1 X) to eliminate
(SUB1 I). We rely the type restriction lemma noted when SUB1 was
introduced to constrain the new variable. The result is:
(IMPLIES (AND (NUMBERP X)
(EQUAL X 0)
(NUMBERP (ADD1 X))
(NUMBERP N)
(NOT (EQUAL (ADD1 X) 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE (ADD1 X) N)
(ADD1 X))),
which simplifies, appealing to the lemma SUB1.ADD1, and expanding
the definitions of DIFFERENCE and LESSP, to:
(TRUE).
Case 4. (IMPLIES (AND (EQUAL (SUB1 N) 0)
(NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I)).
Applying the lemma SUB1.ELIM, we now replace N by (ADD1 X) to
eliminate (SUB1 N). We rely the type restriction lemma noted when
SUB1 was introduced to restrict the new variable. We would thus
like to prove:
(IMPLIES (AND (NUMBERP X)
(EQUAL X 0)
(NUMBERP I)
(NUMBERP (ADD1 X))
(NOT (EQUAL I 0))
(NOT (EQUAL (ADD1 X) 0)))
(LESSP (DIFFERENCE I (ADD1 X)) I)),
which simplifies, applying SUB1.ADD1, and opening up the
definitions of DIFFERENCE and LESSP, to the new goal:
(IMPLIES (AND (NUMBERP I)
(NOT (EQUAL I 0))
(NOT (EQUAL (SUB1 I) 0)))
(LESSP (SUB1 I) I)).
Applying the lemma SUB1.ELIM, we now replace I by (ADD1 X) to
eliminate (SUB1 I). We rely the type restriction lemma noted when
SUB1 was introduced to restrict the new variable. We thus obtain:
(IMPLIES (AND (NUMBERP X)
(NUMBERP (ADD1 X))
(NOT (EQUAL (ADD1 X) 0))
(NOT (EQUAL X 0)))
(LESSP X (ADD1 X))),
which further simplifies, applying SUB1.ADD1, and expanding LESSP,
to:
(IMPLIES (AND (NUMBERP X) (NOT (EQUAL X 0)))
(LESSP (SUB1 X) X)).
Give the above formula the name *1.1.
Case 5. (IMPLIES (AND (LESSP (DIFFERENCE (SUB1 I) (SUB1 N))
(SUB1 I))
(NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I)).
This simplifies, expanding the definition of DIFFERENCE, to:
(IMPLIES (AND (LESSP (DIFFERENCE (SUB1 I) (SUB1 N))
(SUB1 I))
(NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE (SUB1 I) (SUB1 N))
I)).
Appealing to the lemma SUB1.ELIM, we now replace I by (ADD1 X) to
eliminate (SUB1 I). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. This
produces the new formula:
(IMPLIES (AND (NUMBERP X)
(LESSP (DIFFERENCE X (SUB1 N)) X)
(NUMBERP (ADD1 X))
(NUMBERP N)
(NOT (EQUAL (ADD1 X) 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE X (SUB1 N))
(ADD1 X))),
which further simplifies, applying the lemma SUB1.ADD1, and opening
up the definition of LESSP, to the conjecture:
(IMPLIES (AND (NUMBERP X)
(LESSP (DIFFERENCE X (SUB1 N)) X)
(NUMBERP N)
(NOT (EQUAL N 0))
(NOT (EQUAL (DIFFERENCE X (SUB1 N)) 0)))
(LESSP (SUB1 (DIFFERENCE X (SUB1 N)))
X)).
Appealing to the lemma SUB1.ELIM, we now replace N by (ADD1 Z) to
eliminate (SUB1 N). We use the type restriction lemma noted when
SUB1 was introduced to restrict the new variable. This generates:
(IMPLIES (AND (NUMBERP Z)
(NUMBERP X)
(LESSP (DIFFERENCE X Z) X)
(NUMBERP (ADD1 Z))
(NOT (EQUAL (ADD1 Z) 0))
(NOT (EQUAL (DIFFERENCE X Z) 0)))
(LESSP (SUB1 (DIFFERENCE X Z)) X)),
which further simplifies, trivially, to:
(IMPLIES (AND (NUMBERP Z)
(NUMBERP X)
(LESSP (DIFFERENCE X Z) X)
(NOT (EQUAL (DIFFERENCE X Z) 0)))
(LESSP (SUB1 (DIFFERENCE X Z)) X)).
We will try to prove the above conjecture by generalizing it,
replacing (DIFFERENCE X Z) by Y. We restrict the new variable by
appealing to the type restriction lemma noted when DIFFERENCE was
introduced. The result is:
(IMPLIES (AND (NUMBERP Y)
(NUMBERP Z)
(NUMBERP X)
(LESSP Y X)
(NOT (EQUAL Y 0)))
(LESSP (SUB1 Y) X)).
Appealing to the lemma SUB1.ELIM, we now replace Y by (ADD1 V) to
eliminate (SUB1 Y). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. We would
thus like to prove the goal:
(IMPLIES (AND (NUMBERP V)
(NUMBERP (ADD1 V))
(NUMBERP Z)
(NUMBERP X)
(LESSP (ADD1 V) X)
(NOT (EQUAL (ADD1 V) 0)))
(LESSP V X)),
which we further simplify, using the lemma SUB1.ADD1, and opening
up the definition of LESSP, to:
(IMPLIES (AND (NUMBERP V)
(NUMBERP Z)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)).
Eliminate the irrelevant term. This generates:
(IMPLIES (AND (NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)).
Finally give the above formula the name *1.2.
We will appeal to induction. Three inductions are suggested
by terms in the conjecture. However, they merge into one likely
candidate induction. We will induct according to the following
scheme:
(AND (IMPLIES (NOT (NUMBERP X)) (p V X))
(IMPLIES (EQUAL X 0) (p V X))
(IMPLIES (NOT (NUMBERP V)) (p V X))
(IMPLIES (EQUAL V 0) (p V X))
(IMPLIES (AND (NUMBERP X)
(NOT (EQUAL X 0))
(NUMBERP V)
(NOT (EQUAL V 0))
(p (SUB1 V) (SUB1 X)))
(p V X))).
The inequality SUB1.LESSP establishes that the measure (COUNT V)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. Note, however, the inductive
instance chosen for X. The above induction scheme generates six
new conjectures:
Case 1. (IMPLIES (AND (EQUAL V 0)
(NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)),
which we simplify, expanding the definition of LESSP, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL V 0))
(NOT (NUMBERP (SUB1 V)))
(NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)).
This simplifies, trivially, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL V 0))
(NOT (NUMBERP (SUB1 X)))
(NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)).
Of course, this simplifies, trivially, to:
(TRUE).
Case 4. (IMPLIES (AND (NOT (EQUAL V 0))
(EQUAL (SUB1 X) 0)
(NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)).
This simplifies, expanding LESSP, to:
(TRUE).
Case 5. (IMPLIES (AND (NOT (EQUAL V 0))
(NOT (LESSP (SUB1 V) (SUB1 (SUB1 X))))
(NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)),
which simplifies, opening up LESSP, to:
(TRUE).
Case 6. (IMPLIES (AND (NOT (EQUAL V 0))
(LESSP (SUB1 V) (SUB1 X))
(NUMBERP V)
(NUMBERP X)
(NOT (EQUAL X 0))
(LESSP V (SUB1 X)))
(LESSP V X)).
This simplifies, expanding LESSP, to:
(TRUE).
That finishes the proof of *1.2.
So let us turn our attention to:
(IMPLIES (AND (NUMBERP X) (NOT (EQUAL X 0)))
(LESSP (SUB1 X) X)),
which we named *1.1 above. Perhaps we can prove it by induction.
There is only one plausible induction. We will induct according to
the following scheme:
(AND (IMPLIES (EQUAL X 0) (p X))
(IMPLIES (NOT (NUMBERP X)) (p X))
(IMPLIES (EQUAL (SUB1 X) 0) (p X))
(IMPLIES (NOT (NUMBERP (SUB1 X)))
(p X))
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(NOT (EQUAL (SUB1 X) 0))
(NUMBERP (SUB1 X))
(p (SUB1 X)))
(p X))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. The above induction scheme leads to
three new goals:
Case 1. (IMPLIES (AND (NOT (NUMBERP (SUB1 X)))
(NUMBERP X)
(NOT (EQUAL X 0)))
(LESSP (SUB1 X) X)).
This simplifies, trivially, to:
(TRUE).
Case 2. (IMPLIES (AND (EQUAL (SUB1 X) 0)
(NUMBERP X)
(NOT (EQUAL X 0)))
(LESSP (SUB1 X) X)).
This simplifies, expanding the definition of LESSP, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (EQUAL (SUB1 X) 0))
(NUMBERP (SUB1 X))
(LESSP (SUB1 (SUB1 X)) (SUB1 X))
(NUMBERP X)
(NOT (EQUAL X 0)))
(LESSP (SUB1 X) X)),
which simplifies, opening up the definition of LESSP, to:
(TRUE).
That finishes the proof of *1.1, which, consequently, also
finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##10.241 seconds
.ENDASIS
.SS |REMAINDER|
.ASIS
Definition.
(REMAINDER I J)
=
(IF (ZEROP J)
(FIX I)
(IF (LESSP I J)
(FIX I)
(REMAINDER (DIFFERENCE I J) J)))
The lemma RECURSION.BY.DIFFERENCE, together with the definition
of LESSP, establish that (COUNT I) goes down according to the
well-founded relation LESSP in each recursive call. Hence,
REMAINDER is accepted under the definition principle. Observe that
(NUMBERP (REMAINDER I J)) is a theorem.
CPU time (devoted to theorem-proving):##1.446 seconds
.ENDASIS
.SS |QUOTIENT|
.ASIS
Definition.
(QUOTIENT I J)
=
(IF (ZEROP J)
0
(IF (LESSP I J)
0
(ADD1 (QUOTIENT (DIFFERENCE I J) J))))
The lemma RECURSION.BY.DIFFERENCE, together with the definition
of LESSP, inform us that (COUNT I) goes down according to the
well-founded relation LESSP in each recursive call. Hence, QUOTIENT
is accepted under the principle of definition. Observe that
(NUMBERP (QUOTIENT I J)) is a theorem.
CPU time (devoted to theorem-proving):##1.381 seconds
.ENDASIS
.SS |REMAINDER.QUOTIENT.ELIM|
.ASIS
Theorem. REMAINDER.QUOTIENT.ELIM (rewrite):
(IMPLIES (AND (NOT (ZEROP Y)) (NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X))
This formula simplifies, expanding the definitions of ZEROP, NOT, AND
and IMPLIES, to:
(IMPLIES (AND (NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X)).
Call the above conjecture *1.
Perhaps we can prove it by induction. There are three plausible
inductions. They merge into two likely candidate inductions.
However, only one is unflawed. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (NUMBERP X)) (p X Y))
(IMPLIES (NOT (NUMBERP Y)) (p X Y))
(IMPLIES (EQUAL X 0) (p X Y))
(IMPLIES (EQUAL Y 0) (p X Y))
(IMPLIES (AND (NUMBERP X)
(NUMBERP Y)
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(p (DIFFERENCE X Y) Y))
(p X Y))).
The inequality RECURSION.BY.DIFFERENCE establishes that the measure
(COUNT X) decreases according to the well-founded relation LESSP in
the induction step of the scheme. The above induction scheme
generates the following three new goals:
Case 1. (IMPLIES (AND (EQUAL X 0)
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X)),
which simplifies, applying the lemma TIMES.ZERO, and expanding the
definitions of LESSP, REMAINDER, QUOTIENT and PLUS, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL X 0))
(NOT (NUMBERP (DIFFERENCE X Y)))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X)),
which we simplify, trivially, to:
(TRUE).
Case 3. (IMPLIES
(AND (NOT (EQUAL X 0))
(EQUAL (PLUS (REMAINDER (DIFFERENCE X Y) Y)
(TIMES Y
(QUOTIENT (DIFFERENCE X Y) Y)))
(DIFFERENCE X Y))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X)).
This simplifies, applying the lemmas TIMES.ZERO, PLUS.RIGHT.ID,
TIMES.ADD1 and COMMUTATIVITY2.OF.PLUS, and expanding the
definitions of REMAINDER and QUOTIENT, to:
(IMPLIES
(AND (NOT (EQUAL X 0))
(EQUAL (PLUS (REMAINDER (DIFFERENCE X Y) Y)
(TIMES Y
(QUOTIENT (DIFFERENCE X Y) Y)))
(DIFFERENCE X Y))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y
(PLUS (REMAINDER (DIFFERENCE X Y) Y)
(TIMES Y
(QUOTIENT (DIFFERENCE X Y) Y))))
X)).
We use the above equality hypothesis by cross-fertilizing
(DIFFERENCE X Y) for:
(PLUS (REMAINDER (DIFFERENCE X Y) Y)
(TIMES Y
(QUOTIENT (DIFFERENCE X Y) Y)))
and throwing away the equality. This produces:
(IMPLIES (AND (NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)),
which we will name *1.1.
Let us appeal to the induction principle. Five inductions are
suggested by terms in the conjecture. However, they merge into one
likely candidate induction. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (NUMBERP Y)) (p Y X))
(IMPLIES (EQUAL Y 0) (p Y X))
(IMPLIES (NOT (NUMBERP X)) (p Y X))
(IMPLIES (EQUAL X 0) (p Y X))
(IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(NUMBERP X)
(NOT (EQUAL X 0))
(p (SUB1 Y) (SUB1 X)))
(p Y X))).
The inequality SUB1.LESSP establishes that the measure (COUNT X)
decreases according to the well-founded relation LESSP in the
induction step of the scheme. Note, however, the inductive
instance chosen for Y. The above induction scheme generates six
new goals:
Case 1. (IMPLIES (AND (EQUAL (SUB1 X) 0)
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)).
Applying the lemma SUB1.ELIM, we now replace X by (ADD1 Z) to
eliminate (SUB1 X). We use the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. The
result is:
(IMPLIES (AND (NUMBERP Z)
(EQUAL Z 0)
(NOT (EQUAL (ADD1 Z) 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP (ADD1 Z))
(NOT (LESSP (ADD1 Z) Y)))
(EQUAL (PLUS Y (DIFFERENCE (ADD1 Z) Y))
(ADD1 Z))).
But this simplifies, appealing to the lemmas SUB1.ADD1 and
PLUS.RIGHT.ID, and unfolding the definitions of LESSP and
DIFFERENCE, to:
(IMPLIES (AND (NOT (EQUAL Y 0))
(NUMBERP Y)
(EQUAL (SUB1 Y) 0))
(EQUAL Y 1)).
Applying the lemma SUB1.ELIM, we now replace Y by (ADD1 Z) to
eliminate (SUB1 Y). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. We would
thus like to prove:
(IMPLIES (AND (NUMBERP Z)
(NOT (EQUAL (ADD1 Z) 0))
(NUMBERP (ADD1 Z))
(EQUAL Z 0))
(EQUAL (ADD1 Z) 1)).
This further simplifies, obviously, to:
(TRUE).
Case 2. (IMPLIES (AND (EQUAL (SUB1 Y) 0)
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)).
This simplifies, unfolding the definition of PLUS, to the new
conjecture:
(IMPLIES (AND (EQUAL (SUB1 Y) 0)
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (ADD1 (PLUS (SUB1 Y) (DIFFERENCE X Y)))
X)),
which we again simplify, opening up PLUS, to:
(IMPLIES (AND (EQUAL (SUB1 Y) 0)
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (ADD1 (DIFFERENCE X Y)) X)).
Appealing to the lemma SUB1.ELIM, replace Y by (ADD1 Z) to
eliminate (SUB1 Y). We rely the type restriction lemma noted
when SUB1 was introduced to constrain the new variable. The
result is:
(IMPLIES (AND (NUMBERP Z)
(EQUAL Z 0)
(NOT (EQUAL X 0))
(NOT (EQUAL (ADD1 Z) 0))
(NUMBERP (ADD1 Z))
(NUMBERP X)
(NOT (LESSP X (ADD1 Z))))
(EQUAL (ADD1 (DIFFERENCE X (ADD1 Z)))
X)).
This simplifies further, using the lemmas SUB1.ADD1 and ADD1.SUB1,
and expanding the definitions of LESSP, DIFFERENCE, NOT and AND,
to:
(IMPLIES (AND (NOT (EQUAL X 0))
(NUMBERP X)
(EQUAL (SUB1 X) 0))
(EQUAL 1 X)).
Applying the lemma SUB1.ELIM, replace X by (ADD1 Z) to
eliminate (SUB1 X). We employ the type restriction lemma noted
when SUB1 was introduced to restrict the new variable. This
produces:
(IMPLIES (AND (NUMBERP Z)
(NOT (EQUAL (ADD1 Z) 0))
(NUMBERP (ADD1 Z))
(EQUAL Z 0))
(EQUAL 1 (ADD1 Z))).
Of course, this further simplifies, obviously, to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (NUMBERP (SUB1 Y)))
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)),
which simplifies, obviously, to:
(TRUE).
Case 4. (IMPLIES (AND (NOT (NUMBERP (SUB1 X)))
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)).
Of course, this simplifies, obviously, to:
(TRUE).
Case 5. (IMPLIES (AND (LESSP (SUB1 X) (SUB1 Y))
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)),
which we simplify, unfolding the function LESSP, to:
(TRUE).
Case 6. (IMPLIES (AND (EQUAL (PLUS (SUB1 Y)
(DIFFERENCE (SUB1 X) (SUB1 Y)))
(SUB1 X))
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP X Y)))
(EQUAL (PLUS Y (DIFFERENCE X Y)) X)).
This simplifies, expanding the definitions of LESSP, DIFFERENCE
and PLUS, to:
(IMPLIES (AND (EQUAL (PLUS (SUB1 Y)
(DIFFERENCE (SUB1 X) (SUB1 Y)))
(SUB1 X))
(NOT (EQUAL X 0))
(NOT (EQUAL Y 0))
(NUMBERP Y)
(NUMBERP X)
(NOT (LESSP (SUB1 X) (SUB1 Y))))
(EQUAL (ADD1 (PLUS (SUB1 Y)
(DIFFERENCE (SUB1 X) (SUB1 Y))))
X)).
Applying the lemma SUB1.ELIM, we now replace Y by (ADD1 Z) to
eliminate (SUB1 Y). We use the type restriction lemma noted
when SUB1 was introduced to constrain the new variable. This
generates:
(IMPLIES (AND (NUMBERP Z)
(EQUAL (PLUS Z (DIFFERENCE (SUB1 X) Z))
(SUB1 X))
(NOT (EQUAL X 0))
(NOT (EQUAL (ADD1 Z) 0))
(NUMBERP (ADD1 Z))
(NUMBERP X)
(NOT (LESSP (SUB1 X) Z)))
(EQUAL (ADD1 (PLUS Z (DIFFERENCE (SUB1 X) Z)))
X)).
Of course, this simplifies further, trivially, to:
(IMPLIES (AND (NUMBERP Z)
(EQUAL (PLUS Z (DIFFERENCE (SUB1 X) Z))
(SUB1 X))
(NOT (EQUAL X 0))
(NUMBERP X)
(NOT (LESSP (SUB1 X) Z)))
(EQUAL (ADD1 (PLUS Z (DIFFERENCE (SUB1 X) Z)))
X)).
Appealing to the lemma SUB1.ELIM, we now replace X by (ADD1 V)
to eliminate (SUB1 X). We rely the type restriction lemma noted
when SUB1 was introduced to constrain the new variable. This
produces:
(IMPLIES (AND (NUMBERP V)
(NUMBERP Z)
(EQUAL (PLUS Z (DIFFERENCE V Z)) V)
(NOT (EQUAL (ADD1 V) 0))
(NUMBERP (ADD1 V))
(NOT (LESSP V Z)))
(EQUAL (ADD1 (PLUS Z (DIFFERENCE V Z)))
(ADD1 V))).
However this simplifies further, applying the lemma ADD1.EQUAL,
to:
(TRUE).
That finishes the proof of *1.1, which, in turn, also finishes
the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##12.334 seconds
.ENDASIS
.SEC |THE CORRECTNESS OF A SIMPLE OPTIMIZING EXPRESSION COMPILER|, SECCOMPILER:
In this and the next two {SECTIONORCHAPTER}s, we construct in our theory
the proofs of three interesting theorems:##the correctness of an expression
compiler, the correctness of a fast string searching algorithm, and
the Fundamental Theorem of Arithmetic. The proofs we discuss are
those discovered by our theorem-proving program.
The examples are presented in the same format as the TAUTOLOGY.CHECKER
example in {YONSEC SECTAUTOLOGYCHECKER}. We first present an informal explanation
of the problem at hand. Then we present the formal development of the
problem and describe the mechanical proofs.
Recall the discussion in {YONSEC SECTAUTOLOGYCHECKER}, where we presented
the roles of the buyer, implementor, mathematician user, and
theorem prover. In particular, recall that the mathematician user
presents to the theorem prover a series of function definitions
and conjectures. The theorem prover is responsible
for verifying that each definition meets the requirements
of our definition principle and for constructing
a proof of each conjecture (possibly relying on previously
proved conjectures). While the mathematician user is of inestimable
value in proposing definitions and conjectures that structure
the problem, the burden of proof rests entirely on the theorem
prover.
In this {SECTIONORCHAPTER} we apply the theory and proof
techniques to establish the correctness of an algorithm for
converting expressions such as:
.ASIS
(PLUS (QUOTIENT X 2) (TIMES X (TIMES Y Z)))
.ENDASIS
into a sequence of instructions, such as might be executed by a
digital computer to compute the value of the expression in an
environment in which X, Y, and Z have numeric values.
The algorithm is a very simple
example of an important class of algorithms known as "compilers."
A compiler is just a translator from a "high-level" programming
language to a "machine" language.
In comparison to most compilers, our example is a toy.{FNOTE |It is useful to keep in mind
. other toys:##dime-store gyroscopes, kites, building blocks,
. crayons, frictionless planes, ideal gases.|}
In particular, we are dealing with only a part of the compiler
problem:##the compilation of expressions. We do not address the
compilation of conditionals, assignments, jumps, and other
control primitives.
We will here exploit the observation by McCarthy {REF MCCARTHYSYMB}
that any program can be translated into a general recursive function with the
same input/output behavior. Because programs can obtain information
other than that "passed" explicitly to them in the form of arguments
(e.g., they can refer to "global variables" or arbitrary memory
locations), and because they can pass on information in ways other
than by simply returning an answer (e.g., by modifying
global variables or memory locations), it is necessary to understand
"input/output" in a general sense.
In general, the recursive function in question must map from
the machine state at the beginning of the program's execution to the machine state
at the end.
We will ultimately exhibit a recursive function
that "is" the compiler and another one that "is" the machine upon which we
expect to "run" the compiled code, and we shall prove that the state of
this machine is correctly transformed by running the compiled code.
.SS |Informal Development|
In this section we illustrate the basic idea of an "expression
compiler" by describing how one might use a certain
pocket calculator to evaluate arithmetic expressions.
Suppose we have an expression such as:
.ASIS
(X:$m-1-2)+(X*(Y*Z))
.ENDASIS
composed entirely of variables, natural numbers, and numerically valued
function symbols of two arguments.
.BLANKFIGURE(FIG1, |The Model 0.0|, 50)
Further, suppose that we want to evaluate the expression for given values of
the variables, using a rudimentary hand-held calculator of the
following description:
.CROWN(8,0,0)
Your new Model 0.0 is illustrated in Figure 1.
Integers may be entered into the display
by pressing the digit buttons. The display may be set to 0 by
depressing the CLEAR button. The contents of the display may
be stored in any of the registers U, V, W, X, Y, and Z
by first pressing STORE and then pressing the register key.
The Model 0.0 has a stack. If any of the the operation
buttons (+, -, *, :$M-1-, EXP, REM, GCD, ACK) is pressed,
the top two occupants of the stack are removed from the stack,
the indicated operation is performed on them, and the result
is pushed on the stack. If a register button is pressed and
then the PUSHV button is pressed, the contents of the
register is pushed on the stack. If the PUSHI button is
pressed, the contents of the display is pushed.
The Model 0.0 is also programmable. If the ENTER button is pressed,
then until the END button is pressed, the intervening
digit, operation, register, and stack keystrokes
are executed as described above and furthermore
the keystrokes are remembered in a program memory.
Pressing the START button causes the most recently
remembered sequence of keystrokes to be
re-executed.
.ENDCROWN
How do we use the Model 0.0 to compute the value of our expression,
.ASIS
(X:$m-1-2)+(X*(Y*Z)),
.ENDASIS
assuming that we have already loaded the Model 0.0's registers
with the appropriate values of the variables?
We first compute
the value of X:$m-1-2 and push it on the stack. We then compute
X*(Y*X) and push that on the stack on top of
our previous result. Then we
press the + key, which causes the Model 0.0 to pop
two things off the stack, add them, and put the result back on the
stack. Thus, we use a sequence of Model 0.0 instructions
like this:
.ASIS
. \
. |
. | (compute and push the value of X:$m-1-2)
. |
. /
. \
. |
. | (compute and push the value of X*(Y*Z))
. |
. /
+ (press the + key)
.ENDASIS
But to compute the value of X:$m-1-2 we proceed as follows.
We first press the X and PUSHV buttons to push the value
of X on the stack. Next, we put 2 into the display and
press the PUSHI button to push 2 on the stack.
Finally, we press the :$m-1- button to remove the
top two numbers from the stack, compute their quotient,
and push the result.
By performing the analogous decomposition of X*(Y*Z), we
arrive at the following sequence of keystrokes for causing the Model 0.0
to compute the value of the given expression:
.ASIS
X
PUSHV
2
PUSHI
:$m-1-
X
PUSHV
Y
PUSHV
Z
PUSHV
*
*
+
.ENDASIS
The above sequence of instructions is a Model 0.0 "program" for
computing the value of the expression. The process of translating
the expression into such a sequence is called "compiling" the expression.
We are interested in defining an algorithm that will correctly compile
any such expression. That is, we want an algorithm that when applied
to an expression in our "high-level" language of expressions
produces a sequence of instructions whose execution
causes our calculator
to compute and push the value of the expression (as defined in
the usual mathematical sense with respect to the assignment
reflecting the state of the calculator's registers).
We do not care how much of the stack the calculator
uses during its computation. However, we do not want the computation
to disturb the entries present on the stack when the computation
begins (we might have several important subtotals saved there).
If the calculator is very slow or if we wish to evaluate the expression repeatedly under
different assignments to the variables, it might be useful to optimize the expression
before compiling it. Optimization is allowed by the specification
sketched, so long as the calculator ends up pushing the correct final value.
The compiler we will describe implements a very simple optimization scheme called
"constant folding." The basic idea is that if asked to compile a subexpression
with constant arguments, we compute and "compile in" the value of
that subexpression. Thus, given:
.ASIS
(2*3)+X,
.ENDASIS
we generate the following Model 0.0 code:
.ASIS
6
PUSHI
X
PUSHV
+
.ENDASIS
rather than force the Model 0.0 to do the arithmetic with:
.ASIS
2
PUSHI
3
PUSHI
*
X
PUSHV
+
.ENDASIS
.SS |Formal Specification of the Problem|
To specify an expression compiler
formally, we must define the "high-level" language
of expressions and we must define the
behavior of our calculator. The calculator
that we formalize is actually a generalization
of the Model 0.0. In our formalization, we
do not limit the calculator to have a finite
stack, finite precision, a finite number
of operations, or a finite number of registers.
.SSS |The High-Level Language|
We need to specify how we shall represent expressions
and how we define the value of an expression.
These are fairly straightforward problems and we will dispense
with them quickly since we discussed similar problems in the
TAUTOLOGY.CHECKER example, {YONSEC SECTAUTOLOGYCHECKER}.
.SSSS |Representing Expressions|
We are interested in tree structured
expressions composed of integers, variables, and
applications of numerically valued dyadic function symbols.
An example expression is (PLUS (QUOTIENT X 2) (TIMES X (TIMES Y Z))).
In the tautology checker example, we employed a special shell to represent
terms. For variety, we here employ the list representation
mentioned in {YONSEC SECTHEFORMALTHEORY}.
We define the recursive function FORMP (see {APP APPTHMS}) to return T if its
argument is a form suitable for compiling, and F otherwise.
We will consider all non-LISTP (i.e., "atomic") objects to be forms. Those that satisfy NUMBERP
will stand for numbers and the remaining atomic objects will represent variables.
We will consider a LISTP object a form if and only if it has the structure
(CONS fn (CONS x (CONS y tail))), where fn is atomic, and x and y are
(recursively) forms. We think of such a list as representing the
term (fn x y). We do not care what tail is because it will be
ignored by the value assignment function.
Thus, if x is a LISTP object and
also a form, then (CAR x) is the function symbol, (CADR x) is the form representing
the first argument, and (CADDR x) is the form representing the second.
By assuming that a form is tree structured, we are glossing
over the important problem of parsing, i.e. converting
a sequence of symbols into a tree structure.
In {REF GLOESS}, Gloess describes a proof by our theorem
prover of the correctness of a simple expression parser for
a language with infix operations.
.SSSS |The Value of Forms|
The value of a form is defined by the function EVAL (of two arguments, the
form and an "environment," envrn, specifying the values of the variables).
The value of a number is itself. The value of a variable, x, is
defined to be (GETVALUE x envrn).
The value of a form representing (fn u v) is defined to be
(APPLY fn u' v'), where u' and v' are the recursively
obtained values of u and v in envrn.
The formal definition of EVAL is exhibited
in {APP APPTHMS}.
The two functions GETVALUE and APPLY are undefined.
GETVALUE is undefined because we do not care what the structure
of an "environment" is, so long as every variable has some value "in" it.
If the reader would care to think of GETVALUE as the function ASSIGNMENT
in {YONSEC SECTAUTOLOGYCHECKER} and "environments" as association lists,
that is acceptable.{FNOTE |In the tautology example,
. we specified the structure of assignments because we
. wanted to be able to write functions for constructing
. assignments with specific properties.|}
As for APPLY, it supposedly takes an arbitrary function symbol
and two arguments and returns the result of applying the function "denoted"
by that symbol to those arguments. But we do not really care what
the function "denoted" by any particular symbol is (so long as it is
numerically valued).
To ensure that the function symbols denote
numeric functions, we add the axiom:
.ASIS
Axiom. NUMBERP.APPLY:
(NUMBERP (APPLY FN X Y)),
.ENDASIS
which is consistent since APPLY is undefined (and until now unmentioned
in the theory).
If we wanted to ensure that the function symbol "PLUS" appearing in
a FORMP was to stand for the recursive function we call PLUS, we could
add the axiom:
.ASIS
(EQUAL (APPLY "PLUS" X Y) (PLUS X Y)),
.ENDASIS
or define APPLY to recognize some fixed set of function symbols
(including "PLUS") and call the numeric function we had
in mind.
However, for the present purposes we do not need to specify the
functions denoted by our symbols.
.SSS |The Low-Level Language|
We now specify our calculator. The calculator is an
idealized version of the Model 0.0.
The development of the specification
is broken up into two parts, the representation of data within the
calculator
and the specification of the machine's "fetch and execute" cycle (i.e.,
how it interprets sequences of instructions).
.SSSS |Representing Data|
.SSSSS |The Named Registers|
We represent the state of the registers as an "environment."
The meaning of the "contents of the
register named x in the environment envrn" is (GETVALUE x envrn).
.SSSSS |Push-Down Stacks|
To represent the state of the push-down stack, we use the objects
in a new shell class:
.ASIS
Shell Definition.
Add the shell PUSH of two arguments
with recognizer STACKP,
accessors TOP and POP,
default values 0 and 0, and
well-founded relation TOP.POPP.
.ENDASIS
The stack resulting from pushing x onto pds will be
(PUSH x pds). The top-most element of pds is (TOP pds),
which is 0 if pds is not the result of a PUSH. The stack resulting
from "popping" the top-most element from pds is (POP pds). If
called on a nonstack, POP returns 0. We could have introduced an
"empty stack" and required that the second argument to PUSH always be
a stack; however we did not (simply because there is no need for any
additional constraints on our stacks).{FNOTE |We could have used lists
. to represent stacks. CONS would be PUSH, LISTP would be STACKP,
. and CAR and CDR would be TOP and POP. We used the shell mechanism
. for variety.|}
.SSSSS |The Instruction Set|
Since the PUSHV button on the Model 0.0 is always used in
combination with a register button, we treat the two
keystrokes as one instruction. We use (CONS "PUSHV" (CONS
reg "NIL")) as the instruction to push the value of register
reg.
Similarly, we use (CONS "PUSHI" (CONS n "NIL")) as the
instruction to push n.
We use atomic (i.e., NLISTP) objects (e.g., "PLUS" and "TIMES") as the
instructions corresponding to the Model 0.0's operation
buttons. An atom, fn, instructs the calculator to pop x and
y off the stack and push (APPLY fn x y).
.SSSSS |Programs|
A program is a list
of instructions.
.SSSS |The Fetch-and-Execute Cycle|
We will describe the behavior of our calculator with a recursive
function that maps from an initial state of the machine to a
final state. Formally, the state of the calculator at any moment
is a triple consisting of
the location in the program from which the next instruction
will be fetched (usually called the "program counter" or "pc"),
the current state of the push-down stack, and
the current settings of all the named registers.
The recursive function EXEC, describing the calculator, thus takes
three arguments:
.ASIS
PC the current list of instructions, the first of which
is the "next" to be executed,
PDS the state of the push-down stack,
ENVRN the state of the named registers.
.ENDASIS
The function returns the state of the push-down stack at the conclusion of the
sequence of instructions. In the final state, the PC will always
be the end of the initial list of instructions, and the environment will
be the original one since no programmable instruction affects the
registers.{FNOTE |The registers of our calculator may be set arbitrarily
. by the user, but they must be set before a program is activated.|}
Thus, returning only the final push-down stack is sufficient.
We want EXEC to iterate down the list of instructions,
interpreting each instruction on the way. Each instruction causes
some modification to PDS.
When the instruction is a (PUSHI x), EXEC should reset PDS to (PUSH x PDS).
When it is a (PUSHV x) instruction,
EXEC should reset PDS to (PUSH (GETVALUE x ENVRN) PDS).
When the instruction is atomic (i.e., an operation button), fn, EXEC
should (a) pop the stack once obtaining some value x (i.e., (TOP PDS)), (b) pop the stack again, obtaining some value y (i.e.,
(TOP (POP PDS))), (c) apply the indicated function, obtaining some value v
(i.e., (APPLY fn y x) -- note that the first argument to the function is
the one that was deepest on the stack),
and (d) push v on the stack (i.e., set PDS to (PUSH v (POP (POP PDS)))).
The way EXEC "iterates" down the PC is to recurse,
each time replacing PC by (CDR PC), PDS by the stack
produced by
interpreting (CAR PC) as above and
leaving ENVRN unchanged. When PC is no longer a list, EXEC
returns PDS.
The formal definition of EXEC is thus:
.ASIS
Definition.
(EXEC PC PDS ENVRN)
=
(IF (NLISTP PC)
PDS
(IF (LISTP (CAR PC))
(IF (EQUAL (CAR (CAR PC)) "PUSHI")
(EXEC (CDR PC)
(PUSH (CAR (CDR (CAR PC))) PDS)
ENVRN)
(EXEC (CDR PC)
(PUSH (GETVALUE (CAR (CDR (CAR PC)))
ENVRN)
PDS)
ENVRN))
(EXEC (CDR PC)
(PUSH (APPLY (CAR PC)
(TOP (POP PDS))
(TOP PDS))
(POP (POP PDS)))
ENVRN))).
.ENDASIS
Let us step back from the problem of evaluating
expressions to consider the problem of
designing a calculator to meet these specifications.
The designer is free to
represent data in the machine any way he sees fit.
For example, if the hardware factory is having trouble producing blue 1-tuples,
the designer
may choose to implement our NUMBERPs as sequences of binary digits.
The designer would then wire the "PLUS" key to a binary addition algorithm
rather than Peano's recursive function. If he desired to __prove_
that his design met these specifications,
he would have to establish the correctness of his
algorithms with respect to his representation.
For example, he would have to prove that when given
the binary representation of two Peano numbers his addition algorithm
yields the binary representation of their Peano sum.
The reader is referred to the theorem
CORRECTNESS.OF.BIG.PLUS in {APP APPTHMS}, which states the above
result formally for an algorithm that adds numbers represented as sequences
of digits in an arbitrary base (binary addition being a special case
of the more general digit-by-digit algorithm with carry).
Readers interested in a method for designing machines and
implementing
them on other machines are referred to Robinson and Levitt's
{REF LARRY}.
.SSS |The Formal Statement of Correctness|
Suppose that COMPILE is a function of one argument, namely a form
to be compiled.
Then, to be correct, COMPILE must have the following property.
If X is a FORMP, then the push-down stack resulting from executing the
output of (COMPILE X) on our calculator, with some initial push-down
stack PDS and some environment ENVRN, is the push-down stack
obtained by pushing (EVAL X ENVRN) on PDS. That is, when the compilation and execution have concluded,
the calculator and COMPILE are completely out of the picture:
the mathematical value of the expression has been PUSHed on the original
stack.
Stated formally this is:
.ASIS
Theorem. CORRECTNESS.OF.OPTIMIZING.COMPILER:
(IMPLIES (FORMP X)
(EQUAL (EXEC (COMPILE X) PDS ENVRN)
(PUSH (EVAL X ENVRN) PDS))).
.ENDASIS
Let us return for a moment to the fact that APPLY and GETVALUE are
undefined (but used by EVAL and EXEC). The job of the compiler
is to cause EXEC to compute the same thing EVAL
does, regardless of the semantics of GETVALUE and the numeric APPLY.
.SS |Formal Definition of the Compiler|
Now that we know exactly what the semantics of forms are, and we know
exactly how the calculator behaves on a sequence of instructions, we
consider the problem of compiling forms for the calculator.
As noted in our informal development of the problem, we wish to
do "constant folding" optimization of the expression. Thus, we
break our compiler into two "passes." The first pass, performed
by the function OPTIMIZE, takes the expression to be compiled and returns a
possibly simpler
form with the same value under all assignments. OPTIMIZE replaces constant
subexpressions with their values.
The second pass of the compiler, CODEGEN,
generates the compiled code for the optimized form. We
compose the two to obtain our compiler.
.SSS |The Optimization Pass|
The function OPTIMIZE, of one argument, optimizes a form
by replacing any subexpression, (fn u v), where u and
v are specific numeric constants, by the result of
applying fn to u and v. The precise (but informal) definition of
(OPTIMIZE X) is as follows:
.ASIS
If X does not represent a function call, return X.
Otherwise, suppose X represents (fn u v).
Let u' be (OPTIMIZE u) and let v' be (OPTIMIZE v).
If (NUMBERP u') and (NUMBERP v'),
then return (APPLY fn u' v').
Otherwise,
return (CONS fn (CONS u' (CONS v' "NIL")))
(i.e., return a representation of the
term (fn u' v')).
.ENDASIS
The formal definition of OPTIMIZE is in {APP APPTHMS}.
.SSS |The Code Generation Pass|
Given the ability to optimize an expression as above, we
now turn our attention to generating correct code for
forms in general (i.e., we ignore the fact that we
know the code generator will be called on optimized forms).
Our objective is to generate code for a form, x, that will cause
the calculator to push the value of x on the stack.
Let us suppose we are compiling x by hand, writing down
the instructions we generate on a note pad.
Clearly, if x is a variable, we write down (PUSHV x).
If x is a number, we write down (PUSHI x). Finally,
if x represents (fn u v), we recursively write down the
instructions for pushing the value of u on the stack, then write down
the instructions for pushing the value of v, and finally write down
the single atomic instruction fn.
When the calculator executes the code for u, it may push and
pop many times,
but it never pops the initial stack.
When the code for u has been executed, the net effect will be to push
the value of u on the initial stack. Then the calculator will
begin to execute the code for v with the value of u safely pushed.
The v computation
may push and pop many times but eventually it will push the
value of v immediately on top of the value for u.
Thus, by the time the calculator sees the atomic instruction, fn,
the two argument values will be the top-most entries on the stack.
To formalize the code generation pass, we must decide how to represent our
"note pad" above. We use a global
collection site, maintained as a list of instructions, and initialized to "NIL".
To "write down" an instruction on the "note pad," we CONS it onto the front of the site.
The final value of the site
will thus be in the reverse of the order in which the instructions
should be executed (e.g., the top-most function symbol in
the expression will be the first element of the final list, but should
be the last instruction executed). Thus, the list should be reversed
before being used as a program.
Since this algorithm side-effects a global variable (the collection site),
its functional representation is as a function of two arguments: the form being
compiled, FORM, and the global collection site, INS. The function returns
the value of the collection site.{FNOTE |Note the similarity to the function MC.FLATTEN of
. {YONSEC SECOVERVIEW}.|} The formal definition is:
.ASIS
Definition.
(CODEGEN FORM INS)
=
(IF (NUMBERP FORM)
(CONS (CONS "PUSHI" FORM "NIL")
INS)
(IF (LISTP (CDDR FORM))
(CONS (CAR FORM)
(CODEGEN (CADDR FORM)
(CODEGEN (CADR FORM) INS)))
(CONS (CONS "PUSHV" FORM "NIL")
INS))).
.ENDASIS
If FORM is a FORMP, then
the test (LISTP (CDDR FORM)) is a cheap way to ask whether FORM has
the structure (CONS fn (CONS u (CONS v tail))), where fn is atomic and u and v
are forms. Note that we compile the first argument of function calls
first (in the innermost recursive call) using the input value of the
collection site. Then we compile the second argument, using the collection
site resulting from the first recursive call. Finally, we CONS the function
symbol onto the front and return the resulting collection site.
.SSS |COMPILE|
The compiler is the composition of OPTIMIZE
and CODEGEN. We must remember to initialize the collection site to "NIL"
before starting the code generation pass, and we must remember to reverse
the final list of instructions.
The formal definition of the compiler is:
.ASIS
Definition.
(COMPILE FORM)
=
(REVERSE (CODEGEN (OPTIMIZE FORM) "NIL")).
.ENDASIS
.SS |The Mechanical Proof of Correctness|
In this {SUBSECTIONORSECTION}, we describe the proof of the correctness of
the optimizing compiler. The presentation is divided into three parts.
We first decompose the main theorem into three lemmas to be proved.
Then we prove the main theorem from those
lemmas. Finally we present the proofs of the lemmas.
.SSS |Decomposition of the Main Goal|
The proof of the correctness of our optimizing compiler can be
naturally decomposed into two parts:##show that the optimizer is correct
and show that the code generator is correct.
The correctness of the optimizer requires two clauses to state:##if given
a form, OPTIMIZE returns a form, and if given a form, OPTIMIZE returns something
with the same value.
These two lemmas are stated formally as:
.ASIS
Theorem. FORMP.OPTIMIZE:
(IMPLIES (FORMP X)
(FORMP (OPTIMIZE X)))
Theorem. CORRECTNESS.OF.OPTIMIZE:
(IMPLIES (FORMP X)
(EQUAL (EVAL (OPTIMIZE X) ENVRN)
(EVAL X ENVRN))).
.ENDASIS
To state the correctness of CODEGEN, we must explain the use of the global "collection site"
and recall that the output of CODEGEN will be reversed.
Exactly what is the state into which our calculator should be driven
if given the program produced by (REVERSE (CODEGEN X INS)) with some initial PDS and
ENVRN? Since CODEGEN is supposed to concatenate the reverse of the code
for X onto INS, and since that concatenation is reversed before running it,
the code in (REVERSE INS) will be executed before the code
for X is encountered. When the code for
X is encountered, the push-down stack will be that produced by executing
the instructions in (REVERSE INS) on PDS and ENVRN. The code for X is supposed to push the value
of X on that push-down stack. Thus, the statement of the correctness of
CODEGEN is:
.ASIS
Theorem. CORRECTNESS.OF.CODEGEN:
(IMPLIES (FORMP X)
(EQUAL (EXEC (REVERSE (CODEGEN X INS))
PDS ENVRN)
(PUSH (EVAL X ENVRN)
(EXEC (REVERSE INS)
PDS ENVRN)))).
.ENDASIS
.SSS |Proof of the Main Goal|
For the moment, let us suppose we have proved these three lemmas.
Now let us consider the theorem prover's proof of the main result:
.ASIS
Theorem. CORRECTNESS.OF.OPTIMIZING.COMPILER:
(IMPLIES (FORMP X)
(EQUAL (EXEC (COMPILE X) PDS ENVRN)
(PUSH (EVAL X ENVRN) PDS))).
.ENDASIS
The proof from our three lemmas is immediate (i.e., involves only
simplification):
Consider the left-hand side of the conclusion of the main goal:
.ASIS
(EXEC (COMPILE X) PDS ENVRN).
.ENDASIS
Since COMPILE is nonrecursive, we expand it to get:
.ASIS
(EXEC (REVERSE (CODEGEN (OPTIMIZE X) "NIL")) PDS ENVRN).
.ENDASIS
We then rewrite this using CORRECTNESS.OF.CODEGEN after establishing
the hypothesis (FORMP (OPTIMIZE X)) by backwards chaining through
FORMP.OPTIMIZE and appealing to the (FORMP X) hypothesis in our main goal.
The result is:
.ASIS
(PUSH (EVAL (OPTIMIZE X) ENVRN)
(EXEC (REVERSE "NIL") PDS ENVRN)).
.ENDASIS
However, this can be further simplified. We may rewrite
the term (EVAL (OPTIMIZE X) ENVRN)
to (EVAL X ENVRN) by CORRECTNESS.OF.OPTIMIZE, appealing
again to the assumption (FORMP X) to relieve the hypothesis
of the rewrite rule. In addition, (REVERSE "NIL") computes to "NIL",
and the resulting (EXEC "NIL" PDS ENVRN) then computes to PDS.
The result of simplifying the left-hand side of the conclusion of
our main goal is thus:
.ASIS
(PUSH (EVAL X ENVRN) PDS),
.ENDASIS
which is the right-hand side of the conclusion. Thus, the
main goal has been proved.
.SSS |Proofs of the Lemmas|
Let us now discuss the proofs of the three lemmas used.
The first two lemmas, FORMP.OPTIMIZE and CORRECTNESS.OF.OPTIMIZE, are proved by straightforward induction on the
structure of forms, as unanimously suggested by all applicable
induction templates. The various cases produced by the inductions
are proved by simplification (using list axioms and function definitions),
elimination of CARs and CDRs, and equality substitution.
The proof of CORRECTNESS.OF.CODEGEN is more interesting.
In developing the statement of the correctness of CODEGEN, we used an important fact
about our calculator:##if called upon to execute the concatenation of
two programs, X and Y, the state of the push-down stack when Y is encountered
is that produced by executing X. This fact is important
to the proof of the correctness of CODEGEN. Stated formally, the lemma is:
.ASIS
Theorem. SEQUENTIAL.EXECUTION:
(EQUAL (EXEC (APPEND X Y) PDS ENVRN)
(EXEC Y
(EXEC X PDS ENVRN)
ENVRN)).
.ENDASIS
SEQUENTIAL.EXECUTION can be proved by induction on X, as suggested by
the result of merging the inductions from (APPEND X Y) and (EXEC X PDS ENVRN). Note that there is a suggested
induction on Y; however, it is flawed by the (APPEND X Y) term.
The proof of SEQUENTIAL.EXECUTION appeals only to axioms and
definitions.
Once SEQUENTIAL.EXECUTION is proved, the CORRECTNESS.OF.CODEGEN can be proved
by induction on the structure of the form X. Note that an induction
on INS is suggested by the (REVERSE INS) term, but that induction is
flawed.
Below is the theorem prover's proof of the correctness of CODEGEN.
We have included only the induction analysis, the proof of the first
base case, and the proof of the induction step. We have extensively
annotated the theorem prover's own output with remarks in brackets ([* ... *]).
.ASIS
Theorem. CORRECTNESS.OF.CODEGEN:
(IMPLIES
(FORMP X)
(EQUAL (EXEC (REVERSE (CODEGEN X INS))
PDS ENVRN)
(PUSH (EVAL X ENVRN)
(EXEC (REVERSE INS) PDS ENVRN))))
.ENDASIS
.ASIS8
Name the conjecture *1.
We will appeal to induction. There are four plausible
inductions. They merge into two likely candidate
inductions. However, only one is unflawed. We will induct
according to the following scheme:
(AND (IMPLIES (NOT (LISTP X))
(p X INS PDS ENVRN))
(IMPLIES (NOT (LISTP (CDR X)))
(p X INS PDS ENVRN))
(IMPLIES (NOT (LISTP (CDR (CDR X))))
(p X INS PDS ENVRN))
(IMPLIES (AND (LISTP X)
(LISTP (CDR X))
(LISTP (CDR (CDR X)))
(p (CAR (CDR (CDR X)))
(CODEGEN (CAR (CDR X)) INS)
PDS ENVRN)
(p (CAR (CDR X)) INS PDS ENVRN))
(p X INS PDS ENVRN))).
The inequalities CAR.LESSP and CDR.LESSP establish that the
measure (COUNT X) decreases according to the well-founded
relation LESSP in the induction step of the scheme. Note,
however, the inductive instances chosen for INS. The
above induction scheme produces the following seven new
goals:
Case 1. (IMPLIES
(AND (NOT (LISTP X)) (FORMP X))
(EQUAL (EXEC (REVERSE (CODEGEN X INS))
PDS ENVRN)
(PUSH (EVAL X ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))),
which simplifies, applying CDR.NLISTP, CAR.CONS, CDR.CONS
and SEQUENTIAL.EXECUTION, and opening up the definitions
of FORMP, CODEGEN, EVAL, REVERSE and EXEC, to:
(TRUE).
.ENDASIS
[* Case 1 is the most interesting base case. We now sketch the
series of simplifications that reduce it to (TRUE).
Consider the left-hand side of the conclusion:
.ASIS
(EXEC (REVERSE (CODEGEN X INS)) PDS ENVRN).
.ENDASIS
Since X is not a list, it represents
a variable or a number. The CODEGEN term in the left-hand side of the conclusion
thus opens up to:
.ASIS
(IF (NUMBERP X)
(CONS (CONS "PUSHI" (CONS X "NIL"))
INS)
(CONS (CONS "PUSHV" (CONS X "NIL"))
INS)).
.ENDASIS
The introduction of the above IF-expression splits the theorem into two cases. In one case, the REVERSE
expression in the left-hand side of the conclusion
has (CONS push INS) as its argument, where push is a
(PUSHI X) instruction and X is known to be numeric. In the other case,
the REVERSE expression has (CONS push INS) as its argument, where push
is a (PUSHV X) instruction and X is known to be not a number.
In both cases, the REVERSE expression (which occupies the first argument of the EXEC-expression
in the left-hand side of the conclusion) opens up
to:
.ASIS
(APPEND (REVERSE INS) (CONS push "NIL")),
.ENDASIS
allowing the
SEQUENTIAL.EXECUTION lemma to rewrite the resulting EXEC-expression to:
.ASIS
(EXEC (CONS push "NIL")
(EXEC (REVERSE INS) PDS ENVRN)
ENVRN).
.ENDASIS
The outermost EXEC-expression above then opens up, and indeed computes, to
either:
.ASIS
(PUSH X (EXEC (REVERSE INS) PDS ENVRN)),
.ENDASIS
or to
.ASIS
(PUSH (GETVALUE X ENVRN) (EXEC (REVERSE INS) PDS ENVRN))
.ENDASIS
depending on whether we are in the numeric or nonnumeric case.
That completes the simplification of the left-hand side of the conclusion.
Now consider the right-hand side of the conclusion. The term
(EVAL X ENVRN) opens up to:
.ASIS
(IF (NUMBERP X)
X
(GETVALUE X ENVRN)).
.ENDASIS
Thus, the right-hand side of the conclusion becomes:
.ASIS
(PUSH (IF (NUMBERP X)
X
(GETVALUE X ENVRN))
(EXEC (REVERSE INS) PDS ENVRN)).
.ENDASIS
When the IF is distributed out, two cases are produced, depending
on whether X is numeric:
.ASIS
(PUSH X (EXEC (REVERSE INS) PDS ENVRN))
.ENDASIS
and
.ASIS
(PUSH (GETVALUE X ENVRN) (EXEC (REVERSE INS) PDS ENVRN)).
.ENDASIS
That completes the simplification of the right-hand side of
the conclusion.
Now consider the concluding equality itself. In the case where X is
a number, the left and right sides simplified to the same term, namely
(PUSH X (EXEC (REVERSE INS) PDS ENVRN)). In the other case,
when X is not a number, both sides simplified to the same term,
namely (PUSH (GETVALUE X ENVRN) (EXEC (REVERSE INS) PDS ENVRN)). So Case 1
above has been proved.
The proofs of Cases 2 through 6 are similar and are thus not
exhibited here. We resume the system's proof on Case 7, the induction step. *]
.ASIS8
.
.
.
Case 7. (IMPLIES
(AND
(LISTP X)
(LISTP (CDR X))
(LISTP (CDR (CDR X)))
(EQUAL
(EXEC
(REVERSE (CODEGEN (CAR (CDR (CDR X)))
(CODEGEN (CAR (CDR X)) INS)))
PDS ENVRN)
(PUSH (EVAL (CAR (CDR (CDR X))) ENVRN)
(EXEC (REVERSE (CODEGEN (CAR (CDR X)) INS))
PDS ENVRN)))
(EQUAL (EXEC (REVERSE (CODEGEN (CAR (CDR X)) INS))
PDS ENVRN)
(PUSH (EVAL (CAR (CDR X)) ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(FORMP X))
(EQUAL (EXEC (REVERSE (CODEGEN X INS))
PDS ENVRN)
(PUSH (EVAL X ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))),
which we simplify, applying CAR.CONS, CDR.CONS,
SEQUENTIAL.EXECUTION and PUSH.EQUAL, and expanding the
definitions of FORMP, CODEGEN, REVERSE, EXEC and EVAL, to
two new formulas:
.ENDASIS
[* The conditions governing Case 7 imply that X represents a function call.
Let us suppose it represents the function call (v d z), where v
is an atomic symbol and d and z are forms (we have used the
letters that the system will introduce in a moment when it
eliminates the CARs and CDRs).
We have two induction hypotheses.
The first is about the code produced for z after d has been
compiled. The second is about the code produced for d.
In particular, the first hypothesis tells us that the execution of
the code for z pushes the value of z on the stack that
is produced by the execution of the code for d. The second hypothesis
tells us that the execution of the code for d pushes the
value of d on the stack produced by the execution of whatever
instructions were on INS to start with.
Now let us look at the left-hand side of the
conclusion:
.ASIS
(EXEC (REVERSE (CODEGEN X INS))
PDS ENVRN).
.ENDASIS
The CODEGEN term opens up to:
.ASIS
(CONS v (CODEGEN z (CODEGEN d INS))).
.ENDASIS
Thus the REVERSE term opens up to:
.ASIS
(APPEND (REVERSE (CODEGEN z (CODEGEN d INS)))
(CONS v "NIL")).
.ENDASIS
This allows the SEQUENTIAL.EXECUTION lemma to rewrite the resulting EXEC
term to:
.ASIS
(EXEC (CONS v "NIL") pds ENVRN),
.ENDASIS
where we have used pds to denote the term
.ASIS
(EXEC (REVERSE (CODEGEN z (CODEGEN d INS))) PDS ENVRN).
.ENDASIS
(EXEC (CONS v "NIL") pds ENVRN) computes to:
.ASIS
(PUSH (APPLY v (TOP (POP pds)) (TOP pds))
(POP (POP pds))).
.ENDASIS
There is nothing more we can do to the left-hand side of the conclusion.
However, on the right-hand side of the conclusion, the
(EVAL X ENVRN) term opens up to (APPLY v (EVAL d ENVRN) (EVAL z ENVRN)), reducing the right-hand side
to:
.ASIS
(PUSH (APPLY v (EVAL d ENVRN) (EVAL z ENVRN))
(EXEC (REVERSE INS) PDS ENVRN)).
.ENDASIS
Since now the left- and right-hand sides of the conclusion are
PUSH-expressions,
we can apply one of the axioms added by the shell principle
when PUSH was defined:
.ASIS
Axiom. PUSH.EQUAL:
(EQUAL (EQUAL (PUSH X1 X2) (PUSH Y1 Y2))
(AND (EQUAL X1 Y1)
(EQUAL X2 Y2))),
.ENDASIS
to split the conjecture into two parts. In the first (called Case 1 below),
we must prove that the two APPLY expressions produced by the left- and
right-hand sides are equal, and in the second (called Case 2), we must prove that
the stacks upon which they are pushed are equal.
The proofs are similar, both involving appeals to the induction hypotheses.
We follow the proof of the equivalence of the APPLY expressions. *]
.ASIS8
Case 1. (IMPLIES
(AND
(LISTP X)
(LISTP (CDR X))
(LISTP (CDR (CDR X)))
(EQUAL
(EXEC
(REVERSE
(CODEGEN (CAR (CDR (CDR X)))
(CODEGEN (CAR (CDR X)) INS)))
PDS ENVRN)
(PUSH
(EVAL (CAR (CDR (CDR X))) ENVRN)
(EXEC (REVERSE (CODEGEN (CAR (CDR X)) INS))
PDS ENVRN)))
(EQUAL
(EXEC (REVERSE (CODEGEN (CAR (CDR X)) INS))
PDS ENVRN)
(PUSH (EVAL (CAR (CDR X)) ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(NOT (LISTP (CAR X)))
(FORMP (CAR (CDR X)))
(FORMP (CAR (CDR (CDR X)))))
(EQUAL
(APPLY
(CAR X)
(TOP
(POP
(EXEC
(REVERSE
(CODEGEN (CAR (CDR (CDR X)))
(CODEGEN (CAR (CDR X)) INS)))
PDS ENVRN)))
(TOP
(EXEC
(REVERSE
(CODEGEN (CAR (CDR (CDR X)))
(CODEGEN (CAR (CDR X)) INS)))
PDS ENVRN)))
(APPLY (CAR X)
(EVAL (CAR (CDR X)) ENVRN)
(EVAL (CAR (CDR (CDR X))) ENVRN)))).
Applying the lemma CAR/CDR.ELIM, we now replace X by
(CONS V Z) to eliminate (CDR X) and (CAR X), Z by
(CONS D W) to eliminate (CDR Z) and (CAR Z) and W by
(CONS Z C) to eliminate (CAR W) and (CDR W). This
produces the new conjecture:
(IMPLIES
(AND
(LISTP (CONS V (CONS D (CONS Z C))))
(LISTP (CONS D (CONS Z C)))
(LISTP (CONS Z C))
(EQUAL
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)
(PUSH (EVAL Z ENVRN)
(EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN)))
(EQUAL (EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN)
(PUSH (EVAL D ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(NOT (LISTP V))
(FORMP D)
(FORMP Z))
(EQUAL
(APPLY V
(TOP
(POP
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)))
(TOP
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)))
(APPLY V
(EVAL D ENVRN)
(EVAL Z ENVRN)))),
which further simplifies, clearly, to:
(IMPLIES
(AND
(EQUAL
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)
(PUSH (EVAL Z ENVRN)
(EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN)))
(EQUAL (EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN)
(PUSH (EVAL D ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(NOT (LISTP V))
(FORMP D)
(FORMP Z))
(EQUAL
(APPLY V
(TOP
(POP
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)))
(TOP
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)))
(APPLY V
(EVAL D ENVRN)
(EVAL Z ENVRN)))).
.ENDASIS
[* Note that the first equality hypothesis tells us that the stack we called pds above
(i.e., the result of executing INS followed by the code for D
followed by the code for Z) is (PUSH (EVAL Z ENVRN) pds'), where
pds' is the stack resulting from executing INS followed by the
code for D. The hypothesis can be used by cross-fertilization because
pds occurs in the conclusion. *]
.ASIS8
We use the first equality hypothesis by
cross-fertilizing:
(PUSH (EVAL Z ENVRN)
(EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN))
for:
(EXEC (REVERSE (CODEGEN Z (CODEGEN D INS)))
PDS ENVRN)
and throwing away the equality. This generates:
(IMPLIES
(AND
(EQUAL (EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN)
(PUSH (EVAL D ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(NOT (LISTP V))
(FORMP D)
(FORMP Z))
(EQUAL
(APPLY V
(TOP (POP (PUSH (EVAL Z ENVRN)
(EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN))))
(TOP (PUSH (EVAL Z ENVRN)
(EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN))))
(APPLY V
(EVAL D ENVRN)
(EVAL Z ENVRN)))).
.ENDASIS
[* Having substituted an explicit PUSH-expression for pds we can now
use the axioms about (TOP (PUSH x y)) and (POP (PUSH x y)) to clean up the
conjecture. *]
.ASIS8
This further simplifies, applying POP.PUSH and TOP.PUSH,
to:
(IMPLIES
(AND
(EQUAL (EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN)
(PUSH (EVAL D ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(NOT (LISTP V))
(FORMP D)
(FORMP Z))
(EQUAL
(APPLY V
(TOP (EXEC (REVERSE (CODEGEN D INS))
PDS ENVRN))
(EVAL Z ENVRN))
(APPLY V
(EVAL D ENVRN)
(EVAL Z ENVRN)))).
.ENDASIS
[* We now use the second induction hypothesis. It tells us that pds'
(i.e., the result of executing INS followed by the code for D) is
(PUSH (EVAL D ENVRN) pds''), where pds'' is the result of executing INS.
We use it by cross-fertilizing the PUSH-expression
for pds'. *]
.ASIS8
We use the above equality hypothesis by
cross-fertilizing:
(PUSH (EVAL D ENVRN)
(EXEC (REVERSE INS) PDS ENVRN))
for (EXEC (REVERSE (CODEGEN D INS)) PDS ENVRN) and
throwing away the equality. We would thus like to
prove:
(IMPLIES
(AND (NOT (LISTP V))
(FORMP D)
(FORMP Z))
(EQUAL
(APPLY V
(TOP (PUSH (EVAL D ENVRN)
(EXEC (REVERSE INS) PDS ENVRN)))
(EVAL Z ENVRN))
(APPLY V
(EVAL D ENVRN)
(EVAL Z ENVRN)))),
.ENDASIS
[* Having substituted an explicit PUSH-expression for pds',
we can use the TOP.PUSH axiom to reduce (TOP pds') to (EVAL D ENVRN).
Note that after performing the rewrite, both sides of the concluding
equality are identical. *]
.ASIS8
which finally simplifies, using the lemma TOP.PUSH, to:
(TRUE).
Case 2.
.
.
.
.ENDASIS
[* Recall that the above is one of two cases split off the induction
step. The second case is the analogous theorem about the stacks upon which
the two APPLY-expressions are pushed. Its proof is exactly analogous
to the one above and is thus not exhibited here. *]
.ASIS8
.
.
.
That finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##40.03 seconds
.ENDASIS
As described, the above proof may seem complicated. But it should
be noted that it was carried out entirely automatically.
Having proved all the lemmas in the decomposition of the
main goal, and having proved the main goal from our lemmas,
we have completed the proof
of the correctness
of our optimizing expression compiler.
.SS |Notes|, SSCOMPILERNOTES:
In this {SUBSECTIONORSECTION}, we describe
three bugs our theorem prover uncovered in earlier versions
of our optimizing expression compiler,
and we present a brief history of the expression-compiler problem.
.SSS |Bugs Uncovered by the Theorem Prover|
In our original efforts to formalize this problem, we made three
mistakes that did not come to light until the theorem prover
failed to prove the relevant lemmas and essentially exhibited counterexamples.
The reader might wonder where in the proofs the axiom:
.ASIS
(NUMBERP (APPLY FN X Y))
.ENDASIS
was used. The answer is that it is crucial in
the proof of the correctness of OPTIMIZE.
Recall that if the optimizer encounters a form representing (fn x y),
where x and y are specific constants, then it replaces it by (APPLY fn x y).
Consider what would happen if (APPLY "FN" 3 4) were "Z". Then the representation
of the
expression (FN 3 4) would be "optimized" to the representation of the expression Z. But these
two expressions do not have the same value in all environments.
In particular, the first expression has the value "Z", and the second
expression has whatever value the variable Z is assigned in the environment.
This problem does not arise if APPLY is known to be numeric
since the value of a number is itself.
We did not realize we had confined ourselves to numerically valued functions
until the system, in trying to prove CORRECTNESS.OF.OPTIMIZE, without the
numeric APPLY axiom, produced
the goal:
.ASIS
(IMPLIES (NOT (LISTP Z))
(EQUAL Z (GETVALUE Z ENVRN))).
.ENDASIS
The second bug concerned the instruction set of the calculator and the
legal function symbols in expressions. When we first formalized the
problem, we did not require that the function symbols of expressions
be atomic. We thought it did not matter what they were. However,
consider the behavior of CODEGEN when the form
being compiled represents ((PUSHI 7) X Y). The
compiled code is:
.ASIS
(PUSHV X)
(PUSHV Y)
(PUSHI 7)
.ENDASIS
This code pushes three things on the stack and halts.
But the value of the representation of the expression
((PUSHI 7) X Y), defined by EVAL, is
the result of applying the representation of (PUSHI 7) (whatever that is) to the values of the two arguments.
Thus, in FORMP, we had to specify that function symbols
were atomic; that fact was actually used several times in the
foregoing proof of the
correctness of CODEGEN, although we brushed over it in our
description of the proof.
The third bug was in our definition of the calculator. Recall that when
it encounters an atomic function symbol it pops x off the stack, then
it pops y off the stack, and then it pushes (APPLY fn y x). In our
original definition of the machine, we forgot that the first argument
to fn would naturally have been pushed first (and thus be the second
thing popped off). Thus, we specified that the machine push (APPLY fn x y).
Our error showed up when we tried to prove the correctness of CODEGEN.
If we reconstruct the proof of CODEGEN (described above) with the
faulty version of EXEC (or CODEGEN, depending on your point of view),
the goal that finally reduced to (TRUE) above would be:
.ASIS
(IMPLIES (AND (NOT (LISTP V))
(FORMP D)
(FORMP Z))
(EQUAL (APPLY V (EVAL Z ENVRN) (EVAL D ENVRN))
(APPLY V (EVAL D ENVRN) (EVAL Z ENVRN)))).
.ENDASIS
We could then generalize the two EVAL expressions and then eliminate
the two FORMP hypotheses as irrelevant. The resulting goal would
be:
.ASIS
(IMPLIES (NOT (LISTP V))
(EQUAL (APPLY V X Y) (APPLY V Y X))).
.ENDASIS
Since this contains no recursive functions, we would have eliminated it
as irrelevant (i.e., falsifiable) and quit. Note that we thus reduced
the correctness of CODEGEN to proving that all functions are
commutative!
One final note about these bugs. Our interactive system allows
functions to be evaluated so that after they are defined the user
can test them. We tested our three different (and faulty)
versions of the compiler and calculator on a variety of forms
and failed to expose any bugs because we limited our tests to
well-formed expressions involving only PLUS and TIMES (both of which
are numeric and commutative).
.SSS |The History of the Problem|
To the best of our knowledge, our mechanical theorem prover
was the first to undertake the proof of the correctness of an __optimizing_ expression compiler.
However, the problem of the correctness of a function similar to our
CODEGEN was first raised by McCarthy and Painter {REF MCCPAINTER}
in 1967. They proved, by hand, the correctness of an
expression compiler for an idealized
machine that contained addressable registers
rather than a push-down stack like our calculator.
Milner and Weyhrauch {REF MILNER}, in 1972, mechanically proof-checked
a version of
the
McCarthy-Painter correctness proof with a considerable amount of user
interaction. Cartwright {REF CARTWRIGHT}, in 1977, produced a mechanical
proof requiring somewhat less user assistance
than the Milner-Weyhrauch proof.
Aubin {REF AUBIN}, in 1976, produced a mechanical proof exactly
analogous to our proof of the correctness of CODEGEN, requiring
no user help other than
a
single lemma similar to our SEQUENTIAL.EXECUTION lemma.
.SEC |THE CORRECTNESS OF A FAST STRING SEARCHING ALGORITHM|, SECFSTRPOS:
Both the tautology checker and the compiler examples dealt with
recursive algorithms for handling tree-structured data. We here
apply the theory and proof techniques to establish the correctness of an
iterative program processing linear, indexed arrays. In particular,
we prove the correctness of a program for finding the first occurrence
of one character string in another.
String searching algorithms can be easily written;
the problem becomes more difficult and more interesting, however, if one
considers implementing an efficient algorithm. We prove the
correctness of one of the fastest known ways to solve the string
searching problem.
In further contrast to the compiler example, where we used the
functional approach to program semantics, we here attach meaning
to our program in another way. The method we use is called
the "inductive assertion" method (see Floyd {REF FLOYD} and
also Naur {REF NAUR}, Hoare {REF HOARE}, and Manna and Pnueli {REF MANNA}).
We will explain the method when we use it.
In fact, the primary intent of this {SECTIONORCHAPTER} is to demonstrate,
with a realistic example, that a theory based on recursive functions (rather than quantification)
may be profitably used to specify programs by the inductive assertion
method.
The structure of this {SECTIONORCHAPTER} is as follows.
We first describe the string searching problem informally and
derive and explain a very efficient string searching algorithm.
Then we formally specify the string searching problem and, using the
inductive assertion method, derive the formulas (called "verification
conditions") that we must prove to establish the algorithm
correct. Then we sketch the proofs of these verification
conditions. We conclude with some remarks addressing commonly held
misconceptions about the inductive assertion method.
.SS |Informal Development|, SSFSTRPOSEXAMPLE:
Throughout this {SECTIONORCHAPTER} we are concerned with sequences
of characters, usually called "character strings." We are
interested only in strings of finite length, containing characters from some
finite alphabet. We enumerate the characters in a string from the
left, starting at 0. Thus, the left-most character has "position" (or "index")
0, the second from the left has position 1, etc.
.SSS |The Naive String Searching Algorithm|
Suppose we have two strings, PAT and STR, and we want to find out
whether PAT is a substring of STR. That is, we want to know whether
there is a position, i, in STR such that if the 0^^th^ character of PAT
is placed on top of the i^^th^ character of STR, each of the
characters of PAT matches the corresponding character of STR.
If PAT does so occur in STR, we would like to determine the smallest
i at which such a match occurs, and otherwise we would like to indicate
that no match occurs.
For example, given the two strings:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
.ENDASIS
the appropriate answer is 25:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
(position 25)
.ENDASIS
There is an obvious way to compute the smallest such i. Consider each
of the successive values of i, starting at 0, and ask whether
each of the successive characters of PAT (starting at 0) is equal
to the corresponding character of STR (starting at the current i).
If a match is found, then we stop and i is the position of the left-most match.
But if the end of STR is encountered, then
since we tried all possible positions, no match occurs.
We will eventually define a recursive function, STRPOS, of two arguments,
that embodies this naive algorithm. We will take STRPOS as the
definition of what it means to find the position of the left-most
occurrence of PAT in STR. It is convenient to
define STRPOS to return the length of STR (an "illegal" position in
STR since we begin indexing at 0) to indicate that PAT does not
occur in STR. (This is useful in our specification of the problem
because we can pretend that PAT occurs just beyond the end of STR.)
.SSS |An Example of a Faster Method|
"String searching" is fairly common in everyday computing.
For example, string searching is crucial to the on-line preparation
of text (e.g., editing programs stored in text files, preparing
letters and memos on "word processors," and inputting and correcting
text for large scale computer typesetting applications).
Thus, it is advantageous to use an efficient algorithm.
A standard way to measure the efficiency of an algorithm is to
count the number of machine instructions required to execute it
on the average. For a string searching algorithm, this number is
usually proportional to the number of times a character from STR is
fetched before a match is found or STR is exhausted at position i. The naive
algorithm, the one embodied by STRPOS, suffers from the fact that
it looks at each of the first i characters of STR at least once.{FNOTE |In the
. worse case, the naive algorithm is "quadratic" in that it looks at k*i
. characters, where k is the length of the pattern and i is the location
. of the winning match. Consider the case where PAT is 'AAAB' and
. STR is 'AAAAA...AAAAAB'. Knuth, Morris, and Pratt {REF KMP} developed
. a "linear" algorithm that always makes order i+k comparisons. However,
. the worst-case behavior of the simple algorithm
. rarely occurs in real string searching applications. On the
. average, the simple algorithm is practically linear.|}
At first sight, it is not obvious that one can do better than to look at
each of the first i characters.{FNOTE |In fact, Rivest {REF RIVEST}
. has shown that for each string searching algorithm there exist
. PAT and STR for which that algorithm inspects at least i characters.|}
To see how it can be done, let us look again
at the example:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
.ENDASIS
Rather than focus our attention on the beginning of STR, consider
the character of STR aligned with the __right-most_ character of PAT,
namely the '_' indicated by the arrow below:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
.ENDASIS
Since '_' is not equal to the last character of PAT, we know we do not have
a match at the current juxtaposition of PAT and STR. More than
that, since '_' does not even occur in PAT, we know that we can slide
PAT to the right by its length and not miss a match. If sliding PAT by
less than its length would produce a match, then the '_' at which we
are pointing would be involved in the match. In particular, '_' would
have to be equal to (i.e., __be_) some character
in PAT. So we can slide PAT down by its length, to put it
just past the position of the arrow above. Then we move the arrow down STR so that it
is once again under the right-most character of PAT:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
.ENDASIS
Now let us repeat the process. Consider the character indicated by the
arrow. It matches the right-most character of PAT. Thus we may have a match.
To check this, we move the arrow to the __left_ by 1:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
.ENDASIS
The character 'D' does not occur in PAT. Thus we can slide PAT down
by its length again (from the current position of the arrow):
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
.ENDASIS
Once again we shift our attention to the end of PAT and find that
the corresponding character of STR, 'I', does not occur in PAT.
So we slide PAT down again by its length:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
.ENDASIS
This time we fetch an 'X'. It does not match the last character
of PAT, so we are not at a match. But 'X' does occur in PAT, so we
may not slide PAT down by its length. However, the
__right-most_ occurrence of 'X' in PAT is five characters from the __right-hand_
end of PAT. Thus, if we were to slide PAT down by just one, or two, or any
number less than five, we would not find a match:##if a match were to occur
at such a juxtaposition, then the 'X' at which we were pointing would be involved
in the match and would have to be equal to a character in PAT (namely an 'X') to the right
of the right-most 'X' in PAT! So we may slide PAT down by five (so as
to align the current position of the arrow with
the right-most 'X' in PAT) without risking a miss. Then we move the arrow
so that it once again points to the end of PAT:
.ASIS
PAT: EXAMPLE
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^
.ENDASIS
Finally, we see that the indicated character of STR is equal to the corresponding
one of PAT. By looking for a mismatch backwards, as before, we
find that all the characters of PAT are similarly matched. Thus,
we have found the left-most occurrence of PAT in STR.
Here are the characters we fetched from STR, up to the time we had
made the final alignment and were about to confirm the match:
.ASIS
STR: LET_US_CONSIDER_A_SIMPLE_EXAMPLE.
$a^ $a^$a^ $a^ $a^
.ENDASIS
Of course, we had to spend seven more comparisons confirming the final match.
But in skimming past the first 25 characters of STR, we only had to look
at five of them.{FNOTE |The algorithm just illustrated
. has quadratic worst-case behavior.
. However, on the average it
. looks at fewer than i characters of STR before finding a match at i, and
. its behavior improves as patterns get longer
. (because it may slide the pattern further each move),
. and deteriorates as the alphabet gets smaller (because the chances
. are increased that the character just fetched from STR occurs close to the end of PAT).
. The algorithm can be implemented so that if searching for English
. patterns of length five or more, through English text, fewer than i
. machine instructions are executed on the average before the pattern is found at position i.
. The algorithm is actually a simplification of the Boyer-Moore fast
. string searching algorithm {REF FSTRPOS}, which treats the finite set of terminal
. substrings of PAT in a way analogous to the way we just treated the characters of
. the alphabet. The Boyer-Moore fast string searching algorithm
. is, on the average, much faster than the simplified version on
. small alphabets (e.g., binary ones) but only marginally faster on large
. alphabets (e.g., English text).
. The worst-case behavior of the Boyer-Moore algorithm is linear, as proved by
. Knuth in {REF KMP}. Guibas and Odlyzko in {REF GUIBAS} also prove
. (and improve upon) the linearity result.|}
.SSS |Preprocessing the Pattern|
One might wonder why the measure of the number of characters fetched
from STR is relevant here, given that every time we fetched one
we had to ask whether and where it occurred in PAT. However,
because the alphabet is finite, we can, for a given PAT, precompute the
answers to all those questions.
The algorithm requires that whenever we fetch a character, C, from
STR that does not match the corresponding character of PAT, we be able
to determine how far down we can slide the pattern without missing
a match.
If we are standing under the right end of PAT when we fetch C,
then we want to know how many characters there are between
the right end of PAT and the right-most occurrence of C in PAT.
We know we may slide PAT that far forward, so as to align the C we
just discovered in STR with the right-most C in PAT.
If C does not occur in PAT at all, then we may slide PAT forward
by its length (i.e., we can pretend C occurs at "position" -1).
This number, called the "delta1" for C and PAT in {REF FSTRPOS},
can be obtained by scanning PAT from right to left, counting
the number of characters seen before encountering C (or running off the
beginning of PAT).
For example, if PAT were the string 'EXAMPLE', then the
following table contains all the information we need (over the alphabet 'A' through 'Z' and '_'):
.ASIS
C delta1 for C and 'EXAMPLE'
A 4
B 7
C 7
D 7
E 0
F 7
.
.
.
K 7
L 1
M 3
N 7
O 7
P 2
Q 7
.
.
.
W 7
X 5
Y 7
Z 7
_ 7
.ENDASIS
It is possible to set up this table in order (k + the alphabet size)
instructions where
k is the length of PAT.{FNOTE |The table can be set up by filling it with the number k
. (as though no character occurs in PAT), and then sweeping
. through PAT once from left to right filling in the correct value
. for each occurrence of each character. Thus, in the example above, the 'E' entry first
. has a 7 in it (i.e., the length of PAT), then 6 (as a result of seeing
. the first 'E'), and then finally 0 (as a result of seeing the last 'E').|}
We will not discuss the preprocessing
further. Instead, we assume we have a function, DELTA1, that
takes C and PAT and returns the table entry as defined above.
.SSS |How To Do a Fast String Search|, SSSENGLISHFSTRPOS:
We now tell the reader how to carry
out a fast string search, assuming the reader knows how to compute
DELTA1 as above.
The directions involve several variable names.
We imagine that when the reader is following these directions to
carry out an actual search, he has in mind an environment
that associates some specific mathematical
value (such as an integer or string) to each of the variables
mentioned. Every time he encounters an expression during the course
of following these instructions, he is to evaluate the expression with
respect to the current environment. We sometimes direct the reader
to "Let var be expr." By this we mean for the reader
to construct the new environment in which all the variables
except var have the same values they had in the old environment.
The value of var under the new environment is to be the
value of expr under the old environment. We expect
the reader to use this new environment in the evaluation of all subsequently
encountered expressions (until we instruct him to change the environment again).
We assume that (LENGTH STR) is the number of characters in
STR, and that (NTHCHAR I STR) is the I^^th^ character of STR.
We occasionally make "claims" regarding what we believe to be
true every time the reader arrives at an indicated step in the process.
These claims can be ignored while using the description as a
means of finding a pattern in a string. Suppose we wish
to find the left-most occurrence of PAT* in STR* if one exists.
.ASIS
1. The initial environment should associate with the
variable PAT the string PAT* and with the variable STR
the string STR*. Our object is to produce a "final answer"
equal to the one produced by the naive algorithm:
(STRPOS PAT* STR*).
2. We are interested only in the values of the variables
PAT and STR, and the following additional variables:
I, J, PATLEN, STRLEN, NEXTI, and C. We are indifferent
to the initial values of the additional variables.
3. Let PATLEN be (LENGTH PAT).
4. If (EQUAL PATLEN 0) is true, then do the following
(and otherwise continue at line 5):
Claim 1:##You will never arrive at this point while
following these directions unless 0 is equal to
(STRPOS PAT* STR*).
Therefore you should stop and consider 0 the
final answer.
5. Let STRLEN be (LENGTH STR).
6. Let I be (SUB1 PATLEN). The value of I will always
be the position in STR of the "$a^" we have drawn while
illustrating the algorithm at work. It now points to the
character of STR directly under the right-most
character of PAT (with PAT left-aligned with the
beginning of STR).
7. Claim 2:##Every time you come past this point there
are at least as many characters to the left of I
in STR as there are characters to the left of the
right-most in PAT (so we may compare them pairwise).
Furthermore, either I marks the right-hand end of
the winning match of PAT in STR, or else the right-hand
end of the winning match is somewhere to the right of
I (or else there is no winning match).
In any case, we have not yet passed the winning match
but might be standing at its right-hand end.
However, it is in general possible that I is already
beyond the end of STR. Therefore we must check that
I is indeed a legal index into STR before we start
investigating whether I marks the end of a match.
8. If (GREATEREQP I STRLEN) is true (i.e., I>$M-1_STRLEN),
then do the following (and otherwise continue at line 9):
Claim 3:##You will never get here while following
these directions unless STRLEN is (STRPOS PAT* STR*).
Therefore you should stop and consider STRLEN the
final answer.
9. Let J be (SUB1 PATLEN).
10. Let NEXTI be (ADD1 I). We are about to start backing
up, comparing characters from PAT with characters from
STR. I (the "$a^") will mark the position in STR from
which we will fetch characters, and J will mark the
corresponding position in PAT. We may later need to
know the position currently to the left of I, so we
have saved it in NEXTI.
11. Claim 4:##Every time you come past this point, we claim
that everything we say in Claim 2 is true (except that
(SUB1 NEXTI) should be used in place of I); furthermore
J is the same distance to the left of PATLEN as
I is to the left of NEXTI, NEXTI is no bigger than
STRLEN, J is less than or equal to I, and it is the
case that the terminal substring of PAT starting at
position (ADD1 J) matches the terminal substring of
STR starting at position (ADD1 I).
The last part of this claim is vacuously true initially,
but as we back up establishing that the characters from
PAT are equal to their counterparts in STR it is more
interesting.
12. Let C be (NTHCHAR I STR).
13. If (EQUAL C (NTHCHAR J PAT)) is true, then do the
following (and otherwise continue at line 18):
14. If (EQUAL J 0) is true, then do the following
(and otherwise continue at line 15):
Claim 5: You will never get here while following
these directions unless I is (STRPOS PAT* STR*).
Therefore, you should stop and consider I the
final answer.
15. Let I be (SUB1 I). Note that this backs up the
"$a^" by 1.
16. Let J be (SUB1 J).
17. Go to line 11 and continue.
18. Let I be the maximum of the two integers (PLUS I
(DELTA1 C PAT)) and NEXTI. This step slides the pattern
down. At first sight one is tempted to slide the pattern
down by incrementing I with (DELTA1 C PAT), for that
quantity can be regarded as the sum of (a) the distance we
must slide the pattern to align the current "$a^" with the
right-most C in PAT, plus (b) the distance we must move the
"$a^" to put it at the end of the new location of PAT.
This reasoning is entirely accurate but it ignores the fact
that the right-most occurrence of C might have already been
passed:
PAT: EXAMPLE
STR: ... IT_IS_ELEMENTARY
I: $a^**
NEXTI: $a^
In the example above, we have matched the two characters
marked with *'s and have backed up to the I indicated.
But since the right-most 'E' in PAT has already been
passed, incrementing I by (DELTA1 'E' PAT) = 0 would
slide PAT backwards. Instead, we choose to slide
PAT forward by one, namely to the position marked by
NEXTI.
19. Go to line 7 and continue.
.ENDASIS
This concludes the informal presentation of the algorithm. Most programmers
could now go away and implement it. However, we are interested in proving it
correct.
.SS |Formal Specification of the Problem|
In this {SUBSECTIONORSECTION}, we specify the string searching problem formally
by defining STRPOS.
In the next {SUBSECTIONORSECTION}, we use the inductive assertion method to specify the
fast string searching algorithm and derive its "verification
conditions."
.SSS |Strings|
From the mathematical point of view, what is a string? It is
a sequence of objects (that we will think of as characters in this
application). Consequently, from the mathematical point of view we can
regard a string as a list.
The only two operations on strings required by
our string searching algorithm are LENGTH and NTHCHAR. These are
recursively defined in {APP APPTHMS}. For example, the 0^^th^
character of X is (CAR X) and the i+1^^st^ character of X is
the i^^th^ character of (CDR X).
A program semanticist may object that our definition
of the mathematical object "string" with CONS, CAR, and CDR is
naive because it dictates an implementation of strings less
efficient than the usual one using indexed byte operations.
This objection is as unfounded as the analogous objection to defining
the mathematical object "integer" with ADD1 and SUB1. An engineer
or systems programmer is as free to implement strings efficiently
as he is to implement integers using twos-complement arithmetic.
.SSS |The String Matching Problem|
We wish to define the notion of whether PAT occurs as a substring of STR,
and if so, what is the position in STR of the left-most such occurrence.
We first define the function MATCH that determines whether PAT
is equal to an initial piece of STR. This is the case precisely if PAT is empty
or if both PAT and STR are nonempty and (a) their first characters
are identical and (b) (CDR PAT) is (recursively) an initial piece of (CDR STR).
.ASIS
Definition.
(MATCH PAT STR)
=
(IF (LISTP PAT)
(IF (LISTP STR)
(IF (EQUAL (CAR PAT) (CAR STR))
(MATCH (CDR PAT) (CDR STR))
F)
F)
T).
.ENDASIS
Now we define STRPOS. It is to tell us how many characters in STR
must be "stepped over" before finding a terminal substring of STR
that has PAT as an initial piece (or STR is exhausted):
.ASIS
Definition.
(STRPOS PAT STR)
=
(IF (MATCH PAT STR)
0
(IF (LISTP STR)
(ADD1 (STRPOS PAT (CDR STR)))
0)).
.ENDASIS
.SS |Developing the Verification Conditions for the Algorithm|
We want to prove that the fast string searching algorithm,
exhibited above, always computes
(STRPOS PAT* STR*). This requires that we formally define DELTA1 and
that we somehow formalize what it means for the algorithm to compute
(STRPOS PAT* STR*).
The first task is trivial. As for the second, note that if our claims are correct, specifically Claims 1,
3, and 5, the algorithm is correct:##it never returns an answer except
when the answer is (claimed) equal to (STRPOS PAT* STR*). Therefore,
we could prove the algorithm correct by proving our claims. This raises
two problems: (1) our claims have not been written down formally, and
(2) they involve the values of the variables in the
environment current at the time the claims are encountered.
.SSS |The Formal Definition of DELTA1|
Recall that (DELTA1 C PAT) is to return the number of characters to the
right of the right-most C in PAT. The number can be obtained by
scanning PAT from right to left, counting the number of characters stepped
over before the first C is encountered (or the beginning of the
pattern is reached). This is just a STRPOS string search for
the singleton string containing C, over the reverse of the pattern.
We thus use the following definition of DELTA1:
.ASIS
Definition. DELTA1:
(DELTA1 C PAT)
=
(STRPOS (CONS C "NIL") (REVERSE PAT)).
.ENDASIS
Since (STRPOS PAT STR) is the length of STR if PAT does not occur,
this definition of DELTA1 returns the length of the pattern if C does not occur
in it.
.SSS |Formalizing the Claims|
We here formalize each of the five claims. We reproduce (the relevant part of) each claim before
expressing it formally. All the functions mentioned are defined in {APP APPTHMS}.
.SSSS |Claim 1|
Claim 1 is that "0 is equal to (STRPOS PAT* STR*)."
Thus, the formal statement of Claim 1 is:
.ASIS
~Claim 1.
(EQUAL 0 (STRPOS PAT* STR*)).
.ENDASIS
.SSSS |Claim 2|
Claim 2 is irrelevant to the correctness of the algorithm;
we care only about the truth of the "exit" Claims 1, 3, and 5.
However, we formalize Claim 2 because it will be involved in the
proofs of the other claims. For example, we will prove Claim 3 by proving that if
Claim 2 is true, then, when we reach Claim 3, it is true.
Claim 2 is that "there are at least as many characters to the left
of I in STR as there are characters to the left of the right-most
in PAT" and that "I marks the right-hand
end of the winning match of PAT in STR, or else the right-hand end of
the winning match is somewhere to the right of I (or else there is no winning
match)."
The first part of this can be formally phrased (LESSEQP (SUB1 PATLEN) I).
The second can be expressed as (LESSP I (PLUS PATLEN (STRPOS PAT STR))). The PLUS expression is
the position, in STR, of the character just to the right of the right-hand end of the first
occurrence of PAT in STR. The claim is that I is strictly less than
that position. If PAT does not occur in STR, then (STRPOS PAT STR) is
the length of STR and the statement still handles our claim.
Claim 2, as currently stated, is inadequate to prove Claim 3.
Among other things, we have not said that PAT is (still) PAT*, that PATLEN is (LENGTH PAT),
and that PATLEN is nonzero.
Thus, we actually strengthen Claim 2 to the following:
.ASIS
~Claim 2.
(AND (EQUAL PAT PAT*)
(EQUAL STR STR*)
(EQUAL PATLEN (LENGTH PAT))
(LISTP PAT)
(EQUAL STRLEN (LENGTH STR))
(NUMBERP I)
(LESSEQP (SUB1 PATLEN) I)
(LESSP I (PLUS PATLEN (STRPOS PAT STR)))).
.ENDASIS
We make ~Claim 2 the body of the definition of the function
TOP.ASSERT, to make future discussion more succinct.
As noted, ~Claim 2 is irrelevant to the correctness of the
algorithm, so the reader should not be bothered by its complicated
nature (except insofar as it affects the difficulty of proof).
.SSSS |Claim 3|
Our third claim is that "STRLEN is (STRPOS PAT* STR*)." The formal
statement of this is:
.ASIS
~Claim 3.
(EQUAL STRLEN (STRPOS PAT* STR*)).
.ENDASIS
.SSSS |Claim 4|
Like Claim 2, Claim 4 is irrelevant to the correctness of the algorithm,
but it is important in establishing the other claims.
Claim 4 is that "Claim 2 is true (except that (SUB1 NEXTI) should be used in place of I); furthermore, J is the same distance to
the left of PATLEN as I is to the left of NEXTI, NEXTI is no bigger
than STRLEN, J is less than or equal to I, and it is the case that
the terminal substring of PAT starting at position (ADD1 J) matches
the terminal substring of STR starting at position (ADD1 I)."
To formalize the relationship between J, PATLEN, I, and NEXTI, we
claim that NEXTI is equal to PATLEN plus the difference between
I and J. To formalize the relationship between the terminal substrings
of PAT and STR, we use the function NTH (which underlies the definition of NTHCHAR) to define the terminal
substring starting at a given position, and our previously defined MATCH
to characterize when one string matches the initial part of
another.
For the same reasons that we had to strengthen Claim 2, we have to
strengthen Claim 4. Its formal statement is:
.ASIS
~Claim 4
(AND (TOP.ASSERT PAT STR (SUB1 NEXTI) PATLEN STRLEN PAT* STR*)
(NUMBERP I)
(NUMBERP J)
(NUMBERP NEXTI)
(LESSP J PATLEN)
(LESSP I STRLEN)
(EQUAL NEXTI (PLUS PATLEN (DIFFERENCE I J)))
(LESSEQP NEXTI STRLEN)
(LESSEQP J I)
(MATCH (NTH PAT (ADD1 J))
(NTH STR (ADD1 I)))).
.ENDASIS
We make ~Claim 4 the body of the definition of the function LOOP.ASSERT.
.SSSS |Claim 5|
Our final claim is that "I is (STRPOS PAT* STR*)."
.ASIS
~Claim 5.
(EQUAL I (STRPOS PAT* STR*)).
.ENDASIS
.SSS |Applying the Inductive Assertion Method|
Now that the claims have been formalized, we must eliminate their
implicit reliance upon the flow of control through the procedure.
It is at this point that we employ Floyd's inductive assertion method.
.SSSS |A Sketch of the Inductive Assertion Method|
To explain how we eliminate the "dynamic" nature of the claims,
it is useful to have a copy of the algorithm
with the formal claims in place of the informal ones. Since the
description of the algorithm given above
is so long, we
abbreviate it here. We have numbered the steps the same
way we did earlier.
.NEXT PAGE
.ASIS
1. Procedure FSTRPOS(PAT,STR);
2. Variables I,J,PATLEN,STRLEN,NEXTI,C;
3. PATLEN <- LENGTH(PAT);
4. If PATLEN=0
then
[Claim 1: (EQUAL 0 (STRPOS PAT* STR*))]
return 0;
close;
5. STRLEN <- LENGTH(STR);
6. I <- PATLEN-1;
7. top:##[Claim 2: (TOP.ASSERT PAT STR I PATLEN
STRLEN PAT* STR*)]
8. If I _$M-1> STRLEN
then
[Claim 3: (EQUAL STRLEN (STRPOS PAT* STR*))]
return STRLEN;
close;
9. J <- PATLEN-1;
10. NEXTI <- I+1;
11. loop: [Claim 4: (LOOP.ASSERT PAT STR I J PATLEN
STRLEN NEXTI PAT* STR*)]
12. C <- STR(I);
13. If C=PAT(J)
then
14. If J=0
then
[Claim 5: (EQUAL I (STRPOS PAT* STR*))]
return I;
close;
15. I <- I-1;
16. J <- J-1;
17. goto loop;
close;
18. I <- MAX(I+DELTA1(C,PAT),NEXTI);
19. goto top;
end;
.ENDASIS
We desire to prove that each claim is true every time it is encountered
while using the above procedure to search for PAT* in STR*.
The inductive assertion method may be applied to a program, provided the
program has been annotated with a sufficient number of claims so that
every entrance and exit has a claim and so that in traversing
any loop at least one claim is encountered. If a sufficient
number of claims has been supplied, then we can prove that the program
is correct by considering the finite number of paths that begin and end at a
claim (and have no interior claims). If for each such path
the claim at the beginning of the path (together with the
tests along the path) implies the claim at the end of the path
(under the environment produced by the "Let" statements
along the path), then, by induction on the number of steps
in the computation, every claim is true every time it is encountered.
Thus the exit claims, in particular, are true whenever the
program exits.{FNOTE |Note, however, that we have only proved
. partial correctness: __if_ the program exits, it exits
. with the correct answer. The inductive assertion method
. we have described can be easily adapted to include proofs
. of termination: one needs to check that some well-founded
. relation is decreasing on each of the finite paths.|}
We have provided a sufficient number of claims to apply the method
to FSTRPOS.
.SSSS |The Paths Through FSTRPOS|
The relevant paths through FSTRPOS are:
.BEGIN
.INDENT1_0
.INDENT2_9
Path 1:##From the entrance to ~Claim 1,
performing the assignment on line 3 and
assuming the test on line 4 to be true. (Since we did not
explicitly annotate the entrance to FSTRPOS with a claim,
we assume the entrance claim is T.)
Path 2:##From the entrance to ~Claim 2,
performing the assignment on line 3,
assuming the test on line 4 to be false, and
performing the assignments on lines 5 and 6.
Path 3:##From ~Claim 2 to ~Claim 3,
assuming the test on line 8 to be true.
Path 4:##From ~Claim 2 to ~Claim 4,
assuming the test on line 8 to be false and performing
the assignments on lines 9 and 10.
Path 5:##From ~Claim 4 to ~Claim 5,
performing the assignment on line 12 and assuming
the tests on lines 13 and 14 to be true.
Path 6:##From ~Claim 4 to ~Claim 4,
performing the assignment on line 12, assuming
the test on line 13 to be true, assuming the test on line 14 to be false,
and performing the assignments on lines 15 and 16.
Path 7:##From ~Claim 4 to ~Claim 2,
performing the assignment on line 12, assuming
the test on line 13 to be false, and performing the assignment
on line 18.
.END
.SSSS |Generating the Verification Conditions|
For each of these seven paths, we must prove its
"verification condition"; that is, we must prove that if the
starting claim is true and the tests along the path are
true, then the final claim is true (in the environment
produced by the assignment statements along the path).
Below we present the generation of two of the seven verification
conditions.{FNOTE |To produce
. formal verification conditions, one must have a formal
. semantics for his programming language. We do not present
. such a semantics here, but we have precisely formalized
. such a semantics in {REF METHDOC}. We generated the
. verifications here using an implementation of that
. semantics.|}
.SSSSS |The Generation of FSTRPOS.VC1|
Consider the first path. Starting with an environment in which PAT is PAT*
and STR is STR*, we are to perform the assignment on line 3, assume that the test
at line 4 is true, and then prove ~Claim 1 under the environment thus produced.
The statement at line 3 is:
.ASIS
3. PATLEN <- LENGTH(PAT);
.ENDASIS
This means:##change the environment so that PAT and STR
still have their old values, but PATLEN has the value that (LENGTH PAT)
has in the current environment. Thus, in our new environment, PAT is PAT*,
STR is STR*, and PATLEN is (LENGTH PAT*).
Next we hit the test at line 4 and are to assume it true:
.ASIS
4. If PATLEN=0
then ...
.ENDASIS
This means that we should assume the current value of
(EQUAL PATLEN 0) to be true. That is, we should assume (EQUAL (LENGTH PAT*) 0).
Finally, we hit ~Claim 1:
.ASIS
[Claim 1: (EQUAL 0 (STRPOS PAT* STR*))]
.ENDASIS
which we must prove given the assumption above.
The resulting verification condition for Path 1 is:
.ASIS
Theorem. FSTRPOS.VC1:
(IMPLIES (EQUAL (LENGTH PAT*) 0)
(EQUAL 0 (STRPOS PAT* STR*))).
.ENDASIS
.SSSSS |The Generation of FSTRPOS.VC7|
Let us look at a more interesting path, namely path 7. Starting at ~Claim 4, we are to perform
the assignment on line 12, fail the test at line 13,
perform the assignment on line 18, and prove ~Claim 2 under the resulting
environment.
Assume that we have an initial environment in which the program variable I
has the value I, the program variable J has the value J, etc. Assume ~Claim 4
is true in that environment:
.ASIS
(LOOP.ASSERT PAT STR I J PATLEN STRLEN NEXTI PAT* STR*).
.ENDASIS
At line 12:
.ASIS
12. C <- STR(I);
.ENDASIS
C receives the value (NTHCHAR I STR).
Next we encounter the test at line 13 and are to assume it false:
.ASIS
13. If C=PAT(J)
then ...
.ENDASIS
This means we assume that the current value of (EQUAL C
(NTHCHAR J PAT)) is false:
.ASIS
~TEST.
(NOT (EQUAL (NTHCHAR I STR) (NTHCHAR J PAT))).
.ENDASIS
Finally we hit line 18:
.ASIS
18. I <- MAX(I+DELTA1(C,PAT),NEXTI);
.ENDASIS
and change the environment to:
.ASIS
~ENVRN.
variable value
after line 18
PAT PAT
STR STR
I (IF (LESSP (PLUS I
(DELTA1 (NTHCHAR I STR)
PAT))
NEXTI)
NEXTI
(PLUS I (DELTA1 (NTHCHAR I STR) PAT))){FNOTE |Our
. mechanical verification condition generator is driven off the
. compiled code for our high-level language. Our compiler compiles
. (MAX x y) "open" in the sense that it is treated as though it
. were (IF (LESSP y x) x y). Hence the IF in this value where a
. MAX was expected.|}
J J
PATLEN PATLEN
STRLEN STRLEN
NEXTI NEXTI
C (NTHCHAR I STR)
.ENDASIS
After line 18 we encounter the "goto top" and return to ~Claim 2,
which we must prove:
.ASIS
7. top:##[Claim 2: (TOP.ASSERT PAT STR I PATLEN
STRLEN PAT* STR*)]
.ENDASIS
after instantiating it with the environment ~ENVRN and assuming ~Claim 4 and ~TEST.
That is, the verification condition for path 7 is:
.ASIS
Theorem. FSTRPOS.VC7:
(IMPLIES (AND (LOOP.ASSERT PAT STR I J PATLEN
STRLEN NEXTI PAT* STR*)
(NOT (EQUAL (NTHCHAR I STR)
(NTHCHAR J PAT))))
(TOP.ASSERT
PAT
STR
(IF (LESSP (PLUS I (DELTA1 (NTHCHAR I STR) PAT))
NEXTI)
NEXTI
(PLUS I (DELTA1 (NTHCHAR I STR) PAT)))
PATLEN
STRLEN
PAT*
STR*)).
.ENDASIS
This formula requires us to prove that if the assertion in the
inner loop is true and we find a mismatch on some character at position
I in STR, then the assertion at the outer loop holds for the value of
I obtained by skipping ahead by DELTA1 (or to NEXTI, as appropriate).
.SSSSS |The Remaining Verification Conditions|
The five remaining verification conditions are similarly generated and
are listed in {APP APPTHMS} under the names FSTRPOS.VCi, for i from 2 to 6.
It requires induction to prove that
FSTRPOS.VC1 through FSTRPOS.VC7 are sufficient to
establish that all our claims are true every time they are encountered.
In particular, one must induct on the number of
steps in the computation {REF FLOYD}. This induction is crucial in order to unwind
the iteration inherent in a procedure described the way FSTRPOS is described.
It is from this use of induction that the "inductive assertion"
method gets its name.
But now we must prove FSTRPOS.VC1 through FSTRPOS.VC7. They involve
the natural numbers (which are inductively defined), sequences (which are
inductively defined), and functions such as NTH, MATCH, and
STRPOS (which are recursively defined). To prove them, we also need
induction. This second use of induction is crucial because of
the nature of the mathematical objects with which programs deal.
.SS |The Mechanical Proofs of the Verification Conditions|
The theorem prover has proved the seven verification conditions for
FSTRPOS. We will not go into the proofs in detail since this {SECTIONORCHAPTER}
was intended to demonstrate, by realistic example, that our theory is applicable
to the specification of programs by the inductive assertion method.
We sketch briefly the proof of each of the verification conditions.
Our sketches will concern themselves mainly with the string processing
lemmas that have to be proved in order to set up the proofs of the
verification conditions. A fair amount of arithmetic
is generally involved. Since the proof of the correctness of FSTRPOS is
actually conducted after the theorem prover has proved the unique
prime factorization theorem (and remembered all the theorems along the way),
it knows a good deal of arithmetic by the time it starts proving FSTRPOS.VC1.
However, we had it prove several additional theorems about arithmetic,
almost all of them involving LESSP, because of its rather poor handling
of transitivity. All of the lemmas mentioned below are in {APP APPTHMS}.
.SSS |Proofs of FSTRPOS.VC1 and FSTRPOS.VC2|
FSTRPOS.VC1 and FSTRPOS.VC2 can be reduced to true by simplification alone
(in the presence of all the previously proved arithmetic theorems).
.SSS |Proof of FSTRPOS.VC3|
FSTRPOS.VC3 is the verification condition that establishes that
if the algorithm exits because I is eventually pushed beyond the end
of STR, then (STRPOS PAT* STR*) is STRLEN. This has to be proved
assuming ~Claim 2. But ~Claim 2 provides the hypothesis that
(LESSP I (PLUS PATLEN (STRPOS PAT STR))). If I is greater than or equal to
STRLEN, then by transitivity of LESSP, we can conclude that (PLUS PATLEN (STRPOS PAT STR)) is greater than
STRLEN. The proof can then be completed if we have previously proved
that when (STRPOS PAT STR) is not equal to (LENGTH STR), it is at least
(LENGTH PAT) shy of (LENGTH STR). This lemma, called STRPOS.BOUNDARY.CONDITION,
must be proved by induction on the length of STR, and requires the
inductively proved theorem that if PAT MATCHes STR then the length of
STR is at least that of PAT.
.SSS |Proof of FSTRPOS.VC4|
FSTRPOS.VC4, the verification condition for the path from ~Claim 2
to ~Claim 4, requires nothing more than arithmetic.
.SSS |Proof of FSTRPOS.VC5|
FSTRPOS.VC5 is more interesting. This verification condition
corresponds to the winning exit from the procedure. In particular,
assuming that ~Claim 4 holds and that the I^^th^ character
of STR is equal to the J^^th^ character of PAT, and that J is 0,
we must establish that I is equal to (STRPOS PAT* STR*). ~Claim 4
informs us that we have a MATCH established between the terminal
substrings of PAT and STR, and the conditions on the path
establish that the first character of PAT is equal to the I^^th^ character of STR.
Thus, we certainly have a MATCH at position I in STR. However, this
does not immediately imply that (STRPOS PAT* STR*) is I because there
might be an earlier match. But ~Claim 4 tells us that
~Claim 2 holds, and ~Claim 2 tells us that there is no match to our left.
Thus, we can complete the proof if we have proved:
.ASIS
Theorem. STRPOS.EQUAL:
(IMPLIES (AND (LESSP I (LENGTH STR))
(NOT (LESSP (STRPOS PAT STR) I))
(NUMBERP I)
(MATCH PAT (NTH STR I)))
(EQUAL (STRPOS PAT STR) I).
.ENDASIS
This lemma says that if I is a legal index into STR and (STRPOS PAT STR)
is greater than or equal to I, and PAT matches the I^^th^ terminal substring
of STR, then (STRPOS PAT STR) __is_ I. This is one of the obvious properties
of the intuitive definition of the "position of the left-most match"
and must be proved by induction (on I and STR) from the definition of
STRPOS.
.SSS |Proof of FSTRPOS.VC6|
FSTRPOS.VC6 is the verification condition for the path from ~Claim 4 back to ~Claim 4.
On that path, we find that the I^^th^ character of STR is
the J^^th^ character of PAT but that J is not 0.
It is straightforward to confirm that ~Claim 4 still holds after
the match has been extended by one character in the backwards direction.
.SSS |Proof of FSTRPOS.VC7|
FSTRPOS.VC7 is the most interesting verification condition;
it is the only one involving DELTA1. It requires us to prove
that if ~Claim 4 holds and we find a mismatch at position I, then
we can increment I by (DELTA1 C PAT) (or set it to NEXTI) and still prove ~Claim 2.
Of course, the interesting part of ~Claim 2 is that we have not
missed a match.
The proof rests mainly on two lemmas, both of
which require induction to prove, and both of which themselves
rest on inductively proved lemmas.
The first is called EQ.CHARS.AT.STRPOS.
It assures us that if the I^^th^ character of STR is not equal to the
J^^th^ character of PAT, under certain obvious restrictions on I and J,
then (STRPOS PAT STR) is not
the difference between I and J. In particular, this lemma tells us
that if the inner loop finds a mismatch of two corresponding characters anywhere in the
region of interest, then we are not currently in a match. Therefore, we can move I down
by at least one.
The second lemma is called DELTA1.LEMMA.
It states that if I is a legal index into STR,
and the right-hand end of the winning match of PAT in STR is at I or to the right,
then one does not miss a match by incrementing I
by (DELTA1 (NTHCHAR I STR) PAT).
Proving this lemma requires substantial reasoning about STRPOS and
MATCH, in addition to many lemmas about list processing
and arithmetic. For example, one key fact
is DELTA1.LESSP.IFF.MEMBER, which states that (DELTA1 CHAR PAT) is strictly
less than the length of PAT if and only if CHAR is a MEMBER of PAT (a crucial
fact if incrementing I by DELTA1 is not going to skip over
a possible alignment).{FNOTE |We were
. pleased to see that many "toy" theorems the theorem prover has
. proved for years actually get used in this nontoy problem.
. For example, proving DELTA1.LESSP.IFF.MEMBER requires using the lemmas that the length of (REVERSE X) is the
. length of X, and that CHAR is a MEMBER of (REVERSE X) if and only
. if it is a MEMBER of X.|}
The induction argument to prove DELTA1.LEMMA was exhibited
at the conclusion of the discussion on induction, {YONSEC SECINDUCTION}.
It was the example in which the field of ten candidate inductions was
narrowed to one by merging and the consideration of flaws.
.SSS |What Have We Proved?|
We have thus completed sketching the proofs of the verification
conditions. What exactly have we proved about the program FSTRPOS?
Appealing to the induction argument behind the Floyd method, we have
proved that each of our claims is true every time it is encountered during
the execution of the procedure. In particular, the "exit" claims
establish that whenever the procedure returns an answer, it is equal to
that computed by STRPOS.
But one should always ask of a proof:##"Upon what axioms or assumptions
does the proof rest?" That is, if someone is going to "buy" the
correctness of FSTRPOS, what must he accept?
The answer is that he must accept:
.BULLET
Our axioms of Peano arithmetic, lists, and literal atoms
as provided by the shell addition scheme
(literal atoms are involved only because of the use of "NIL").
The definition of STRPOS (and thus of MATCH) as
being the meaning of "left-most match."
The correctness of the verification condition generator
with respect to the programming language used in FSTRPOS.
The soundness of our theorem prover.{FNOTE |This is not
. an assumption to be taken lightly, given the complexity of the
. system. However, it is an assumption that could be relieved for
. all time and for all future proofs by careful scrutiny of the theorem prover by the mathematics community. While such
. an endeavor is clearly not cost effective
. for our current theorem prover (because of its rudimentary skills),
. it would be a cheap price to pay for the reliable service of a
. truly powerful mechanical theorem prover.|}
.ENDBULLET
One might ask:##"But what of all the definitions? How do I know that
PLUS is right? That LESSP is right? That NTH and NTHCHAR and MEMBER
and REVERSE and DELTA1 are all right?" The answer is that they are all
__defined_, and because they are defined and are not involved
in the statement of the theorem (namely that FSTRPOS(PAT*,STR*) returns
(STRPOS PAT* STR*)), they are eliminable. It is our opinion that
this is the most important reason why people should
__define_ concepts whenever possible (with a mechanically checked
definition principle when the logic is mechanized) rather than merely
add arbitrary axioms. For example, had DELTA1 been
constrained to have certain properties by the addition of nondefinitional
axioms, then the "buyer" of the correctness of FSTRPOS would
have had
to understand and believe in those axioms.
.SS |Notes|
We here comment on the difficulty of the proofs and on the
use of recursive functions with the inductive assertion specification method.
.SSS |Intuitive Simplicity versus Formal Difficulty|
The string searching algorithm is easier to explain than it is to prove formally correct.
The algorithm is based on some
obvious visual intuitions about strings, but the formalization
of those intuitions involves ugly arithmetic expressions.
However, this is not a condemnation of formal reasoning but
a recommendation of it. The program
implementing those visual intuitions about string
does not rely upon those intuitions at all,
but rather upon their translation into arithmetic operations.
In particular, it is very easy to make "__+_1" and boundary
errors in defining
or using DELTA1.
Furthermore, the string searching algorithm, even when mistakes of
this sort are present, often produces the correct answer in many test cases because, except in very
close proximity to the winning match, one can afford to skip ahead by
too much.
In order to run our verification condition generator
on the FSTRPOS procedure, we had to code the procedure in our "high-level"
programming language. We did this by working from the published version of the
algorithm {REF FSTRPOS}. We nevertheless made several
translation mistakes that did not show up until we tried to prove
the resulting verification conditions mechanically.
We learned one interesting fact about our algorithm from the theorem
prover. Until we tried proving FSTRPOS correct, we held the mistaken belief
that the MAX expression involved in the incrementing of I was
necessary for the termination of the algorithm but not for its correctness.
That is, we believed that if one accidentally moved the pattern backwards
it would not hurt anything except that the algorithm might not terminate.
Upon reflection (or careful scrutiny by a theorem prover), this can be seen to be wrong.
Consider what happens if in moving the pattern backwards
its left-hand end is moved off the left-hand end of the string.
Then it is possible to find a match out there by fetching "illegal"
characters from the string. Many readers may object
that a well-designed, high-level language would expose this bug as soon as it
arose (because of the attempt to index illegally into the string).
However, well-designed, high-level languages are almost never
used to code algorithms of this sort because the overhead involved
in ensuring legal access to strings
offsets the advantage of using the algorithm in the first place.
.SSS |Common Misconceptions about the Inductive Assertion Method|
We comment here on three misconceptions
about the inductive assertion method. We have found these misconceptions
rather widespread in the program verification community and feel that
they should be addressed, even though the subject is technically
beyond the scope of this book.
One common misconception is that the use of the inductive assertion
method requires a "program specification language" providing the usual
unbounded universal and existential quantifiers.
Our intent has been to show that this is unnecessary
and that the inductive assertion method is a way of attaching meaning
to programs that is independent of what mathematical language one uses
to express the specifications. We feel that the bounded quantification provided by
recursive functions is not only sufficient for almost all
specification needs, but often results in cleaner, better structured specifications,
and aids mechanical generation of proofs.
Another common misconception is that the inductive assertion
method eliminates the need for induction. The foregoing proof
sketches illustrate that induction may be useful in the proofs
of the verification conditions themselves. It happens, in the
FSTRPOS example, that the correctness can be stated so that the verification
conditions involve little more than linear arithmetic and quantification.
Thus, it is possible, using, say, Presburger's decision procedure {REF PRESBURGER} and a little
reasoning about function symbols, to prove the
FSTRPOS verification conditions without induction. Of course, given
the right lemmas, it is possible to prove anything without induction.
The point is that whether induction is involved in the proofs of
the verification conditions depends upon how much the theorem
prover knows or assumes about the particular mathematical operations
involved, and not upon whether induction was used to attach meaning
to the program.
A third misconception is that the inductive assertion method somehow
magically "modernizes" mathematics so that it can deal with side-effects
such as destructive assignment to arrays. In fact,
the method provides a very pretty, easy way of eliminating the dynamic
nature of a program by reducing its correctness to the correctness
of finite paths, each of which can be viewed statically.
For example, many programming languages permit one to write:
.ASIS
STR(I) <- 0;
.ENDASIS
When executed, this destructively deposits a 0 in the memory location containing the
I^^th^ element of STR. Let us assume that 0 was not already in
that location. From the computational point of view, STR is
the same object it was before, but now has a different I^^th^ element.
However, the inductive assertion method tells us that the correct
way to view the situation, mathematically, is that before the
assignment, STR denotes one (mathematical) sequence; after the assignment, it
denotes another (mathematical) sequence. For a path containing
such an assignment, the inductive assertion method would produce
a verification condition (i.e., a mathematical conjecture)
concerning two mathematical sequences, not a dynamically changing object.
These remarks are not meant to detract from the induction assertion
method. The method is a very natural way to assign meaning to certain kinds
of programs.
However, it should be recognized for what it is:##a straightforward
and well-defined way of mapping
assertions about a program into logical formulas amenable to mathematical
proof.
.SEC |THE UNIQUE PRIME FACTORIZATION THEOREM|, SECPRIMEFACTORIZATION:
In this {SECTIONORCHAPTER}, we discuss our system's proof of the unique
prime factorization theorem, also known as the Fundamental Theorem of
Arithmetic.
This theorem is certainly the deepest and
hardest theorem yet proved by our theorem prover. The
principal difficulty behind the proof is that Euclid's greatest common divisor
function (GCD)
plays an important role, even
though it is not involved in the statement of the theorem.
A beautiful but surprising fact (that
multiplication distributes over GCD) is used; the more obvious
fact that the GCD of two numbers divides both
of them is also used.
No other theorem yet proved by the theorem prover employs as a lemma
a surprising fact about a function not involved in the statement of
the theorem.
.SS |The Context|, SSCONTEXT:
To prove the unique prime factorization theorem, we start at
the very beginning with the axioms of Peano arithmetic.
We also need the axioms of lists and literal atoms (because we
will eventually need to deal with lists of numbers).
We then introduce, with the definition principle, the
usual elementary functions on the natural numbers:
.CROWN(5,0,0)
PLUS -- the sum of its two arguments.
TIMES -- the product of its two arguments.
DIFFERENCE -- the first argument minus the second argument unless the
first is less than the second, in which case
the answer is 0.
QUOTIENT -- the integer quotient of the first argument when divided
by the second argument. If the divisor is 0, then the answer is 0.
REMAINDER -- the remainder after dividing the first argument by
the second. If the divisor is 0, then the answer is the first argument.
DIVIDES -- the predicate whether the remainder of the
second argument divided by the first argument is 0.
GCD -- the greatest common divisor of the two arguments (0 if both
are 0).
.ENDCROWN
For all these functions, the convention is observed
always to treat any argument that is not a number as if it were 0.
We also have the theorem prover prove the usual elementary facts
about these functions, such as that PLUS is associative and commutative
and that TIMES distributes over PLUS.
We eventually reach less elementary theorems such as:
.ASIS
Theorem. REMAINDER.QUOTIENT.ELIM:
(IMPLIES (AND (NOT (ZEROP Y))
(NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X)),
Theorem. RECURSION.BY.QUOTIENT:
(IMPLIES (AND (NUMBERP I)
(NOT (EQUAL I 0))
(NUMBERP J)
(NOT (EQUAL J 0))
(NOT (EQUAL J 1)))
(LESSP (QUOTIENT I J) I)),
Theorem. DISTRIBUTIVITY.OF.TIMES.OVER.GCD:
(EQUAL (GCD (TIMES X Z) (TIMES Y Z))
(TIMES Z (GCD X Y))),
Theorem. GCD.DIVIDES.BOTH:
(AND (EQUAL (REMAINDER X (GCD X Y))
0)
(EQUAL (REMAINDER Y (GCD X Y))
0)).
.ENDASIS
In {APP APPTHMS}, we present the complete sequence of definitions
and theorems leading to the unique prime factorization theorem.
In this {SECTIONORCHAPTER}, we do not further discuss
those definitions and theorems preceding the definition of PRIME.
However, we recommend those elementary theorems to any student
of the foundations of mathematics and to anybody interested in
mechanical theorem-proving. All the heuristics
necessary to prove the unique prime factorization theorem were discovered
and mechanized while proving those simpler theorems. In {YONSEC SECELEMENTARY},
we presented proofs of some of those theorems.
Throughout the rest of this
{SECTIONORCHAPTER}, we will assume the reader is familiar with
the theorems preceding the definition of PRIME in {APP APPTHMS}.
It is worth noting that the theorem prover knows those theorems
because it has proved them all from Peano's axioms
(which it knows because it has been told to assume them).
.SS |Formal Development of the Unique Prime Factorization Theorem|
One may well ask how the
uniqueness of prime factorizations may even be stated within our theory.
McCarthy {REF MCCARTHYBASIS}, for example, thought that the
statement of the theorem was beyond the scope of his theory,
which is very similar to ours. In our statement of the theorem,
we use lists of numbers to represent factorizations of
numbers, and we use explicit functions to overcome our
lack of existential quantification. Our statement of the
theorem has two parts. The first part states
that an explicitly given function produces a prime factorization of any given nonzero
integer. The second part states that
any two lists of prime numbers whose "products"
are the same are in fact permutations of one
another.
We now precisely define the necessary concepts and
formally state these two parts of our version of the unique factorization
theorem.
.SSS |Definition of the Concepts|
.SSSS |The Definition of PRIME|
First, let us consider the definition of the
concept of prime number.
The usual definition is: X is prime provided it is an integer greater than 1 and its
only divisors are itself and 1. This definition,
strictly speaking, involves the consideration of
all integers as possible divisors of X.
We cannot use
our principle of definition to introduce a concept that requires
considering an infinite number of questions.
Fortunately, we need consider only the finite
number of integers less than X, since every divisor of a positive
number X is
less than or equal to X.{FNOTE |In particular, the theorem
. {ASIS}(IMPLIES (AND (NOT (ZEROP X)) (DIVIDES Y X)) (LESSEQP Y X)){ENDASIS} can
. be proved by simplification alone, given the
. definitions of the functions and the rudimentary facts about LESSP.|}
Therefore, we can write
a definition of prime within our theory.
We need the auxiliary function PRIME1 that returns T
if and only if X has no divisors less than or equal to Y (and greater than 1):
.ASIS
Definition.
(PRIME1 X Y)
=
(IF (ZEROP Y)
F
(IF (EQUAL Y 1)
T
(AND (NOT (DIVIDES Y X))
(PRIME1 X (SUB1 Y))))).
.ENDASIS
We then define PRIME as:
.ASIS
Definition.
(PRIME X)
=
(AND (NOT (ZEROP X))
(NOT (EQUAL X 1))
(PRIME1 X (SUB1 X))).
.ENDASIS
That is, PRIME checks that its argument is not 0, not 1,
and has no divisor less than itself and greater than 1.
Readers unhappy about this constructive definition of prime number
may be comforted to learn that in order to prove the
unique prime factorization theorem, we will have to
prove as lemmas the essential content of the
ordinary definition of prime. These lemmas and their
proofs are discussed in {YONSS MECHPROOFS}.
.SSSS |PRIME.LIST, TIMES.LIST, and PERM|
We now introduce the other concepts needed
in the statement of the theorem.
The statement of the unique factorization theorem
requires three new concepts:##PRIME.LIST,
TIMES.LIST, and PERM.
PRIME.LIST checks that every member of its argument
is a prime. TIMES.LIST computes the product of the members of
its argument.
.ASIS
Definition.
(PRIME.LIST L)
=
(IF (NLISTP L)
T
(AND (PRIME (CAR L))
(PRIME.LIST (CDR L)))),
Definition.
(TIMES.LIST L)
=
(IF (NLISTP L)
1
(TIMES (CAR L)
(TIMES.LIST (CDR L)))).
.ENDASIS
The function PERM computes whether its first argument, A, is
a permutation of its second argument, B. If A is
not a list (that is, A is empty), PERM
requires that B not be a list; but if
A is a list, then PERM requires that (CAR A)
be a member of B and that (CDR A) be a permutation of
the result of deleting (CAR A) from B.
The definitions of DELETE and PERM are:
.ASIS
Definition.
(DELETE X L)
=
(IF (NLISTP L)
L
(IF (EQUAL X (CAR L))
(CDR L)
(CONS (CAR L)
(DELETE X (CDR L))))),
.ENDASIS
.ASIS
Definition.
(PERM A B)
=
(IF (NLISTP A)
(NLISTP B)
(AND (MEMBER (CAR A) B)
(PERM (CDR A)
(DELETE (CAR A) B)))).
.ENDASIS
.SSS |The Statement of the Theorem|
We are now able to state the two parts of our formulation
of the unique factorization theorem. The first part
states that there exists a prime factorization of
any positive integer. We handle the existential quantification by
exhibiting a recursive function, PRIME.FACTORS, that
computes such a factorization. In particular, we
prove that (PRIME.FACTORS X), when X is a nonzero integer, is a
list of primes whose product is X:
.ASIS
Theorem. PRIME.FACTORIZATION.EXISTENCE:
(IMPLIES (NOT (ZEROP X))
(AND (EQUAL (TIMES.LIST (PRIME.FACTORS X))
X)
(PRIME.LIST (PRIME.FACTORS X)))).
.ENDASIS
The definition of PRIME.FACTORS has not yet been exhibited
because its definition is irrelevant:##if the above theorem is
true, then regardless of the definition of PRIME.FACTORS,
every positive integer has at least one prime decomposition.
We have to define PRIME.FACTORS to prove the theorem, but we
can define it any way we please.
The second part of the unique prime factorization theorem states the
uniqueness of the decomposition. We will prove that
if two lists of primes have the same product, then the lists
are permutations of one another:
.ASIS
Theorem. PRIME.FACTORIZATION.UNIQUENESS:
(IMPLIES (AND (PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2)).
.ENDASIS
.SS |The Mechanical Proofs|, MECHPROOFS:
Now that we have formally expressed the
unique prime factorization theorem in our theory,
we proceed to discuss proofs. In {APP APPTHMS}, we
present in complete detail the sequence of lemmas
that the system is asked to prove on the way
to the proof of PRIME.FACTORIZATION.UNIQUENESS and
PRIME.FACTORIZATION.EXISTENCE. In the following discussion
of the proofs, we do not discuss certain
of these lemmas. Most of those we omit are proved
only because they state obvious facts not
"obvious" to the theorem prover until they
have been explicitly proved.
We describe the proofs much as they are described in number
theory textbooks. We leave as exercises for the reader (or the theorem
prover), the details.
.SSS |Elementary Facts about Primes|, SSSELEMENTARYFACTSABOUTPRIMES:
We first turn to the problem of proving the simplest
facts about prime numbers, facts virtually
equivalent to the ordinary definition of prime.
The reason we have our theorem prover
prove these lemmas is that unless they are proved explicitly,
the theorem prover will never consider
trying to prove that some number is prime by asking
whether it has a factor. That is, the quantification
implicit in the definition of prime is not apparent
to the theorem prover.
.SSSS |Primes Have No Divisors|
There are two main parts to the ordinary definition of
prime. The first tells us that if a number X has a divisor
that is not 1 and not X, then X is not a prime. This
part of the definition of prime is expressed in the
lemma:
.ASIS
Theorem. PRIME.BASIC:
(IMPLIES (AND (NOT (EQUAL Z 1))
(NOT (EQUAL Z X))
(DIVIDES Z X))
(NOT (PRIME1 X (SUB1 X)))).
.ENDASIS
The proof of this lemma involves a subsidiary lemma,
.ASIS
Theorem. PRIME1.BASIC:
(IMPLIES (AND (NOT (EQUAL Z 1))
(NOT (EQUAL Z (ADD1 X)))
(EQUAL (REMAINDER (ADD1 X) Z)
0))
(NOT (PRIME1 (ADD1 X) (PLUS Z L)))).
.ENDASIS
PRIME1.BASIC is actually more general than PRIME.BASIC
because the conclusion of PRIME.BASIC, the
formula (PRIME1 X (SUB1 X)), suffers from having
X occur in both arguments. This double occurrence
of X effectively prohibits PRIME.BASIC's being
proved by induction. PRIME1.BASIC is more general
because the two arguments to PRIME1 in the conclusion
have no variables in common. It can be proved in one induction.
.SSSS |Nonprimes Do Have Divisors|
The second part of the ordinary definition of
PRIME tells us that if a number X is not a prime
and not 0 or 1, then it has a divisor that is
neither 1 nor X. To express the existence of
such a factor we define the function
GREATEST.FACTOR and prove that it has the appropriate properties.
.SSSSS |GREATEST.FACTOR|
We want a function that returns a factor of X, less than X and
greater than 1, if X is a nonprime
greater than 1. We can define this function any way we wish
(provided it is acceptable to our definition principle).
We have chosen to compute the greatest factor of X in exactly
the way that PRIME1 discovers whether X is prime. Namely, starting
at Y (which, in our use of the function will usually
be (SUB1 X)), we count down, looking for a number that divides X:
.ASIS
Definition.
(GREATEST.FACTOR X Y)
=
(IF (OR (ZEROP Y) (EQUAL Y 1))
X
(IF (DIVIDES Y X)
Y
(GREATEST.FACTOR X (SUB1 Y)))).
.ENDASIS
Intuitively, if PRIME1 returns F it
is because it ran down to and discovered
the GREATEST.FACTOR.
.SSSSS |The Properties of GREATEST.FACTOR|
We prove that if X is a nonprime number (and not 0 or 1), then the GREATEST.FACTOR of X divides X, is less than X,
and is not 0, 1, or a nonnumber.
These last three properties are captured by
the theorems GREATEST.FACTOR.0, GREATEST.FACTOR.1, and NUMBERP.GREATEST.FACTOR.
These theorems state the (trivial) conditions under which GREATEST.FACTOR
is 0, 1, or not a number. Each is proved easily in one induction.
We are left with the two main properties of GREATEST.FACTOR.
The lemma GREATEST.FACTOR.DIVIDES establishes that nonprimes greater than 1 have at least
one divisor, namely, that computed by GREATEST.FACTOR:
.ASIS
Theorem. GREATEST.FACTOR.DIVIDES:
(IMPLIES (AND (LESSP Y (ID X))
(NOT (PRIME1 X Y))
(NOT (ZEROP X))
(NOT (EQUAL X 1))
(NOT (ZEROP Y)))
(EQUAL (REMAINDER X
(GREATEST.FACTOR X Y))
0)).
.ENDASIS
Note that this lemma is stated more generally than
one might at first have thought necessary. Instead
of proving a theorem about (PRIME X) and (GREATEST.FACTOR X (SUB1 X)),
we prove a theorem about (PRIME1 X Y) and
(GREATEST.FACTOR X Y). The only reason for this
generality is that one cannot prove the less
general theorem by induction directly. However,
the more general theorem is easily proved by
the theorem prover in one induction.{FNOTE |The use of the function ID
. (which is just the identity function on numbers)
. was necessary to the mechanical proofs because otherwise the
. induction heuristic merges the suggested inductions
. on Y and X, flawing the "right" induction on Y. This problem was
. mentioned in the discussion of induction, {YONSEC SECINDUCTION}.
. The use of ID illustrates a subtle way in which
. the user can influence the theorem prover's behavior.|}
While the above theorem establishes that the
GREATEST.FACTOR of X is indeed a factor of X (under the right hypotheses),
it does not assure us that it is not X itself. The theorem
GREATEST.FACTOR.LESSP establishes that in fact the GREATEST.FACTOR
returns something less than X (and thus not equal to X):
.ASIS
Theorem. GREATEST.FACTOR.LESSP:
(IMPLIES (AND (LESSP Y (ID X))
(NOT (PRIME1 X Y))
(NOT (ZEROP X))
(NOT (EQUAL X 1))
(NOT (ZEROP Y)))
(LESSP (GREATEST.FACTOR X Y) X)).
.ENDASIS
The generality of GREATEST.FACTOR.LESSP was desired
for precisely the same reasons that we stated
GREATEST.FACTOR.DIVIDES as generally as we did.
This concludes our description of the rather
elaborate groundwork that must be laid in
the form of explicit lemmas, so that the
theorem prover is aware of the facts implicit
in the ordinary definition of prime. We now
proceed to the more interesting theorems concerning
the existence and uniqueness of the prime factorization.
.SSS |The Existence of a Prime Factorization|, SSSPRIMEFACTORIZATIONEXISTENCE:
The proof of the existence of a prime factorization of
every number greater than 0 is simple in comparison
to the (coming) proof of the uniqueness of such a factorization.
Recall that our objective is to prove:
.ASIS
Theorem. PRIME.FACTORIZATION.EXISTENCE:
(IMPLIES (NOT (ZEROP X))
(AND (EQUAL (TIMES.LIST (PRIME.FACTORS X))
X)
(PRIME.LIST (PRIME.FACTORS X)))).
.ENDASIS
The key to making a proof of this theorem difficult or
easy lies in the definition of the function
PRIME.FACTORS. Recall that we are happy, for
the purposes of the unique prime factorization theorem,
with any function whatsoever for computing an appropriate factorization.
Our description of the proof of PRIME.FACTORIZATION.EXISTENCE
is divided into three parts. The first presents the
definition of PRIME.FACTORS that we choose to use. The
second describes the proof that PRIME.FACTORS returns a
list of primes. The third describes the proof that
the product over that list is the desired integer.
.SSSS |The Definition of PRIME.FACTORS|
How can we compute a prime
decomposition of a nonzero integer X?
We first find the greatest factor of
X less than X. Then we recursively compute a prime decomposition of
that factor and a prime decomposition of the result of dividing X by that factor. Finally, we return the concatenation of the two decompositions.
.ASIS
Definition.
(PRIME.FACTORS X)
=
(IF
(OR (ZEROP X)
(EQUAL (SUB1 X) 0))
"NIL"
(IF
(PRIME1 X (SUB1 X))
(CONS X "NIL")
(APPEND
(PRIME.FACTORS (GREATEST.FACTOR X (SUB1 X)))
(PRIME.FACTORS (QUOTIENT X
(GREATEST.FACTOR X
(SUB1 X))))))).
.ENDASIS
We chose to define PRIME.FACTORS the way we have
because it makes one half of the proof of PRIME.FACTORIZATION.EXISTENCE trivial
and the other half easy.
The trivial half of the
proof is that PRIME.FACTORS always returns a list
of PRIMES. The easy half is showing that
the product of (PRIME.FACTORS X) is X.
Both these halves are proved by induction.
The induction used is the one analogous
to the recursion involved in the
definition of PRIME.FACTORS. Hence, it
is doubly important that we first look
at the justification of the definition of PRIME.FACTORS.
The theorem prover decides that the definition
PRIME.FACTORS is acceptable by determining that
the COUNT of the argument decreases on
each recursive call. There are two calls. In the first, X is replaced by
a GREATEST.FACTOR expression, and in the second, X is replaced
by the QUOTIENT of X by that greatest factor.
The proof that X is getting smaller in the first call relies on
GREATEST.FACTOR.LESSP, mentioned earlier.{FNOTE |Actually, the definitional facility
. must be provided with a trivial variant of it called
. GREATEST.FACTOR.LESSP.IND, proved as an induction lemma,
. that makes explicit use of COUNT since GREATEST.FACTOR is
. not always numeric.|} The proof that X is getting smaller in the second call
relies on RECURSION.BY.QUOTIENT, noted in {YONSS SSCONTEXT}.
.SSSS |PRIME.FACTORS Returns a List of Primes|
The proof that PRIME.FACTORS returns a list of primes
requires the easy lemma:
.ASIS
Theorem. PRIME.LIST.APPEND:
(EQUAL (PRIME.LIST (APPEND X Y))
(AND (PRIME.LIST X)
(PRIME.LIST Y))).
.ENDASIS
Once this theorem is known, a simple induction
proves that the output
of PRIME.FACTORS is always a list of primes.
"NIL" is a list of primes, (CONS X "NIL") is
a list of primes if X is a prime, and (by induction) the
recursive calls of PRIME.FACTORS return lists
of primes, so their concatenation is a list
of primes, by PRIME.LIST.APPEND.
.SSSS |PRIME.FACTORS Factors Its Argument|
All that remains to establish the existence of a prime factorization
of any nonzero number X is
the proof that (TIMES.LIST (PRIME.FACTORS X))
is X. This theorem is proved by one induction
(according to the way that PRIME.FACTORS recurses)
after proving the two lemmas:
.ASIS
Theorem. QUOTIENT.TIMES1:
(IMPLIES (AND (NUMBERP Y)
(NUMBERP X)
(NOT (EQUAL X 0))
(DIVIDES X Y))
(EQUAL (TIMES X (QUOTIENT Y X))
Y))
.ENDASIS
and
.ASIS
Theorem. TIMES.LIST.APPEND:
(EQUAL (TIMES.LIST (APPEND X Y))
(TIMES (TIMES.LIST X)
(TIMES.LIST Y)))
.ENDASIS
and observing that the lemma GREATEST.FACTOR.DIVIDES
helps to relieve the hypotheses of QUOTIENT.TIMES1.
.SSS |The Uniqueness of a Prime Factorization|
We now move on to the more difficult proof that the prime decomposition
of a number is unique, up to permutation. We first prove a key theorem
about primes, after which we carry off the final proof.
.SSSS |A Key Theorem about Primes|
The key fact about primes necessary in our proof of the unique
prime factorization theorem is the theorem that states that
if p is a prime and p divides the product of a and b, then p
divides a or p divides b. All the lemmas mentioned in
the other parts of this {SECTIONORCHAPTER} are, comparatively speaking,
routine. However, this lemma is decidedly not routine because
its proof employs the GCD function in a surprising way.
We formulate this key lemma thus:
.ASIS
Theorem. PRIME.KEY:
(IMPLIES (AND (NUMBERP Z)
(PRIME X)
(NOT (DIVIDES X Z))
(NOT (DIVIDES X B)))
(NOT (EQUAL (TIMES X K)
(TIMES B Z)))).
.ENDASIS
To prove PRIME.KEY, we first need to prove the
two lemmas:
.ASIS
Theorem. HACK1:
(IMPLIES (AND (NOT (DIVIDES X A))
(EQUAL A
(GCD (TIMES X A) (TIMES B A))))
(NOT (EQUAL (TIMES K X)
(TIMES B A)))),
.ENDASIS
.ASIS
Theorem. PRIME.GCD:
(IMPLIES (AND (NOT (DIVIDES X B))
(PRIME1 X (SUB1 X)))
(EQUAL (EQUAL (GCD B X) 1) T)).
.ENDASIS
Once these two lemmas have been proved, the proof of
PRIME.KEY is as follows.
We first rewrite the conclusion of PRIME.KEY
to (EQUAL (TIMES K X) (TIMES B Z)) and try to use HACK1 to establish the conclusion
of PRIME.KEY. To use HACK1, we must establish the two hypotheses:
(NOT (DIVIDES X Z)) and (EQUAL Z (GCD (TIMES Z X) (TIMES Z B))).
We have the first of these hypotheses among the hypotheses of
PRIME.KEY. To establish the equality, we first rewrite it
using the DISTRIBUTIVITY.OF.TIMES.OVER.GCD
to (EQUAL Z (TIMES Z (GCD X B))). A simple arithmetic lemma
(called TIMES.IDENTITY) tells us that to establish such an equality
we need to check that (EQUAL (GCD X B) 1). But this is a direct
consequence of PRIME.GCD and the hypotheses in PRIME.KEY. Q.E.D.
Now let us prove the two lemmas we used, HACK1 and PRIME.GCD.
First, we prove HACK1. The proof is most easily seen by reformulating
HACK1 in the contrapositive:
.ASIS
(IMPLIES (AND (EQUAL (TIMES K X) (TIMES B A))
(EQUAL A (GCD (TIMES X A) (TIMES B A))))
(DIVIDES X A)).
.ENDASIS
Since (TIMES K X) is (TIMES B A) by hypothesis, we obtain, by substituting into
the other hypothesis, that A is equal to (GCD (TIMES X A) (TIMES K X)).
By the commutativity of TIMES and the DISTRIBUTIVITY.OF.TIMES.OVER.GCD,
we obtain that A is equal to (TIMES X (GCD A K)), which implies that
X divides A.
Finally, we turn to the proof of the second lemma we used, PRIME.GCD; since (GCD X B) divides X (because
of the lemma GCD.DIVIDES.BOTH) and since X is a PRIME by
hypothesis, then (GCD X B) must be X or 1. If (GCD X B)
were X, then X would divide B (since (GCD X B) divides both),
but this contradicts the hypotheses that (NOT (DIVIDES X B)).
So (GCD X B) must be 1.
.SSSS |The Unique Factorization|
Now that we have established the lemma PRIME.KEY, it is routine
work to obtain the uniqueness of the prime factorization.
First we establish the lemma that tells us that if the product
of a list of primes is divisible by a prime, then the prime is
a member of the list:
.ASIS
Theorem. PRIME.LIST.TIMES.LIST:
(IMPLIES (AND (PRIME C)
(PRIME.LIST L2)
(NOT (MEMBER C L2)))
(NOT (EQUAL (REMAINDER (TIMES.LIST L2) C)
0))).
.ENDASIS
It is here that we make use of our key theorem about primes,
PRIME.KEY.
The proof of PRIME.LIST.TIMES.LIST is by induction on the length
of the list L2. If C divides (TIMES.LIST L2), then by PRIME.KEY, C
divides (CAR L2) or C divides (TIMES.LIST (CDR L2)). If C divides
(CAR L2), then (since L2 is a list of primes), C
is (CAR L2). If C divides (TIMES.LIST (CDR L2)), then by
the inductive hypothesis, C is a member of the (CDR L2).
Given PRIME.LIST.TIMES.LIST, the unique factorization theorem:
.ASIS
Theorem. PRIME.FACTORIZATION.UNIQUENESS:
(IMPLIES (AND (PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2))
.ENDASIS
can be
proved by inducting according to the way that PERM
recurses. That is, in the inductive step, we assume
an instance of the theorem in which L1 is replaced
by (CDR L1) and L2 is replaced by (DELETE (CAR L1) L2).
If L1 and L2 are both nonempty lists of primes and
(TIMES.LIST L1) is equal to (TIMES.LIST L2), then we
wish to establish that L1 is a permutation of L2.
But (CAR L1)
divides (TIMES.LIST L2). By PRIME.LIST.TIMES.LIST, (CAR L1)
must be a member of L2. Thus we need establish only
that (CDR L1) is a permutation of (DELETE (CAR L1) L2). To do so, we
try to use our induction hypothesis. Clearly, (CDR L1) is a list
of primes. Further,
(DELETE (CAR L1) L2) is a list of primes, by the easily proved lemma:
.ASIS
Theorem. PRIME.LIST.DELETE:
(IMPLIES (PRIME.LIST L2)
(PRIME.LIST (DELETE X L2))).
.ENDASIS
Finally, (TIMES.LIST (CDR L1)) is equal to
(TIMES.LIST (DELETE (CAR L1) L2)) by the lemma:
.ASIS
Theorem. TIMES.LIST.DELETE:
(IMPLIES (AND (NOT (ZEROP C))
(MEMBER C L))
(EQUAL (TIMES.LIST (DELETE C L))
(QUOTIENT (TIMES.LIST L) C))).
.ENDASIS
Therefore, we can use the inductive hypothesis to
conclude that (CDR L2) is a permutation of (DELETE (CAR L1) L2).
Q.E.D.
We conclude by presenting the output of the theorem
prover for PRIME.FACTORIZATION.UNIQUENESS.
In the output, the lemma PRIME.LIST.TIMES.LIST
is not actually mentioned, but a mild reformulation
of it called PRIME.MEMBER is. Note that the proof generates an inductively
proved subgoal, namely, that if the product over
a list of primes is 1, then the list is empty. Prime
factorizations would not be unique if 1 were a prime.
.ASIS
Theorem. PRIME.FACTORIZATION.UNIQUENESS:
(IMPLIES (AND (PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2))
.ENDASIS
.ASIS8
Name the above subgoal *1.
Let us appeal to the induction principle. The
recursive terms in the conjecture suggest five inductions.
They merge into two likely candidate inductions. However,
only one is unflawed. We will induct according to the
following scheme:
(AND (IMPLIES (NOT (LISTP L1)) (p L1 L2))
(IMPLIES (AND (LISTP L1)
(p (CDR L1) (DELETE (CAR L1) L2)))
(p L1 L2))).
The inequality CDR.LESSP establishes that the measure
(COUNT L1) decreases according to the well-founded relation
LESSP in the induction step of the scheme. Note, however,
the inductive instance chosen for L2. The above induction
scheme leads to five new goals:
Case 1. (IMPLIES (AND (NOT (LISTP L1))
(PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2)),
which simplifies, opening up the functions PRIME.LIST,
TIMES.LIST and PERM, to:
(IMPLIES (AND (NOT (LISTP L1))
(PRIME.LIST L2)
(EQUAL 1 (TIMES.LIST L2)))
(NOT (LISTP L2))),
which has an irrelevant term in it. By eliminating this
term we get:
(IMPLIES (AND (PRIME.LIST L2)
(EQUAL 1 (TIMES.LIST L2)))
(NOT (LISTP L2))).
Name the above subgoal *1.1.
Case 2. (IMPLIES (AND (LISTP L1)
(NOT (PRIME.LIST (CDR L1)))
(PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2)),
which we simplify, opening up PRIME.LIST, to:
(TRUE).
Case 3. (IMPLIES
(AND (LISTP L1)
(NOT (PRIME.LIST (DELETE (CAR L1) L2)))
(PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2)),
which we simplify, using the lemma PRIME.LIST.DELETE, to:
(TRUE).
Case 4. (IMPLIES
(AND
(LISTP L1)
(NOT (EQUAL (TIMES.LIST (CDR L1))
(TIMES.LIST (DELETE (CAR L1) L2))))
(PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2)),
which we simplify, appealing to the lemma PRIME.MEMBER,
and expanding the definitions of PRIME.LIST, TIMES.LIST
and PERM, to the formula:
(IMPLIES
(AND
(LISTP L1)
(NOT (EQUAL (TIMES.LIST (CDR L1))
(TIMES.LIST (DELETE (CAR L1) L2))))
(NOT (EQUAL (CAR L1) 0))
(NUMBERP (CAR L1))
(NOT (EQUAL (CAR L1) 1))
(PRIME1 (CAR L1) (SUB1 (CAR L1)))
(PRIME.LIST (CDR L1))
(PRIME.LIST L2)
(EQUAL (TIMES (CAR L1) (TIMES.LIST (CDR L1)))
(TIMES.LIST L2)))
(PERM (CDR L1) (DELETE (CAR L1) L2))),
which again simplifies, applying the lemmas
TIMES.LIST.DELETE, PRIME.MEMBER and DIVIDES.IMPLIES.TIMES,
to:
(TRUE).
Case 5. (IMPLIES (AND (LISTP L1)
(PERM (CDR L1) (DELETE (CAR L1) L2))
(PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2)).
This simplifies, appealing to the lemma PRIME.MEMBER, and
expanding PRIME.LIST, TIMES.LIST and PERM, to:
(TRUE).
So we now return to:
(IMPLIES (AND (PRIME.LIST L2)
(EQUAL 1 (TIMES.LIST L2)))
(NOT (LISTP L2))),
which we named *1.1 above. Let us appeal to the induction
principle. Two inductions are suggested by terms in the
conjecture. However, they merge into one likely candidate
induction. We will induct according to the following
scheme:
(AND (IMPLIES (NOT (LISTP L2)) (p L2))
(IMPLIES (AND (LISTP L2) (p (CDR L2)))
(p L2))).
The inequality CDR.LESSP establishes that the measure
(COUNT L2) decreases according to the well-founded relation
LESSP in the induction step of the scheme. The above
induction scheme generates the following three new formulas:
Case 1. (IMPLIES (AND (NOT (PRIME.LIST (CDR L2)))
(PRIME.LIST L2)
(EQUAL 1 (TIMES.LIST L2)))
(NOT (LISTP L2))),
which simplifies, opening up the function PRIME.LIST, to:
(TRUE).
Case 2. (IMPLIES (AND (NOT (EQUAL 1 (TIMES.LIST (CDR L2))))
(PRIME.LIST L2)
(EQUAL 1 (TIMES.LIST L2)))
(NOT (LISTP L2))).
This simplifies, applying TIMES.EQUAL.1, and opening up
the definitions of PRIME.LIST and TIMES.LIST, to:
(IMPLIES (AND (NOT (EQUAL 1 (TIMES.LIST (CDR L2))))
(NOT (EQUAL (CAR L2) 0))
(NUMBERP (CAR L2))
(NOT (EQUAL (CAR L2) 1))
(PRIME1 (CAR L2) (SUB1 (CAR L2)))
(PRIME.LIST (CDR L2))
(NOT (EQUAL 0 (TIMES.LIST (CDR L2))))
(EQUAL 0 (SUB1 (CAR L2)))
(EQUAL 0
(SUB1 (TIMES.LIST (CDR L2)))))
(NOT (LISTP L2))),
which again simplifies, opening up the function PRIME1,
to:
(TRUE).
Case 3. (IMPLIES (AND (NOT (LISTP (CDR L2)))
(PRIME.LIST L2)
(EQUAL 1 (TIMES.LIST L2)))
(NOT (LISTP L2))),
which we simplify, applying the lemmas TIMES.EQUAL.1 and
SUB1.ADD1, and opening up the definitions of PRIME.LIST
and TIMES.LIST, to:
(IMPLIES (AND (NOT (LISTP (CDR L2)))
(NOT (EQUAL (CAR L2) 0))
(NUMBERP (CAR L2))
(NOT (EQUAL (CAR L2) 1))
(PRIME1 (CAR L2) (SUB1 (CAR L2)))
(EQUAL 0 (SUB1 (CAR L2))))
(NOT (LISTP L2))),
which again simplifies, expanding the function PRIME1, to:
(TRUE).
That finishes the proof of *1.1, which, consequently,
finishes the proof of *1. Q.E.D.
CPU time (devoted to theorem-proving):##94.717 seconds
.ENDASIS
.APPENDIX |DEFINITIONS ACCEPTED AND THEOREMS PROVED BY OUR SYSTEM|, APPTHMS:
Here is a complete list (as of May, 1978), in the order processed by
the system, of all our standard definitions and theorems.
Whenever we add a new proof technique or change an old one, we
make sure that the "improved" theorem prover can still prove all
these theorems. The current list contains 286 theorems and 110 definitions.
After each theorem or axiom
we list the user-supplied "types" (i.e., rewrite, elimination,
generalization, and induction). A theorem with no types
is proved but not made available for future use.
When the system begins processing the sequence, it knows only the axioms,
definitions, lemmas, and principles described in {YONSEC SECTHEFORMALTHEORY}.
.ASIS
1. Definition.
(NLISTP X)
=
(NOT (LISTP X))
2. Definition.
(APPEND X Y)
=
(IF (LISTP X)
(CONS (CAR X) (APPEND (CDR X) Y))
Y)
3. Definition.
(REVERSE X)
=
(IF (LISTP X)
(APPEND (REVERSE (CDR X))
(CONS (CAR X) "NIL"))
"NIL")
4. Definition.
(TIMES I J)
=
(IF (ZEROP I)
0
(PLUS J (TIMES (SUB1 I) J)))
5. Theorem. ASSOCIATIVITY.OF.APPEND (rewrite):
(EQUAL (APPEND (APPEND X Y) Z)
(APPEND X (APPEND Y Z)))
6. Definition.
(PLISTP X)
=
(IF (LISTP X)
(PLISTP (CDR X))
(EQUAL X "NIL"))
7. Theorem. APPEND.RIGHT.ID (rewrite):
(IMPLIES (PLISTP X)
(EQUAL (APPEND X "NIL") X))
8. Theorem. PLISTP.REVERSE (generalize and rewrite):
(PLISTP (REVERSE X))
9. Theorem. APPEND.REVERSE (rewrite):
(EQUAL (REVERSE (APPEND A B))
(APPEND (REVERSE B) (REVERSE A)))
10. Theorem. PLUS.RIGHT.ID (rewrite):
(EQUAL (PLUS X 0) (FIX X))
11. Theorem. PLUS.ADD1 (rewrite):
(EQUAL (PLUS X (ADD1 Y))
(IF (NUMBERP Y)
(ADD1 (PLUS X Y))
(ADD1 X)))
12. Theorem. COMMUTATIVITY2.OF.PLUS (rewrite):
(EQUAL (PLUS X (PLUS Y Z))
(PLUS Y (PLUS X Z)))
13. Theorem. COMMUTATIVITY.OF.PLUS (rewrite):
(EQUAL (PLUS X Y) (PLUS Y X))
14. Theorem. ASSOCIATIVITY.OF.PLUS (rewrite):
(EQUAL (PLUS (PLUS X Y) Z)
(PLUS X (PLUS Y Z)))
15. Theorem. TIMES.ZERO (rewrite):
(EQUAL (TIMES X 0) 0)
16. Theorem. DISTRIBUTIVITY.OF.TIMES.OVER.PLUS (rewrite):
(EQUAL (TIMES X (PLUS Y Z))
(PLUS (TIMES X Y) (TIMES X Z)))
17. Theorem. TIMES.ADD1 (rewrite):
(EQUAL (TIMES X (ADD1 Y))
(IF (NUMBERP Y)
(PLUS X (TIMES X Y))
(FIX X)))
18. Theorem. COMMUTATIVITY.OF.TIMES (rewrite):
(EQUAL (TIMES X Y) (TIMES Y X))
19. Theorem. COMMUTATIVITY2.OF.TIMES (rewrite):
(EQUAL (TIMES X (TIMES Y Z))
(TIMES Y (TIMES X Z)))
20. Theorem. ASSOCIATIVITY.OF.TIMES (rewrite):
(EQUAL (TIMES (TIMES X Y) Z)
(TIMES X (TIMES Y Z)))
21. Theorem. EQUAL.TIMES.0 (rewrite):
(EQUAL (EQUAL (TIMES X Y) 0)
(OR (ZEROP X) (ZEROP Y)))
22. Shell Definition.
Add the shell PUSH of two arguments with
recognizer STACKP,
accessors TOP and POP,
default values 0 and 0, and
well-founded relation TOP.POPP.
23. Undefined Function.
(APPLY FN X Y)
24. Undefined Function.
(GETVALUE VAR ENVRN)
25. Axiom. NUMBERP.APPLY (rewrite):
(NUMBERP (APPLY FN X Y))
26. Definition.
(FORMP X)
=
(IF (LISTP X)
(IF (LISTP (CAR X))
F
(IF (LISTP (CDR X))
(IF (LISTP (CDR (CDR X)))
(IF (FORMP (CAR (CDR X)))
(FORMP (CAR (CDR (CDR X))))
F)
F)
F))
T)
27. Definition.
(EVAL FORM ENVRN)
=
(IF (NUMBERP FORM)
FORM
(IF (LISTP (CDDR FORM))
(APPLY (CAR FORM)
(EVAL (CADR FORM) ENVRN)
(EVAL (CADDR FORM) ENVRN))
(GETVALUE FORM ENVRN)))
28. Definition.
(OPTIMIZE FORM)
=
(IF (LISTP (CDDR FORM))
(IF (NUMBERP (OPTIMIZE (CADR FORM)))
(IF (NUMBERP (OPTIMIZE (CADDR FORM)))
(APPLY (CAR FORM)
(OPTIMIZE (CADR FORM))
(OPTIMIZE (CADDR FORM)))
(CONS (CAR FORM)
(OPTIMIZE (CADR FORM))
(OPTIMIZE (CADDR FORM))
"NIL"))
(CONS (CAR FORM)
(OPTIMIZE (CADR FORM))
(OPTIMIZE (CADDR FORM))
"NIL"))
FORM)
29. Definition.
(CODEGEN FORM INS)
=
(IF (NUMBERP FORM)
(CONS (CONS "PUSHI" FORM "NIL") INS)
(IF (LISTP (CDDR FORM))
(CONS (CAR FORM)
(CODEGEN (CADDR FORM)
(CODEGEN (CADR FORM) INS)))
(CONS (CONS "PUSHV" FORM "NIL") INS)))
30. Definition.
(COMPILE FORM)
=
(REVERSE (CODEGEN (OPTIMIZE FORM) "NIL"))
31. Theorem. FORMP.OPTIMIZE (rewrite):
(IMPLIES (FORMP X)
(FORMP (OPTIMIZE X)))
32. Theorem. CORRECTNESS.OF.OPTIMIZE (rewrite):
(IMPLIES (FORMP X)
(EQUAL (EVAL (OPTIMIZE X) ENVRN)
(EVAL X ENVRN)))
33. Definition.
(EXEC PC PDS ENVRN)
=
(IF
(NLISTP PC)
PDS
(IF
(LISTP (CAR PC))
(IF
(EQUAL (CAR (CAR PC)) "PUSHI")
(EXEC (CDR PC)
(PUSH (CAR (CDR (CAR PC))) PDS)
ENVRN)
(EXEC (CDR PC)
(PUSH (GETVALUE (CAR (CDR (CAR PC))) ENVRN)
PDS)
ENVRN))
(EXEC (CDR PC)
(PUSH (APPLY (CAR PC)
(TOP (POP PDS))
(TOP PDS))
(POP (POP PDS)))
ENVRN)))
34. Theorem. SEQUENTIAL.EXECUTION (rewrite):
(EQUAL (EXEC (APPEND X Y) PDS ENVRN)
(EXEC Y (EXEC X PDS ENVRN) ENVRN))
35. Theorem. CORRECTNESS.OF.CODEGEN (rewrite):
(IMPLIES
(FORMP X)
(EQUAL (EXEC (REVERSE (CODEGEN X INS))
PDS ENVRN)
(PUSH (EVAL X ENVRN)
(EXEC (REVERSE INS) PDS ENVRN))))
36. Theorem. CORRECTNESS.OF.OPTIMIZING.COMPILER:
(IMPLIES (FORMP X)
(EQUAL (EXEC (COMPILE X) PDS ENVRN)
(PUSH (EVAL X ENVRN) PDS)))
37. Theorem. SUB1.LESSP1 (rewrite):
(IMPLIES (AND (NUMBERP X) (NOT (EQUAL X 0)))
(LESSP (SUB1 X) X))
38. Theorem. TRANSITIVITY.OF.LESSP (rewrite):
(IMPLIES (AND (NOT (LESSP X Z)) (LESSP Y Z))
(NOT (LESSP X Y)))
39. Theorem. TRANSITIVITY.OF.LESSP2 (rewrite):
(IMPLIES (AND (NOT (LESSP X Z)) (LESSP X Y))
(NOT (LESSP Y Z)))
40. Theorem. TRANSITIVITY.OF.LESSP3 (rewrite):
(IMPLIES (AND (LESSP Y Z) (LESSP X Y))
(LESSP X Z))
41. Theorem. TRANSITIVITY.OF.NOT.LESSP (rewrite):
(IMPLIES (AND (LESSP X Z) (NOT (LESSP Y Z)))
(LESSP X Y))
42. Theorem. TRANSITIVITY.OF.NOT.LESSP2 (rewrite):
(IMPLIES (AND (LESSP X Z) (NOT (LESSP X Y)))
(LESSP Y Z))
43. Theorem. TRANSITIVITY.OF.NOT.LESSP3 (rewrite):
(IMPLIES (AND (NOT (LESSP Y Z))
(NOT (LESSP X Y)))
(NOT (LESSP X Z)))
44. Theorem. LESSP.NOT.REFLEXIVE (rewrite):
(NOT (LESSP X X))
45. Definition.
(EQP X Y)
=
(EQUAL (FIX X) (FIX Y))
46. Theorem. LESSP.EQUAL (rewrite):
(IMPLIES (AND (NOT (EQP X Y))
(NOT (LESSP Y X)))
(LESSP X Y))
47. Theorem. REVERSE.REVERSE (rewrite):
(IMPLIES (PLISTP X)
(EQUAL (REVERSE (REVERSE X)) X))
48. Definition.
(FLATTEN X)
=
(IF (LISTP X)
(APPEND (FLATTEN (CAR X))
(FLATTEN (CDR X)))
(CONS X "NIL"))
49. Definition.
(MC.FLATTEN X Y)
=
(IF (LISTP X)
(MC.FLATTEN (CAR X)
(MC.FLATTEN (CDR X) Y))
(CONS X Y))
50. Theorem. FLATTEN.MC.FLATTEN (rewrite):
(EQUAL (MC.FLATTEN X Y)
(APPEND (FLATTEN X) Y))
51. Definition.
(MEMBER X L)
=
(IF (LISTP L)
(IF (EQUAL X (CAR L))
T
(MEMBER X (CDR L)))
F)
52. Theorem. MEMBER.APPEND (rewrite):
(IMPLIES (MEMBER A B)
(MEMBER A (APPEND B C)))
53. Theorem. MEMBER.APPEND2 (rewrite):
(IMPLIES (MEMBER A C)
(MEMBER A (APPEND B C)))
54. Theorem. MEMBER.REVERSE (rewrite):
(EQUAL (MEMBER X (REVERSE Y))
(MEMBER X Y))
55. Definition.
(LENGTH X)
=
(IF (LISTP X)
(ADD1 (LENGTH (CDR X)))
0)
56. Theorem. LENGTH.REVERSE (rewrite):
(EQUAL (LENGTH (REVERSE X))
(LENGTH X))
57. Definition.
(INTERSECT X Y)
=
(IF (LISTP X)
(IF (MEMBER (CAR X) Y)
(CONS (CAR X) (INTERSECT (CDR X) Y))
(INTERSECT (CDR X) Y))
"NIL")
58. Theorem. MEMBER-INTERSECT:
(IMPLIES (AND (MEMBER A B) (MEMBER A C))
(MEMBER A (INTERSECT B C)))
59. Definition.
(UNION X Y)
=
(IF (LISTP X)
(IF (MEMBER (CAR X) Y)
(UNION (CDR X) Y)
(CONS (CAR X) (UNION (CDR X) Y)))
Y)
60. Theorem. MEMBER.UNION:
(IMPLIES (OR (MEMBER A B) (MEMBER A C))
(MEMBER A (UNION B C)))
61. Definition.
(SUBSETP X Y)
=
(IF (LISTP X)
(IF (MEMBER (CAR X) Y)
(SUBSETP (CDR X) Y)
F)
T)
62. Theorem. SUBSETP.UNION:
(IMPLIES (SUBSETP A B)
(EQUAL (UNION A B) B))
63. Theorem. SUBSETP.INTERSECT:
(IMPLIES (AND (PLISTP A) (SUBSETP A B))
(EQUAL (INTERSECT A B) A))
64. Definition.
(NTH X N)
=
(IF (ZEROP N)
X
(NTH (CDR X) (SUB1 N)))
65. Theorem. NTH.MEMBER:
(IMPLIES (LISTP (NTH X N))
(MEMBER (CAR (NTH X N)) X))
66. Definition.
(GREATERP X Y)
=
(LESSP Y X)
67. Definition.
(LESSEQP X Y)
=
(NOT (LESSP Y X))
68. Definition.
(GREATEREQP X Y)
=
(NOT (LESSP X Y))
69. Theorem. TRANSITIVITY.OF.GREATERP:
(IMPLIES (AND (GREATERP X Y) (GREATERP Y Z))
(GREATERP X Z))
70. Theorem. TRANSITIVITY.OF.LESSEQP:
(IMPLIES (AND (LESSEQP X Y) (LESSEQP Y Z))
(LESSEQP X Z))
71. Theorem. TRICHOTOMY.OF.LESSP:
(OR (LESSP X Y)
(OR (EQP X Y) (LESSP Y X)))
72. Definition.
(ORDERED L)
=
(IF (LISTP L)
(IF (LISTP (CDR L))
(IF (LESSP (CAR (CDR L)) (CAR L))
F
(ORDERED (CDR L)))
T)
T)
73. Definition.
(ADDTOLIST X L)
=
(IF (LISTP L)
(IF (LESSP X (CAR L))
(CONS X L)
(CONS (CAR L) (ADDTOLIST X (CDR L))))
(CONS X "NIL"))
74. Definition.
(SORT L)
=
(IF (LISTP L)
(ADDTOLIST (CAR L) (SORT (CDR L)))
"NIL")
75. Theorem. LESSEQP.PLUS (rewrite):
(NOT (LESSP (PLUS X Y) X))
76. Theorem. LESSEQP.PLUS2 (rewrite):
(NOT (LESSP (PLUS X Y) Y))
77. Theorem. COMMUTATIVITY.OF.APPEND.WRT.LENGTH:
(EQUAL (LENGTH (APPEND A B))
(LENGTH (APPEND B A)))
78. Definition.
(LAST L)
=
(IF (LISTP L)
(IF (LISTP (CDR L)) (LAST (CDR L)) L)
L)
79. Definition.
(ASSOC X Y)
=
(IF (LISTP Y)
(IF (EQUAL X (CAR (CAR Y)))
(CAR Y)
(ASSOC X (CDR Y)))
"NIL")
80. Definition.
(PAIRLIST X Y)
=
(IF (LISTP X)
(IF (LISTP Y)
(CONS (CONS (CAR X) (CAR Y))
(PAIRLIST (CDR X) (CDR Y)))
"NIL")
"NIL")
81. Theorem. ASSOC.PAIRLIST (rewrite):
(IMPLIES (AND (NOT (LESSP (LENGTH C) (LENGTH B)))
(MEMBER A B))
(LISTP (ASSOC A (PAIRLIST B C))))
82. Definition.
(MAPCAR X FN)
=
(IF (LISTP X)
(CONS (APPLY FN (CAR X) "NIL")
(MAPCAR (CDR X) FN))
"NIL")
83. Theorem. MAPCAR.APPEND:
(EQUAL (MAPCAR (APPEND A B) FN)
(APPEND (MAPCAR A FN) (MAPCAR B FN)))
84. Theorem. LENGTH.MAPCAR:
(EQUAL (LENGTH (MAPCAR A FN))
(LENGTH A))
85. Theorem. REVERSE.MAPCAR:
(EQUAL (REVERSE (MAPCAR A FN))
(MAPCAR (REVERSE A) FN))
86. Definition.
(LIT X Y FN)
=
(IF (LISTP X)
(APPLY FN (CAR X) (LIT (CDR X) Y FN))
Y)
87. Theorem. LIT.APPEND (rewrite):
(EQUAL (LIT (APPEND A B) C FN)
(LIT A (LIT B C FN) FN))
88. Definition.
(BOOLEAN X)
=
(OR (EQUAL X T) (EQUAL X F))
89. Definition.
(IFF X Y)
=
(AND (IMPLIES X Y) (IMPLIES Y X))
90. Theorem. IFF.EQUAL.EQUAL:
(IMPLIES (AND (BOOLEAN P) (BOOLEAN Q))
(EQUAL (IFF P Q) (EQUAL P Q)))
91. Theorem. NTH.NIL (rewrite):
(EQUAL (NTH "NIL" I) "NIL")
92. Theorem. NTH.APPEND1:
(EQUAL (NTH A (PLUS I J))
(NTH (NTH A I) J))
93. Theorem. COMMUTATIVITY.OF.EQUAL:
(EQUAL (EQUAL A B) (EQUAL B A))
94. Theorem. TRANSITIVITY.OF.EQUAL:
(IMPLIES (AND (EQUAL A B) (EQUAL B C))
(EQUAL A C))
95. Theorem. ASSOCIATIVITY.OF.EQUAL:
(IMPLIES (AND (BOOLEAN A)
(AND (BOOLEAN B) (BOOLEAN C)))
(EQUAL (EQUAL (EQUAL A B) C)
(EQUAL A (EQUAL B C))))
96. Definition.
(ODD X)
=
(IF (ZEROP X)
F
(IF (ZEROP (SUB1 X))
T
(ODD (SUB1 (SUB1 X)))))
97. Definition.
(EVEN1 X)
=
(IF (ZEROP X) T (ODD (SUB1 X)))
98. Definition.
(EVEN2 X)
=
(IF (ZEROP X)
T
(IF (ZEROP (SUB1 X))
F
(EVEN2 (SUB1 (SUB1 X)))))
99. Definition.
(DOUBLE I)
=
(IF (ZEROP I)
0
(ADD1 (ADD1 (DOUBLE (SUB1 I)))))
100. Theorem. EVEN1.DOUBLE:
(EVEN1 (DOUBLE I))
101. Definition.
(HALF I)
=
(IF (ZEROP I)
0
(IF (ZEROP (SUB1 I))
0
(ADD1 (HALF (SUB1 (SUB1 I))))))
102. Theorem. HALF.DOUBLE:
(IMPLIES (NUMBERP I)
(EQUAL (HALF (DOUBLE I)) I))
103. Theorem. DOUBLE.HALF:
(IMPLIES (AND (NUMBERP I) (EVEN1 I))
(EQUAL (DOUBLE (HALF I)) I))
104. Theorem. DOUBLE.TIMES.2:
(EQUAL (DOUBLE I) (TIMES 2 I))
105. Theorem. SUBSETP.CONS (rewrite):
(IMPLIES (SUBSETP X Y)
(SUBSETP X (CONS Z Y)))
106. Theorem. LAST.APPEND (rewrite):
(EQUAL (LAST (APPEND A B))
(IF (LISTP B)
(LAST B)
(IF (LISTP A)
(CONS (CAR (LAST A)) B)
B)))
107. Theorem. LAST.REVERSE:
(IMPLIES (LISTP A)
(EQUAL (LAST (REVERSE A))
(CONS (CAR A) "NIL")))
108. Definition.
(EXP I J)
=
(IF (ZEROP J)
1
(TIMES I (EXP I (SUB1 J))))
109. Theorem. EXP.PLUS (rewrite):
(EQUAL (EXP I (PLUS J K))
(TIMES (EXP I J) (EXP I K)))
110. Theorem. EXP.TIMES (rewrite):
(EQUAL (EXP I (TIMES J K))
(EXP (EXP I J) K))
111. Theorem. EVEN1.EVEN2:
(EQUAL (EVEN1 X) (EVEN2 X))
112. Theorem. GREATERP.CONS:
(GREATERP (LENGTH (CONS A B))
(LENGTH B))
113. Theorem. DUPLICITY.OF.LESSEQP:
(OR (LESSEQP A B) (LESSEQP B A))
114. Theorem. LESSEQP.NTH:
(LESSEQP (LENGTH (NTH L I))
(LENGTH L))
115. Theorem. MEMBER.SORT:
(EQUAL (MEMBER A (SORT B))
(MEMBER A B))
116. Theorem. LENGTH.SORT:
(EQUAL (LENGTH (SORT A)) (LENGTH A))
117. Definition.
(COUNT.LIST A L)
=
(IF (LISTP L)
(IF (EQUAL A (CAR L))
(ADD1 (COUNT.LIST A (CDR L)))
(COUNT.LIST A (CDR L)))
0)
118. Theorem. COUNT.LIST.SORT:
(EQUAL (COUNT.LIST A (SORT L))
(COUNT.LIST A L))
119. Theorem. ORDERED.APPEND:
(IMPLIES (ORDERED (APPEND A B))
(ORDERED A))
120. Theorem. LESSEQP.HALF:
(LESSEQP (HALF I) I)
121. Definition.
(COPY A)
=
(IF (LISTP A)
(CONS (COPY (CAR A)) (COPY (CDR A)))
A)
122. Theorem. EQUAL.COPY:
(EQUAL (COPY A) A)
123. Definition.
(EQUALP X Y)
=
(IF (LISTP X)
(IF (LISTP Y)
(IF (EQUALP (CAR X) (CAR Y))
(EQUALP (CDR X) (CDR Y))
F)
F)
(EQUAL X Y))
124. Definition.
(NUMBER.LISTP L)
=
(IF (LISTP L)
(IF (NUMBERP (CAR L))
(NUMBER.LISTP (CDR L))
F)
(EQUAL L "NIL"))
125. Theorem. ORDERED.SORT (rewrite):
(ORDERED (SORT X))
126. Theorem. SORT.OF.ORDERED.NUMBER.LIST (rewrite):
(IMPLIES (AND (ORDERED X) (NUMBER.LISTP X))
(EQUAL (SORT X) X))
127. Definition.
(XOR P Q)
=
(IF Q (IF P F T) (EQUAL P T))
128. Theorem. SORT.ORDERED (rewrite):
(IMPLIES (NUMBER.LISTP L)
(EQUAL (EQUAL (SORT L) L)
(ORDERED L)))
129. Definition.
(SUBST X Y Z)
=
(IF (EQUAL Y Z)
X
(IF (LISTP Z)
(CONS (SUBST X Y (CAR Z))
(SUBST X Y (CDR Z)))
Z))
130. Theorem. SUBST.A.A:
(EQUAL (SUBST A A B) B)
131. Definition.
(OCCUR X Y)
=
(IF (EQUAL X Y)
T
(IF (LISTP Y)
(IF (OCCUR X (CAR Y))
T
(OCCUR X (CDR Y)))
F))
132. Theorem. MEMBER.OCCUR:
(IMPLIES (MEMBER A B) (OCCUR A B))
133. Theorem. OCCUR.SUBST:
(IMPLIES (NOT (OCCUR A B))
(EQUAL (SUBST C A B) B))
134. Theorem. COMMUTATIVITY.OF.EQUALP:
(EQUAL (EQUALP A B) (EQUALP B A))
135. Theorem. TRANSITIVITY.OF.EQUALP:
(IMPLIES (AND (EQUALP A B) (EQUALP B C))
(EQUALP A C))
136. Theorem. EQUAL.EQUALP (rewrite):
(EQUAL (EQUALP A B) (EQUAL A B))
137. Definition.
(SWAPTREE X)
=
(IF (LISTP X)
(CONS (SWAPTREE (CDR X))
(SWAPTREE (CAR X)))
X)
138. Theorem. SWAPTREE.SWAPTREE (rewrite):
(EQUAL (SWAPTREE (SWAPTREE X)) X)
139. Theorem. FLATTEN.SWAPTREE (rewrite):
(EQUAL (FLATTEN (SWAPTREE A))
(REVERSE (FLATTEN A)))
140. Definition.
(TIPCOUNT X)
=
(IF (LISTP X)
(PLUS (TIPCOUNT (CAR X))
(TIPCOUNT (CDR X)))
1)
141. Theorem. LENGTH.TIPCOUNT:
(EQUAL (LENGTH (FLATTEN A))
(TIPCOUNT A))
142. Definition.
(COUNTPS-LOOP L PRED ANS)
=
(IF (LISTP L)
(IF (APPLY PRED (CAR L) "NIL")
(COUNTPS-LOOP (CDR L) PRED (ADD1 ANS))
(COUNTPS-LOOP (CDR L) PRED ANS))
ANS)
143. Definition.
(COUNTPS- L PRED)
=
(COUNTPS-LOOP L PRED 0)
144. Definition.
(COUNTPS L PRED)
=
(IF (LISTP L)
(IF (APPLY PRED (CAR L) "NIL")
(ADD1 (COUNTPS (CDR L) PRED))
(COUNTPS (CDR L) PRED))
0)
145. Theorem. COUNTPS-COUNTPS (rewrite):
(IMPLIES (NUMBERP N)
(EQUAL (COUNTPS-LOOP L PRED N)
(PLUS N (COUNTPS L PRED))))
146. Definition.
(FACT I)
=
(IF (ZEROP I)
1
(TIMES I (FACT (SUB1 I))))
147. Definition.
(FACT-LOOP I ANS)
=
(IF (ZEROP I)
ANS
(FACT-LOOP (SUB1 I) (TIMES I ANS)))
148. Definition.
(FACT- I)
=
(FACT-LOOP I 1)
149. Theorem. FACT-LOOP.FACT (rewrite):
(IMPLIES (NUMBERP I)
(EQUAL (FACT-LOOP J I)
(TIMES I (FACT J))))
150. Theorem. FACT-FACT:
(EQUAL (FACT- I) (FACT I))
151. Definition.
(REVERSE-LOOP X ANS)
=
(IF (LISTP X)
(REVERSE-LOOP (CDR X)
(CONS (CAR X) ANS))
ANS)
152. Definition.
(REVERSE- X)
=
(REVERSE-LOOP X "NIL")
153. Theorem. REVERSE-LOOP.APPEND.REVERSE (rewrite):
(EQUAL (REVERSE-LOOP X Y)
(APPEND (REVERSE X) Y))
154. Theorem. REVERSE-REVERSE (rewrite):
(EQUAL (REVERSE-LOOP X "NIL")
(REVERSE X))
155. Theorem. REVERSE-APPEND:
(EQUAL (REVERSE- (APPEND A B))
(APPEND (REVERSE- B) (REVERSE- A)))
156. Theorem. REVERSE-REVERSE-:
(IMPLIES (PLISTP X)
(EQUAL (REVERSE- (REVERSE- X)) X))
157. Definition.
(PLUS- I J)
=
(IF (ZEROP I)
J
(PLUS- (SUB1 I) (ADD1 J)))
158. Theorem. PLUS-PLUS:
(IMPLIES (NUMBERP J)
(EQUAL (PLUS- I J) (PLUS I J)))
159. Definition.
(UNION- X Y)
=
(IF (LISTP X)
(IF (MEMBER (CAR X) Y)
(UNION- (CDR X) Y)
(UNION- (CDR X) (CONS (CAR X) Y)))
Y)
160. Definition.
(SORT-LP X Y)
=
(IF (LISTP X)
(SORT-LP (CDR X)
(ADDTOLIST (CAR X) Y))
Y)
161. Definition.
(SORT- X)
=
(SORT-LP X "NIL")
162. Theorem. MEMBER.UNION-:
(IMPLIES (MEMBER A C)
(MEMBER A (UNION- B C)))
163. Theorem. ORDERED.ADDTOLIST (rewrite):
(IMPLIES (ORDERED Y)
(ORDERED (ADDTOLIST X Y)))
164. Theorem. ORDERED.SORT-LP (rewrite):
(IMPLIES (ORDERED Y)
(ORDERED (SORT-LP X Y)))
165. Theorem. COUNT.SORT-LP (rewrite):
(EQUAL (COUNT.LIST Z (SORT-LP X Y))
(PLUS (COUNT.LIST Z X)
(COUNT.LIST Z Y)))
166. Theorem. APPEND.CANCELLATION (rewrite):
(EQUAL (EQUAL (APPEND A B) (APPEND A C))
(EQUAL B C))
167. Definition.
(DIFFERENCE I J)
=
(IF (ZEROP I)
0
(IF (ZEROP J)
I
(DIFFERENCE (SUB1 I) (SUB1 J))))
168. Theorem. COUNTING.UP.BY.1 (induction):
(IMPLIES (LESSP X Y)
(LESSP (DIFFERENCE Y (ADD1 X))
(DIFFERENCE Y X)))
169. Theorem. COUNTING.DOWN.BY.N+1 (rewrite):
(EQUAL (LESSP (DIFFERENCE I N) I)
(AND (NOT (ZEROP I)) (NOT (ZEROP N))))
170. Theorem. RECURSION.BY.DIFFERENCE (induction):
(IMPLIES (AND (NUMBERP I)
(NUMBERP N)
(NOT (EQUAL I 0))
(NOT (EQUAL N 0)))
(LESSP (DIFFERENCE I N) I))
171. Definition.
(QUOTIENT I J)
=
(IF (ZEROP J)
0
(IF (LESSP I J)
0
(ADD1 (QUOTIENT (DIFFERENCE I J) J))))
172. Definition.
(REMAINDER I J)
=
(IF (ZEROP J)
(FIX I)
(IF (LESSP I J)
(FIX I)
(REMAINDER (DIFFERENCE I J) J)))
173. Definition.
(POWER.EVAL L BASE)
=
(IF (LISTP L)
(PLUS (CAR L)
(TIMES BASE
(POWER.EVAL (CDR L) BASE)))
0)
174. Definition.
(BIG.PLUS1 L I BASE)
=
(IF
(LISTP L)
(IF (ZEROP I)
L
(CONS (REMAINDER (PLUS (CAR L) I) BASE)
(BIG.PLUS1 (CDR L)
(QUOTIENT (PLUS (CAR L) I) BASE)
BASE)))
(CONS I "NIL"))
175. Theorem. REMAINDER.QUOTIENT (rewrite):
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
(FIX X))
176. Theorem. POWER.EVAL.BIG.PLUS1 (rewrite):
(EQUAL (POWER.EVAL (BIG.PLUS1 L I BASE) BASE)
(PLUS (POWER.EVAL L BASE) I))
177. Definition.
(BIG.PLUS X Y I BASE)
=
(IF
(LISTP X)
(IF
(LISTP Y)
(CONS
(REMAINDER (PLUS I (PLUS (CAR X) (CAR Y)))
BASE)
(BIG.PLUS (CDR X)
(CDR Y)
(QUOTIENT (PLUS I (PLUS (CAR X) (CAR Y)))
BASE)
BASE))
(BIG.PLUS1 X I BASE))
(BIG.PLUS1 Y I BASE))
178. Theorem. POWER.EVAL.BIG.PLUS (rewrite):
(EQUAL (POWER.EVAL (BIG.PLUS X Y I BASE)
BASE)
(PLUS I
(PLUS (POWER.EVAL X BASE)
(POWER.EVAL Y BASE))))
179. Theorem. LESSP.DIFFERENCE1 (rewrite):
(NOT (LESSP X (DIFFERENCE X Y)))
180. Theorem. REMAINDER.WRT.1 (rewrite):
(EQUAL (REMAINDER Y 1) 0)
181. Theorem. REMAINDER.WRT.12 (rewrite):
(IMPLIES (NOT (NUMBERP X))
(EQUAL (REMAINDER Y X) (FIX Y)))
182. Theorem. LESSP.REMAINDER2 (rewrite and generalize):
(EQUAL (LESSP (REMAINDER X Y) Y)
(NOT (ZEROP Y)))
183. Theorem. LESSP.DIFFERENCE (rewrite):
(IMPLIES (NOT (LESSP Y X))
(EQUAL (DIFFERENCE X Y) 0))
184. Theorem. REMAINDER.X.X (rewrite):
(EQUAL (REMAINDER X X) 0)
185. Theorem. REMAINDER.QUOTIENT.ELIM (elimination):
(IMPLIES (AND (NOT (ZEROP Y)) (NUMBERP X))
(EQUAL (PLUS (REMAINDER X Y)
(TIMES Y (QUOTIENT X Y)))
X))
186. Theorem. PLUS.EQUAL.0 (rewrite):
(EQUAL (EQUAL (PLUS X Y) 0)
(AND (ZEROP X) (ZEROP Y)))
187. Theorem. PLUS.CANCELATION1 (rewrite):
(EQUAL (EQUAL (PLUS X Y) X)
(AND (NUMBERP X) (ZEROP Y)))
188. Theorem. LESSP.PLUS.TIMES (rewrite):
(IMPLIES (AND (NOT (ZEROP Z)) (NOT (ZEROP J)))
(LESSP X (PLUS Z (TIMES J X))))
189. Theorem. LESSP.QUOTIENT1 (rewrite):
(EQUAL (LESSP (QUOTIENT I J) I)
(AND (NOT (ZEROP I))
(OR (ZEROP J) (NOT (EQUAL J 1)))))
190. Theorem. LESSP.REMAINDER1 (rewrite):
(EQUAL (LESSP (REMAINDER X Y) X)
(AND (NOT (ZEROP Y))
(NOT (ZEROP X))
(NOT (LESSP X Y))))
191. Theorem. RECURSION.BY.QUOTIENT (induction):
(IMPLIES (AND (NUMBERP I)
(NOT (EQUAL I 0))
(NUMBERP J)
(NOT (EQUAL J 0))
(NOT (EQUAL J 1)))
(LESSP (QUOTIENT I J) I))
192. Definition.
(POWER.REP I BASE)
=
(IF
(ZEROP I)
"NIL"
(IF (ZEROP BASE)
(CONS I "NIL")
(IF (EQUAL BASE 1)
(CONS I "NIL")
(CONS (REMAINDER I BASE)
(POWER.REP (QUOTIENT I BASE) BASE)))))
193. Theorem. POWER.EVAL.POWER.REP (rewrite):
(EQUAL (POWER.EVAL (POWER.REP I BASE) BASE)
(FIX I))
194. Theorem. CORRECTNESS.OF.BIG.PLUS (rewrite):
(EQUAL (POWER.EVAL (BIG.PLUS (POWER.REP I BASE)
(POWER.REP J BASE)
0 BASE)
BASE)
(PLUS I J))
195. Definition.
(SGCD X Y I)
=
(IF (ZEROP I)
0
(IF (ZEROP (REMAINDER X I))
(IF (ZEROP (REMAINDER Y I))
I
(SGCD X Y (SUB1 I)))
(SGCD X Y (SUB1 I))))
196. Definition.
(GCD X Y)
=
(IF (ZEROP X)
(FIX Y)
(IF (ZEROP Y)
X
(IF (LESSP X Y)
(GCD X (DIFFERENCE Y X))
(GCD (DIFFERENCE X Y) Y))))
197. Theorem. LESSP.NOT.COMMUTATIVE (rewrite):
(IMPLIES (LESSP Y X)
(NOT (LESSP X Y)))
198. Theorem. COMMUTATIVITY.OF.GCD (rewrite):
(EQUAL (GCD X Y) (GCD Y X))
199. Theorem. SGCD.X.0.X (rewrite):
(EQUAL (SGCD X 0 X) (FIX X))
200. Theorem. SGCD.X.X.X (rewrite):
(EQUAL (SGCD X X X) (FIX X))
201. Theorem. COMMUTATIVITY.OF.SGCD (rewrite):
(EQUAL (SGCD X Y Z) (SGCD Y X Z))
202. Theorem. RECURSION.BY.REMAINDER (induction):
(IMPLIES (AND (NUMBERP Y)
(NOT (EQUAL Y 0))
(LESSP Y X))
(LESSP (REMAINDER X Y) X))
203. Definition.
(NTHCHAR N STR)
=
(CAR (NTH STR N))
204. Theorem. ELEMENT.APPEND:
(EQUAL (NTH A I)
(NTH (APPEND C A)
(PLUS I (LENGTH C))))
205. Theorem. NTH.APPEND (rewrite):
(EQUAL (NTH (APPEND A B) I)
(APPEND (NTH A I)
(NTH B (DIFFERENCE I (LENGTH A)))))
206. Theorem. PLUS.NEQUAL.X (rewrite):
(NOT (EQUAL (ADD1 (PLUS X Y)) X))
207. Theorem. NEQUAL.PLUS.ADD1 (rewrite):
(NOT (EQUAL (ADD1 (PLUS Y X)) X))
208. Theorem. DIFFERENCE.PLUS (rewrite):
(EQUAL (DIFFERENCE (PLUS X Y) X)
(FIX Y))
209. Theorem. PLUS.DIFFERENCE3 (rewrite):
(EQUAL (DIFFERENCE (PLUS X Y) (PLUS X Z))
(DIFFERENCE Y Z))
210. Theorem. TIMES.DIFFERENCE (rewrite):
(EQUAL (DIFFERENCE (TIMES C X) (TIMES W X))
(TIMES X (DIFFERENCE C W)))
211. Definition.
(DIVIDES X Y)
=
(ZEROP (REMAINDER Y X))
212. Theorem. DIVIDES.TIMES (rewrite):
(EQUAL (REMAINDER (TIMES X Z) Z) 0)
213. Theorem. DIFFERENCE.PLUS2 (rewrite):
(EQUAL (DIFFERENCE (PLUS B (PLUS A C)) A)
(PLUS B C))
214. Theorem. EQUAL.DIFFERENCE (rewrite):
(EQUAL (EQUAL X (DIFFERENCE Y K))
(IF (LESSP K Y)
(IF (NUMBERP X)
(IF (NUMBERP Y)
(EQUAL Y (PLUS X K))
(EQUAL X 0))
F)
(EQUAL X 0)))
215. Theorem. DIFFERENCE.ADD1.CANCELLATION (rewrite):
(EQUAL (DIFFERENCE (ADD1 (PLUS Y Z)) Z)
(ADD1 Y))
216. Theorem. REMAINDER.ADD1 (rewrite):
(IMPLIES (AND (NOT (ZEROP Y))
(NOT (EQUAL Y 1)))
(NOT (EQUAL (REMAINDER (ADD1 (TIMES X Y)) Y)
0)))
217. Theorem. DIVIDES.PLUS.REWRITE1 (rewrite):
(IMPLIES (AND (EQUAL (REMAINDER X Z) 0)
(EQUAL (REMAINDER Y Z) 0))
(EQUAL (REMAINDER (PLUS X Y) Z) 0))
218. Theorem. DIVIDES.PLUS.REWRITE2 (rewrite):
(IMPLIES (AND (EQUAL (REMAINDER X Z) 0)
(NOT (EQUAL (REMAINDER Y Z) 0)))
(NOT (EQUAL (REMAINDER (PLUS X Y) Z) 0)))
219. Theorem. DIVIDES.PLUS.REWRITE (rewrite):
(IMPLIES (EQUAL (REMAINDER X Z) 0)
(EQUAL (EQUAL (REMAINDER (PLUS X Y) Z) 0)
(EQUAL (REMAINDER Y Z) 0)))
220. Theorem. DIVIDES.PLUS.REWRITE.COMMUTED (rewrite):
(IMPLIES (EQUAL (REMAINDER X Z) 0)
(EQUAL (EQUAL (REMAINDER (PLUS Y X) Z) 0)
(EQUAL (REMAINDER Y Z) 0)))
221. Theorem. LESSP.DIFFERENCE2 (rewrite):
(EQUAL (EQUAL (DIFFERENCE X Y) 0)
(NOT (LESSP Y X)))
222. Theorem. DIFFERENCE.ELIM (elimination):
(IMPLIES (AND (NUMBERP Y) (LESSEQP X Y))
(EQUAL (PLUS X (DIFFERENCE Y X)) Y))
223. Theorem. LESSP.PLUS.CANCELLATION (rewrite):
(EQUAL (LESSP (PLUS X Y) (PLUS X Z))
(LESSP Y Z))
224. Theorem. LESSP.PLUS.CANCELATION2 (rewrite):
(EQUAL (LESSP (PLUS X Y) (PLUS Z X))
(LESSP Y Z))
225. Theorem. EUCLID (rewrite):
(IMPLIES (EQUAL (REMAINDER X Z) 0)
(EQUAL (EQUAL (REMAINDER (DIFFERENCE Y X) Z)
0)
(IF (LESSP X Y)
(EQUAL (REMAINDER Y Z) 0)
T)))
226. Theorem. LESSP.TIMES.CANCELLATION (rewrite):
(EQUAL (LESSP (TIMES X Z) (TIMES Y Z))
(AND (NOT (ZEROP Z)) (LESSP X Y)))
227. Theorem. DISTRIBUTIVITY.OF.TIMES.OVER.GCD (rewrite):
(EQUAL (GCD (TIMES X Z) (TIMES Y Z))
(TIMES Z (GCD X Y)))
228. Theorem. GCD.DIVIDES.BOTH (rewrite):
(AND (EQUAL (REMAINDER X (GCD X Y)) 0)
(EQUAL (REMAINDER Y (GCD X Y)) 0))
229. Theorem. GCD.IS.THE.GREATEST:
(IMPLIES (AND (NOT (ZEROP X))
(NOT (ZEROP Y))
(DIVIDES Z X)
(DIVIDES Z Y))
(LESSEQP Z (GCD X Y)))
230. Shell Definition.
Add the shell CONS.IF of three arguments with
recognizer IF.EXPRP,
accessors TEST, LEFT.BRANCH, and RIGHT.BRANCH,
default values "NIL", "NIL", and "NIL", and
well-founded relation TEST.LEFT.BRANCH.RIGHT.BRANCHP.
231. Definition.
(ASSIGNMENT VAR ALIST)
=
(IF (EQUAL VAR T)
T
(IF (EQUAL VAR F)
F
(IF (NLISTP ALIST)
F
(IF (EQUAL VAR (CAAR ALIST))
(CDAR ALIST)
(ASSIGNMENT VAR (CDR ALIST))))))
232. Definition.
(VALUE X ALIST)
=
(IF (IF.EXPRP X)
(IF (VALUE (TEST X) ALIST)
(VALUE (LEFT.BRANCH X) ALIST)
(VALUE (RIGHT.BRANCH X) ALIST))
(ASSIGNMENT X ALIST))
233. Definition.
(IF.DEPTH X)
=
(IF (IF.EXPRP X)
(ADD1 (IF.DEPTH (TEST X)))
0)
234. Theorem. IF.DEPTH.GOES.DOWN (induction):
(IMPLIES
(AND (IF.EXPRP X) (IF.EXPRP (TEST X)))
(LESSP (IF.DEPTH (CONS.IF (TEST (TEST X)) Y Z))
(IF.DEPTH X)))
235. Definition.
(IF.COMPLEXITY X)
=
(IF (IF.EXPRP X)
(TIMES (IF.COMPLEXITY (TEST X))
(PLUS (IF.COMPLEXITY (LEFT.BRANCH X))
(IF.COMPLEXITY (RIGHT.BRANCH X))))
1)
236. Theorem. IF.COMPLEXITY.NOT.0 (rewrite):
(NOT (EQUAL (IF.COMPLEXITY X) 0))
237. Theorem. LESSP.D.V (rewrite):
(IMPLIES (AND (NOT (ZEROP D))
(NOT (ZEROP V))
(NOT (ZEROP Z)))
(LESSP V
(PLUS (TIMES D V) (TIMES D Z))))
238. Theorem. IF.COMPLEXITY.GOES.DOWN1 (induction):
(IMPLIES (IF.EXPRP X)
(LESSP (IF.COMPLEXITY (LEFT.BRANCH X))
(IF.COMPLEXITY X)))
239. Theorem. IF.COMPLEXITY.GOES.DOWN2 (induction):
(IMPLIES (IF.EXPRP X)
(LESSP (IF.COMPLEXITY (RIGHT.BRANCH X))
(IF.COMPLEXITY X)))
240. Theorem. IF.COMPLEXITY.STAYS.EVEN (induction):
(IMPLIES
(AND (IF.EXPRP X) (IF.EXPRP (TEST X)))
(EQUAL
(IF.COMPLEXITY
(CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))))
(IF.COMPLEXITY X)))
241. Definition.
(NORMALIZE X)
=
(IF
(IF.EXPRP X)
(IF
(IF.EXPRP (TEST X))
(NORMALIZE (CONS.IF (TEST (TEST X))
(CONS.IF (LEFT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))
(CONS.IF (RIGHT.BRANCH (TEST X))
(LEFT.BRANCH X)
(RIGHT.BRANCH X))))
(CONS.IF (TEST X)
(NORMALIZE (LEFT.BRANCH X))
(NORMALIZE (RIGHT.BRANCH X))))
X)
242. Definition.
(NORMALIZED.IF.EXPRP X)
=
(IF (IF.EXPRP X)
(AND (NOT (IF.EXPRP (TEST X)))
(NORMALIZED.IF.EXPRP (LEFT.BRANCH X))
(NORMALIZED.IF.EXPRP (RIGHT.BRANCH X)))
T)
243. Definition.
(ASSIGNEDP VAR ALIST)
=
(IF (EQUAL VAR T)
T
(IF (EQUAL VAR F)
T
(IF (NLISTP ALIST)
F
(IF (EQUAL VAR (CAAR ALIST))
T
(ASSIGNEDP VAR (CDR ALIST))))))
244. Definition.
(ASSUME.TRUE VAR ALIST)
=
(CONS (CONS VAR T) ALIST)
245. Definition.
(ASSUME.FALSE VAR ALIST)
=
(CONS (CONS VAR F) ALIST)
246. Definition.
(TAUTOLOGYP X ALIST)
=
(IF
(IF.EXPRP X)
(IF (ASSIGNEDP (TEST X) ALIST)
(IF (ASSIGNMENT (TEST X) ALIST)
(TAUTOLOGYP (LEFT.BRANCH X) ALIST)
(TAUTOLOGYP (RIGHT.BRANCH X) ALIST))
(AND (TAUTOLOGYP (LEFT.BRANCH X)
(ASSUME.TRUE (TEST X) ALIST))
(TAUTOLOGYP (RIGHT.BRANCH X)
(ASSUME.FALSE (TEST X) ALIST))))
(ASSIGNMENT X ALIST))
247. Theorem. ASSIGNMENT.APPEND (rewrite):
(EQUAL (ASSIGNMENT X (APPEND A B))
(IF (ASSIGNEDP X A)
(ASSIGNMENT X A)
(ASSIGNMENT X B)))
248. Theorem. VALUE.CAN.IGNORE.REDUNDANT.ASSIGNMENTS (rewrite):
(AND
(IMPLIES (AND (IFF VAL (ASSIGNMENT VAR A))
(VALUE X A))
(VALUE X (CONS (CONS VAR VAL) A)))
(IMPLIES (AND (IFF VAL (ASSIGNMENT VAR A))
(NOT (VALUE X A)))
(NOT (VALUE X (CONS (CONS VAR VAL) A)))))
249. Theorem. VALUE.SHORT.CUT (rewrite):
(IMPLIES (AND (IF.EXPRP X)
(NORMALIZED.IF.EXPRP X))
(EQUAL (VALUE (TEST X) A)
(ASSIGNMENT (TEST X) A)))
250. Theorem. ASSIGNMENT.IMPLIES.ASSIGNEDP (rewrite):
(IMPLIES (ASSIGNMENT X A)
(ASSIGNEDP X A))
251. Theorem. TAUTOLOGYP.IS.SOUND (rewrite):
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(TAUTOLOGYP X A1))
(VALUE X (APPEND A1 A2)))
252. Definition.
(TAUTOLOGY.CHECKER X)
=
(TAUTOLOGYP (NORMALIZE X) "NIL")
253. Definition.
(FALSIFY1 X ALIST)
=
(IF (IF.EXPRP X)
(IF (ASSIGNEDP (TEST X) ALIST)
(IF (ASSIGNMENT (TEST X) ALIST)
(FALSIFY1 (LEFT.BRANCH X) ALIST)
(FALSIFY1 (RIGHT.BRANCH X) ALIST))
(IF (FALSIFY1 (LEFT.BRANCH X)
(ASSUME.TRUE (TEST X) ALIST))
(FALSIFY1 (LEFT.BRANCH X)
(ASSUME.TRUE (TEST X) ALIST))
(FALSIFY1 (RIGHT.BRANCH X)
(ASSUME.FALSE (TEST X) ALIST))))
(IF (ASSIGNEDP X ALIST)
(IF (ASSIGNMENT X ALIST) F ALIST)
(CONS (CONS X F) ALIST)))
254. Definition.
(FALSIFY X)
=
(FALSIFY1 (NORMALIZE X) "NIL")
255. Theorem. FALSIFY1.EXTENDS.MODELS (rewrite):
(IMPLIES (ASSIGNEDP X A)
(EQUAL (ASSIGNMENT X (FALSIFY1 Y A))
(IF (FALSIFY1 Y A)
(ASSIGNMENT X A)
(EQUAL X T))))
256. Theorem. FALSIFY1.FALSIFIES (rewrite):
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(FALSIFY1 X A))
(EQUAL (VALUE X (FALSIFY1 X A)) F))
257. Theorem. TAUTOLOGYP.FAILS.MEANS.FALSIFY1.WINS (rewrite):
(IMPLIES (AND (NORMALIZED.IF.EXPRP X)
(NOT (TAUTOLOGYP X A))
A)
(FALSIFY1 X A))
258. Theorem. NORMALIZE.IS.SOUND (rewrite):
(EQUAL (VALUE (NORMALIZE X) A)
(VALUE X A))
259. Theorem. NORMALIZE.NORMALIZES (rewrite):
(NORMALIZED.IF.EXPRP (NORMALIZE X))
260. Theorem. TAUTOLOGY.CHECKER.COMPLETENESS.BRIDGE (rewrite):
(IMPLIES (AND (EQUAL (VALUE Y (FALSIFY1 X A))
(VALUE X (FALSIFY1 X A)))
(FALSIFY1 X A)
(NORMALIZED.IF.EXPRP X))
(EQUAL (VALUE Y (FALSIFY1 X A)) F))
261. Theorem. TAUTOLOGY.CHECKER.IS.COMPLETE:
(IMPLIES (NOT (TAUTOLOGY.CHECKER X))
(EQUAL (VALUE X (FALSIFY X)) F))
262. Theorem. TAUTOLOGY.CHECKER.SOUNDNESS.BRIDGE (rewrite):
(IMPLIES (AND (TAUTOLOGYP Y A1)
(NORMALIZED.IF.EXPRP Y)
(EQUAL (VALUE X A2)
(VALUE Y (APPEND A1 A2))))
(VALUE X A2))
263. Theorem. TAUTOLOGY.CHECKER.IS.SOUND:
(IMPLIES (TAUTOLOGY.CHECKER X)
(VALUE X A))
264. Theorem. FLATTEN.SINGLETON (rewrite):
(EQUAL (EQUAL (FLATTEN X) (CONS Y "NIL"))
(AND (NLISTP X) (EQUAL X Y)))
265. Definition.
(LEFTCOUNT X)
=
(IF (NLISTP X)
0
(ADD1 (LEFTCOUNT (CAR X))))
266. Theorem. LEFTCOUNT.GOES.DOWN (induction):
(IMPLIES
(AND (LISTP X) (LISTP (CAR X)))
(LESSP (LEFTCOUNT (CONS (CAAR X)
(CONS (CDAR X) (CDR X))))
(LEFTCOUNT X)))
267. Definition.
(GOPHER X)
=
(IF (OR (NLISTP X) (NLISTP (CAR X)))
X
(GOPHER (CONS (CAAR X)
(CONS (CDAR X) (CDR X)))))
268. Theorem. GOPHER.PRESERVES.COUNT (induction):
(EQUAL (COUNT (GOPHER X)) (COUNT X))
269. Definition.
(SAMEFRINGE X Y)
=
(IF (OR (NLISTP X) (NLISTP Y))
(EQUAL X Y)
(AND (EQUAL (CAR (GOPHER X))
(CAR (GOPHER Y)))
(SAMEFRINGE (CDR (GOPHER X))
(CDR (GOPHER Y)))))
270. Theorem. LISTP.GOPHER (rewrite):
(EQUAL (LISTP (GOPHER X)) (LISTP X))
271. Theorem. GOPHER.RETURNS.LEFTMOST.ATOM (rewrite):
(EQUAL (CAR (GOPHER X))
(IF (LISTP X)
(CAR (FLATTEN X))
"NIL"))
272. Theorem. GOPHER.RETURNS.CORRECT.STATE (rewrite):
(EQUAL (FLATTEN (CDR (GOPHER X)))
(IF (LISTP X)
(CDR (FLATTEN X))
(CONS "NIL" "NIL")))
273. Theorem. CORRECTNESS.OF.SAMEFRINGE (rewrite):
(EQUAL (SAMEFRINGE X Y)
(EQUAL (FLATTEN X) (FLATTEN Y)))
274. Definition.
(PRIME1 X Y)
=
(IF (ZEROP Y)
F
(IF (EQUAL Y 1)
T
(AND (NOT (DIVIDES Y X))
(PRIME1 X (SUB1 Y)))))
275. Definition.
(PRIME X)
=
(AND (NOT (ZEROP X))
(NOT (EQUAL X 1))
(PRIME1 X (SUB1 X)))
276. Definition.
(GREATEST.FACTOR X Y)
=
(IF (OR (ZEROP Y) (EQUAL Y 1))
X
(IF (DIVIDES Y X)
Y
(GREATEST.FACTOR X (SUB1 Y))))
277. Definition.
(ID X)
=
(IF (ZEROP X) X (ADD1 (ID (SUB1 X))))
278. Theorem. LESSP.ID2 (rewrite):
(IMPLIES (NOT (LESSP X Y))
(NOT (LESSP X (ID Y))))
279. Theorem. GREATEST.FACTOR.LESSP (rewrite):
(IMPLIES (AND (LESSP Y (ID X))
(NOT (PRIME1 X Y))
(NOT (ZEROP X))
(NOT (EQUAL X 1))
(NOT (ZEROP Y)))
(LESSP (GREATEST.FACTOR X Y) X))
280. Theorem. GREATEST.FACTOR.DIVIDES (rewrite):
(IMPLIES (AND (LESSP Y (ID X))
(NOT (PRIME1 X Y))
(NOT (ZEROP X))
(NOT (EQUAL X 1))
(NOT (ZEROP Y)))
(EQUAL (REMAINDER X (GREATEST.FACTOR X Y))
0))
281. Theorem. LESSP.ID3 (rewrite):
(IMPLIES (LESSP X Y) (LESSP X (ID Y)))
282. Theorem. GREATEST.FACTOR.LESSP.IND (induction):
(IMPLIES (AND (LESSP Y X)
(NOT (PRIME1 X Y))
(NOT (ZEROP X))
(NOT (EQUAL X 1))
(NOT (ZEROP Y)))
(LESSP (COUNT (GREATEST.FACTOR X Y))
(COUNT X)))
283. Theorem. GREATEST.FACTOR.0 (rewrite):
(EQUAL (EQUAL (GREATEST.FACTOR X Y) 0)
(AND (OR (ZEROP Y) (EQUAL Y 1))
(EQUAL X 0)))
284. Theorem. GREATEST.FACTOR.1 (rewrite):
(EQUAL (EQUAL (GREATEST.FACTOR X Y) 1)
(EQUAL X 1))
285. Theorem. NUMBERP.GREATEST.FACTOR (rewrite):
(EQUAL (NUMBERP (GREATEST.FACTOR X Y))
(NOT (AND (OR (ZEROP Y) (EQUAL Y 1))
(NOT (NUMBERP X)))))
286. Definition.
(PRIME.FACTORS X)
=
(IF
(OR (ZEROP X) (EQUAL (SUB1 X) 0))
"NIL"
(IF
(PRIME1 X (SUB1 X))
(CONS X "NIL")
(APPEND
(PRIME.FACTORS (GREATEST.FACTOR X (SUB1 X)))
(PRIME.FACTORS
(QUOTIENT X
(GREATEST.FACTOR X (SUB1 X)))))))
287. Definition.
(PRIME.LIST L)
=
(IF (NLISTP L)
T
(AND (PRIME (CAR L))
(PRIME.LIST (CDR L))))
288. Definition.
(TIMES.LIST L)
=
(IF (NLISTP L)
1
(TIMES (CAR L) (TIMES.LIST (CDR L))))
289. Theorem. TIMES.LIST.APPEND (rewrite):
(EQUAL (TIMES.LIST (APPEND X Y))
(TIMES (TIMES.LIST X) (TIMES.LIST Y)))
290. Theorem. PRIME.LIST.APPEND (rewrite):
(EQUAL (PRIME.LIST (APPEND X Y))
(AND (PRIME.LIST X) (PRIME.LIST Y)))
291. Theorem. PRIME.LIST.PRIME.FACTORS (rewrite):
(PRIME.LIST (PRIME.FACTORS X))
292. Theorem. QUOTIENT.TIMES1 (rewrite):
(IMPLIES (AND (NUMBERP Y)
(NUMBERP X)
(NOT (EQUAL X 0))
(DIVIDES X Y))
(EQUAL (TIMES X (QUOTIENT Y X)) Y))
293. Theorem. QUOTIENT.LESSP (rewrite):
(IMPLIES (AND (NOT (ZEROP X)) (LESSP X Y))
(NOT (EQUAL (QUOTIENT Y X) 0)))
294. Theorem. ID.ADD1 (rewrite):
(EQUAL (ID (ADD1 X)) (ADD1 (ID X)))
295. Theorem. LESSP.ADD1.ID (rewrite):
(LESSP X (ADD1 (ID X)))
296. Theorem. ENOUGH.FACTORS (rewrite):
(IMPLIES (NOT (ZEROP X))
(EQUAL (TIMES.LIST (PRIME.FACTORS X))
X))
297. Theorem. PRIME.FACTORIZATION.EXISTENCE:
(IMPLIES (NOT (ZEROP X))
(AND (EQUAL (TIMES.LIST (PRIME.FACTORS X))
X)
(PRIME.LIST (PRIME.FACTORS X))))
298. Theorem. PRIME.KRUTCH (rewrite):
(IMPLIES (AND (LESSP X Z)
(NOT (EQUAL Z (ADD1 X))))
(NOT (LESSP Z (ADD1 X))))
299. Theorem. PRIME.BRIDGE (rewrite):
(IMPLIES
(AND (EQUAL (REMAINDER (ADD1 X) Z) 0)
(NOT (EQUAL Z (ADD1 X)))
(NOT (PRIME1 (ADD1 X)
(PLUS (DIFFERENCE X Z) Z))))
(NOT (PRIME1 (ADD1 X) X)))
300. Theorem. PRIME1.BASIC (rewrite):
(IMPLIES (AND (NOT (EQUAL Z 1))
(NOT (EQUAL Z (ADD1 X)))
(EQUAL (REMAINDER (ADD1 X) Z) 0))
(NOT (PRIME1 (ADD1 X) (PLUS Z L))))
301. Theorem. PRIME.BASIC (rewrite):
(IMPLIES (AND (NOT (EQUAL Z 1))
(NOT (EQUAL Z X))
(DIVIDES Z X))
(NOT (PRIME1 X (SUB1 X))))
302. Theorem. REMAINDER.GCD (rewrite):
(IMPLIES (EQUAL (GCD B X) Y)
(EQUAL (REMAINDER B Y) 0))
303. Theorem. REMAINDER.GCD.1 (rewrite):
(IMPLIES (NOT (EQUAL (REMAINDER B X) 0))
(NOT (EQUAL (GCD B X) X)))
304. Theorem. DIVIDES.TIMES1 (rewrite):
(IMPLIES (EQUAL A (TIMES Z Y))
(EQUAL (REMAINDER A Z) 0))
305. Theorem. TIMES.IDENTITY (rewrite):
(IMPLIES (EQUAL Y 1)
(EQUAL (EQUAL X (TIMES X Y))
(NUMBERP X)))
306. Theorem. KLUDGE.BRIDGE (rewrite):
(IMPLIES (EQUAL Y (TIMES K X))
(EQUAL (GCD Y (TIMES A X))
(TIMES X (GCD A K))))
307. Theorem. HACK1 (rewrite):
(IMPLIES (AND (NOT (DIVIDES X A))
(EQUAL A
(GCD (TIMES X A) (TIMES B A))))
(NOT (EQUAL (TIMES K X) (TIMES B A))))
308. Theorem. PRIME.GCD (rewrite):
(IMPLIES (AND (NOT (DIVIDES X B))
(PRIME1 X (SUB1 X)))
(EQUAL (EQUAL (GCD B X) 1) T))
309. Theorem. PRIME.KEY (rewrite):
(IMPLIES (AND (NUMBERP Z)
(PRIME X)
(NOT (DIVIDES X Z))
(NOT (DIVIDES X B)))
(NOT (EQUAL (TIMES X K) (TIMES B Z))))
310. Theorem. QUOTIENT.DIVIDES (rewrite):
(IMPLIES
(AND (NUMBERP Y)
(NOT (EQUAL (TIMES X (QUOTIENT Y X)) Y)))
(NOT (EQUAL (REMAINDER Y X) 0)))
311. Theorem. LITTLE.STEP (rewrite):
(IMPLIES (AND (PRIME X)
(NOT (EQUAL Y 1))
(NOT (EQUAL X Y)))
(NOT (EQUAL (REMAINDER X Y) 0)))
312. Definition.
(DELETE X L)
=
(IF (NLISTP L)
L
(IF (EQUAL X (CAR L))
(CDR L)
(CONS (CAR L) (DELETE X (CDR L)))))
313. Definition.
(PERM A B)
=
(IF (NLISTP A)
(NLISTP B)
(AND (MEMBER (CAR A) B)
(PERM (CDR A) (DELETE (CAR A) B))))
314. Theorem. REMAINDER.TIMES (rewrite):
(EQUAL (REMAINDER (TIMES Y X) Y) 0)
315. Theorem. PRIME.LIST.DELETE (rewrite):
(IMPLIES (PRIME.LIST L2)
(PRIME.LIST (DELETE X L2)))
316. Theorem. DIVIDES.TIMES.LIST (rewrite):
(IMPLIES (AND (NOT (ZEROP C)) (MEMBER C L))
(EQUAL (REMAINDER (TIMES.LIST L) C)
0))
317. Theorem. QUOTIENT.TIMES (rewrite):
(EQUAL (QUOTIENT (TIMES Y X) Y)
(IF (ZEROP Y) 0 (FIX X)))
318. Theorem. DISTRIBUTIVITY.OF.DIVIDES (rewrite):
(IMPLIES (AND (NOT (ZEROP A)) (DIVIDES A W))
(EQUAL (TIMES C (QUOTIENT W A))
(QUOTIENT (TIMES C W) A)))
319. Theorem. TIMES.LIST.DELETE (rewrite):
(IMPLIES (AND (NOT (ZEROP C)) (MEMBER C L))
(EQUAL (TIMES.LIST (DELETE C L))
(QUOTIENT (TIMES.LIST L) C)))
320. Theorem. PRIME.LIST.TIMES.LIST (rewrite):
(IMPLIES (AND (PRIME C)
(PRIME.LIST L2)
(NOT (MEMBER C L2)))
(NOT (EQUAL (REMAINDER (TIMES.LIST L2) C)
0)))
321. Theorem. IF.TIMES.THEN.DIVIDES (rewrite):
(IMPLIES (AND (NOT (ZEROP C))
(NOT (DIVIDES C X)))
(NOT (EQUAL (TIMES C Y) X)))
322. Theorem. PRIME.MEMBER (rewrite):
(IMPLIES (AND (PRIME C)
(PRIME.LIST L2)
(EQUAL (TIMES C (TIMES.LIST L1))
(TIMES.LIST L2)))
(MEMBER C L2))
323. Theorem. DIVIDES.IMPLIES.TIMES (rewrite):
(IMPLIES (AND (NOT (ZEROP A))
(NUMBERP C)
(EQUAL (TIMES A C) B))
(EQUAL (EQUAL C (QUOTIENT B A)) T))
324. Theorem. TIMES.EQUAL.1 (rewrite):
(EQUAL (EQUAL (TIMES A B) 1)
(AND (NOT (EQUAL A 0))
(NOT (EQUAL B 0))
(NUMBERP A)
(NUMBERP B)
(EQUAL (SUB1 A) 0)
(EQUAL (SUB1 B) 0)))
325. Theorem. PRIME.FACTORIZATION.UNIQUENESS:
(IMPLIES (AND (PRIME.LIST L1)
(PRIME.LIST L2)
(EQUAL (TIMES.LIST L1)
(TIMES.LIST L2)))
(PERM L1 L2))
326. Definition.
(MAXIMUM L)
=
(IF (NLISTP L)
0
(IF (LESSP (CAR L) (MAXIMUM (CDR L)))
(MAXIMUM (CDR L))
(CAR L)))
327. Theorem. MEMBER.MAXIMUM (rewrite):
(IMPLIES (LISTP X)
(MEMBER (MAXIMUM X) X))
328. Theorem. LESSP.DELETE.REWRITE (rewrite):
(EQUAL (LESSP (LENGTH (DELETE X L))
(LENGTH L))
(MEMBER X L))
329. Theorem. LESSP.LENGTH (induction):
(IMPLIES (LISTP L)
(LESSP (LENGTH (DELETE (MAXIMUM L) L))
(LENGTH L)))
330. Definition.
(ORDERED2 L)
=
(IF (LISTP L)
(IF (LISTP (CDR L))
(IF (LESSP (CAR L) (CADR L))
F
(ORDERED2 (CDR L)))
T)
T)
331. Definition.
(DSORT L)
=
(IF (NLISTP L)
"NIL"
(CONS (MAXIMUM L)
(DSORT (DELETE (MAXIMUM L) L))))
332. Definition.
(ADDTOLIST2 X L)
=
(IF (LISTP L)
(IF (LESSP X (CAR L))
(CONS (CAR L) (ADDTOLIST2 X (CDR L)))
(CONS X L))
(CONS X "NIL"))
333. Definition.
(SORT2 L)
=
(IF (NLISTP L)
"NIL"
(ADDTOLIST2 (CAR L) (SORT2 (CDR L))))
334. Theorem. SORT2.GEN.1 (rewrite):
(PLISTP (SORT2 X))
335. Theorem. SORT2.GEN.2 (rewrite):
(ORDERED2 (SORT2 X))
336. Theorem. SORT2.GEN (generalize):
(AND (PLISTP (SORT2 X))
(ORDERED2 (SORT2 X)))
337. Theorem. ADDTOLIST2.DELETE (rewrite):
(IMPLIES (AND (PLISTP Y)
(ORDERED2 Y)
(NOT (EQUAL X V)))
(EQUAL (ADDTOLIST2 V (DELETE X Y))
(DELETE X (ADDTOLIST2 V Y))))
338. Theorem. DELETE.ADDTOLIST2 (rewrite):
(IMPLIES (PLISTP Y)
(EQUAL (DELETE V (ADDTOLIST2 V Y)) Y))
339. Theorem. ADDTOLIST2.KLUDGE (rewrite):
(IMPLIES (AND (NOT (LESSP V W))
(EQUAL (ADDTOLIST2 V Y) (CONS V Y)))
(EQUAL (ADDTOLIST2 V (ADDTOLIST2 W Y))
(CONS V (ADDTOLIST2 W Y))))
340. Theorem. LESSP.MAXIMUM.ADDTOLIST2 (rewrite):
(IMPLIES (NOT (LESSP V (MAXIMUM Z)))
(EQUAL (ADDTOLIST2 V (SORT2 Z))
(CONS V (SORT2 Z))))
341. Theorem. SORT2.DELETE.CONS (rewrite):
(IMPLIES (LISTP X)
(EQUAL (CONS (MAXIMUM X)
(DELETE (MAXIMUM X) (SORT2 X)))
(SORT2 X)))
342. Theorem. SORT2.DELETE (rewrite):
(EQUAL (SORT2 (DELETE X L))
(DELETE X (SORT2 L)))
343. Theorem. DSORT.SORT2 (rewrite):
(EQUAL (DSORT X) (SORT2 X))
344. Theorem. COUNT.LIST.SORT2:
(EQUAL (COUNT.LIST A (SORT2 L))
(COUNT.LIST A L))
345. Theorem. LESSP.PLUS.SUB1 (rewrite):
(NOT (LESSP (PLUS Y Z) (SUB1 Z)))
346. Undefined Function.
(DECREMENTP X)
347. Undefined Function.
(MEASURE X)
348. Undefined Function.
(DECREMENT X)
349. Axiom. PK (induction):
(IMPLIES (NOT (DECREMENTP X))
(LESSP (MEASURE (DECREMENT X))
(MEASURE X)))
350. Undefined Function.
(FIDDLE X)
351. Definition.
(FIDDLE.DOWN X Y)
=
(IF (DECREMENTP X)
Y
(FIDDLE (FIDDLE.DOWN (DECREMENT X) Y)))
352. Definition.
(FIDDLE.DOWN.2 X Y)
=
(IF (DECREMENTP X)
Y
(FIDDLE.DOWN.2 (DECREMENT X)
(FIDDLE Y)))
353. Theorem. FIDDLE.EQUAL:
(EQUAL (FIDDLE.DOWN X Y)
(FIDDLE.DOWN.2 X Y))
354. Theorem. PLUS.CANCELLATION (rewrite):
(EQUAL (EQUAL (PLUS X Y) (PLUS X Z))
(EQP Y Z))
355. Definition.
(MATCH PAT STR)
=
(IF (LISTP PAT)
(IF (LISTP STR)
(IF (EQUAL (CAR PAT) (CAR STR))
(MATCH (CDR PAT) (CDR STR))
F)
F)
T)
356. Definition.
(STRPOS PAT STR)
=
(IF (MATCH PAT STR)
0
(IF (LISTP STR)
(ADD1 (STRPOS PAT (CDR STR)))
0))
357. Definition.
(DELTA1 CHAR PAT)
=
(STRPOS (CONS CHAR "NIL")
(REVERSE PAT))
358. Definition.
(TOP.ASSERT PAT STR I PATLEN STRLEN PAT* STR*)
=
(AND (EQUAL PAT PAT*)
(EQUAL STR STR*)
(EQUAL PATLEN (LENGTH PAT))
(LISTP PAT)
(EQUAL STRLEN (LENGTH STR))
(NUMBERP I)
(LESSEQP (SUB1 PATLEN) I)
(LESSP I
(PLUS PATLEN (STRPOS PAT STR))))
359. Definition.
(LOOP.ASSERT PAT STR I J PATLEN STRLEN NEXTI PAT* STR*)
=
(AND (TOP.ASSERT PAT STR
(SUB1 NEXTI)
PATLEN STRLEN PAT* STR*)
(NUMBERP I)
(NUMBERP J)
(NUMBERP NEXTI)
(LESSP J PATLEN)
(LESSP I STRLEN)
(EQUAL NEXTI
(PLUS PATLEN (DIFFERENCE I J)))
(LESSEQP NEXTI STRLEN)
(LESSEQP J I)
(MATCH (NTH PAT (ADD1 J))
(NTH STR (ADD1 I))))
360. Theorem. ZEROP.LENGTH (rewrite):
(EQUAL (EQUAL (LENGTH X) 0)
(NOT (LISTP X)))
361. Theorem. FSTRPOS.VC1:
(IMPLIES (EQUAL (LENGTH PAT*) 0)
(EQUAL 0 (STRPOS PAT* STR*)))
362. Theorem. SUB1.LESSP.PLUS (rewrite):
(EQUAL (LESSP (SUB1 X) (PLUS X Y))
(IF (ZEROP X) (NOT (ZEROP Y)) T))
363. Theorem. FSTRPOS.VC2:
(IMPLIES (NOT (EQUAL (LENGTH PAT*) 0))
(TOP.ASSERT PAT* STR*
(SUB1 (LENGTH PAT*))
(LENGTH PAT*)
(LENGTH STR*)
PAT* STR*))
364. Theorem. MATCH.LENGTHS (rewrite):
(IMPLIES (MATCH X Y)
(NOT (LESSP (LENGTH Y) (LENGTH X))))
365. Theorem. MATCH.LENGTHS1 (rewrite):
(IMPLIES (LESSP (LENGTH Y) (LENGTH X))
(NOT (MATCH X Y)))
366. Theorem. STRPOS.BOUNDARY.CONDITION (rewrite):
(IMPLIES (NOT (EQUAL (STRPOS PAT STR) (LENGTH STR)))
(NOT (LESSP (LENGTH STR)
(PLUS (LENGTH PAT)
(STRPOS PAT STR)))))
367. Theorem. FSTRPOS.VC3:
(IMPLIES (AND (GREATEREQP I STRLEN)
(TOP.ASSERT PAT STR I PATLEN STRLEN
PAT* STR*))
(EQUAL STRLEN (STRPOS PAT* STR*)))
368. Theorem. PLUS.DIFFERENCE.SUB1.REWRITE (rewrite):
(EQUAL (PLUS X (DIFFERENCE Y (SUB1 X)))
(IF (ZEROP X)
(FIX Y)
(IF (LESSP Y (SUB1 X))
(FIX X)
(ADD1 Y))))
369. Theorem. LISTP.NTH (rewrite):
(EQUAL (LISTP (NTH X I))
(LESSP I (LENGTH X)))
370. Theorem. CDR.NTH (rewrite):
(EQUAL (CDR (NTH X Y))
(NTH (CDR X) Y))
371. Theorem. STRPOS.EQUAL (rewrite):
(IMPLIES (AND (LESSP I (LENGTH STR))
(NOT (LESSP (STRPOS PAT STR) I))
(NUMBERP I)
(MATCH PAT (NTH STR I)))
(EQUAL (STRPOS PAT STR) I))
372. Theorem. VC4.HACK.1 (rewrite):
(IMPLIES (LESSP I (LENGTH STR))
(NOT (LESSP (SUB1 (LENGTH STR)) I)))
373. Theorem. FSTRPOS.VC4:
(IMPLIES (AND (NOT (GREATEREQP I STRLEN))
(TOP.ASSERT PAT STR I PATLEN STRLEN
PAT* STR*))
(LOOP.ASSERT PAT STR I
(SUB1 PATLEN)
PATLEN STRLEN
(ADD1 I)
PAT* STR*))
374. Theorem. SWAPPED.PLUS.CANCELLATION (rewrite):
(EQUAL (LESSP (PLUS B A) (PLUS A C))
(LESSP B C))
375. Theorem. LESSP.SUB1.PLUS.CANCELLATION (rewrite):
(EQUAL (LESSP (SUB1 (PLUS Y X)) (PLUS X Z))
(IF (ZEROP Y)
(IF (ZEROP X) (NOT (ZEROP Z)) T)
(LESSP (SUB1 Y) Z)))
376. Theorem. VC5.HACK1 (rewrite):
(IMPLIES (LESSP (SUB1 I) (STRPOS PAT STR))
(NOT (LESSP (STRPOS PAT STR) I)))
377. Theorem. FSTRPOS.VC5:
(IMPLIES (AND (EQUAL J 0)
(EQUAL (NTHCHAR I STR)
(NTHCHAR J PAT))
(LOOP.ASSERT PAT STR I J PATLEN STRLEN
NEXTI PAT* STR*))
(EQUAL I (STRPOS PAT* STR*)))
378. Theorem. FSTRPOS.VC6:
(IMPLIES (AND (NOT (EQUAL J 0))
(EQUAL (NTHCHAR I STR)
(NTHCHAR J PAT))
(LOOP.ASSERT PAT STR I J PATLEN STRLEN
NEXTI PAT* STR*))
(LOOP.ASSERT PAT STR
(SUB1 I)
(SUB1 J)
PATLEN STRLEN NEXTI PAT* STR*))
379. Theorem. STRPOS.LESSEQP.STRLEN (rewrite):
(NOT (LESSP (LENGTH STR) (STRPOS PAT STR)))
380. Theorem. LESSP.KLUDGE1 (rewrite):
(IMPLIES (NOT (LESSP B A))
(EQUAL (LESSP A (PLUS B C))
(IF (ZEROP C) (LESSP A B) T)))
381. Theorem. STRPOS.LIST.APPEND (rewrite):
(EQUAL (STRPOS (CONS C "NIL") (APPEND A B))
(IF (MEMBER C A)
(STRPOS (CONS C "NIL") A)
(PLUS (LENGTH A)
(STRPOS (CONS C "NIL") B))))
382. Theorem. STRPOS.LESSEQP.CRUTCH (rewrite):
(IMPLIES (NOT (LESSP (LENGTH Q) (LENGTH P)))
(NOT (LESSP (LENGTH Q) (STRPOS PAT P))))
383. Theorem. STRPOS.EQUAL.0 (rewrite):
(EQUAL (EQUAL (STRPOS PAT STR) 0)
(OR (NLISTP STR) (MATCH PAT STR)))
384. Theorem. LESSP.KLUDGE2 (rewrite):
(IMPLIES (LESSP I (LENGTH PAT))
(LESSP (SUB1 I)
(PLUS (LENGTH PAT) Z)))
385. Theorem. MATCH.IMPLIES.CAR.MEMBER (rewrite):
(IMPLIES (AND (LISTP PAT)
(NOT (MEMBER (CAR STR) PAT)))
(NOT (MATCH PAT STR)))
386. Theorem. MATCH.IMPLIES.CAR.MEMBER1 (rewrite):
(IMPLIES (AND (LISTP PAT) (MATCH PAT STR))
(MEMBER (CAR STR) PAT))
387. Theorem. MATCH.IMPLIES.MEMBER (rewrite):
(IMPLIES (AND (LESSP I (LENGTH PAT))
(MATCH PAT STR))
(MEMBER (CAR (NTH STR I)) PAT))
388. Theorem. DELTA1.LESSP.IFF.MEMBER (rewrite):
(EQUAL (LESSP (STRPOS (CONS CHAR "NIL")
(REVERSE PAT))
(LENGTH PAT))
(MEMBER CHAR PAT))
389. Theorem. LESSP.PLUS (rewrite):
(IMPLIES (NOT (LESSP X Z))
(NOT (LESSP (PLUS X Y) Z)))
390. Theorem. LESSP.PLUS1 (rewrite):
(IMPLIES (NOT (LESSP Y Z))
(NOT (LESSP (PLUS X Y) Z)))
391. Theorem. MATCH.IMPLIES.DELTA1.OK (rewrite):
(IMPLIES
(AND (MATCH PAT STR)
(LESSP I (LENGTH PAT)))
(LESSP (PLUS I
(STRPOS (CONS (CAR (NTH STR I)) "NIL")
(REVERSE PAT)))
(LENGTH PAT)))
392. Theorem. SUB1.LENGTH (rewrite):
(EQUAL (SUB1 (LENGTH X))
(LENGTH (CDR X)))
393. Theorem. DELTA1.LEMMA (rewrite):
(IMPLIES
(AND (LISTP PAT)
(LESSP I (LENGTH STR))
(LESSP I
(PLUS (LENGTH PAT) (STRPOS PAT STR))))
(LESSP (PLUS I
(STRPOS (CONS (CAR (NTH STR I)) "NIL")
(REVERSE PAT)))
(PLUS (LENGTH PAT) (STRPOS PAT STR))))
394. Theorem. MATCH.EPSILON (rewrite):
(IMPLIES (AND (LESSP J (LENGTH PAT))
(MATCH PAT STR))
(EQUAL (CAR (NTH PAT J))
(CAR (NTH STR J))))
395. Theorem. STRPOS.EPSILON (rewrite):
(IMPLIES
(AND (LESSP J (LENGTH PAT))
(LESSP (PLUS J (STRPOS PAT STR))
(LENGTH STR)))
(EQUAL (CAR (NTH STR (PLUS J (STRPOS PAT STR))))
(CAR (NTH PAT J))))
396. Theorem. EQ.CHARS.AT.STRPOS (rewrite):
(IMPLIES (AND (NOT (LESSP I J))
(NOT (EQUAL (CAR (NTH STR I))
(CAR (NTH PAT J))))
(LESSP I (LENGTH STR))
(LESSP J (LENGTH PAT)))
(NOT (EQUAL (STRPOS PAT STR)
(DIFFERENCE I J))))
397. Theorem. LESSP.DIFFERENCE.1 (rewrite):
(IMPLIES (LESSP I J)
(EQUAL (DIFFERENCE I J) 0))
398. Theorem. LESSP.SUB1.SUB1 (rewrite):
(EQUAL (LESSP (SUB1 (SUB1 X)) X)
(NOT (ZEROP X)))
399. Theorem. PLUS.2.NOT (rewrite):
(NOT (EQUAL (ADD1 (ADD1 (PLUS V Z))) V))
400. Theorem. LESSP.SUB1.SUB1.PLUS (rewrite):
(EQUAL (LESSP (SUB1 (SUB1 Y)) (PLUS Z Y))
(OR (NOT (ZEROP Z)) (NOT (ZEROP Y))))
401. Theorem. LESSP.KLUDGE3 (rewrite):
(EQUAL (LESSP (SUB1 (PLUS L (DIFFERENCE I J)))
I)
(IF (LESSP I J)
(LESSP (SUB1 L) I)
(IF (ZEROP L)
(NOT (ZEROP I))
(NOT (LESSP J L)))))
402. Theorem. GT.SUB1 (rewrite):
(NOT (LESSP (PLUS X Y) (SUB1 X)))
403. Theorem. LESSP.SUB1.HACK1 (rewrite):
(IMPLIES (AND (NOT (LESSP I J))
(NOT (EQUAL I J))
(NUMBERP J)
(NUMBERP I))
(NOT (LESSP (SUB1 I) J)))
404. Theorem. FSTRPOS.VC7:
(IMPLIES
(AND (NOT (EQUAL (NTHCHAR I STR)
(NTHCHAR J PAT)))
(LOOP.ASSERT PAT STR I J PATLEN STRLEN NEXTI
PAT* STR*))
(TOP.ASSERT PAT STR
(IF (LESSP (PLUS I (DELTA1 (NTHCHAR I STR) PAT))
NEXTI)
NEXTI
(PLUS I (DELTA1 (NTHCHAR I STR) PAT)))
PATLEN STRLEN PAT* STR*))
.ENDASIS
.APPENDIX |THE IMPLEMENTATION OF THE SHELL PRINCIPLE|, APPSHELL:
Below we give the axioms added by our theorem prover
in response to the user command:
.ASIS
add the shell const, of n arguments,
with (optionally, bottom object (btm),)
recognizer r,
accessors ac[&1], ..., ac[&n],
type restrictions tr[&1], ..., tr[&n], and
default values dv[&1], ..., dv[&n].
.ENDASIS
Our implementation of the shell principle differs from the formal
presentation in {YONSEC SECTHEFORMALTHEORY} in two ways. First,
we do not actually require (or allow) the user to specify the
name of a new well-founded relation to be defined for the class.
Instead, we axiomatize COUNT for the class and add the appropriate
induction lemmas, using COUNT and LESSP. In {YONSEC SECTHEFORMALTHEORY}
we justified
the introduction of COUNT and LESSP. The second difference between the formal
description and our implementation is that our implementation adds
lemmas that are more useful to the theorem prover than would be
the axioms noted in {YONSEC SECTHEFORMALTHEORY}. For example,
certain of the formal axioms are reformulated so that they are
more useful as rewrite rules. In all cases, the lemmas added by
our implementation follow immediately from the axioms given
in {YONSEC SECTHEFORMALTHEORY}.
Most of the axioms have names. We indicate the names schematically
below. For example, when the CONS shell is added, the schematic
name ac[&1].const denotes CAR.CONS.
After the name, we indicate in parentheses the "type" of
the axiom (e.g., rewrite, elimination, or induction). No generalization lemmas, per se,
are added by the shell mechanism; however, rewrite lemmas encoded as
type prescriptions may restrict generalizations of shell functions
since the generalization heuristic employs type sets.
.ASIS
Axiom. r.const (rewrite):
(r (const X1 ... Xn)).
Axiom. r.btm (rewrite):
(r (btm)).
Axiom. BOOLEAN.r (rewrite):
(OR (EQUAL (r X) T) (EQUAL (r X) F)).
For each i from 1 to n, let tr'[&i] be tr[&i] with all
occurrences of Xi replaced by (ac[&i] X), and add:
Axiom. TYPE.OF.ac[&i] (rewrite)
tr'[&i].
(Observe that all of the above axioms are stored as
type prescriptions.)
For each i from 1 to n, add:
Axiom. ac[&i].const (rewrite):
(EQUAL (ac[&i] (const X1 ... Xn))
(IF tr[&i] Xi dv[&i])).
Axiom. ac[&i].Nr (rewrite):
(IMPLIES (NOT (r X))
(EQUAL (ac[&i] X) dv[&i])).
Axiom. ac[&i].TYPE.RESTRICTION (rewrite):
(IMPLIES (NOT tr[&i])
(EQUAL (const X1 ... Xi ... Xn)
(const X1 ... dv[&i] ... Xn))).
Axiom. ac[&i].btm (rewrite):
(EQUAL (ac[&i] (btm)) dv[&i]).
Axiom. ac[&i].LESSP (induction):
(IMPLIES (AND (r X)
(NOT (EQUAL X (btm))))
(LESSP (COUNT (ac[&i] X)) (COUNT X))).
Let s be the substitution replacing X1 by Y1, ..., and
Xn by Yn, and let tr[&i]/s denote the result of applying s
to tr[&i]. Add:
Axiom. const.EQUAL (rewrite):
(EQUAL (EQUAL (const X1 ... Xn) (const Y1 ... Yn))
(AND (IF tr[&1]
(IF tr[&1]/s
(EQUAL X1 Y1)
(EQUAL X1 dv[&1]))
(IF tr[&1]/s
(EQUAL dv[&1] Y1)
T))
...
(IF tr[&n]
(IF tr[&n]/s
(EQUAL Xn Yn)
(EQUAL Xn dv[&n]))
(IF tr[&n]/s
(EQUAL dv[&n] Yn)
T)))).
Axiom. const.ac[&1]. ... .ac[&n] (rewrite):
(EQUAL (const (ac[&1] X) ... (ac[&n] X))
(IF (AND (r X)
(NOT (EQUAL X (btm))))
X
(const dv[&1] ... dv[&n]))).
Axiom. ac[&1]/ ... /ac[&n].ELIM (elimination):
(IMPLIES (AND (r X)
(NOT (EQUAL X (btm))))
(EQUAL (const (ac[&1] X) ... (ac[&n] X))
X)).
Axiom. COUNT.const (rewrite):
(EQUAL (COUNT (const X1 ... Xn))
(ADD1 (PLUS (IF tr[&1] (COUNT X1) 0)
...
(IF tr[&n] (COUNT Xn) 0)))).
Axiom. COUNT.btm (rewrite):
(EQUAL (COUNT (btm)) 0).
.ENDASIS
The handling of the special case in which no bottom object is supplied
should be obvious.
We simplify the right-hand sides of concluding equalities in rewrite
axioms by expanding nonrecursive functions (e.g., AND), putting
IF-expressions into IF-normal form, and simplifying
IF-expressions with explicit value tests (e.g., (IF T x y) is replaced by x).
The following axioms resulting from an application of the shell principle are
"wired-in" to the theorem prover.
.ASIS
(NOT (EQUAL (const X1 ... Xn) (btm))),
(NOT (r T)),
(NOT (r F)), and
(IMPLIES (r X) (NOT (r' X))).
.ENDASIS
The first of the above axioms is built into the rules for
rewriting an EQUAL expression given in {YONSEC SECREWRITESIMPLIFY}.
The other axioms above are built into the type set
mechanism.
.APPENDIX |CLAUSES FOR OUR THEORY|, APPCLAUSES:
Readers familiar with other mechanical theorem provers might be interested
in seeing our theory cast in the more usual clausal form. We
do not formulate our shell principle, induction principle, or definition
principle in clausal form.{FNOTE |It is interesting that the set theory of von Neumann, Bernays,
. and Goedel {REF GOEDEL} can be stated in a finite number of clauses.
. Thus, in principle, one could use a finitely axiomatized set theory with a resolution
. theorem prover to investigate problems normally requiring
. the axiom schemes (i.e., infinite axioms) of induction and comprehension.|}
However, we do give the clauses generated
by these principles on specific examples.
Here we give, in clausal form, axioms for T, F, IF, EQUAL, numbers, literal
atoms, and ordered pairs. These axioms, together with our induction principle,
definition principle, and the well-foundedness of LESSP and induced
lexicographic relations, are equivalent to the theory described
in {YONSEC SECTHEFORMALTHEORY}. We also exhibit the axioms of definition for
the functions used in the MC.FLATTEN example in {YONSEC SECOVERVIEW},
and we exhibit a clausal formulation of the first induction step used in
that example.
In the following clauses, we use a common notation for function
application and clauses {REF ROBINSON}. T, F, 0, and NIL
are
constants. X, Y, Z, P, Q, X1, X2, Y1, and Y2 are
variables.
.SS |Logical Definitions|
.ASIS
L1. $A{T/$M-1=F$A}
L2. $A{X/$M-1=Y EQUAL(X,Y)=T$A}
L3. $A{X=Y EQUAL(X,Y)=F$A}
L4. $A{X/$M-1=F IF(X,Y,Z)=Z$A}
L5. $A{X=F IF(X,Y,Z)=Y$A}
L6. $A{NOT(P)=IF(P,F,T)$A}
L7. $A{AND(P,Q)=IF(P,IF(Q,T,F),F))$A}
L8. $A{OR(P,Q)=IF(P,T,IF(Q,T,F))$A}
L9. $A{IMPLIES(P,Q)=IF(P,IF(Q,T,F),T)$A}
.ENDASIS
.SS |Axioms for Natural Numbers|
.ASIS
A1. $A{NUMBERP(ADD1(X1))=T}
A2. $A{NUMBERP(0)=T}
A3. $A{NUMBERP(X)=T NUMBERP(X)=F}
A4. $A{NUMBERP(SUB1(X))}
A5. $A{SUB1(ADD1(X1))=IF(NUMBERP(X1),X1,0)}
A6. $A{NUMBERP(X)=T SUB1(X)=0}
A7. $A{NUMBERP(X1)=T ADD1(X1)=ADD1(0)}
A8. $A{SUB1(0)=0}
A9. $A{NUMBERP(X)=F X=0 LESSP(COUNT(SUB1(X)),COUNT(X))=T}
A10. $A{EQUAL(ADD1(X1),ADD1(Y1))=
IF(NUMBERP(X1),
IF(NUMBERP(Y1),EQUAL(X1,Y1),EQUAL(X1,0)),
IF(NUMBERP(Y1),EQUAL(0,Y1),T))}
A11. $A{ADD1(SUB1(X))=IF(AND(NUMBERP(X),NOT(EQUAL(X,0))),X,ADD1(0))}
A12. $A{COUNT(ADD1(X1))=ADD1(IF(NUMBERP(X1),COUNT(X1),0))}
A13. $A{COUNT(0)=0}
A14. $A{0/$M-1=ADD1(X1)$A}
A15. $A{NUMBERP(T)=F$A}
A16. $A{NUMBERP(F)=F$A}
A17. $A{ZEROP(X)=OR(EQUAL(X,0),NOT(NUMBERP(X)))$A}
A18. $A{FIX(X)=IF(NUMBERP(X),X,0)$A}
A19. $A{LESSP(X,Y)=IF(ZEROP(Y),
F,
IF(ZEROP(X),T,LESSP(SUB1(X),SUB1(Y))))$A}
A19. $A{PLUS(X,Y)=IF(ZEROP(X),FIX(Y),ADD1(PLUS(SUB1(X),Y)))$A}
.ENDASIS
.SS |Axioms for Literal Atoms|
.ASIS
B1. $A{LITATOM(PACK(X1))=T}
B2. $A{LITATOM(NIL)=T}
B3. $A{LITATOM(X)=T LITATOM(X)=F}
B4. $A{UNPACK(PACK(X1))=X1}
B5. $A{LITATOM(X)=T UNPACK(X)=0}
B6. $A{UNPACK(NIL)=0}
B7. $A{LITATOM(X)=F X=NIL LESSP(COUNT(UNPACK(X)),COUNT(X))=T}
B8. $A{EQUAL(PACK(X1),PACK(Y1))=EQUAL(X1,Y1)}
B9. $A{PACK(UNPACK(X))=IF(AND(LITATOM(X),NOT(EQUAL(X,NIL))),X,PACK(0))}
B10. $A{COUNT(PACK(X1))=ADD1(COUNT(X1))}
B11. $A{COUNT(NIL)=0}
B12. $A{NIL/$M-1=PACK(X1)$A}
B13. $A{LITATOM(T)=F$A}
B14. $A{LITATOM(F)=F$A}
B15. $A{LITATOM(X)=F NUMBERP(X)=F$A}
.ENDASIS
.SS |Axioms for Ordered Pairs|
.ASIS
C1. $A{LISTP(CONS(X1,X2))=T}
C2. $A{LISTP(X)=T LISTP(X)=F}
C3. $A{CAR(CONS(X1,X2))=X1}
C4. $A{CDR(CONS(X1,X2))=X2}
C5. $A{LISTP(X)=T CAR(X)=NIL}
C6. $A{LISTP(X)=T CDR(X)=NIL}
C7. $A{LISTP(X)=F LESSP(COUNT(CAR(X)),COUNT(X))=T}
C8. $A{LISTP(X)=F LESSP(COUNT(CDR(X)),COUNT(X))=T}
C9. $A{EQUAL(CONS(X1,X2),CONS(Y1,Y2))=AND(EQUAL(X1,Y1),EQUAL(X2,Y2))}
C10. $A{CONS(CAR(X),CDR(X))=IF(LISTP(X),X,CONS(NIL,NIL))}
C11. $A{COUNT(CONS(X1,X2))=ADD1(PLUS(COUNT(X1),COUNT(X2)))}
C12. $A{LISTP(T)=F$A}
C13. $A{LISTP(F)=F$A}
C14. $A{LISTP(X)=F NUMBERP(X)=F$A}
C15. $A{LISTP(X)=F LITATOM(X)=F$A}
.ENDASIS
.SS |A Sample Theorem in Clausal Form|
To "define" APPEND, FLATTEN, and MC.FLATTEN for a resolution theorem
prover, one could add
the clauses:
.ASIS
$A{APPEND(X,Y)=IF(LISTP(X),CONS(CAR(X),APPEND(CDR(X),Y)),Y)$A},
$A{FLATTEN(X)=IF(LISTP(X),APPEND(FLATTEN(CAR(X)),FLATTEN(CDR(X))),
CONS(X,NIL))$A},
$A{MC.FLATTEN(X,Y)=IF(LISTP(X),MC.FLATTEN(CAR(X),MC.FLATTEN(CDR(X),Y)),
CONS(X,Y))$A}.
.ENDASIS
When our theorem prover is given the definitions of APPEND, FLATTEN,
and MC.FLATTEN, it discovers and remembers the following theorems:
.ASIS
$A{LISTP(APPEND(X,Y))=T APPEND(X,Y)=Y$A},
$A{LISTP(FLATTEN(X))=T$A},
$A{LISTP(MC.FLATTEN(X))=T$A}.
.ENDASIS
One could, in principle, use a resolution theorem prover to help perform
the noninductive parts of our proofs. For example, one might
ask such a theorem prover to undertake the first
inductive step of the FLATTEN.MC.FLATTEN
example of {YONSEC SECOVERVIEW}. One might therefore provide such a theorem
prover with all the foregoing clauses of this appendix and then, letting A and ANS
be constants, attempt to derive a contradiction from:
.ASIS
$A{LISTP(A)=T$A},
$A{MC.FLATTEN(CAR(A),MC.FLATTEN(CDR(A),ANS)),
=APPEND(FLATTEN(CAR(A)),MC.FLATTEN(CDR(A),ANS))$A},
$A{MC.FLATTEN(CDR(A),ANS)=APPEND(FLATTEN(CDR(A)),ANS)$A}, and
$A{MC.FLATTEN(A,ANS)/$M-1=APPEND(FLATTEN(A),ANS)$A}.
.ENDASIS
Of course, the imagined resolution theorem prover would probably fail to find
a contradiction, because we know of no proof that does not depend
upon the associativity of APPEND. While our theorem prover discovered
and inductively proved that APPEND is associative in the course of
the FLATTEN.MC.FLATTEN proof, one would need to add the clause:
.ASIS
$A{APPEND(APPEND(X,Y),Z)=APPEND(X,APPEND(Y,Z))$A}
.ENDASIS
to the previous collection of clauses before a resolution theorem
prover might be expected to derive a contradiction.
.APPENDIX |INDEX|, APPINDEX:
In this index a number indicates the page on which a concept
is introduced, a number preceded by "A-" indicates the
number of the defining formula in Appendix A, and a shell
name (e.g., ADD1) indicates that the indexed name is
introduced as a result of axiomatizing the shell. The
naming conventions for shell axioms are given in Appendix B.
.ASIS
accessor ??
ACK ??
ADD1 ??
ADD1.EQUAL ADD1
ADD1.SUB1 ADD1
ADDTOLIST A-73
ADDTOLIST2 A-332
ADDTOLIST2.DELETE A-337
ADDTOLIST2.KLUDGE A-339
alist ??
Allen ??
AND ??
APPEND A-2
APPEND.CANCELLATION A-166
APPEND.REVERSE A-9
APPEND.RIGHT.ID A-7
applies ??
APPLY A-23
ASSIGNEDP A-243
ASSIGNMENT A-231
assignment ??
ASSIGNMENT.APPEND A-247
ASSIGNMENT.IMPLIES.ASSIGNEDP A-250
ASSOC A-79
ASSOC.PAIRLIST A-81
association list ??
ASSOCIATIVITY.OF.APPEND A-5
ASSOCIATIVITY.OF.EQUAL A-95
ASSOCIATIVITY.OF.PLUS A-14
ASSOCIATIVITY.OF.TIMES A-20
ASSUME.FALSE A-245
ASSUME.TRUE A-244
atom ??
atomic ??
Aubin ??
backwards chaining ??
Ballantyne ??
Bendix ??
BIG.PLUS A-177
BIG.PLUS1 A-174
binding ??
Bledsoe ??
body ??
BOOLEAN A-88
Boolean ??
bottom object ??
bound ??
Bourbaki ??
Brotz ??
Burstall ??
CAAR ??
CADDR ??
CADR ??
call of ??
CAR CONS
CAR.CDRP CONS
CAR.CONS CONS
CAR.LESSP CONS
CAR/CDR.ELIM CONS
Cartwright ??
CDAR ??
CDDR ??
CDR CONS
CDR.CONS CONS
CDR.LESSP CONS
CDR.NLISTP CONS
CDR.NTH A-370
Chang ??
changeables ??
changing variables ??
character string ??
Church ??
clause ??
closed ??
CODEGEN A-29
COMMUTATIVITY.OF.APPEND.WRT.LENGTH A-77
COMMUTATIVITY.OF.EQUAL A-93
COMMUTATIVITY.OF.EQUALP A-134
COMMUTATIVITY.OF.GCD A-198
COMMUTATIVITY.OF.PLUS A-13
COMMUTATIVITY.OF.SGCD A-201
COMMUTATIVITY.OF.TIMES A-18
COMMUTATIVITY2.OF.PLUS A-12
COMMUTATIVITY2.OF.TIMES A-19
COMPILE A-30
CONS ??
CONS.EQUAL CONS
CONS.IF A-230
constructor ??
COPY A-121
CORRECTNESS.OF.BIG.PLUS A-194
CORRECTNESS.OF.CODEGEN A-35
CORRECTNESS.OF.OPTIMIZE A-32
CORRECTNESS.OF.OPTIMIZING.COMPILER A-36
CORRECTNESS.OF.SAMEFRINGE A-273
COUNT ??
COUNT.LIST A-117
COUNT.LIST.SORT A-118
COUNT.LIST.SORT2 A-344
COUNT.SORT-LP A-165
COUNT1 ??
COUNTING.DOWN.BY.N+1 A-169
COUNTING.UP.BY.1 A-168
COUNTPS A-144
COUNTPS- A-143
COUNTPS-COUNTPS A-145
COUNTPS-LOOP A-142
cross-fertilization ??
Darlington ??
DEC ??
DECREMENT A-348
DECREMENTP A-346
default value ??
definition ??
definition type set ??
DELETE A-312
DELETE.ADDTOLIST2 A-338
DELTA1 A-357
delta1 ??
DELTA1.LEMMA A-393
DELTA1.LESSP.IFF.MEMBER A-388
destructor ??
DIFFERENCE A-167
DIFFERENCE.ADD1.CANCELLATION A-215
DIFFERENCE.ELIM A-222
DIFFERENCE.PLUS A-208
DIFFERENCE.PLUS2 A-213
DISTRIBUTIVITY.OF.DIVIDES A-318
DISTRIBUTIVITY.OF.TIMES.OVER.GCD A-227
DISTRIBUTIVITY.OF.TIMES.OVER.PLUS A-16
DIVIDES A-211
DIVIDES.IMPLIES.TIMES A-323
DIVIDES.PLUS.REWRITE A-219
DIVIDES.PLUS.REWRITE.COMMUTED A-220
DIVIDES.PLUS.REWRITE1 A-217
DIVIDES.PLUS.REWRITE2 A-218
DIVIDES.TIMES A-212
DIVIDES.TIMES.LIST A-316
DIVIDES.TIMES1 A-304
DOUBLE A-99
DOUBLE.HALF A-103
DOUBLE.TIMES.2 A-104
DSORT A-331
DSORT.SORT2 A-343
DUPLICITY.OF.LESSEQP A-113
elaboration ??
ELEMENT.APPEND A-204
elimination ??
ENOUGH.FACTORS A-296
EQ.CHARS.AT.STRPOS A-396
EQP A-45
EQUAL ??
EQUAL.COPY A-122
EQUAL.DIFFERENCE A-214
EQUAL.EQUALP A-136
EQUAL.TIMES.0 A-21
EQUALP A-123
EUCLID A-225
EVAL A-27
EVEN1 A-97
EVEN1.DOUBLE A-100
EVEN1.EVEN2 A-111
EVEN2 A-98
EXEC A-33
EXP A-108
EXP.PLUS A-109
EXP.TIMES A-110
explicit value ??
explicit value preserving ??
explicit value template ??
extension ??
F ??
f-free ??
FACT A-146
FACT- A-148
FACT-FACT A-150
FACT-LOOP A-147
FACT-LOOP.FACT A-149
FALSE ??
FALSIFY A-254
FALSIFY1 A-253
FALSIFY1.EXTENDS.MODELS A-255
FALSIFY1.FALSIFIES A-256
FIDDLE A-350
FIDDLE.DOWN A-351
FIDDLE.DOWN.2 A-352
FIDDLE.EQUAL A-353
FIX ??
FLATTEN A-48
FLATTEN.MC.FLATTEN A-50
FLATTEN.SINGLETON A-264
FLATTEN.SWAPTREE A-139
flawed ??
Floyd ??
FORMP A-26
FORMP.OPTIMIZE A-31
free variable ??
fringe ??
FSTRPOS ??
FSTRPOS.VC1 A-361
FSTRPOS.VC2 A-363
FSTRPOS.VC3 A-367
FSTRPOS.VC4 A-373
FSTRPOS.VC5 A-377
FSTRPOS.VC6 A-378
FSTRPOS.VC7 A-404
functional semantics ??
GCD A-196
GCD.DIVIDES.BOTH A-228
GCD.IS.THE.GREATEST A-229
general recursive ??
generalizable ??
Gentzen ??
GETVALUE A-24
Gloess ??
Goedel ??
Goodstein ??
GOPHER A-267
GOPHER.PRESERVES.COUNT A-268
GOPHER.RETURNS.CORRECT.STATE A-272
GOPHER.RETURNS.LEFTMOST.ATOM A-271
governs ??
GREATEREQP A-68
GREATERP A-66
GREATERP.CONS A-112
GREATEST.FACTOR A-276
GREATEST.FACTOR.0 A-283
GREATEST.FACTOR.1 A-284
GREATEST.FACTOR.DIVIDES A-280
GREATEST.FACTOR.LESSP A-279
GREATEST.FACTOR.LESSP.IND A-282
GT.SUB1 A-402
Guibas ??
HACK1 A-307
HALF A-101
HALF.DOUBLE A-102
Henneman ??
Hoare ??
ID A-277
ID.ADD1 A-294
IF ??
IF-normal form ??
IF.COMPLEXITY A-235
IF.COMPLEXITY.GOES.DOWN1 A-238
IF.COMPLEXITY.GOES.DOWN2 A-239
IF.COMPLEXITY.NOT.0 A-236
IF.COMPLEXITY.STAYS.EVEN A-240
IF.DEPTH A-233
IF.DEPTH.GOES.DOWN A-234
IF.EXPRP CONS.IF
IF.TIMES.THEN.DIVIDES A-321
IFF A-89
IFF.EQUAL.EQUAL A-90
IMPLIES ??
induced ??
induction ??
induction template ??
inductive assertion ??
instance ??
INTERLISP ??
INTERSECT A-57
Kelley ??
KLUDGE.BRIDGE A-306
Knuth ??
Lankford ??
LAST A-78
LAST.APPEND A-106
LAST.REVERSE A-107
Lee ??
left-most match ??
LEFT.BRANCH CONS.IF
LEFT.BRANCH.CONS.IF CONS.IF
LEFT.BRANCH.LESSP CONS.IF
LEFTCOUNT A-265
LEFTCOUNT.GOES.DOWN A-266
LENGTH A-55
LENGTH.MAPCAR A-84
LENGTH.REVERSE A-56
LENGTH.SORT A-116
LENGTH.TIPCOUNT A-141
LESSEQP A-67
LESSEQP.HALF A-120
LESSEQP.NTH A-114
LESSEQP.PLUS A-75
LESSEQP.PLUS2 A-76
LESSP ??
LESSP.ADD1.ID A-295
LESSP.D.V A-237
LESSP.DELETE.REWRITE A-328
LESSP.DIFFERENCE A-183
LESSP.DIFFERENCE.1 A-397
LESSP.DIFFERENCE1 A-179
LESSP.DIFFERENCE2 A-221
LESSP.EQUAL A-46
LESSP.ID2 A-278
LESSP.ID3 A-281
LESSP.KLUDGE1 A-380
LESSP.KLUDGE2 A-384
LESSP.KLUDGE3 A-401
LESSP.LENGTH A-329
LESSP.MAXIMUM.ADDTOLIST2 A-340
LESSP.NOT.COMMUTATIVE A-197
LESSP.NOT.REFLEXIVE A-44
LESSP.PLUS A-389
LESSP.PLUS.CANCELATION2 A-224
LESSP.PLUS.CANCELLATION A-223
LESSP.PLUS.SUB1 A-345
LESSP.PLUS.TIMES A-188
LESSP.PLUS1 A-390
LESSP.QUOTIENT1 A-189
LESSP.REMAINDER1 A-190
LESSP.REMAINDER2 A-182
LESSP.SUB1.HACK1 A-403
LESSP.SUB1.PLUS.CANCELLATION A-375
LESSP.SUB1.SUB1 A-398
LESSP.SUB1.SUB1.PLUS A-400
LESSP.TIMES.CANCELLATION A-226
Levitt ??
lexicographic ??
lexicographic relation ??
LISP ??
LISTP CONS
LISTP.CONS CONS
LISTP.GOPHER A-270
LISTP.NTH A-369
lists ??
LIT A-86
LIT.APPEND A-87
LITATOM PACK
literal ??
literal atoms ??
LITTLE.STEP A-311
LOOP.ASSERT A-359
Loveland ??
machine ??
MACRO-10 ??
Manna ??
MAPCAR A-82
MAPCAR.APPEND A-83
MATCH A-355
MATCH.EPSILON A-394
MATCH.IMPLIES.CAR.MEMBER A-385
MATCH.IMPLIES.CAR.MEMBER1 A-386
MATCH.IMPLIES.DELTA1.OK A-391
MATCH.IMPLIES.MEMBER A-387
MATCH.LENGTHS A-364
MATCH.LENGTHS1 A-365
MAXIMUM A-326
MC.FLATTEN A-49
McCarthy ??
MEASURE A-347
measure ??
measured subset ??
MEMBER A-51
MEMBER-INTERSECT A-58
MEMBER.APPEND A-52
MEMBER.APPEND2 A-53
MEMBER.MAXIMUM A-327
MEMBER.OCCUR A-132
MEMBER.REVERSE A-54
MEMBER.SORT A-115
MEMBER.UNION A-60
MEMBER.UNION- A-162
merge ??
Milner ??
minimal ??
Morris ??
Morris ??
Morse ??
Naur ??
NEQUAL.PLUS.ADD1 A-207
new ??
NIL PACK
NLISTP A-1
nonrecursive ??
NORMALIZE A-241
NORMALIZE.IS.SOUND A-258
NORMALIZE.NORMALIZES A-259
NORMALIZED.IF.EXPRP A-242
NOT ??
NTH A-64
NTH.APPEND A-205
NTH.APPEND1 A-92
NTH.MEMBER A-65
NTH.NIL A-91
NTHCHAR A-203
NUMBER.LISTP A-124
NUMBERP ADD1
NUMBERP.APPLY A-25
NUMBERP.GREATEST.FACTOR A-285
OCCUR A-131
OCCUR.SUBST A-133
ODD A-96
Odlyzko ??
Oppen ??
OPTIMIZE A-28
OR ??
ORDERED A-72
ORDERED.ADDTOLIST A-163
ORDERED.APPEND A-119
ORDERED.SORT A-125
ORDERED.SORT-LP A-164
ORDERED2 A-330
OTHERS ??
PACK ??
Painter ??
PAIRLIST A-80
parameter ??
partially correct ??
PERM A-313
permutative ??
Peter ??
PK A-349
PLISTP A-6
PLISTP.REVERSE A-8
PLUS ??
PLUS- A-157
PLUS-PLUS A-158
PLUS.2.NOT A-399
PLUS.ADD1 A-11
PLUS.CANCELATION1 A-187
PLUS.CANCELLATION A-354
PLUS.DIFFERENCE.SUB1.REWRITE A-368
PLUS.DIFFERENCE3 A-209
PLUS.EQUAL.0 A-186
PLUS.NEQUAL.X A-206
PLUS.RIGHT.ID A-10
Pnueli ??
POP PUSH
POP-2 ??
POP.PUSH PUSH
position ??
POWER.EVAL A-173
POWER.EVAL.BIG.PLUS A-178
POWER.EVAL.BIG.PLUS1 A-176
POWER.EVAL.POWER.REP A-193
POWER.REP A-192
Pratt ??
predicates ??
Presburger ??
PRIME A-275
PRIME.BASIC A-301
PRIME.BRIDGE A-299
PRIME.FACTORIZATION.EXISTENCE A-297
PRIME.FACTORIZATION.UNIQUENESS A-325
PRIME.FACTORS A-286
PRIME.GCD A-308
PRIME.KEY A-309
PRIME.KRUTCH A-298
PRIME.LIST A-287
PRIME.LIST.APPEND A-290
PRIME.LIST.DELETE A-315
PRIME.LIST.PRIME.FACTORS A-291
PRIME.LIST.TIMES.LIST A-320
PRIME.MEMBER A-322
PRIME1 A-274
PRIME1.BASIC A-300
proper list ??
propositional IF-expression ??
pure LISP ??
PUSH A-22
PUSH.EQUAL PUSH
QUOTIENT A-171
QUOTIENT.DIVIDES A-310
QUOTIENT.LESSP A-293
QUOTIENT.TIMES A-317
QUOTIENT.TIMES1 A-292
recognizer ??
RECURSION.BY.DIFFERENCE A-170
RECURSION.BY.QUOTIENT A-191
RECURSION.BY.REMAINDER A-202
recursive ??
REMAINDER A-172
REMAINDER.ADD1 A-216
REMAINDER.GCD A-302
REMAINDER.GCD.1 A-303
REMAINDER.QUOTIENT A-175
REMAINDER.QUOTIENT.ELIM A-185
REMAINDER.TIMES A-314
REMAINDER.WRT.1 A-180
REMAINDER.WRT.12 A-181
REMAINDER.X.X A-184
replacement principle ??
result of substituting ??
REVERSE A-3
REVERSE- A-152
REVERSE-APPEND A-155
REVERSE-LOOP A-151
REVERSE-LOOP.APPEND.REVERSE A-153
REVERSE-REVERSE A-154
REVERSE-REVERSE- A-156
REVERSE.MAPCAR A-85
REVERSE.REVERSE A-47
rewrite with lemmas ??
RIGHT.BRANCH CONS.IF
RIGHT.BRANCH.CONS.IF CONS.IF
RIGHT.BRANCH.LESSP CONS.IF
Rivest ??
Robinson, J.A. ??
Robinson, L. ??
RUSSELL ??
SAMEFRINGE A-269
score ??
SEQUENTIAL.EXECUTION A-34
SGCD A-195
SGCD.X.0.X A-199
SGCD.X.X.X A-200
shell ??
Skolem ??
smaller ??
SORT A-74
SORT- A-161
SORT-LP A-160
SORT.OF.ORDERED.NUMBER.LIST A-126
SORT.ORDERED A-128
SORT2 A-333
SORT2.DELETE A-342
SORT2.DELETE.CONS A-341
SORT2.GEN A-336
SORT2.GEN.1 A-334
SORT2.GEN.2 A-335
STACKP PUSH
STRPOS A-356
STRPOS.BOUNDARY.CONDITION A-366
STRPOS.EPSILON A-395
STRPOS.EQUAL A-371
STRPOS.EQUAL.0 A-383
STRPOS.LESSEQP.CRUTCH A-382
STRPOS.LESSEQP.STRLEN A-379
STRPOS.LIST.APPEND A-381
structural induction ??
SUB1 ADD1
SUB1.ADD1 ADD1
SUB1.ELIM ADD1
SUB1.LENGTH A-392
SUB1.LESSP ADD1
SUB1.LESSP.PLUS A-362
SUB1.LESSP1 A-37
SUB1.TYPE.RESTRICTION ADD1
SUB1P ADD1
SUBSETP A-61
SUBSETP.CONS A-105
SUBSETP.INTERSECT A-63
SUBSETP.UNION A-62
SUBST A-129
SUBST.A.A A-130
substitution ??
subsume ??
subsumes ??
SUM ??
SWAPPED.PLUS.CANCELLATION A-374
SWAPTREE A-137
SWAPTREE.SWAPTREE A-138
T ??
tautology ??
TAUTOLOGY.CHECKER A-252
TAUTOLOGY.CHECKER.COMPLETENESS.BRIDGE A-260
TAUTOLOGY.CHECKER.IS.COMPLETE A-261
TAUTOLOGY.CHECKER.IS.SOUND A-263
TAUTOLOGY.CHECKER.SOUNDNESS.BRIDGE A-262
TAUTOLOGYP A-246
TAUTOLOGYP.FAILS.MEANS.FALSIFY1.WINS A-257
TAUTOLOGYP.IS.SOUND A-251
Teitelman ??
term ??
TEST CONS.IF
TEST.CONS.IF CONS.IF
TEST.LEFT.BRANCH.RIGHT.BRANCHP CONS.IF
theorem ??
TIMES A-4
TIMES.ADD1 A-17
TIMES.DIFFERENCE A-210
TIMES.EQUAL.1 A-324
TIMES.IDENTITY A-305
TIMES.LIST A-288
TIMES.LIST.APPEND A-289
TIMES.LIST.DELETE A-319
TIMES.ZERO A-15
TIPCOUNT A-140
TOP PUSH
TOP.ASSERT A-358
TOP.POPP PUSH
TOP.PUSH PUSH
TRANSITIVITY.OF.EQUAL A-94
TRANSITIVITY.OF.EQUALP A-135
TRANSITIVITY.OF.GREATERP A-69
TRANSITIVITY.OF.LESSEQP A-70
TRANSITIVITY.OF.LESSP A-38
TRANSITIVITY.OF.LESSP2 A-39
TRANSITIVITY.OF.LESSP3 A-40
TRANSITIVITY.OF.NOT.LESSP A-41
TRANSITIVITY.OF.NOT.LESSP2 A-42
TRANSITIVITY.OF.NOT.LESSP3 A-43
TRICHOTOMY.OF.LESSP A-71
TRUE ??
type ??
type prescription ??
type restriction ??
type set ??
type set alist ??
types ??
unchangeables ??
unchanging ??
UNION A-59
UNION- A-159
UNIVERSE ??
UNPACK PACK
UNPACKP PACK
VALUE A-232
value ??
VALUE.CAN.IGNORE.REDUNDANT.ASSIGNMENTS A-248
VALUE.SHORT.CUT A-249
variable alist ??
VC4.HACK.1 A-372
VC5.HACK1 A-376
verification conditions ??
Waldinger ??
Wegbreit ??
well-founded ??
Weyhrach ??
WHILELOOP ??
worse than ??
XOR A-127
ZERO ADD1
ZEROP ??
ZEROP.LENGTH A-360
.ENDASIS
.ALLREFS
.REFER JOHNALLEN, |J. Allen, __The Anatomy of LISP_,
. McGraw-Hill Publishing Co., New York (1978).|
.REFER AUBIN, |R. Aubin, "Mechanizing Structural Induction," Ph.D. Thesis,
. University of Edinburgh, Edinburgh (1976).|
.REFER BLEDSOEPROVER, |W. Bledsoe, "Splitting and Reduction Heuristics
. in Automatic Theorem-proving," __Artificial Intelligence_, Vol. 2,
. pp. 55-77 (1971).|
.REFER BLEDSOELIMIT, |W. Bledsoe, R. Boyer, and W. Henneman, "Computer
. Proofs of Limit Theorems," __Artificial Intelligence_, Vol. 3,
. pp. 27-60 (1972).|
.REFER BLEDSOESURVEY, |W. Bledsoe, "Non-resolution Theorem Proving,"
. __Artificial Intelligence_, Vol. 9, pp. 1-36 (1977).|
.REFER BOURBAKI, |N. Bourbaki, __Elements of Mathematics Theory of Sets_,
. (Addison-Wesley, Reading, Mass., 1968).|
.REFER JACM, |R. Boyer and J Strother Moore, "Proving Theorems about LISP
. Functions," __Journal of the ACM_, Vol. 22, No. 1, pp. 129-144 (1975).|
.REFER IJCAI77, |R. Boyer and J Strother Moore, "A Lemma Driven Automatic
. Theorem Prover for Recursive Function Theory," Proceedings of the
. 5th International Joint Conference on Artificial Intelligence,
. Department of Computer Science, Carnegie-Mellon University,
. Pittsburgh, PA, pp. 511-520 (1977).|
.REFER FSTRPOS, |R. Boyer and J Strother Moore, "A Fast String Searching
. Algorithm," __Communications of the ACM_,
. Vol. 20, No. 10, pp. 762-772 (1977).|
.REFER METHDOC, |R. Boyer and J Strother Moore, "A Formal Semantics
. for the SRI Hierarchical Program Design Methodology," Technical
. Report, Computer Science Laboratory, SRI International, Menlo
. Park, California (1978).|
.REFER BROTZ,|D. Brotz, "Proving Theorems by Mathematical Induction,"
. Ph.D. Thesis, Computer Science Department, Stanford University,
. Stanford (1974).|
.REFER BURSTALL, |R. Burstall, "Proving Properties of Programs
. by Structural Induction," __The Computer Journal_, Vol. 12, No. 1,
. pp. 41-48 (1969).|
.REFER BURSTALLTRANS, |R. Burstall and J. Darlington, "A
. Transformation System for Developing Recursive Programs,"
. __Journal of the ACM_,
. Vol. 21, No. 1, pp. 44-67 (1977).|
.REFER CARTWRIGHT, |R. Cartwright, "A Practical Formal Semantic Definition
. and Verification System for Typed LISP," Ph. D. thesis, Stanford University,
. Stanford (1976).|
.REFER CHANG, |C. Chang and R. Lee, __Symbolic Logic and Mechanical Theorem
. Proving_, (Academic Press, New York, 1973).|
.REFER CHURCHLAMBDA, |A. Church, "The Calculi of Lambda-Conversion,"
. __Annals of Mathematical Studies_, No. 6 (Princeton University
. Press, Princeton, New Jersey, 1941).|
.REFER CHURCH, |A. Church, __Introduction to Mathematical Logic_
. (Princeton University Press, Princeton, New Jersey, 1956).|
.REFER FLOYD, |R. Floyd, "Assigning Meanings to Programs,"
. __Mathematical Aspects of Computer Science,
. Proceedings of Symposia in Applied Mathematics_, Vol. XIX, American
. Mathematical Society, Providence, Rhode Island, pp. 19-32 (1967).|
.REFER GENTZEN, |G. Gentzen, "The Consistency of Elementary Number
. Theory," in __The Collected Papers of Gerhard Gentzen_,
. M. E. Szabo, Ed. (North-Holland, Amsterdam, 1969).|
.REFER GLOESS, |P. Gloess, "A Proof of the Correctness of a Simple
. Parser of Expressions by the Boyer-Moore System," Technical Report,
. Computer Science Laboratory, SRI International, Menlo Park,
. California (1978).|
.REFER GOEDEL, |K. Goedel, __The Consistency of the Axiom of Choice
. and of the Generalized Continuum-Hypothesis with the Axioms of
. Set Theory_ (Princeton University Press, Princeton, New Jersey, 1940).|
.REFER GOODSTEIN, |R. Goodstein, __Recursive Number Theory. A Development
. of Recursive Arithmetic in a Logic Free Equation Calculus_, North-Holland
. Publishing Co., Amsterdam (1957).|
.REFER GUIBAS, |L. Guibas and A. Odlyzko, "A New Proof of the Linearity of the
. Boyer-Moore String Searching Algorithm," Proceedings of the
. 18th Annual IEEE Symposium on Foundations of Computer Science, (1977).|
.REFER HOARE, |C. Hoare, "An Axiomatic Basis for Computer Programming,"
. __Communications of the ACM_, Vol. 12, No. 10, pp. 576-583 (1969).|
.REFER KELLEY, |J. Kelley, __General Topology_ (D. van Nostrand,
. Princeton, New Jersey, 1955).|
.REFER KNUTHBENDIX, |D. Knuth and P. Bendix, "Simple Word Problems
. in Universal Algebras," __Computational Problems in Abstract Algebras_,
. J. Leech, Ed., pp. 263-297 (Pergamon Press, Oxford, 1970).|
.REFER KMP, |D. Knuth, J. Morris, and V. Pratt, "Fast Pattern
. Matching in Strings," __SIAM Journal on Computing_, Vol. 6,
. No. 2, pp. 323-350 (1977).|
.REFER BALLANTYNE, |D. Lankford and A. Ballantyne, "Decision Procedures
. for Simple Equational Theories with Permutative Equations: Complete
. Sets of Permutative Reductions," Workshop on Automatic Deduction,
. MIT, Cambridge, Mass., (1977).|
.REFER LOVELAND, |D. Loveland, __Automated Theorem Proving: A
. Logical Basis_, North-Holland Publishing Co., Amsterdam (1978).|
.REFER MANNA, |Z. Manna and A. Pnueli, "Formalization of Properties
. of Functional Programs," __Journal of the ACM_, Vol. 17, No. 3,
. pp. 555-569, (1970).|
.REFER MW, |Z. Manna and R. Waldinger, "The Logic of Computer Programming,"
. __IEEE Transactions on Software Engineering_, Vol. SE-4, No. 3,
. pp. 199-229 (1978).|
.REFER MCCARTHYSYMB, |J. McCarthy, "Recursive Functions of Symbolic Expressions
. and Their Computation by Machine," __Communications of the ACM_,
. Vol. 3, No. 4, pp. 184-195 (1960).|
.REFER MCCARTHYCHECKING, |J. McCarthy, "Computer Programs for Checking Mathematical
. Proofs," __Recursive Function Theory, Proceedings of a Symposium in Pure Mathematics_, Vol. V, American
. Mathematical Society, Providence Rhode Island, pp. 219-227 (1962).|
.REFER MCCARTHYBASIS, |J. McCarthy, "A Basis for a Mathematical
. Theory of Computation," in __Computer Programming and Formal
. Systems_, edited by P. Braffort and D. Hershberg, (North-Holland,
. Amsterdam, 1963).|
.REFER LISPMANUAL, |J. McCarthy, et al., __LISP 1.5 Programmer's Manual_
. (The MIT Press, Cambridge, Massachusetts, 1965).|
.REFER MCCPAINTER, |J. McCarthy and J. Painter, "Correctness of a Compiler
. for Arithmetic Expressions," __Mathematical Aspects of Computer Science,
. Proceedings of Symposia in Applied Mathematics_, Vol. XIX, American
. Mathematical Society, Providence, Rhode Island, pp. 33-41 (1967).|
.REFER MILNER, |R. Milner and R. Weyhrauch, "Proving Compiler Correctness in a
. Mechanized Logic," __Machine Intelligence 7_, B. Meltzer and D.
. Michie, Eds., pp. 51-70, (Edinburgh University Press,
. Edinburgh, 1972).|
.REFER THESIS, |J Strother Moore, "Computational Logic:##Structure
. Sharing and Proof of Program Properties," Ph.D. thesis, University
. of Edinburgh (1973).|
.REFER SIGART, |J Strother Moore, "Automatic Proof of the Correctness
. of a Binary Addition Algorithm," __SIGART Newsletter_, No. 52, pp. 13-14
. (1975).|
.REFER IEEE, |J Strother Moore, "Introducing Iteration into the Pure
. LISP Theorem Prover," __IEEE Transactions on Software Engineering_, Vol. 1, No. 3,
. pp. 328-338 (1975).|
.REFER VM, |J Strother Moore, "The INTERLISP Virtual Machine
. Specification," CSL 76-5, Xerox Palo Alto Research Center,
. Palo Alto, California (1976).|
.REFER MORRIS, |J. Morris and B. Wegbreit, "Subgoal Induction,"
. __Communications of the ACM_, Vol. 20, No. 4, pp. 209-222 (1977).|
.REFER MORSE, |A. P. Morse, __A Theory of Sets_ (Academic Press, New York,
. 1965).|
.REFER NAUR, |P. Naur, "Proof of Algorithms by General Snapshots,"
. __BIT_, Vol. 6, pp. 310-316 (1966).|
.REFER OPPEN, |D. Oppen, "Reasoning about Recursively Defined
. Data Structures," CS Report STAN-CS-78-678, Stanford
. University, 1978. (Appeared in proceedings
. of the Fifth ACM Symposium on Principles of Programming Languages, 1978.) |
.REFER PETER, |R. Peter, __Recursive Functions_, Academic Press, New York (1967).|
.REFER PRESBURGER, |M. Presburger, "Uber die Vollstandigkeit eines gewissen Systems der Arithmetik ganzer Zahlen, in welchem die Addition als einzige Operation hervortritt,"
. __Comptes-Rendus du I Congres de Mathematiciens des pays Slaves_, Warsaw, pp. 92-101, 395 (1929).|
.REFER RIVEST, |R. Rivest, "On the Worst-Case Behavior of String-Searching
. Algorithms," __SIAM Journal of Computing_, Vol. 6, No. 4, pp. 669-674
. (1977).|
.REFER ROBINSON, |J. A. Robinson, "A Machine-Oriented Logic Based
. on the Resolution Principle," __Journal of the ACM_, Vol. 12, No. 1, pp. 23-41 (1965).|
.REFER ROBINSON2, |J. A. Robinson, "Computational Logic: the Unification
. Algorithm," in __Machine Intelligence 6_, B. Meltzer and
. D. Michie, Eds., pp. 63-72 (Edinburgh University Press, Edinburgh,
. 1971).|
.REFER LARRY, |L. Robinson and K. Levitt, "Proof Techniques for
. Hierarchically Structured Programs," __Communications of the
. ACM_, Vol. 20, No. 4, pp. 271-283 (1977).|
.REFER SKOLEM, |T. Skolem, "The Foundations of Elementary
. Arithmetic Established by Means of the Recursive Mode of Thought,
. without the Use of Apparent Variables Ranging over Infinite
. Domains," in __From Frege to Goedel_, J. van Heijenoort, Ed.
. (Harvard University Press, Cambridge, Massachusetts, 1967).|
.REFER TEITELMAN, |W. Teitelman, "INTERLISP Reference Manual,"
. Xerox Palo Alto Research Center, Palo Alto, California (1975).|
.ENDREFS
.STANDARD BACK
*