Problem: Develop a solution to the following specification. In order to make it interesting, assume that the programming language has no multiplication or exponentiation operations.
|[ con N : int; { N>=0 }
var r : int;
compute_cube
{ post: r = N3 }
]|
Because we are not to use multiplication or exponentiation, it would seem that a solution will include at least one loop. Applying the "replace a constant by a variable" heuristic to arrive at a possible loop invariant, we get
r = n3
as a possible invariant. The loop should terminate when n=N,
at which time we will have r=n3 & n=N,
which implies (by (3.84)) the postcondition. From this discussion, the
program has been refined to the following:
|[ con N : int; { N>=0 }
var r : int;
var n : int;
n,r := E0, E1;
{ P : r=n3 }
do n != N --->
n,r := F0,F1;
od
{ r=n3 & n=N }
{ Q : r = N3 }
]|
To what values should n and r be initialized?
To truthify the loop invariant, we need to establish
r=n3.
The only two obvious choices are to set n to either 0 or 1.
(For any other value of n, it is not clear how we could
initialize r to n3 without using
multiplication, exponentiation, or another loop.) The fact that n
will be initialized to a "small" value suggests that it be incremented each
time around the loop. The fact that N could be zero suggests
that we initialize n to zero rather than one. Our refined program is
|[ con N : int; { N>=0 }
var r : int;
var n : int;
n,r := 0,0;
{ P : r=n3 }
do n != N --->
n,r := n+1,F;
od
{ r=n3 & n=N }
{ Q : r = N3 }
]|
It remains to calculate F. We need F to be an expression that truthifies the following Hoare triple (in accord with item (ii) on loop checklist):
{P & B} n,r := n+1,F {P}
Equivalently, this is [P & B ==> wp.(n,r := n+1,F).P].
So, we assume P & B and attempt to prove wp.(...).P:
wp.(n,r := n+1,F).P
= < wp assignment law, defn of P, textual sub. >
F = (n+1)3
= < algebra >
F = n3 + 3n2 + 3n + 1
= < assumption: r = n3 >
F = r + 3n2 + 3n + 1
At this point, we use the strengthen the invariant heuristic, by which
we augment the invariant to include s = 3n2 + 3n + 1
as a new conjunct, where s is a fresh variable.
Continuing from above, we get
= < assumption: s = 3n2 + 3n + 1 >
F = r + s
But now we must insert code that correctly initializes
Clearly, the correct choice for E is 1. To calculate F, we attempt to find
an expression F that truthifies the Hoare triple
(where P is the updated version that includes
Thus, we could plug in for F the expression derived above in order to
complete the program. However, this expression is not very elegant. So,
instead, let's strengthen the invariant once again by introducing a
fresh variable
Of course, we must initialize
Clearly, the correct choice for E is 6. To calculate F, we attempt to find
an expression F that truthifies the Hoare triple
(where P is the updated version that includes s and
that correctly updates s during each iteration of the loop.
Our updated program is
|[ con N : int; { N>=0 }
var r : int;
var n,s : int;
n,r,s := 0,0,E;
{ P : r=n3 & s = 3n2 + 3n + 1 }
do n != N --->
n,r,s := n+1,r+s,F;
od
{ r=n3 & n=N }
{ Q : r = N3 }
]|
{P & B} n,r,s := n+1,r+s,F {P}s = 3n2 + 3n + 1 as a conjunct).
wp.(n,r,s := n+1,r+s,F).P
= < wp assignment law, defn of P, textual sub. >
r+s = (n+1)3 & F = 3(n+1)2 + 3(n+1) + 1
= < 1st conjunct follows from earlier derivation, (3.39) >
F = 3(n+1)2 + 3(n+1) + 1
= < algebra >
F = 3n2 + 9n + 7
= < assumption: s = 3n2 + 3n + 1 >
F = s + 6n + 6
= < 6n = n + n + n + n + n + n >
F = s + n + n + n + n + n + n + 6
t:
F = s + 6n + 6
= < assumption: t = 6n + 6 >
F = s + t
t and update it on each
loop iteration. Our updated program is
|[ con N : int; { N>=0 }
var r : int;
var n,s,t : int;
n,r,s,t := 0,0,1,E;
{ P : r=n3 & s = 3n2 + 3n + 1 & t = 6n + 6 }
do n != N --->
n,r,s,t := n+1,r+s,s+t,F;
od
{ r=n3 & n=N }
{ Q : r = N3 }
]|
{P & B} n,r,s,t := n+1,r+s,s+t,F {P}t = 6n + 6
as a conjunct).
wp.(n,r,s,t := n+1,r+s,s+t,F).P
= < wp assignment law, defn of P, textual sub. >
r+s = (n+1)3 & s+t = 3(n+1)2 + 3(n+1) + 1 & F = 6(n+1) + 6
= < earlier derivations showed 1st two conjuncts, (3.39) >
F = 6(n+1) + 6
= < algebra >
F = 6n + 12
= < algebra >
F = 6n + 6 + 6
= < assumption: t = 6n + 6 >
F = t + 6
The final program is
|[ con N : int; { N>=0 }
var r : int;
var n,s,t : int;
n,r,s,t := 0,0,1,7;
{ P : r=n3 & s = 3n2 + 3n + 1 & t = 6n + 6 }
do n != N --->
n,r,s,t := n+1,r+s,s+t,t+6;
od
{ r=n3 & n=N }
{ Q : r = N3 }
]|