• No results found

Coverset induction in the Maude ITP

Chapter 5 Sufficient completeness

7.3 Coverset induction in the Maude ITP

We have extended the Maude ITP with two commands cov and cov* which apply coverset induction when invoked by the user. The difference between the two commands is that cov* will automatically simplify all of the subgoals generated by coverset induction with the auto command, while cov will leave them unchanged. Each command takes the pattern as an argument with the syntax:

(cov on pattern ) (cov* on pattern )

where pattern is a term whose variables are universally quantified in the current formula.

One useful feature of coverset induction is that, in addition to generating potentially useful induction hypotheses, it specializes terms appearing in the current problem to match additional rules in the specification. This allows them to be simplified by rewriting. Splitting based on constructors is called constructor splitting, and has been quite useful in our powerlist case study. The ITP already offers a command ctor-term-split to do this, but the command only replaced a single variable with its constructor memberships, and did not explicitly attempt to match a term against the left-hand sides of equations. As a consequence, ctor-term-split often had to be invoked several times to achieve the required matching. In contrast, a single coverset induction command would have done the job. Coverset induction also potentially introduced induction hypotheses even if they were not necessary, and so we decided to add the com- mands eq-split and eq-split* which essentially perform coverset induction, but do not add the induction hypotheses.

(eq-split on pattern .) (eq-split* on pattern .) The difference between these two commands is that eq-split* invokes the auto command to attempt to automatically discharge each subgoal while eq-split does not modify the generated goals.

Coverset induction is the main type of induction that we use in the powerlist case study in Chapter 8. Our experience led us to improve the theoretical algorithm described in the previous section in several ways: (1) apply the ∆- rule only to variables that are demanded by the most equations in E ; (2) use a simple subsumption test to eliminate redundant induction cases; (3) allow substitutions in subgoals to be further specialized by additional patterns; and (4) allow the user to define alternative constructors for sorts in the specification.

7.3.1

Most demanded variables

One of the main differences between our approach to coverset induction in mem- bership equational logic and the original idea in unsorted logics is that our scheme may potentially generate multiple induction subgoals for each equation. One heuristic to reduce the number of subgoals is to use an intelligent strategy for deciding when to expand a variable x using the rule (7.3). For the ITP, if multiple variables may be expanded by the rule (7.3), we expand the variable demanded by a maximal number of equations. This is similar to the idea of natural narrowing [46], with the main difference being that we are narrowing a variable to consider all ground instances of a term rather than just considering specific instances that unify with a set of patterns.

To illustrate why the choice of which variable to expand is important, con- sider the theory E with constants a and b and a binary symbol f . In addition E contains constructor memberships a : s and b : s, and equations:

f (a, x) f (b, a) f (b, b)

If asked to perform coverset induction with the pattern f (x1, x2)x1:s∧x2:s, we

can expand either x1 or x2. If we expand x2 in f (x1, x2)x1:s∧x2:s using the

rule (7.3), we get the patterns

{ f (x1, a)x1:s, f (x1, b)x1:s}.

We next can only expand x1 in both of these goals and the narrowing phase

terminates with four cases:

{ f (a, a), f (a, b), f (b, a), f (a, b) }

The schema generation phases will then produce four separate subgoals, one for each term. However, if we expand x1 first, we obtain the patterns

{ f (a, x2)x2:s, f (b, x2)x2:s}.

We then only need to expand x2 in f (b, x2), and thus the narrowing phase

terminates with the patterns

{ f (a, x2)x2:s, f (b, a), f (b, b) }

which are then instantiated into three subgoals.

Given a pattern p and an equation l = r if α, we say that a variable x ∈ vars(p) is demanded by l iff there is a most-general unifier θ = mgu(p, t) such that θ(x) is not a variable. The strategy we have chosen for the ITP is to only apply the rule (7.3) to variables that are demanded by a maximal number of equations in E . This is a greedy algorithm, but has worked well in the Powerlist

case study described in the next chapter.

7.3.2

Subsumption checking

A second optimization that we use is to perform subsumption checking to re- duce the number of cases. We say that a conditional term tα subsumes t0α0

iff each ground instance of t0α0 is a ground instance of tα. Due to the poten-

tial for arbitrary conditionsα and α0, it is in general undecidable whether one conditional term subsumes another. This means that in general, our cover- set induction approach will always generate an induction scheme, but it may have redundant cases. To eliminate some of those redundant cases, we have implemented an approximate solution that can often detect subsumption syn- tactically. To understand our approach, first observe that tα subsumes t0α0 if

