Equational reasoning in Isabelle

Equational reasoning in Isabelle

Science of Computer North-Holland Programming EQUATIONAL Tobias 123 12 (1989) 123-149 REASONING IN ISABELLE NIPKOW* Laboratory for Cornpurer S...

2MB Sizes 54 Downloads 102 Views

Science of Computer North-Holland

Programming

EQUATIONAL Tobias

123

12 (1989) 123-149

REASONING

IN ISABELLE

NIPKOW*

Laboratory for Cornpurer Science, Massachuserls Institute of Technology, 545 Technology Square, Cambridge, MA 02139, U.S.A.

Communicated by C.B. Jones Received August 1988 Revised January 1989

1. Introduction

This paper reports on a case study carried out with the generic theorem prover Isabelle. The purpose of this study was to investigate the process of instantiating a generic system like Isabelle for a particular logic (equational logic in this case). Isabelle is like a compiler-compiler, except that it compiles a logic definition into an LCF-style theorem prover for that logic. To make that theorem prover usable, a number of logic-specific “tactics”, embodying useful theorem proving techniques in that logic, must be built on top. Equational logic was chosen as a test case because it comes with a large body of well-tried algorithms. It will be shown how a variety of different algorithms in the area of equational reasoning can be implemented in a unified way using a powerful tactic language. The problems tackled are term rewriting, unification and inductive theorem proving and the tactic language is ML. The main advantages of this approach can be summarized as follows: Correctness. Our approach any changes to the inference algorithms

are presented

of incorporating rewriting techniques does not require engine of the theorem prover. Particular term rewriting

as tactics which use the basic equational

rules, very much in the style of [20]. The obvious soundness of all deductions (provided the underlying

calculus

inference

advantage is the guaranteed theorem prover is sound). In

addition an algorithm in terms of inference rules is sometimes easier to understand than one written to operate directly on the underlying tree representation of formulae. Particular examples are the unification and matching algorithms presented in Section 4.4.1. Extensibility. The resulting system is not closed but can be extended at two levels: by new tactics and by new inference rules. The former is a consequence of the * Part of this research was carried out at the University of Manchester with support from Alvey grant GR/D/60294. At MIT the author was supported in part by NYNEX, NSF grant CCR-8706652, and by the Advanced Research Projects Agency of the DOD, monitored by the ONR under contract N00014-83-K0125.

0167-6423/89/$3.50

@ 1989, Elsevier

Science

Publishers

B.V. (North-Holland)

7: Nipkow

124

LCF-philosophy whereas the latter is due to the generic nature of Isabelle. openness has permitted us to incorporate inductive theorem proving techniques our collection similar

of tactics,

development

Simplicity. symbolic

Isabelle’s

theorem

something

is reported primitives

proving.

which

goes beyond

pure equational

This into

logic. A

in [4]. provide

In particular

most

of the functionality

it offers both functional

required

for

and logic program-

ming, albeit at different levels. Functional programming is available through ML, and logic programming is embodied in Isabelle’s Horn clause formalization of inference rules, including logical variables. As a consequence most of the algorithms could be implemented

in a short time and required

little code.

