p
e -► e
to P2» we obtain the schema
- 21 -
S2 : begin
comment tentative binary-search schema
suggest 00
(F,y) := (0,1)
loop suggest !;<<(>( p), 4>(p)<£+y
until y(p)|(p), (p) |t) .
Applying the abstraction mapping
r -*• I
u ■* (u)
x -»■ p
t -* e
to these subgoals yields
purpose Z<$( p), (p)e).
This is not however identical with the subgoals for P2; to make them
equivalent requires extending the analogy with
S+y «— ► w.
If we let ti be their abstract counterpart, then
y -* r\-Z
must be added to the abstraction mapping of P2 and
- 23 -
w
to the mapping for Q2 .
There are, however, problems with applying the transformation y-*"n-£
to the statements of P2« If we apply it in a straightforward manner to the
initialization assignment (E ,y) : = (0,1) , then we obtain (F,,t)-?;): = (0,1) . But
the assignment n-£:=l is illegal, as an expression such as n-^ may not appear
on the left-hand side of an assignment. Nevertheless, the desired effect of
making the difference between the new values of r\ and E equal to 1 can be
achieved by the legal assignment r|:=l+0, since is the new value of £. Simi-
larly, the transformed loop-body assignment n-!;: =(n-£)/2 is illegal. To make
it legal, the £ must be transposed to the right-hand side; the resulant
assignment is n:=(Ti+^)/2 .
We are not yet finished, however, as the value of the difference Tp£
also changes whenever £ is assigned to. Accordingly, we must look at the
then-branch assignment £:=£+y, or rather at (5,y) :=(£+y ,y) , where we have
explicitly included a dummy assignment to the variable y. Transforming this
gives (r, ,ti-C): = (^+ti-^,ti-^). Thus, £ should get the value n and n should get
the value rr? plus the new value of £, i.e. the old value of n. The appropri-
ate legal assignment is accordingly (£,n) : = (Ti,2*n-£).
At this stage, the abstracted program is
- 24 -
begin
comment tentative binary-search schema
suggest 00
a,n) :- (0,1)
loop suggest £<(p), (p) I ( p ) (p) 4>(v)(u)(v).
Combined with the previous precondition, we have
4»(u)(v) ,
which holds, in particular, if <\> is the inverse of a monotonic function ,
i.e. if <()((p(u)) ! »u and u(u)<(v) •
Putting everything together, the complete abstraction mapping for P2
is
u/d -»• 4>(u)
c -»• p
e -*■ e
dx u -► 4>(u)
y -*> rrl
-+ o
1 -► 1
and we have derived the schema
- 27 -
begin
comment binary-search schema
assert (Ku)(v) > o<(p)0
(E,n) := (0,1)
loop assert £<(p), (p)(p)|(v) » 0<4>(p)0
(£>n) := (o,\-o)
loop assert £<<|>(p), (p ) | at the point p within a tolerance e.
We show now how this binary-search schema may be applied to the com-
putation of integer square-roots. Our goal is to construct a program that
sets the value of a variable z to L^nJ , where nelN and (_uj is the largest
integer less than or equal to u. This attempt will illustrate some of the
- 28 -
difficulties that may arise in trying to apply a schema.
In this case, we cannot directly match our goal
achieve z=j_/nj varying z
with the output specification of the schema
assert |e-<(>(p) |
we can compare these invariants with our goal* This suggests the instantia-
tion mapping
S - z
-* /""
p -* n
e -► 1
to achieve the first two conjuncts of the goal. In addition we will have to
somehow achieve zeZ.
The preconditions for the schema's correctness are
assert 4>(u)(v) , o<(u)0, the first condition may be satis-
2
fied by taking 4>(u) to be u , provided that the argument u is never negative.
Noting that /n>0 suggests letting o=0; /n
-* r
P
-*■ n
veQ.
Now, we must consider the verification conditions. Applying the
transformations to the initialization condition of P3 we get
T(6( X ),i)-e(x)
on the other hand, applying the transformations to the initialization condi-
tion of Q3 gives
t(0(x),O)=0( X )
XeQ.
- 35 -
The shared condition
xeQ
becomes a precondition for the schema. To unify the remaining conditions of
the two programs we add to the analogy
1 -*• a) +- 0,
to obtain the abstract condition
T(e(x),w)-e veQ
until v»y
(C,v) :- (T(a(v),C),6(v))
repeat
assert C"9(x)
end.
In this manner we have obtained a general schema for computing a
function 9(x). It applies to recursive functions 9(x) such that 9(y)™w is a
unit of an associative and commutative function x, and 9(u)°t(9(6(u) ) ,o(u) )
- 38 -
when i#y The schema is similar to one of the recursion-to-iteration
transformations of Darlington and Burstall [1978].
To see how this schema may be applied to another problem, consider
the specifications
R3 : begin
comment list-reversal program
assert lei
achieve z=reverse(J? ) varying z
end,
where L is a set of lists and reverse(X) is the list containing the elements
of I in reverse order. Assume that we are also given two relevant facts about
reverse: reverse( ())=■() , where () is the empty list, and
reverse(u)=rever8e(tail(u) )*(head(u) ) when u*(), where u*v concatenates the
two lists u and v, (head(u)) is a one element list containing the first ele-
ment of u, and tail(u) is a list of all but the first element.
An initial comparison of the schema's output specification C = 9(x)
with the new specification z=reverse(A) suggests the instantiation
9 -+■ reverse
C -*• z
X - *•
Instantiating the precondition
v#Y D T(9(v),u)-T(e(6(v)),T(o(v),u))
gives
v*Y 3 x(reverse(v) ,u) s »T(reverse(6(v)),x(a(v) ,u) ).
By the second of the above two facts, we have that reverse(v) may be replaced
by reverse(tail(v))*(head(v)), provided that v is not the empty list (). This
- 39 -
suggests the possibility of instantiating y— ► () to obtain
v* ( ) D t(reverse( tail( v) )*(head(v) ) ,u)=-t(reverse(6 (v) ) ,t(o(v) ,u) ) .
The function reverse appears on the two sides of the equality, so we try to
generalize this condition by replacing both occurrences of reverse with an
arbitrary list w. (This is similar to the generalization technique used in
the theorem prover described in Boyer and Moore [1980].) To do that, we must
first unify reverse(6(v)) with reverse(tail(v) ) by instantiating 6— »-tail. We
are left with
v*() D x(w*(head(v)),u)=T(w,T(a(v) ,u)).
Similarly, we unify a(v) with (head(v)), the list containing just the first
element of v, obtaining
v*() Z) x(w*v,u)=t(w,t(v,u)).
This matches with the fact that * is associative, i.e. (w*v)*u=w*(v*u) , by
instantiating t-*-*.
Applying the instantiations that we have found to the other five
preconditions
t(u,w)=u
t(6(y),u)=u
veQ A v*y D Mv)eQ
(3ueIN)6 U (x)=Y
yields
- 40 -
U*0)=*U
reverse( ())*u=u
veQ A v*() D tail(v)eQ
(3uelN)tail U (JD=().
But reverse( ())=() and ()*u=u, since the empty list () is an identity element
of the function *. Thus, the second condition holds. The first suggests let-
ting ar-^O; the third and fourth suggest letting Q-*L. The last condition
then follows from the third, as a property of lists.
The completed instantiation is
-*■ reverse
C -► z
X -* r
Y -► ()
6 -► tail
a(u) -» (head(u))
T -► *
(d - ().
In all, we have derived the following program
R-3 : begin
comment list reversal program
assert £eL
(z,v) :- ((),*)
loop assert reverse(v )*z=»reverse(A) , veL
until v*()
(z,v) := ((head(v))*z,tail(v))
repeat
assert z=reverse(A)
end.
- 41 -
In this example most of the instantiation mapping was derived from
an analysis of the preconditions. The preconditions served, In this way, to
guide the construction of the list-reversal program in the pattern of other
recursive functions.
- 42 -
III . DISCUSSION
We have presented several examples demonstrating a methodology for
deriving an abstract program schema that captures the technique underlying a
given set of concrete programs. Once derived, the schema may be applied to
solve new problems by instantiating the abstract entitites of the schema with
concrete elements from the problem domain. We have also seen how this metho-
dology can be used to derive correctness-preserving program transformations
and to guide their application.
Abstraction and instantiation complement techniques of program
transformation, such as have been advocated by Knuth [1974]. When faced with
the task of developing a new program (or subprogram) to meet a set of specifi-
cations, the programmer ought to first search for an applicable schema. After
instantiating the schema, transformations may be applied to solve any remain-
ing specifications or to increase efficiency. If no applicable schema can be
found, one might still be able to find a schema or program solving some analo-
gous problem, and modify it (see, for example, Dershowitz and Manna [1977]).
The two programs together would then be used to formulate a schema for future
use.
There are a few problems inherent in the use of analogies for pro-
gram abstraction and instantiation. These include "hidden" analogies,
"misleading" analogies, "incomplete" analogies, and "overzealous" analogies.
Hidden analogies arise when given specifications (of the two or more
existing programs in the case of abstraction, and of the abstract schema and
concrete problem in the case of instantiation) that are to be compared with
one another have little syntactically in common. Since the pattern-matching
ideas that we have employed are syntax based, when the specifications are not
syntactically similar, the underlying analogy would be hidden. In such a
situation it is necessary to rephrase the specifications in some equivalent
manner that brings their similarity out, before an analogy can be found. This
is clearly a difficult problem in its own right; in general some form of
means-end analysis seems appropriate.
- 43 -
At the opposite extreme, a syntactic analogy may be misleading. The
same symbol may appear in the specifications of two programs, yet may play
nonanalogous roles in the two programs. Two programs might even have the
exact same specifications, but employ totally different methods of solution.
Situations such as these would be detected in the course of analyzing the
correctness conditions for the abstracted programs.
We have seen how the proof of correctness of a program can be used
to help avoid overzealously applying transformations to unrelated parts of a
program. The proof also helps complete an analogy between two programs, only
part of which was found by a comparison of specifications.
The methods we have described appear to be amenable to automation.
The necessary reasoning ability is the same as is needed for a program-
verification system; the program manipulation abilities are similar to what is
required of program-transformation systems. Of course, we do not expect these
methods alone to suffice for an automatic program-abstraction system to pro-
duce and apply program schemata. But we can envision the possibility of such
methods being embedded in a semi-automatic program-development environment in
which the system performs the more straightforward steps, and the human pro-
grammer guides the machine in the more creative ones.
- 44 -
ACKNOWLEDGMENT
I sincerely thank Zohar Manna and Richard Waldinger for their gui-
dance in initiating this research.
- 45 -
APPENDIX
Gerhart [1975] recommended the hand-compilation of a handbook of
program schemata. Such a collection of shemata, together with a library of
program transformations, could be used in an interactive program-development
system. In this appendix, we have culled fifteen representative schemata from
the programming literature.
We use the following nomenclature:
IN set of natural numbers
3R set of real numbers
Z set of integers
[u:v] set of integers between u and v
j,k,t input variable
x input variable or vector of variables
p,q predicate symbol
c,d,e,f,g,h function symbol
a,b constant symbol
z,r output variable
i,s,y,m program variable
u,v,w universally quantified variable (quantifier often omitted)
n existentially quantified variable
Each of the following schemata is followed by an output assertion giving its
abstract Input-output specification. They are preceded by an input assertion
containing the preconditions for correct application. The general format is
- 46 -
S : begin
comment title (source)
purpose
assert type conditions,
correctness preconditions,
termination precondition
• • •
schema body
• • •
assert output specification
end.
The references are to sources that present an abstract schema; they are some-
what arbitrary, as the methods themselves are all well known. (The schemata
may differ in details from those given in the referenced sources.)
S i : begin
comment element-by-element (Gerhart [1975])
achieve q for all integers between j and k
assert jeZ, kelR, bex,
ue[j:k]Avex 2) h(u,v)ex,
ue[j:k]Avex 3 q(h(u,v),u),
u,we[ j:k]AvexAuk+1, zex
until i>k
(z,i) := (h(i,z),i+l)
repeat
assert ( Vue[ j:k] )q(z ,u) , zex
end
- 47 -
S 2 : begin
comment extremum (Dershowitz and Manna [1975])
achieve q for all Integers between j and k
assert jeZ, kelR,
ue[j:k] D q(u,u),
u,v,we[ j:k]Auk
until i>k-l
i := 1+1
if ~|q(z,i) then z := i fi
repeat
assert (Vue[ j:k] )q(z ,u) , ze[j:k]Vj>k
end
S3 : begin
comment linear-search (Dijkstra [1972])
find least integer between j and k such that q holds
assert jeZ , kelR
z := j
loop assert ( Vue[ j:z-l] )~lq(u) , ze[ j:k+l] Vz=j>k+1
until z>kVq(z)
z := z+1
repeat
assert (3ne[ j:k] )q(n) Z) z=(min ne[ j :k] )q(n) ,
z>j, z>kVq(z)
end
- 48 -
Si*: begin
comment gradient-search (Misra [1978])
search for local extremum
assert aex,
uex 2) t(u) Lx,
uex 3 q(u,u),
u,v,wexAq(w,u)A~lq(w,v) D q(v,u),
uLx 3 g(u)eu,
u,v,wexAq(u,w) 3 q(u,v)Vq(v,w),
(3nelN)|x|=n
comment |x| denotes the number of elements In the set x
z := a
loop (m, s) := (z,t(z))
loop assert ( Vuet(m)-s)q(z ,u) , z,mex, sl_x
until s={}
y :■ g(s)
s := s-{y}
if ~" lq(z,y) then z :■ y fi
repeat
assert (Vuet(m))q(z,u) , zex
until z=m
repeat
assert ( Vuet(z) )q(z ,u) , zex
end
- 49 -
S5 : begin
comment binary-search (Dershowitz and Manna [1975])
approximate transition from q true to q false
assert a,b,telR,
q(a), ~lq(b),
q(u+t)At>v D q(u+v),
t>0
(z,y) := (a,b-a)
loop assert q(z), ~lq(z+y), ab
until yb
end
- 50 -
Sg: begin proc sort(x[j:k] )
comment sorting (Darlington [1978])
sort array segment x[j:k]
assert x[ j:k]ea[ j:k] ,
uea[u':w'] 2) f(u)ea[u" :w' ]*[u' :w'-l] ,
uea[u' :v' ] Avea[v'+1: w'] Z) g(u,v)ea[u' :w'] ,
uea[u':v']Avea[v'+l:w'] 2) bag(g(u,v))=bag(u) Ubag(v) ,
uea[u':w']Af(u)=(w,v) 3 bag(u)=bag(w) ,
uea[u' :w'] Af (u) = (w[u' :w'] ,v) Asorted(w[u' :v] )Asorted(w[v+l:w' ] ) 2)
sorted(g(w[u': v] ,w[v+l:w']))
comment bag(u)=bag(v) means that for each occurrence
of an element in u there is an occurrence of the element in v;
sorted(w[u' :w'] ) = ( Vve[u' :w'-l] )w[v]
~lp(u) D f(u)=h(f(d(u)),u),
(3nelN)p(d n (x))
comment s is the list (s ,s ,, ,,, ,s, );
n n-1 1
head(s)=s ; tail(s)=(s ..•••,8 1 );
n n-1 1
uo s =(u > s n ,-«-,s 1 )
(y,s) := (x,())
loop assert f (x)=h(- • -h(h(f (y) ,s n ) »3 j^) • • • .s^
until p(y)
(y,s) := (d(y),yo s )
repeat
z := c(y)
loop assert f(x)=h( ♦ • «h(h(z ,s ),s , )»««,s, )
n n— l l
until s=()
(z,s) := (h(z,head(s)),tail(s))
repeat
assert z=f(x)
end
- 54 -
» 12 : begin
coament double-recursion (Knuth [1974])
compute f(x)
assert p(u) Z) f(u)=c(u),
lp(u) ^ f(u)-h(f(e(u)),f(d(u))),
h(a,u)=u,
h(u,h(v,w))=h(h(u,v),w),
p(x)V(3nem)g n (x) = {},
where g(u)={e(v) IveuAlp(v)} U{d(v) IveuAlp(v)}
come
nt s Is the
head(s)=s ;
n
list \
tail(s
n n — 1
')=(s n _ r -.
•,s 1 );
-,8^5
(z,s)
uos=(u,s , •
n
:- (a,(x))
",8^
loop
assert f(x) :
»h(z,h(
;s 1 ,h(s 2> h(
•"' h( Vr
V
until s=()
(y,s) := (head(s),
tail(s))
if p(y)
then
z := h(z,c
(y))
else
s :■ e(y)c
d(y)os
fl
repeat
assert z=f(x)
end
))))
- 55 -
s 13 : begin proc back(t,x,z)
consent backtracking (Gerhart and Yelowitz [1976])
collect all vectors beginning with x satisfying p
assert xea, 2Q,
uea 3 t( u ) La,
uLa 2) g(u)eu,
(3nelN)|t*({x})|=n
comment t*(u)=u|_ft (u) Ut~ 2 (u) U- • • ,
where T(u) = U t(v);
veu
I* *
t (u) I denotes the number of elements in the set t (u);
z denotes the value of z upon procedure entry
if p(x) then z := zU{x} fi
y := t(x)
loop assert zU{uet (x)|p(u)}
=zU{uet*(y)|p(u)}
until y={ }
m := g(y)
y := y-{m}
back(t ,m,z)
repeat
assert z=z|_l{uet (x)|p(u)}
end
- 56 -