SE 504
Solution to Array Decomposition Problem

Develop a program to satisfy the following specification.

|[ con N : int; { N > 0 }
   con F : array [0..N) of int;
   var h : array [0..N) of int;

   S

   {(∀k | 0≤k<N : F.k = (+i | 0≤i≤k : h.i)) |
]|

We strengthen the postcondition by replacing the constant N by the fresh variable n and adding the conjunct n=N. Then we take the first conjunct as a possible loop invariant and the negation of the second as the guard of the loop. It would appear that, as is often the case, the variable n should be incremented during each loop iteration. In addition, we probably need to modify h on each iteration. This gives rise to

|[ con N : int; { N > 0 }
   con F : array [0..N) of int;
   var h : array [0..N) of int;
   var n : int;

   n,h := D, E;
   {invariant P: (∀k | 0≤k<n : F.k = (+i | 0≤i≤k : h.i))  ∧  0≤n≤N }
   do n ≠ N  →
      n,h := n+1,G;
   od
   {(∀k | 0≤k<N : F.k = (+i | 0≤i≤k : h.i)) }
]|

To make initialization easy, we could take D to be 0. That would truthify P and make initialization of h unnecessary. If we were to take D to be 1, then to truthify P we would have to initialize h to h(0:F.0). (That is, we would have to copy the value of F.0 into h.0.)

As for G, let us attempt to derive it by showing (ii) of the loop checklist:

  {P ∧ B} n,h := n+1,G {P}   (i.e., [P ∧ B  ⇒  wp.(n,h := n+1,G).P] )

    wp.(n,h := n+1,G).P

 =     < defn of P, wp assignment law, textual sub >

    (∀k | 0≤k<n+1 : F.k = (+i | 0≤i≤k : G.i))  ∧  0≤n+1≤N 
    
 =     < 2nd conjunct is implied by assumption 0≤n≤N ∧ n≠N, (3.39) >

    (∀k | 0≤k<n+1 : F.k = (+i | 0≤i≤k : G.i))

 =     < split off term (8.23) >

    (∀k | 0≤k<n : F.k = (+i | 0≤i≤k : G.i))  ∧  F.n = (+i | 0≤i≤n : G.i)

 =     < assume that G satisfies G.i = h.i for i satisfying 0≤i<n >

    (∀k | 0≤k<n : F.k = (+i | 0≤i≤k : h.i))  ∧  F.n = (+i | 0≤i≤n : G.i)

 =     < assumption P, (3.39) >

    F.n = (+i | 0≤i≤n : G.i)

 =     < assume n>0, and split off term (8.23) >

    F.n = (+i | 0≤i<n : G.i) + G.n

 =     < assume (again) that G satisfies G.i = h.i for i satisfying 0≤i<n >

    F.n = (+i | 0≤i<n : h.i) + G.n

At this point, we notice that the first term on the right-hand side looks very much like a subexpression of the first conjunct of our loop invariant. It would look even more similar if we rewrote the inequality i<n as i≤n-1, so we do that now:

    F.n = (+i | 0≤i<n : h.i) + G.n

 =     < rewrite inequality i<n as i≤n-1 >

    F.n = (+i | 0≤i≤n-1 : h.i) + G.n
The first conjunct of the loop invariant (which we have taken as an assumption, you will recall) says that F.k = (+i | 0≤i≤k : h.i) for every k from zero up to and including n-1. In particular, then, by plugging in n-1 for k we get F.(n-1) = (+i | 0≤i≤n-1 : h.i). Note that we need n>0 to do this. To justify this step technically, we use a slightly more general form of Gries's and Schneider's (9.13) Instantiation theorem, which we call (9.13') and can be found in the Appendix below. Continuing the proof:
    F.n = (+i | 0≤i≤n-1 : h.i) + G.n

 =     < assumptions P (the loop invariant) and n > 0, and application
         of (9.13') (see Appendix), instantiated by 
         x: k, 
         e: n-1,
         R: 0≤k<n, and
         P: F.k = (+i | 0≤i≤k : h.i)   >

    F.n = F.(n-1) + G.n

 =     < algebra >

    G.n = F.n - F.(n-1)

 =     < choose G to be h(n : F.n - F.(n-1)), so that G.n = F.n - F.(n-1)
         and so that earlier assumption that G.i = h.i for i satisfying
         0≤i<n also holds                                                >

    true

Recall that during the derivation above, we assumed that n>0. Hence, our initialization of n should be n:=1 rather than n:=0. The assignment h := h(n : F.n - F.(n-1)) is usually written h.n := F.n - F.(n-1). The program is

|[ con N : int; { N > 0 }
   con F : array [0..N) of int;
   var h : array [0..N) of int;
   var n : int;

   n,h.0 := 1,F.0;
   {invariant P: (∀k | 0≤k<n : F.k = (+i | 0≤i≤k : h.i))  ∧  0≤n≤N }
   do n ≠ N  →
      n, h.n := n+1, F.n - F.(n-1);
   od
   {(∀k | 0≤k<N : F.k = (+i | 0≤i≤k : h.i)) }
]|

Had we recognized from the start that the only modification needing to be made to h on each iteration were to the element h.n, we would have started with our loop body being the assignment

n, h.n := n+1, G;

This would have made the calculation of G somewhat easier.

Appendix: Theorem (9.13')

In Gries & Schneider, Theorem 9.13 (Instantiation) says

(∀x |: P) ⇒ P(x:=e)

Informally, this says that, if every choice of x satisfies P, then e satisfies P.

A somewhat more general form of this theorem is as follows:

Theorem 9.13': R(x:=e) ⇒ ((∀x | R : P) ⇒ P(x:=e))

It is readily seen that (9.13) is obtained from (9.13') by taking R to be true (and then applying (3.73)).

Informally, (9.13') says that, if e satisfies R and P is satisfied by every x satisfying R, then e satisfies P.

Here is a proof of (9.13').

    Assume R(x:=e).

    (∀x | R : P)

=      < (9.2) Trading >

    (∀x |: R ⇒ P)

⇒      < (9.13) Instantiation >

    (R ⇒ P)(x:=e)

=      < textual substitution distributes over operators >

    R(x:=e) ⇒ P(x:=e)

=      < assumption R(x:=e) >

    true ⇒ P(x:=e)

=      < (3.73) true is left identity of ⇒ >

    P(x:=e)