The contribution of this paper does not lie in the originality of the algorithms but in their presentation in the framework of general theorem proving. This is in contrast to most other systems performing equational deduction, for example [5, 161. They are built to execute particular algorithms in an efficient way. If one is interested in proving theorems that go beyond the equational calculus, these systems offer little or no support-that is not what they were designed for. On the other hand it seems unlikely that a general purpose theorem prover will perform as well as these specialized systems when applied to equational problems. Isabelle certainly does not, which is hardly surprising given the overhead incurred by generality. The structure of the paper is as follows. Section 2 introduces the generic theorem prover Isabelle. In particular the representation of logics, the basic tactics, and the combinators for combining them into complex proof procedures are described. Section 3 shows how equational logic is represented in Isabelle. Section 4 is concerned with the general problem of finding normal forms of terms w.r.t. some rewrite relation. In particular we consider rewriting with unconditional and conditional equations, rewriting with assumptions, rewriting modulo equations, and rewriting via higher-order matching. Section 5 presents a simple tactic for inductive proofs of equations based on the rewriting procedures of Section 4, and closes with a series of sample proofs about natural numbers. Isabelle is written in Standard ML (ML in the sequel), as are all of the tactics presented in this paper. We assume that the reader is familiar with the ML syntax for function definitions as for example in [8]. Throughout the paper the sanserif font indicates either ML code or Isabelle input/output. In the latter case some changes have been made to improve the presentation. Lines starting with > are type information inferred by the ML system.

2. IsabeIIe Isabelle is an interactive theorem prover developed and implemented in ML by Larry Paulson at the University of Cambridge. This section gives only a very sketchy account of Isabelle, just enough to make the paper self-contained. A more detailed introduction to Isabelle can be found in [7]. A first explanation of the principles

Equational

underlying using

Isabelle

is contained

higher-order

reasoning

in [21],

irl Isabeile

a formalization

125

of Isabelle’s

metalogic

logic is given in [23].

2.1. Representing

logics

What distinguishes Isabelle from most, if not all, other theorem provers is the fact that it can be parameterized by the object-logic to be used. The definition of a logic consists of the declaration/definition of all - basic types (for example terms, formulae, etc.); - logical constants (operators like =, 3 and V) and variables (x, y, z, P, Q, etc.) with their arity; valid arities are the basic types and function types over them; - inference rules. Section 3 shows how equational logic is represented in Isabelle. The central notion in Isabelle is that of a rule, written as p , . . . p, P



where the Pi and P are well-typed A-calculus terms over the logical constants and variables. The Pi are called the premises and P the conclusion. If m = 0, the rule is called a theorem. Theorem proving rules. The principal

in Isabelle amounts to combining the basic rules to form derived method for combining two rules is resolution: given two rules

* = p, . . . pt?l P

and a substitution

and

u which

q=

9, . ..Qn Q ’

unifies

P with

Q, for some i, resolving

p and q yields

the new rule

Q,...

(+

(

Qi-1 f’, . . . Pm Qi+l . . . Qn >. Q

This brings us to another important than just matching (as for example

(1)

Isabelle feature: it is based on unification rather LCF). Since Isabelle formulae are h-expressions,

Isabelle contains an implementation of higher-order unification which is described in [21]. This means that unification may yield a potentially infinite stream of unifiers; it may even be undecidable. How this is dealt with is described in Section 2.2. However, most of the time all our terms are first-order, i.e. they do not contain function variables or lambdas. Hence there exists at most one most general unifier. Every variable introduced with the definition of a logic can be used in two ways: as an ordinary and as a logical variable. The difference is that logical variables can be instantiated during the resolution process whereas ordinary variables act like constants. The latter should be thought of as universally quantified at the metalogical level (see [23]). Logical variables are distinguished from ordinary ones by being .-_-c.._> . . ...I_ - ‘L-i?? preuxeu WI111 a ! .

T. Nipkow

126

All this sounds

very much

seen as an implementation Finally

I should

mention

like logic programming,

of typed higher-order that the version

and in fact Isabelle

logic programming

of Isabelle

described

can be

(see also [21]). in this paper

is

Isabelle-86. Meanwhile Isabelle has been extended significantly and both the foundations described in [23] and the user manual [24] pertain to the latest version. 2.2. Basic tactics and tacticals Tactics

are a concept

originating

with

LCF

[6, 221. They

are the functional

programmer’s answer to the challenge posed by the length and repetitiveness of proofs from first principles. An Isabelle tactic is a function from a rule to a (potentially infinite) sequence of rules. type tactic = rule + rule sequence; sequence is an abstract type implementing lazy lists. Tactics need to produce sequences of rules to allow for backtracking and also because the basic inference rule, resolution, may produce an infinite number of results due to higher-order unification. In Isabelle the state of a proof is just a rule, where the premises should be thought of as the goals to be solved, and the conclusion the formula to be proved. A proof of the formula P starts with the trivially correct rule f and proceeds backwards by resolution with the premises. Hence the most basic tactic is

> val resolve_tac Applying resolve_tac rl with the ith premise

=fn : rule list + int + tactic

rl i to some rule r yields the stream of resolvents of rules in of r. Resolution includes “standardizing apart”, i.e. renaming

the variables in rl so they are disjoint from the ones in r. The two infix operators RESN and RES resolve two rules directly, derived

yielding

a new

rule: > val RESN =fn : rule * (int * rule) -+ rule > val RES =fn : rule * rule-, rule

Given

two rules p and q, q RESN (i, p) yields the result of resolving

p with the ith

premise of q as in (I), provided it is unique. p RES q is equivalent to p RESN (1, q). Although a!! derived rules are ultimately proved via single resolution steps, Isabelle provides tactics and tacticals (functions for combining tactics) to build up complex proof strategies: > vat all_tac=fn > val no_tac=fn

:tactic

:tactic > val THEN =fn : tactic * tactic + tactic > val ORELSE=fn :tactic * tactictactic > val COND =fn : (rule + bool) + tactic * tactic + tactic

>val REPEAT=fn:tactic+tactic > val UNTIL=fn:(rule+ bool)+

tactic-,

> val UNTlL_THM =fn :tactic+ tactic >val SELECT_lst_GOAL=fn:tactic+tactic

tactic

Equational

In the following identifying

explanation

reasoning

of these tactics

the type sequence

127

in Isabelle

and tacticals

we simplify

with the type list. Hence we abstract

slightly

from problems

arising from representing infinite lists. The basic ML operations on lists are [ 1, the empty list, :: , the infix operator putting provides

an element

in front

the following >val

of a list and @, the infix append

additional

>val

hd=fn:‘a list+‘a map=fn:(‘a+‘b)+‘a

>val

flat=fn

by

operator.

for

Isabelle

functions:

list+‘b

list

:‘a list list+ list

hd yields the first element of a nonempty list, map applies a function to every element of a list, and flat distributes @ over a list of lists. If ML lists were lazy, the following pseudodefinitions would actually work. The tactic all_tac passes all rules through unchanged: fun all_tac

The tactic no_tac

always

fun no-tat

The tactical

rule= [rule];

fails, i.e. returns

rule=[

1;

THEN performs

fun (tacl

an empty list:

one tactic followed

THEN tac2)

rule=flat

by another:

(map tac2 (tacl

rule));

The tactical ORELSE uses the first tactic that returns a nonempty LCF, ORELSE commits to either tacl or tac2 immediately: fun (tacl

The conditional

ORELSE

tactical

Like in

tac2) rule=

rule =[ ] then tad

if tacl

sequence.

selects

rule else tacl

either tacl

rule;

or tac2, depending

on testfun:

fun COND testfun (tacl, tac2) rule= if testfun rule then tacl rule else tac2 rule; REPEAT applies

tat

repeatedly

fun REPEAT tat UNTIL applies

tat

fun UNTlL COND As a particular

rule=((tac

THEN

until satfun reports satfun satfun

instance

REPEAT tat)

no backtracking: ORELSE

all_tac)

rule;

success:

tat rule= (all-tat,

tat THEN

UNTIL

satfun tat)

rule;

we have

val UNTIL_THM=UNTIL which repeats

until it fails. It performs

is-theorem;

a tactic until a theorem

(is-theorem),

i.e. a rule without

premises,

is

obtained. makes the tactic to it.

SELECT_lst_GOAL

and applies

a rule look like it has only one premise,

the first one,

T. Nipkow

128

In addition

to the tactics and tacticals

of other functions,

mostly

described

here, Isabelle

provides

to do with rule and term manipulation,

we discuss. Any function which is only mentioned be assumed to be one of those.or to be a simple

in passing combination

a collection

none

of which

but is not defined of those.

can

3. Representing equational logic Equational logic, a fragment of first-order predicate calculus, is based on the two basic types term and form of terms and formulae. The only logical constant is = of type term + term + form. In addition we can have a selection of function symbols (or extra-logical constants) of type term + * . . + term for building up terms. The letters

u to z stand

for variables

of type term.

y2, etc.) to create new variables. The inference rules of the equational refl=-

calculus

Isabelle consist

allows

“subscripting”

of the three equality

(xl, rules

?x=?x ?x=?y

wm=, .y trans =

.x

?x=?y

?x=?z

and a congruence

rule

?xl =?yl f(?xl,

?y=?z

. . . ?xn=?yn

. . , ?xn)=f(?yl,.

for every n-ary, n 3 0, function

. . , ?yn) symbol

f. In the sequel tongs

such congruence rules for a given set of function symbols. For later use in equational proofs we define the following

denotes

the list of all

tactics:

val trams_tat = resolve_tac [trans] 1 ; val refl_tac=resolve_tac [refl] 1; val sym-tat = resolve_tac [sym] 1; val cong_tac = resolve_tac tongs 1 ; Notice that they all resolve with the first premise

which is usually

the current

focus.

4. Normalization The most basic

mechanism

rewriting, or more precisely,

some given rewrite relation.

in any implementation

of equatorial

logic is term

the process of finding normal forms of terms w.r.t. to For a concise introduction to equational logic and term

Equa/ional

rewriting

see for example

of terms in some theory Although theorem

this problem

proving

reasoning

Isabel/e

129

[lo]. Suffice it to say that under certain can be decided

by comparing

the problem can be expressed normalized and ?x the variable

conditions

their normal

looks like one of transforming

system we have to rephrase

often concerned

in

equality

forms.

terms, in the context

it in terms of inference

of a

rules. In Isabelle

as the equation s = ?x, where s is the term to be we want to bind the normal form to. Hence we are

with rules of the form

s=?x

H (2)

P

where s is a ?-free term, H any further list of formulae and P a formula. Remember that theorem proving in Isabelle is based on backwards reasoning, i.e. the current proof state takes the form of a rule whose premises are the subgoals. Given such a rule, a normalization tactic shall solve the first subgoal, i.e. instantiate ?x to the normal form of s, and return the rule $. When writing tactics for subterm replacement one has to distinguish the two aspects of tree traversal and rule application which are independent of each other. A normalization tactic is a particular tree traversal scheme parameterized by a tactic for applying rewrite rules. The advantage of this approach is one of greater modularity: it is possible to define a collection of tactics, from rewriting of terms to proving equations, without commitment to the kind of rewrite rules they apply to. This is the topic of Section 4.1. The subsequent sections are devoted to instantiating those tactics to perform unconditional and conditional rewriting, rewriting with assumptions, and rewriting module equations. In a final section we study a radically different approach to rewriting based on the higher-order capabilities of Isabelle. 4.1. Basic rewriting As a simple

tools

example

of a reduction

strategy

we present

a bottom

up scheme

which normalizes all subterms of a term before it attempts to apply a rewrite rule at the root. Here is a tactical which applies its argument tactic rew_tac to all subterms of a term: fun ALL_SUBTS

rew_tac=SELECT_lst_GOAL ((tong_tat THEN UNTIL-THM rew_tac) > val ALL_SUBTS =fn : tactics + tactic

ORELSE

refl_tat);

Applied to a rule of the form (2), the goal s = ?x is selected. If s is of the form f(s1,. . , sn), tong-tat instantiates ?x with f(?xl, , ?xn) and yields the subgoals sl =?xl, . , sn=?xn. To these subgoals rew_tac is applied until they have all been solved. If tong-tat fails, s is a constant (or an ordinary variable), i.e. there are no subterms, and the goal can simply be solved by reflexivity. SELECT-1 St-GOAL limits attention to the subgoals created by tong_tat. Otherwise it would not be clear when they have all been solved. It is used to similar effect in the tactics to come.

7: Nipkow

130

Here is the tactical

for bottom-up

fun BU rew-tat

normalization

of terms.

rule=

(SELECT_lst_GOAL (UNTIL_THM (trans_tat

THEN ALL_SUBTS(BU

((trans_tat

THEN rew-tat)

> val BU =fn :tactic+

rew-tat))

ORELSE

THEN

refl_tat))))

rule;

rule-, rule sequence

Note that due to the call-by-value semantics of ML, we need to mention the parameter rule-otherwise the recursive call BU rew_tac would lead to infinite unfolding. As a consequence, the type-checker infers the above expanded type instead of the equivalent but simpler tactic+ tactic. As before, laziness would solve this inconvenience. We assume be applied to to some t such by taking all

that the parameter rew_tac represents a rewrite relation + and can any rule of the form (2), yielding a rule F, where ?x has been bound that s + t holds. Roughly speaking + represents the relation obtained instances of all rules in a term rewriting system and BU yields the

closure of + w.r.t. all congruences in tongs. Let us quickly do a symbolic trace of BU: given a rule of the form (2), the first premise is selected and the main body of BU is applied to it until no subgoal remains; trans_tat yields s=?y, ?y=?x; ALL_SUBTS(BU rew_tac) binds ?y to the result of normalizing all subterms of s, say t, yielding t = ?x; another application of trams_tat yields t = ?z, ?z = ?x; if rew_tac succeeds, ?z is bound to some r with t + r, leaving us in the same situation as initially, but with r instead of S. If rew_tac fails, it follows that t is in normal form: its subterms are (due to ALL_SUBTS(BU rew_tat)), and rewriting at the root has failed too. Hence trans._tat THEN rew_tac as a whole fails, we are back at t = ?x, which is finally solved by reflexivity, instantiating ?x to the normal form t, as required. In order to use BU in conjunction with a list of equations (rewrite rules) rwrls, we simply need to instantiate its parameter by a tactic for resolving with those very rules: fun REW_TAC >val

rwrls=resolve_tac

REW_TAC=fn:rule

rwrls 1;

list+ tactic

fun NORM_LHS-TAC rwrls=BU (REW-TAC > val NORM_LHS_TAC=fn : rule list + tactic

rwrls);

The understanding is that rwrls is a list of equations of the form I = r. Unifying with an equation s = ?x, where s is ?-free, clearly has the effect of instantiating with the result of a single I = r rewrite of s at the root.

Example

4.1. Let N_rules=[O+?y=?y,

s(?x)+?Y=s(?x+?Y)]

that ?x

Equarional

be a simple

equational

definition

We look at the application

reasoning in Isabel/e

of addition

131

(+) in terms of 0 and successor

of NORM_LHS_TAC

N-rules

(s).

to a rule with the first

premise

trans_tat: ALL_SUBTS(BU

rew-tat):

trans-tat rew_tac:

s(0 +O) =?x s(O+O)=?y3

trans_tat: ALL_SUBTS(BU

?y=?x ?yl =?x ?y3=?x

rew_tac:

s(O)=?x ?y4 = ?x s(0) =?y4 fails, back to s(O)=?x

refl_tat:

solves the subgoal,

rew-tat):

trans_tat:

Instead outermost.

s(0) +o=?x s(0) +0=?y s(0) +0=?x s(0) +O=?yl

binding

?x to s(0).

of bottom-up, we can also implement other strategies like leftmostIn order not to overwhelm the reader with ML code this one example

will have to suffice. In the sequel we are not just interested in simplifying individual expressions both sides of an equation. This can be accomplished by splitting the equation according to the following rule: ?s=?x split-eqn

?t=?y

=

?x=?y

?s=?t

which can be derived

from the basic equational

laws as follows:

?x=?y ?y=?x

?t=?y ?s=?x

but first

?t=?x ?x=?t ?s=?t

In Isabelle

this linearizes

to

val split_eqn=trans RESN (2, sym RES (trans RESN > val split_eqn =? : rule

(2, sym)));

Since rule is an abstract ML type, its representation is hidden, which the system indicates by printing a ?. We leave it to the reader to verify that this composition does indeed yield the desired rule. Simplifying both sides of an equation is just a matter of splitting the equation via split_eqn and simplifying both sides separately: fun NORM-EON norm_lhs_tac= resolve_tac [split_eqn] 1 THEN norm_lhs_tac > val NORM_EQN=fn:tactic+ tactic

THEN

norm-lhs-tat;

T. Nipkow

132

Proving an equation reflexivity:

is achieved

fun PROVE-EQN NORM-EQN

by normalizing

it followed

by an application

of

norm_lhs_tac= norm_lhs_tac

THEN

refl_tat;

= fn : tactic + tactic

> val PROVE_EQN

Of course this yields only a decision procedure if norm-lhs-tat represents a confluent and terminating set of rewrite rules. However, even if that is the case, we can still only derive equalities in Isabelle. The fact that an equation is nor provable is a statement

in the meta-logic and cannot be derived in the object-logic. The above definition of PROVE-EON, although correct, can be very inefficient due to the subtleties of backtracking: if the equation we try to prove is not valid, the final application of refl_tac will fail. That, however, leads to backtracking in the tactic for normalizing both sides of the equation. This means that, because of backtracking, the normalization tactic enumerates all normal forms of a term (w.r.t. the given rewriting strategy). If the congruence closure of + is confluent, all normal forms are identical, i.e. the enumeration is wasteful. This can be stopped with the DETERM tactical available in Isabelle which chops off further results, thus making the result of a tactic application deterministic: fun DETERM

tat

rule=if

tat rule=[]

> val DETERM =fn :tactic+

Thus

a

more

efficient

version

of

then [] else hd(tac rule);

tactic PROVE-EQN

uses

DETERM(NORM_EQN

norm_lhs_tac). Now that we have introduced the basic mechanisms for rewriting, let us apply them to more advanced targets like conditional equations or rewriting with assump-

tions. 4.2. Conditional

rewrite rules

So far we have only given

one instantiation of our rewriting mechanism using simple equations (REW_TAC and NORM_LHS-TAC). However, for many theorem proving applications this is too restrictive. Hence we present an extension to conditional equations. There are different possibilities predicate calculus, for example sl=tl

of representing conditional as theorems of the form

equations

in first-order

& . . . & sn=tn*s=t

where & is conjunction and + inference rules of the form sl=tl . ..sn=tn s=t

implication.

(3)

We have chosen

to represent

them as

(4)

Both representations are logically equivalent but the second one is easier to handle: applying (4) to some goal equation is achieved by resolving with it. For (3) simple

Equational

resolution

does not work because

It is easy to provide

a function

reasoning

the logical

in Isabel/e

133

connectives

for the translation

+

and & get in the way,

from (3) to (4): repeated

resolution

with the rules imp_elim

=

?P

?P3?0

and

?Q

conj_intr=

?P

?Q

?P & ?Q

does the job. Using the basic rewriting tactics in conjunction with conditional equations of the form (4) is quite simple. All that is required is a tactic for applying conditional equations. A conditional equation is applicable if all its premises can be proved: fun CREW_TAC

prove_eqn-tat

crwrls=SELECT_lst_GOAL

(resolve_tac crwrls 1 THEN UNTIL-THM prove_eqn_tac); > val CREW_TAC =fn : tactic + rule list + tactic

This tactic has two parameters: crwrls is a list of conditional rewrite rules and prove_eqn_tac a tactic for proving the premises of rules in crwrls. In its simplest form, prove_eqn_tac does again involve conditional rewriting. This cycle is expressed in the following recursive tactic for normalizing the left-hand side of an equation. Instead of BU any other reduction strategy could be used. fun CNORM-LHS_TAC

crwrls=

let fun crew-tat rule = CREW-TAC prove_eqn_tac and cnorm_lhs_tac rule = BU crew_tac rule and prove-eqn-tat

rule = PROVE-EON

in cnorm_lhs_tac end; > val CNORM_LHS_TAC=fn

be the following

R,=

RI=

and apply

CNORM_LHS-TAC

rule

list of conditional

rewrite

rules

s(?x)
?x
cnorm_lhs_tac

: rule list+ tactic

Example 4.2. Let L-rules

?x
crwrls rule

?x
to the inference

rule

=?x s(0) =?x

s(s(s(0))) -c s(0) s(s(s(0))) <

Because all subterms of the left-hand side are in normal form, rewriting will eventually reach the root. At that point resolve_tat L-rules 1 (in CREW_TAC) results in the application of rule Rj,since R, and R2 do not match s(s(s(0)))
T. Nipkow

128

In addition

to the tactics and tacticals

of other functions,

mostly

described

here, Isabelle

provides

to do with rule and term manipulation,

we discuss. Any function which is only mentioned be assumed to be one of those.or to be a simple

in passing combination

a collection

none

of which

but is not defined of those.

can

3. Representing equational logic Equational logic, a fragment of first-order predicate calculus, is based on the two basic types term and form of terms and formulae. The only logical constant is = of type term + term + form. In addition we can have a selection of function symbols (or extra-logical constants) of type term + * . . + term for building up terms. The letters

u to z stand

for variables

of type term.

y2, etc.) to create new variables. The inference rules of the equational refl=-

calculus

Isabelle consist

allows

“subscripting”

of the three equality

(xl, rules

?x=?x ?x=?y

wm=, .y trans =

.x

?x=?y

?x=?z

and a congruence

rule

?xl =?yl f(?xl,

?y=?z

. . . ?xn=?yn

. . , ?xn)=f(?yl,.

for every n-ary, n 3 0, function

. . , ?yn) symbol

f. In the sequel tongs

such congruence rules for a given set of function symbols. For later use in equational proofs we define the following

denotes

the list of all

tactics:

val trams_tat = resolve_tac [trans] 1 ; val refl_tac=resolve_tac [refl] 1; val sym-tat = resolve_tac [sym] 1; val cong_tac = resolve_tac tongs 1 ; Notice that they all resolve with the first premise

which is usually

the current

focus.

4. Normalization The most basic

mechanism

rewriting, or more precisely,

some given rewrite relation.

in any implementation

of equatorial

logic is term

the process of finding normal forms of terms w.r.t. to For a concise introduction to equational logic and term

Equational reasoning in

In order to avoid this trap, universally:

the sequent

ALL permits

us to obtain

free variables

ALL X.X+0=x arbitrarily

135

Isabel/e

in assumptions

need to be quantified

I- 1 +(0 +0) =O is provable.

many instances

is possible, the quantifiers have to be removed. tions are removed by resolution with

of a formula.

Universal

The presence

of

Before rewriting

quantifiers

in the assump-

?A, ?P’(?x), ?B F ?P a”-‘ntr-asm a simple derived tification should self-explanatory:

=?A, ALL x.?P’(x), ?B !- ?P

rule in predicate calculus. The concrete syntax of universal quanbe sufficiently close to ordinary mathematics to make this rule each application of all-intr_asm peels off one quantifier, replacing

the bound variable by a ?-variable. The formalization treated in more detail in Section 4.6. Now rewriting with assumptions becomes

of quantifiers

in Isabelle

val strip_asm_tac=REPEAT(resolve_tac [all_intr_asm] 1); > val strip_asm_tac=fn :tactic vat asm_rew_tac=strip_asm_tac THEN resolve_tat [assume] > val asm_rew_tac =fn : tactic

is

1;

If (after strip_asm_tac) the first goal is of the form A, I = r, B I- s = ?x and s is an instance of I, resolving with assume binds ?X to the corresponding instance of r. Rewriting with assumptions alone is not interesting. Instead we look at the combination of assumptions and conditional equations as in Section 4.2. Due to the modular construction of our tactics we just need to change the definition of crew_tac in CNORM-LHS-TAC to

fun crew_tac rule= (CREW_TAC prove-eqn-tat

crwrls

ORELSE asm_rew_tac)

This tactic first tries to rewrite with the given list of (possibly

conditional)

rule

equations

crwrls, and if that fails, tries to use an assumption.

There is a subtle point here concerning the removal of universal quantifiers in each rewrite step: there should exist another “copy” of the quantified assumptions which can be used in subsequent reduction steps. A careful analysis of the above rewriting tactic shows that this second copy is the result of the application of trans_tat before rew_tac in BU: the transitivity rule (5) generates two subgoals, duplicating the assumptions. Although the above definition of asm-rew_tac only works for quantified unconditional equations, it is not difficult to extend it to implicative assumptions. Since that only involves a new predicate calculus rule but no new ideas, it is not discussed here. 4.4. Rewriting

module equations

It is often advantageous to integrate them directly

not to formulate certain properties as rewrite rules but into the rewriting machinery. This does not only enhance

T. Nipkow

136

the expressive

power of term rewriting

to termination

problems,

rewrite

certain

rules. To overcome

this problem,

split into a set of equations

but may actually

between

rewriting

equations

%-equivalence is rather

be mandatory:

like commutativity, presentations

8 and a set of rewrite

is now a relation modulo

systems

properties,

classes

subtle

cannot

of equational

theories

rules 9. Conceptually of terms.

The general

and is discussed

due

be used as are

rewriting theory

for example

of

in [12,

141. Let us just say that under certain conditions rewriting modulo equations reduces to normal rewriting, except that matching has to be performed modulo 8. Hence two things are required: a general tactic for applying rewrite rules which is parameterized by the matching tactic to be used, and a matching tactic for each equational theory of interest. Below the problems are tackled in exactly this order. The following tactical EQ-REW_TAC takes a set of rules and a tactic for matching two terms and returns a tactic for rewriting module matching. fun EQ_REW_TAC

match-tat rwrIs= trans_tat THEN resolve_tat rwrls 2 THEN match_tat; > val EQ_REW-TAC =fn : tactic + rule list + tactic

match_tat

should s=t

be a tactic taking

a rule of the form

H ’

P

where s is ?-free, and enumerating (via backtracking) all possible matches oft with s. This means it returns the rule $, having instantiated the variables in t yielding some t’ such that s=t’ holds. Here is a symbolic trace of an application of EQ_REW_TAC to a rule with the premises trans-tat: resolve_tac

rwrls 2:

match_tat:

s=?x s=?y

H ?y=?x

s=l

H

H [?x==r] [?x=r,

H

a]

The rightmost column shows the resulting variable bindings: I = r is some equation in rwrls and u a substitution generated by match_tat such that s and a(l) are equal. After having defined the generic tactic for rule application, let us now look at some popular

equational

theories

and their matching

problems.

UniJication and matching In this section unification and matching algorithms for commutativity, associativity, and associativity+ commutativity are described. I do not claim that the algorithms themselves are original but, apart from commutativity, I am not aware of a similar presentation in terms of proof rules. The basic idea is due to Martelli and Montanari: systems of equations are solved by successive transformation [18]. This idea has been elevated to a principle in Claude Kirchner’s work on unification (e.g. [13]). In Isabelle it is realized as transformations between rules of the form 4.4.1.

ul =wl

. . un=wn P

(6)

E9uotional reasoning in Isabel/e

where the equations should

simplify

equations

above the line are the ones to be solved.

the equations

have disappeared,

on the way constitute two kinds

137

in some

The process

i.e. have been solved.

a solution.

of simplifications,

sense.

In contrast

decomposition

Each transformation terminates

The variable

to Claude

Kirchner,

and mutation,

bindings

when

all

created

who distinguishes

we are less specific and

simply assume that the transformations are expressed as conditional equations of the form (4). In Prolog terms the equations above the line in (6) are the query and the Horn clause transformation rules the program to answer it. To simplify the termination problem, equations of the form ?x = t (or vice versa) are treated separately: they do not need further simplification and can be solved directly by reflexivity, i.e. by binding ?x to t. Notice that reflexivity fails if ?x occurs in t (occur-check!). Hence this principle is only adequate for so-called simple theories, i.e. theories where the above equation does not have a solution. The theories discussed in this section happen to meet this restriction. A second observation is that all congruence rules (tongs) are valid decomposition rules and do not jeopardize

termination.

Thus the following

general tactic is obtained:

fun unify decomp_rules=SELECT_lst_GOAL (UNTIL_THM (COND var (refl-tat, resolve_tat ORELSE refl_tat))); > val unify=fn : rule list + tactic

(tongs

@ decomp_rules)

1

where val var=fn : rule + boQl is a function which tests whether the first premise of a rule is an equation with a ?-variable on either side. The application of the decomposition rules is guarded by ORELSE refl-tat to take care of equations c = c for constants c which cannot be decomposed further. The first premise is assumed to be the original unification problem. Decomposition and reflexivity are applied to it until all equations A trivial instantiation need as decomposition

have been solved. of unify yields the Robinson unification laws are the congruence rules tongs:

algorithm.

All we

val robinson = unify [ 1;

> val robinson =fn : tactic Of course Isabelle provides higher-order and thus in particular Robinson unification anyway. The simplest nontrivial example is commutative unification. Commutativity gives rise to two decomposition rules: the original congruence rule and congruence modified by commutativity. Lemma 4.3. {f(x, y) =f(y, If g is in Fc

Let Fc be the set of commutative function symbols, let C = x)/f6 F,}, and let s = g(s,, . . . , s,) and t = g(tl, . . . , t,) be fwo terms.

27 Nipkow

138

Otherwise s =c t

e Vi. si =c t,.

All we need to do is to generate

the second

rule

?x2=?yl

?xl =?y2 comm-cong=f(?xl,

decomposition

?x2)=f(?yl,

?y2)

from the rules ?xl =?yl

?x2 = ?y2

and

Cong=f(?xl,?x2)=f(?yl,?y2)

comm=

f(?xl, ?x2)=f(?x2,

?xl)

It is not difficult to see that trans RES tong RES comm yields comm-tong. the following function computes the required decomposition rule fun c_decomp(cong,

comm)=trans

RES comm

Thus

RES tong;

=fn : rule * rule + rule

> val c-decomp

and unify [c_decomp(cong, camp)] yields a commutative unification algorithm for the function symbol f. The same algorithm can be found many times in the literature, also in [ 131, where it is presented in terms of the above two decomposition rules too. A more traditional account can be found in [9], where this algorithm is also shown to terminate. It yields a complete but not minimal set of unifiers. The same decomposition idea works for associativity too.

Lemma

4.4.

Let

F_, be

the

set

{ftf(x, y), z) =f(x,f(y, z>> Ife W, two terms. Zf g is in FA s

=A

t e

(SI

=A

t, A s2 =A

of

associative

and let s = g(s,,

t2) v (s,

v (ds,,

=A

g(h,

u,

function

u,

=A

symbols,

. . . , s,) and t = g(tl,.

A du,

t, n s2 =A

s2)

d”,

=A

let

A =

. . , r,) be

t2)

b))

for some term u. Otherwise s

=A

t

c3

vi. si

=A

tj.

In exactly the same way as for commutativity, it yields a unification algorithm. However, the process of deriving the two additional decomposition rules in Lemma 4.4 by resolution of the basic equality rules and associativity is more complex. Given ?xl =?yl Cong=f(?xl,

?x2 =?y2

?x2)=f(?yl,?y2)

and

asso=

f(f(?x, ?y)* ?z)=f(?x,

f(?y. ?z))

Equational reasoning in Isabel/e

139

the ML expression (trans RESN (2,cong RES refl)) RES ((trans RES (tong RESN (2, refl)))

evaluates

RESN (2, asso))

to acongl

In a similar

?x=f(?z,

=

f(?u, ?y)=?t

f(?x, ?y)=f(?z,

manner

acong2 =

?u)

(exercise!) f(?x, ?u)=?z

?t)

one can derive ?y=f(?u,

f(?x. ?y)=f(?z,

?t)

?t)

Since we do not care to spell out this process

in detail,

we simply

assume

there is

a function =fn : rule * rule + rule list

> val a_decomp

which takes a (tong, asso)-pair and returns the list [acongl, acong2]. This list can then be passed to unify to obtain a tactic for associative unification. It should however be added that there are two problems with the resulting tactic. It is well known [25] that complete sets of unifiers modulo associativity may be infinite, as for example in f(a, ?x)=f(?x, a), and that the decision problem is quite complex [17]. Our algorithm can be shown to be equivalent to Plotkin’s [25]. Therefore it enumerates all unifiers but is not guaranteed to terminate, even if there is a finite complete set of unifiers. Still worse, the definition of unify is based on a depth-first strategy (UNTIL) of applying the decomposition rules and may therefore not even enumerate all unifiers but disappear down some infinite branch. This latter problem can be fixed by using a breadth-first version of UNTIL which is also available in Isabelle. Fortunately, matching modulo associativity always leads to finite sets of unifiers and the above algorithm is guaranteed to terminate. Since matching is sufficient for rewriting, our algorithm fits the bill. The last and maybe most useful example is associativity-f commutativity (AC). It can be shown that the following three rules, in addition to the ones for associativity and commutativity alone, constitute a correct and complete system of inference rules for equality module AC. ?x=f(?t,

?u)

f(?u, ?y)=?z

f(?x, ?y) =f(?z, f(?x, ?u)=?t

?t)

?y=f(?u,

?z)

f(?x, ?y) =f(?z, ?t) ?x=f(?ul,?u2)

?y=f(?vl,?v2)

f(?ul,?vl)=?z

f(?x, ?y)=f(?z,

f(?u2,?v2)=?t

?t)

The derivation of these rules is not very difficult. The completeness proof involves a large number of case distinctions and shall not concern us here. The termination result is similar to associativity alone: unification need not terminate (although there

140

T. Nipkow

is always

a finite

surprising

if a naive

unification

complete

problem,

equations.

where

It is pleasant

With respect

set of unifiers),

syntactic

approach all known

enough

matching

It would

have been

could

solve the AC

algorithms

solving

diophantine

that matching

to the ML implementation

does.

like the one above involve

can be done in that fashion.

let us just assume that there is a function

=fn : rule * rule * rule + rule list

> vat ac_decomp

which computes all the required decomposition rules by composing associativity and commutativity-hence three arguments. There are a number of other theories which admit this treatment.

congruence, Usually

the

respective decomposition rules allow only matching, for example distributivity [ 191. Only trivial theories like idempotence yield a unification algorithm. Since we have demonstrated the basic mechanism and looked at some of the more useful theories we will not go into the subject more deeply. 4.5. Some simpli$cation

tactics

This section shows how the various kinds of rewriting introduced in the preceding sections can be combined into more powerful tactics for simplifying equations. Combining rewriting with rules (REW_TAC, Section 4.1) and assumptions (asm_rew_tac, Section 4.3), we obtain fun ASM_REW_TAC Integrating definition

rewriting

rwrls=REW_TAC

modulo

of asm_rew_tac

equations

rwrls ORELSE

asm_rew-tat;

as well is not quite as simple because the

makes no provisions

for a matching

tactic.

Hence

we

first need fun eq_asm_rew_tac strip_left_tac

match_tac=

THEN trans-tat

resolve_tat [assume] > val eq_asm_rew_tac=fn which extends asm_rew_tac

THEN

2 THEN match_tat; :tactic+ tactic

to take matching

into account.

EQASM-REW-TAC

is similar to ASM-REW-TAC: fun EQ_ASM_REW-TAC

match_tat

rwrls=

EQ_REW_TAC match_tat rwrls ORELSE eq_asm_rew_tac match-tat; > val EQ_ASM_REW_TAC=fn : tactic + rule list + tactic Finally

we have two simplification

NORM_EQN

and BU from Section

fun SIMP_TAC > val SIMP_TAC

tactics for equations

based

on the tacticals

4.1:

rwrls = NORM_EQN(BU(ASM_REW_TAC

rwrls));

=fn : rule list + tactic

fun EQ-SlMP_TAC match-tat rwrls= NORM_EQN(BU(EQ_ASM_REW_TAC > val EQ_SIMP_TAC=fn

: tactic+

match_tat

rule list + tactic

rwrls));

Equational

These

simplification

Therefore 4.6.

tactics

we refrain

Rewriting

Up to now

are sufficient

from presenting

by higher-order

we have

reasoning in Isabelle

141

for the sample

the integration

proofs

of conditional

in this

paper.

rewriting

as well.

of Isabelle.

All the

matching

not made

use of any special

feature

algorithms could be implemented on any general purpose theorem prover with a tactic language. What makes Isabelle special is the fact that it is based on higher-order logic, i.e. constants and variables in the object-logic can have function types. Consequently the basic inference engine contains a higher-order unification algorithm. We can use this fact to derive some simple rewriting tactics based on higher-order matching. The congruence rule for equational logic is sometimes expressed

as x=y

crx1= C[Yl ’ where x and y are terms and C stands for an arbitrary “context”. inference rule can be formalized almost exactly like this, assuming term is declared as a function variable:

In Isabelle this that C : term +

?x=?y h"-cong=?C(?x)=?C(?y) Given

a particular

val ho_eq=

equation,

ho_cong

ho_eq =

for example

RES eq yields

?C(O+?x)=?C(?x)

the rule .

Let us see what happens if ho_eq is resolved with an equational goal, for example s(0) +(0 +O)=?y. The unification algorithm instantiates ?C to hz.s(O) +z, ?x to 0 and ?y to s(O) +O. If there is more than one occurrence of 0 +?x, Isabelle’s unification algorithm matches against all of them, thus leading to a simultaneous replacement of multiple subterms: resolving (0 +0) +(0 +0) =?y with ho-eq leads to ?C=hz.z +z, ?x=O and

?y=O +O. Unfortunately, any equational goal can be resolved with ho-eq, even if the pattern O+?x does not appear on its right-hand side: ?C is simply matched to a constant function. Resolving the goal O=?y with ho_eq leads to ?C=Az.O, ?x=?x and ?y=O. Hence any repeated application of rewriting via higher-order matching has to detect normal forms by detecting that a rewrite step has had no effect. Instead of presenting a normalization tactic in the usual style, we can try and be a bit more fancy. Up to now we have only been concerned with normalizing terms and equations. If this is to be used for general theorem proving, we must be able

T. Nipkow

142

to normalize

subterms

of arbitrary

out for free. In the sequel ho_form_cong Resolving

an equation

=

formulae.

With higher-order

let P’ be a variable ?x=?y

variables

this drops

of type term + form and

?P’(?y)

?P’( ?x)

s = t with ho_form_cong

yields the rule M.

Using this rule

backward, we can replace s by t in an arbitrary formula P’. This leads to a simple tactic for normalizing all subterms of the first premise of a rule: fun HO-NORM-FORM let fun unchanged fun check_tat

ho-rules= rule1 rule2 =premisel rule1 =COND

fun ho_rew_tac

(rulel) =premisel

(unchanged

rulel)

(rule2);

(no_tac, all_tat);

rule=

(resolve_tat ho-rules 1 THEN check_tat in REPEAT ho_rew_tac end; >val HO_NORM_FORM=fn:rule list+ tactic

The parameter ho-rules should be a list of rules equations can be brought into this form by

rule) rule

of the form w_ Any list of elementwise resolution with

ho-form-tong.

The main body of the function is pretty obvious: rewriting is applied until it fails, indicating that we have reached a normal form. Rule application consists of resolving the first goal of the current rule with a rule in the list ho-rules, followed by a check that this has actually led to a rewrite, i.e. the first goal has changed. This check is performed in check_tat: depending on whether unchanged returns true or false, COND selects no_tac, i.e. fails, or all_tac, i.e. passes the rule through unchanged. The function premise1 of type rule+ term returns the leftmost premise of a rule and is provided Unfortunately,

by Isabelle. it only works

for unquantified

formulae.

In Isabelle,

quantified

formulae converted

are represented as A-expressions. For example ALL x.0+x=x would be to G =AII(Ax.O +x=x), where All is a logical constant of type (term+ form) + form. Unification of G with ?P’(O +?x) yields only the trivial unifier, i.e. the constant function, for ?P’. The reason is that it is impossible to write G as (At.AII(Ax.t=x))(O-tx)

because

be different. This problem can be solved the correct rule would be

p-conversion by going

would

to a higher

force the x in t=x

and 0+x

to

type level. In the case above,

?R(Ax.x) vho-cong=?R(Ax.O+x)

where ?R is of type (term + term) + form. This scheme works because any subterm of the form O+t can be written as (Ax.O+x)(t). However, it is not possible to give a rule like ho_form_cong which could turn any equation into an inference rule like vho-tong. This is because the exact form

Equorional reasoning

of the higher-order equation.

inference

A higher-order

rule depends

version

in Isabelle

143

on the number

of for example

?x +?y=?y

of free variables

in the

+?x is

?R(Ax.Ay.x +y) ?R(Ax.Ay.y+x) Having presented

the basic ideas, it is not very difficult to generalize

to conditional

rewrite rules. The exact details are omitted here as they do not involve new ideas. On the other hand it is not clear whether rewriting modulo equations and higher-order matching can be combined. The reason is that higher-order matching combines redex selection and matching. Hence it seems difficult to try different matches, for example by permuting arguments. The same is true for built-in notions of equality which the latest version of Isabelle provides. Using higher-order matching or built-in equality yields simpler and/or faster rewriting tactics, doing it by basic equality reasoning is ultimately more flexible if sometimes prohibitively more expensive. 4.7. Termination So far we have not mentioned the problem of termination. th,at the given set of rewrite rules induces a well-founded are a large number of techniques for proving termination (see [l]), all of which share the property that they require tion effort. Hence we have refrained from implementing However, there is no principle problem; all it requires the internal representation of terms in Isabelle.

5. Inductive

theorem

We have tacitly assumed relation on terms. There of term rewriting systems considerable implementaany of them for this work. is some knowledge about

proving

This section presents a simple tactic for inductive proofs of equations and uses it in conjunction with the simplification tactics of Section 4.5 to prove a collection of results about the natural numbers from first principles. The tactic itself is very simple: all subgoals resulting from the application of an induction schema are proved

by rewriting,

where

subgoals

representing

the induction

step can also be

rewritten with the induction hypothesis. In order to formulate induction schemata we need both universal quantification and some form of implication which for example sequents as introduced in Section 4.3 provide. A typical induction rule, the one for natural numbers generated by 0 and s (successor), looks like this: N_ind=?A

I- ?P’(O)

?A, ?P’(x) t ?P’(s(x))

?A F- ALL x. ?P’(x) where P’ is a variable of type term + form and A a list of assumptions. Isabelle provides the means for expressing that x should not occur free in ?P’ or ?A.

(8) also

144

T. Nipkow

We will now discuss

the induction

fun IND_TAC

sch eq-tat

ind_sch_tac

sch

simp_tac

starting

from the top-level

IND_TAC:

var=

sch var THEN simp_qnt_eqns

eq_tac

simp_tat;

=fn : rule + tactic + tactic + string + tactic

> val IND_TAC

The parameters

tactic,

and

var represent

the induction

schema

and

the induction

variable. The latter comes as a string to facilitate interactive use. The tactic ind_sch_tac is responsible for applying the given induction schema with the given variable: fun ind_sch-tat

sch var=

qnt_frees-tat

The function

var THEN resolve_tac

qnt_frees_tac

universally

quantifies

[sch] 1;

all free variables

in the first

premise, ensuring that the outermost quantification involves the induction variable var. We omit all code for qnt_frees_tac because it involves too much Isabelle specific detail and not much “logic”. Suffice it to say that universal quantification over some variable v is achieved by resolving with the predicate calculus rule a,,_e,im

=ALL x. ?P’(x) ?p’(?x)

after having instantiated variables, consider

?x with v. To see the need for explicit

quantification

of all

Example 5.1. We assume the usual equational definition of the data type of lists. For simplicity we use the ML notation for lists. We define two reverse functions on lists and show their equivalence: rev: list + list rev(( I)=[ I rev(a::I)=rev(l)@[a] irev: list x list + list irev([ 1, s)=s irev(a::l, s)=irev(l, a::s)

Structural

induction list_ind =

over lists can be written ?P’([ 1)

as

?P’(I) k (a::l)

ALL x. ?P’(x)

where neither I nor a may occur free in ?P’. By induction on I we show that irev(l, s)=rev(l)@s

(9)

holds. The base case follows by normalizing both sides. The induction step requires us to prove irev(a ::I, s)=rev(a ::I)@s under the assumption of (9). irev(a ::I, S) rewrites to irev(l, a ::s), which can only be rewritten to rev(l)@(a ::s) ifthe assumption is universally quantified over s. Hence (9) needs to be brought into the form ALL 1. ALL s. irev(l, s) = rev(l)@s.

Equational

After application subgoals eq_tac. depends eq_tac

of the induction

by first simplifying

reasoning

schema,

145

in Isabel/e

IND-TAC

them with simp_tac

tries to solve the resulting

and then finishing

This is where the real work is done and the success largely

on the quality

of the simp_tac

them off with

of an inductive

and eq_tac.

proof

In its simplest

form

is just refl_tat. fun simp_qnt-eqns eq-tat simp_tac= COND is-theorem (all_tat, strip_tat THEN simp_tac THEN ((eq-tat THEN simp-qnt-eqns ORELSE all_tac)

eq-tat

simp-tat)

);

The slightly convoluted form of this recursive tactic is due to the fact that it should either stop if all subgoals have been solved (is-theorem) or if a simplified equation cannot be solved by eq_tac. Since all of our simplification tactics expect to work on equations, strip-tat first removes the quantifiers introduced by ind_sch_tac: val strip_tac=REPEAT(resolve_tac AILintroduction

is the following

all_intr =

Isabelle

ensures

[all_intr]

basic predicate

1);

calculus

rule:

P’(x) ALL x. P’(x)

that the new variable x does not occur free in P’. on induction by presenting a longer example which features and the various simplification and matching tactics described in

We close this section

both induction Section 4.

Example 5.2. Let N_ind be as in (8) above, N_rules=[?At O+?y=?y, ?A+O*?y=O, ?A k- sum(O)=O, be the list of equations

defining

and let

?At- s(?x) +?y=s(?x+?y), ?A~s(?x)*?y=?y+(?x*?y), ?A I- sum(s(?x))=s(s(O))

addition,

multiplication

* s(?x) +sum(?x)]

and the sum of the first n

even numbers. Eventually we want to show that sum(x) =x * s(x) holds. On the way to this goal we show associativity and commutativity of both + and *, thus gaining access to rewriting modulo AC. The simplification tactics come from Section 4.5. Initially we have val simp_tac=SlMP_TAC val N_ind_tac=IND_TAC Our first goal is associativity

N-rules; N-ind refl_tac of addition:

goal “At-(x+y)+z=x+(y+z)“; >A~(x+y)+z=x+y+z ~1. A~(x+y)+z=x+y+z

simp_tat;

T. Nipkow

146

The function

goal is part of Isabelle’s

the only imperative formula

simple user interface

to the “subgoal

manager”,

part of the system: it reads a string and makes the corresponding

the first goal to be solved.

The output

(lines

starting

read as an inference

rule where the first line is the conclusion

lines are the premises

(=subgoals).

Remember

rule f and work our way backwards.

with >) should

that we start with the trivially

We attack

subgoal

be

and the numbered

1 by induction

correct

on x:

by(N_ind_tac “xl’); >AI-(x+y)+z=x+y+z No subgoal

has remained,

so the proof went through

by a single induction.

We save

the resulting rule by typing vat pa =top_rule( ) which generalizes (replaces x by ?x) the proved theorem and binds the result to the ML variable pa for later use. Next comes commutativity, which needs three inductions. Nonessential system output like the response to goal has been omitted. goal “A I- x +y=y

+x”;

by(N_ind_tac ‘lx”); >l. Akx4=x4+0 >2.

A, ALL u. x3+u=u+x3t-ALL

u. s(x3)+u=u+s(x3)

We are left with two subgoals: neither the induction basis nor the step could be proved by rewriting. We try another induction on “x4”, but only after reversing the first equation (sym_tac)-otherwise the induction hypothesis in that subproof is the nonterminating equation x4=x4+0. (Odd variable names are due to renaming caused by resolution.) by(sym_tac THEN N-ind_tac “x4”); > 1. A, ALL u. x3+u=u+x3~s(x39+x3)=x39+s(x3)

The first subgoal

has been solved

and simplification

of the second

goal (which

is

now the first) has started. After a final induction on “x39” all subgoals have disappeared. The commutativity theorem is stored in pc. Thus we have proved that + is AC, and we can generate the rules for AC decomposition and the corresponding matching

tactic val p_decomp=ac_decomp(pcong,

pa, PC);

val ac_match_tac=unify(p_decomp);

which gives rise to a more powerful

simplification

and induction

val simp_tac=EQ_SIMP_TAC ac-match-tat val N_ind_tac= ind-tat N_ind ac-match-tat

which helps us to tackle the next theorem,

distributivity

tactic

N-rules; simp-tat;

of * over +:

goal “A F (x +y) * z=x * z +y * z”; by( N_ind_tac

“x”);

One induction proves the equation and we append it to our list of rewrite rules N-rules. The tactics simp-tat and N_ind_tac are redefined with the extended set

Equational

reasoning

of rules.

Next on our list is associativity

relevant

output

in Isabelle

and commutativity

147

of *. Again,

only the

is reproduced:

goal “At-

(x * y) * z=x * y * z”;

by( N_ind_tac

‘lx”);

val ta =top_rule(

);

goal “A k x * y=y * x”; by(N_ind_tac “xl’); >l.At-0=x4*0 >2.A,ALLu.x3*u=u*x3tALLu.s(x3)*u=u*s(x3) by(sym_tac THEN N_ind-tat “x4”); >1.A,ALLu.x3*u=u*x3tx38+x38*x3=x38*s(x3) by(sym_tac

THEN

val tc=top_rule(

N-ind-tat

“x38”);

);

In fact, the proof is rather similar to the one for AC of +. We can now combine the AC decomposition rules to obtain an AC matching algorithm for both + and *:

val t_decomp = ac_decomp(tcong, val ac_match_tac=match_tac(p_decomp The tactics simp_tac Finally we can show:

and

N-ind-tat

ta, tc);

are redefined

@ t-decomp); with the new matching

tactic.

goal “sum(x)=x * s(x)“; by( N_ind_tac ‘lx”);

Since all the proofs have gone through, it is not obvious that we actually needed to prove both + and * AC before we could solve the last proof. Just to give an example of what happens if we try to prove the last theorem directly: N_ind_tac leaves the subgoal > 1. s((x2 +x2 * s(x2)) +s((x2 +x2 * s(x2)) +O))=s(s(x2 around

which requires

+x2 * s(s(x2))))

AC and distributivity.

6. Conclusions We have presented implementations of a number of different techniques for equational proofs in a general theorem proving framework. All of them are rather short, most of them not difficult to understand and some of them even elegant. Partly this is due to the fact that we used a functional language, but mostly to the fact that Isabelle provides the right infrastructure and abstractions (rules, tactics, tacticals). We hope that this is sufficient proof not just of the feasibility but also the attractiveness of our approach. Unfortunately efficiency is still problematic. Ordinary rewriting proceeds at a rate of about 5 reductions per second (on a VAX

T. Nipkow

148

3600). The complexity and the number In addition universal

to the examples

unification

equations A similar

of AC-rewriting

of AC-operators

depends

very much on the size of the term

in it. It is typically presented

an order of magnitude

in the paper

as in [ 111 and the basic Knuth-Bendix

slower.

we have also implemented algorithm

[15], orienting

by user interaction. program

has been carried

out by Larry Paulson

in LCF and reported

in [20]. His rewriting tactics are more general in some respects and less so in others. In particular he does not consider rewriting module equations. On the implementation side the biggest difference is the simplicity of rewriting in Isabelle due to built-in unification, not available in LCF. Another system with similar capabilities to Isabelle is A-Prolog. In [2] it is shown how A-Prolog can be used to specify theorem provers. It does not seem difficult to implement all of our rewriting tactics in A-Prolog. In fact, it would be interesting to see how far one could

go in implementing

them in ordinary

Prolog.

Acknowledgement Many thanks go to Larry Paulson for his Isabelle system and a number of helpful discussions, to Dave Matthews for his Poly/ML system, to Cliff Jones and John Guttag for providing the excellent environment for this research, and to Mario Wolczko for making _ and @ work (almost). Some of the explanations and code in Section 2.2 are directly taken from Isabelle source files.

References [I] N. Dershowitz, Termination of rewriting, J. Symbolic Comput. 3 (1987) 69-117. [2] A. Felty and D. Miller, Specifying theorem provers in a higher-order logic programming language, in: Proceedings CADE-9, Lecture Notes in Computer Science 310 (Springer, Berlin, 1988) 61-80. [3] J.H. Gallier, Logicfor Computer Science (Harper and Row, New York, 1986). [4] S.J. Garland and J.V. Guttag, Inductive methods for reasoning about abstract data types, in: Proceedings 15rh POPL, San Diego, CA (1988) 219-228. [5] A. Geser and H. Hussmann, Experience with the RAP system: A specification interpreter combining term rewriting and resolution, in: Proceedings ESOP-86, Lecture Notes in Computer Science 213 (Springer, Berlin, 1986) 339-350. [6] M.J.C. Gordon, R. Mimer and C.P. Wadsworth, Edinburgh LCF: A Mechanised Logic of Computation, Lecture Notes in Computer Science 78 (Springer, Berlin, 1979). [7] Ph. de Groote, How I Spent My Time in Cambridge with Isabelle, Rept. RR 87-1, Unit6 d’lnformatique, Universite Catholique de Louvain, Belgium (1987). [8] R. Harper, D. MacQueen and R. Milner, Standard ML, Rept. ECS-LFCS-86-2, Lab for Foundations of Computer Science, Department of Computer Science, University of Edinburgh (1986). [9] A. Herold, Combination of unification algorithms in equational theories, Ph.D. Thesis, FB Informatik, Universitat Kaiserslautern (1987). [IO] G. Huet and D.C. Oppen, Equations and rewrite rules: A survey, in: R.V. Book, Ed., Formal Language Theory: Perspectives and Open Probiems (Academic Press, New York, 1980). [ 1 I] H. Hussmann, Unification in conditional-equational theories, in: Proceedings EUROCAL-85, Lecture Notes in Computer Science 204 (Springer, Berlin, 1985).

Equational

reasoning

in Isabelle

149

1121 J.-P. Jouannaud and H. Kirchner, Completion of a set of rules module a set of equations, SIAM J. Comput. 15 (1986) 1155-1194. [13] C. Kirchner, Computing unification algorithms, in: Proceedings Symposium on Logic in Computer Science, Cambridge (1986) 206-217. [14] C. Kirchner and H. Kirchner, REVEUR-3: The implementation of a general completion procedure parameterized by built-in theories and strategies, Sci. Comput. Programming 8 (1987) 69-86. [15] D.E. Knuth and P.B. Bendix, Simple word problems in universal algebra, in: J. Leech, Ed., Computational Problems in Abstract Algebra (Pergamon, Oxford, 1970) 263-297. [16] P. Lescanne, REVE: A rewrite rule laboratory, in: Proceedings CADE-8, Lecture Notes in Computer Science 230 (Springer, Berlin, 1986) 695-696. [17] G.S. Makanin, The problem of solvability of equations in a free semigroup, Soviet Akad. Nauk SSSR 233 (1977). [18]

A. Martelli Languages

and

U. Montanari,

Syst. 4 (2) (1982)

An efficient

unification

algorithm,

ACM

Trans.

Programming

258-282.

J. Mzali, Matching with distributivity, in: Proceedings CADE-8, Lecture Notes in Computer Science 230 (Springer, Berlin, 1986) 496-505. [20] L.C. Paulson, A higher-order implementation of rewriting, Sci. Comput. Programming 3 (1983) [19]

119-149. 1211 L.C. Paulson,

Natural deduction as higher-order resolution, J. Logic Programming 3 (1986) 237-258. L.C. Paulson, Logic and Computation (Cambridge University Press, New York, 1987). [23] L.C. Paulson, The foundation of a generic theorem prover, J. Automated Reasoning (to appear). [24] L.C. Paulson, A preliminary user’s manual for Isabelle, Rept. 133, Computer Laboratory, University of Cambridge (1988). [25] G.D. Plotkin, Building-in equational theories, in B. Meltzerand D. Michie, Eds., Machinelntelligevce 7 (Edinburgh University Press, Edinburgh, 1972) 73-90. [22]