there is a substitution θ such that: • tθ = t0,

• for each equation l = r ∈ α, lθ = rθ ∈ α0, and

• for each membership l : s ∈ α, there is a membership lθ : s0 ∈ α0 such that

s0 is a subsort of s.

These properties are easy to check, and the ITP will remove a conditional term t0α0 from the current conditional terms ∆i when a different conditional term tα

is detected to satisfy these three properties. This removal is sound, because the set of ground instances of ∆i are preserved.

To see how this subsumption is useful, consider the following theory E over a signature with sorts s1 < s2, and unary functions c and f that contains the

memberships:

x : s2if x : s1 c(x) : s1if x : s1 c(x) : s2if x : s2.

Additionally, E contains a single equation with the left-hand side f (c(x)). Given the initial pattern f (x)x:s2, we expand x with the memberships x : s2if x : s1

and c(x) : s2if x : s2. This yields the set

{ f (x)x:s1, f (c(x))x:s2}

We then must further instantiate f (x)x:s1 to yield the final set

{ f (c(x))x:s1, f (c(x))x:s2}

However, since s1is a subsort of s2, we have an extra pattern f (c(x))x:s1 which

would generate a redundant induction case. By using our syntactic check, the ITP will automatically remove f (c(x))x:s1.

7.3.3

Additional patterns

As shown in the next chapter, many of the lemmas in our powerlist case study are discharged with a single cov* command. However, for many of the lemmas where this failed, we could discharge them automatically if we performed ad- ditional constructor splitting on terms appearing in the subgoal. This process requires multiple commands, and we decided to automate the process by intro- ducing two coverset induction commands that take additional patterns, called split patterns, which are used for splitting the subgoals. They are not used to generate the induction hypothesis. The two commands have the following syntax:

(cov-split on pattern split split-patterns ) (cov-split* on pattern split split-patterns )

where pattern is the term used for coverset induction and split-patterns is a semicolon separated list of terms.

The cov-split (resp. cov-split*) commands can be thought of as per- forming coverset induction with the given pattern, and then eq-split (resp. eq-split*) on the induction cases. The actual implementation is somewhat different, and is achieved by modifying the narrowing phase described in the previous section. Essentially, our narrowing phase additionally guarantees for each pattern p in the split patterns and each left-hand side l of an equation in E that

mgu(p, l) 6= ∅ =⇒ p matches l.

Our experience with the powerlist case study has shown that virtually all of the lemmas involving coverset induction and eq-split could be solved in a single cov-split* command.

7.3.4

Alternative constructors

The fourth and final extension to coverset induction that we have implemented in the ITP is the ability to define alternative constructor declarations with the command

(ctor-def name : A{x : s}

(E{Y1} t1= x & cond1) V ... V (E{Yn} tn= x & condn) .)

where each formula condi is a (possibly empty) conjunction of equations and

memberships.

After giving this command to the ITP, the ITP creates a subgoal which requires the user to prove the given formula, and it adds a set of alternative memberships

to the current goal. These memberships can then be used in lieu of the normal constructor memberships with sort s during the narrowing phase of coverset induction. In order to specify which alternative memberships to use, we added the following four commands:

(cov using names on pattern ) (cov* using names on pattern )

(cov-split using names on pattern split split-patterns ) (cov-split* using names on pattern split split-patterns ) where names is a semicolon separated list with the names of constructor def- inition names. Each name in the list must be associated to memberships for a distinct sort, and when a name is provides we replace the memberships in E for that name with the memberships Mnamefor the purposes of instantiating a

variable using the rule (7.3).

Alternate constructors are used in the powerlist case study in several places. A key property of powerlists is that each powerlist with more than one element can be represented as either the concatenation P | Q of two powerlists or the interleaving P × Q of two powerlists. In our Maude specification of powerlists, we use a membership with | as the main constructor, but prove an alternate set of constructors with ×. For operations that are most naturally defined using ×, we use the alternate constructors for coverset induction.

In some cases, one may want to make the alternative constructor definitions the default constructors. This can be done with the command

(set-default-ctor name.)

After issuing this command the memberships with the given name will be used for their associated sort whenever constructor narrowing occurs. The default set of memberships for a sort can be used by calling set-default-ctor with the name of the sort.