SE 504
Computing N3 Without using Multiplication or Exponentiation
(An Example of Applying the Strengthening the Invariant Heuristic)

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; 

   r := ? 

   { Q: 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 fresh variable" heuristic to arrive at a strengthened version of the postcondition, we get

Q': r = n3 ∧ n = N

From Q' we take the first conjunct to be a possible loop invariant and the negation of the second to be the loop's guard. These choices immediately give us (iii) in the loop checklist.

What we have so far, then, is

|[ con N : int;  { N≥0 }
   var r : int;
   var n : int;

   n,r := ?,?;   
   { I : r=n3 }
   do n ≠ N  --->
      n,r := ?,?;  
   od
   { Q': r=n3 ∧ n=N }
   { Q : r = N3 }
]|

What remains is to determine, for variables n and r, to what values to initialize them and how to update them during each iteration of the loop.

To truthify the loop invariant, we need to establish r=n3. The most obvious choice is to initialize n to 0, which would dictate that r be initialized to zero, too. This choice also suggests that n be incremented during each iteration of the loop, which would eventually result in its being equal to N so that the loop would terminate.

Alternatively, we could, for example, choose to initialize n to 7, which would dictate that r be initialized to 343 (73). But since we don't know ahead of time whether N>7 or N<7, our loop body would have to accommodate not only the possibility of n<N but also n>N, which, we suspect, would complicate things considerably.

Therefore, the most obvious choice would seem to be best, too. Our refined program is

|[ con N : int;  { N≥0 }
   var r : int;
   var n : int;

   n,r := 0,0;
   { I : r=n3 }
   do n ≠ N  --->
      n,r := n+1,F;
   od
   { Q': 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):

{I ∧ B} n,r := n+1,F {I}

Equivalently, this is [I ∧ B ⇒ wp.(n,r := n+1,F).I]. So, we assume I ∧ B and attempt to prove wp.(...).I:

     wp.(n,r := n+1,F).I

  =    < wp assignment law >

     I(n,r := n+1,F)

  =    < defn of I, 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 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;
   { I : r=n3  ∧  s = 3n2 + 3n + 1 }
   do n ≠ N  --->
      n,r,s := n+1,r+s,F;
   od
   { Q': r=n3 ∧ n=N }
   { Q : r = N3 }
]|

Clearly, the correct choice for E is 1. To calculate F, we attempt to find an expression F that truthifies the Hoare triple

{I ∧ B} n,r,s := n+1,r+s,F {I}

(where I is the updated version that includes s = 3n2 + 3n + 1 as a conjunct).

    
     wp.(n,r,s := n+1,r+s,F).I

  =    < wp assignment law, defn of I, 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

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 w:

     F = s + 6n + 6

  =    < assumption: w = 6n + 6 >

     F = s + w

Of course, we must initialize w and update it on each loop iteration. Our updated program is

|[ con N : int;  { N≥0 }
   var r : int;
   var n,s,w : int;

   n,r,s,w := 0,0,1,E;
   { I : r=n3  ∧  s = 3n2 + 3n + 1  ∧  w = 6n + 6 }
   do n ≠ N  --->
      n,r,s,w := n+1,r+s,s+w,F;
   od
   { r=n3 ∧ n=N }
   { Q : r = N3 }
]|

Clearly, the correct choice for E is 6. To calculate F, we attempt to find an expression F that truthifies the Hoare triple

{I ∧ B} n,r,s,w := n+1,r+s,s+w,F {I}

(where I is the updated version that includes t = 6n + 6 as a conjunct).

    
     wp.(n,r,s,w := n+1,r+s,s+w,F).I

  =    < wp assignment law, defn of I, textual sub. >

     r+s = (n+1)3  ∧  s+w = 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: w = 6n + 6 >

     F = w + 6

Recognizing that we need a bound function and support in the loop invariant for showing items (iv) and (v) on the loop checklist, we offer the following as the final program.

|[ con N : int;  { N≥0 }
   var r : int;
   var n,s,w : int;

   n,r,s,w := 0,0,1,6;
   { bound t : N - n }
   { I : r=n3  ∧  s = 3n2 + 3n + 1  ∧  w = 6n + 6 ∧ 0≤n≤N }
   do n ≠ N  --->
      n,r,s,w := n+1,r+s,s+w,w+6;
   od
   { Q': r=n3 ∧ n=N }
   { Q : r = N3 }
]|