Professional Documents
Culture Documents
OF PROGRAMMING
David Gries
Chapter 15
Developing Loops from Invariants and
Bounds
1 / 39
This chapter discusses two methods for developing a loop when the
precondition Q, the postcondition R, the invariant P and the bound
function t are given.
2 / 39
15.1 Developing the Guard First
3 / 39
Summing the elements of an array
4 / 39
Thus, variable i has been introduced. The invariant states that at
any point in the computation s contains the sum of the first i values
of b.
The next step is to determine the guard B for the loop do B → S od.
Checklist 11.9 requires P ∧ ¬B ⇒ R, so ¬B is chosen to satisfy it.
Comparing P and R, we conclude that i =n will do. The desired
guard B of the loop is therefore its complement, i 6=n. The program
looks like
i , s:= 0, 0; do i 6=n → ? od
5 / 39
The program looks like
i , s:= 0, 0; do i 6=n → ? od
6 / 39
Discussion
First of all, let us discuss the balance between formality and intuition
observed here.
The pre- and postconditions, the invariant and the bound function
were given formally and precisely.
The development of the parts of the program was given less for-
mally, but checklist 11.9, which is based on the formal theorem for
the Iterative Construct, provided most of the motivation and insight.
7 / 39
An important strategy in the development was finding the guard be-
fore the command. And the prime consideration in finding the guard
B was that it had to satisfy P ∧ ¬B ⇒ R. So, ¬B was developed
and then complemented to yield B.
Some object at first to finding the guard this way, because Tradition
would use the guard i <n instead of i 6=n. However, i 6=n is better,
because a software or hardware error that made i >n would result in
a nonterminating execution. It is better to waste computer time than
suffer the consequences of having an error go undetected, which
would happen if the guard i <n were used. This analysis leads to
the following
(15.1.3) {invariant : P }
{bound : t }
do B → Decrease t, keeping P true od
{P ∧ ¬B }
9 / 39
Searching a two-dimensial array
10 / 39
The invariant P, given below using a diagram, states that x is not in
the already-searched rows b[0:i −1] and not in the already-searched
columns b[i ,0:j −1] of the current row i.
11 / 39
The obvious choice is i , j := 0, 0, for then the section in which “x is
not here” is empty.
12 / 39
Expression ¬B must satisfy P ∧ ¬B ⇒ R. It must be strong enough
so that each of the two disjuncts of R can be established. To provide
for the first disjunct, choose i < m cand x = b[i , j ]; to provide for
the second, choose i = m. The operand cand is needed to ensure
that the expression is well-defined, for b[i , j ] may be undefined if
i > m. Therefore, choose ¬B to be
13 / 39
Since the guard B is to be evaluated only when the invariant P is
true, which means that i 6 m is true, it can be simplified to
B : i 6= m ∧ (i = m cor x 6= b[i , j ])
and finally to
The next step is to determine the loop body. Do it, before reading
further.
14 / 39
The purpose of the loop body is to decrease the bound function t,
which is the number of elements in the untested section: (m−i )∗n−j.
j < n−1 → j := j +1
15 / 39
What do we do if j > n−1? In this case, because invariant P is true,
we have j = n−1. Hence, we must determine what to do if j = n−1,
i.e. if b[i , j ] is the rightmost element of its row. To move b[i , j ] into
the tested section requires moving to the beginning of the next row,
i.e. executing i , j := i +1, 0.
(15.1.7) i , j := 0, 0;
do i 6= m cand x 6= b[i , j ] →
if j < n−1 → j := j +1 8 j = n−1 → i , j := i +1, 0 fi
od
16 / 39
If desired, the body of the loop can be rearranged to yield
i , j := 0, 0;
do i 6= m cand x 6= b[i , j ] →
j := j +1;
if j < n → skip 8 j = n → i , j := i +1, 0 fi
od
17 / 39
Discussion
Note that operation cand (instead of ∧) is really necessary.
but this case is simple enough to handle informally —if care is used.
Second, the command i , j := i +1, 0 was chosen to handle the remai-
ning case, j = n.
Note that the alternative command has the guards j <n−1 and j =n−1,
and not j <n−1 and j >n−1. The guards of the alternative command
have been made as strong as possible, in keeping with principle
14.10, in order to catch errors.
18 / 39
15.2 Making Progress Towards Termina-
tion
19 / 39
Four-tuple Sort
Consider the following problem. Write a program that sorts the four
integer variables q0, q1, q2, q3. That is, upon termination the follo-
wing should be true: q06q16q26q3.
Implicit is the fact that the values of the variables should be permu-
ted —for example, the assignment q0, q1, q2, q3:= 0, 0, 0, 0 is not
a solution, even though it establishes q06q16q26q3. To convey
this information explicitly, we use Qi to denote the initial value of qi,
and write the formal specification
Q : q0 = Q0 ∧ q1 = Q1 ∧ q2 = Q2 ∧ q3 = Q3
R : q06q16q26q3 ∧ perm((q0,q1,q2,q3), (Q0,Q1,Q2,Q3))
P : perm((q0,q1,q2,q3), (Q0,Q1,Q2,Q3))
20 / 39
The bound function is the number of inversions in the sequence
(q0, q1, q2, q3). For a sequence (q0 , · · · , qn−1 ), the number of in-
versions is the number of pairs (qi , qj ), i <j, that are out of order
—i.e. qi >qj .
Note that this includes all pairs, and not just adjacent ones. For
example, the number of inversions in (1,3,2,0) is 4. So the bound
function is
21 / 39
The invariant indicates that the four variables must always contain
a permutation of their initial values.
22 / 39
In the last section, at this point of the development the guard of the
loop was determined.
The invariant indicates that the only possible commands are those
that swap (permute) the values of two or more of the variables. To
keep things simple, consider only swaps of two variables.
There are six possibilities: q0, q1:= q1, q0 and q1, q2:= q2, q1, etc.
23 / 39
Now, execution of a command must make progress towards ter-
mination. Consider one possible command, q0, q1:= q1, q0. It de-
creases the number of inversions in (q0, q1, q2, q3) iff q0>q1. Hen-
ce, the guarded command q0>q1 → q0, q1:= q1, q0 will do. Each
of the other 5 possibilities are similar, and together they yield the
program
24 / 39
It still remains to prove that upon termination the result R is esta-
blished —this is point 3 of checklist 11.9, P ∧ ¬BB ⇒ R.
Suppose all the guards are false. Then q06q1 (because the first
guard is false), q16q2 (because the second guard is false) and
q26q3 (because the third guard is false); therefore
q06q16q26q3.
25 / 39
But note that only the first three guards were needed to establish
the desired result.
26 / 39
Discussion
(15.2.1) •Strategy for developing a loop: Develop guarded
commands, creating each command so that it makes
progress towards termination and creating the corres-
ponding guard to ensure that the invariant is maintained.
The progress of developing guarded commands is finis-
hed when enough of them have been developed to prove
P ∧ ¬B ⇒ R.
28 / 39
This little program is nondeterministic in execution, because two,
and even three, guards can be true at the same time. But, for any
initial state there is exactly one final state, so that in terms of the
result the program is deterministic.
29 / 39
Searching a two-dimensial array
30 / 39
The invariant P, given below using a diagram, states that x is not in
the already-searched rows b[0:i −1] and not in the already-searched
columns b[i ,0:j −1] of the current row i.
31 / 39
The obvious choice is i , j := 0, 0, for then the section in which “x is
not here” is empty.
Note carefully how the invariant includes j 6n, instead of j <n. This
is necessary because the number of columns, n, could be 0.
32 / 39
The obvious command to try is j := j +1, because it decreases t.
(Another possibility, to be investigated subsequently, is i := i +1). A
suitable guard must ensure that P remains true. Formally or infor-
mally, we can see that i 6= m ∧ j 6= n cand x 6= b[i , j ] can be
used, so that the guarded command is
i 6= m ∧ j 6= n cand x 6= b[i , j ] → j := j +1
Now, does a loop with this single guarded command solve the pro-
blem? Why or why not? If not, what other guarded command can
be used?
33 / 39
The loop with only this guarded command could terminate with
i <m ∧ j =n, and this, together with the invariant, is not enough to
prove R. Indeed, if the first row of b does not contain x, the loop will
terminate after searching through only the first row! Some guarded
command must deal with increasing i.
(15.2.4) i , j := 0, 0;
do i 6= m ∧ j 6= n cand x 6= b[i , j ] → j := j +1
8 i 6= m ∧ j = n → i , j := i +1, 0
od
34 / 39
(15.2.4) i , j := 0, 0;
do i 6= m ∧ j 6= n cand x 6= b[i , j ] → j := j +1
8 i 6= m ∧ j = n → i , j := i +1, 0
od
and this together with P implies the result R. Hence, the program is
correct. Note that in the case i =m the invariant implies that x is not
in rows 0 through m−1 of b, which means that x ∈ / b.
35 / 39
Discussion
This led to a loop with a form radically different from what most pro-
grammers are used to developing (partly because they don’t usually
know about guarded commands).
36 / 39
This problem is often used to argue for the inclusion of gotos or
loop “exits” in a conventional language, because, unless one uses
an extra variable commonly called a “flag”, the conventional solution
to the problem needs two nested loops and an “exit” from the inner
one:
(15.2.5) i , j := 0, 0;
while i < m do
begin while j < n do
if x = b[i , j ] then goto loopexit
else j := j +1;
i := i + 1; j := 0
end;
loopexit :
We see, then, that the guarded command notation and the method
of development together lead to a simpler, easier-to-understand, so-
lution to the problem —provided one understands the methodology.
37 / 39
How could program (15.2.4) be executed effectively? An optimizing
compiler could analyze the guards and commands and determine
the paths of execution given in diagram (15.2.6) —in the diagram,
an arrow with F (T ) on it represents the path to be taken when the
term from which it emanates is false (true).
(15.2.6) i , j := 0, 0;
8i <m ∧ j =n → i , j := i +1, 0
od
38 / 39
Program (15.2.4) is developed from sound principles.
39 / 39