CSC 161 Grinnell College Spring, 2010
 
Imperative Problem Solving and Data Structures
 

Introduction to Loop Invariants

Goals

This laboratory exercise introduces the concept of loop invariants and provides some practice in using loop invariants in developing programs.

Approaches to Problem Solving

Problem: Read a (nonzero) number r from the keyboard and compute (and print) r0, r1, r2, r3, ..., r10.

Solutions: Program loop-invariants-1.c shows three correct solutions to this problem, illustrating that even a simple problem may be solved in a rather large number of ways. Since each code segment represents a somewhat different way of thinking about problem solving and loops, the following discussion considers each solution in some detail.

Code Segment 1


  printf ("First Solution\n");
  prod = 1;
  i = 0;
  while (i <= 10) {
    printf ("\t%6.2lf", prod);
    prod *= r;  
    i++;
  }
  printf("\n");

In this first approach, at the top of the loop, i represents an exponent and prod represents an ri value that is ready to be printed. Initially, i=0 and prod=1, which sets up the values for the first pass through the loop.

Within the loop, the previously computed values are printed, and then both i and prod are updated for the next time.

To review, the code executes correctly because the following ideas work together properly.

  1. At the start of each time through the loop, i represents a current exponent of r and prod represents ri — a value that has not yet been printed.
  2. i and prod are correctly initialized for r0, so statement A is true when the loop first begins.
  3. Both i and prod are updated correctly during each time through the loop, so statement A is true whenever the loop starts again.
  4. The while-loop condition (i<=10) is consistent with the values i represents, so the loop terminates at the correct time.

Jargon

In the statement while (i <= 10), the test (i <= 10) is sometimes called a loop-continue condition; the loop continues as long as this condition is true. In contrast, the negative of this expression i > 10 is sometimes call a exit condition.

In contrast, statement A above is called a loop invariant. A loop invariant is a statement about variables and relationships among them, where the statement is to be true every time the machine gets to the very top or bottom of a loop (whether the loop continues or not). For a while loop, therefore, a loop invariant is a statement that is true every time the Boolean expression is evaluated.

Code Segment 2


  printf ("Second Solution\n");
  printf ("\t%6.2lf", 1.0);
  prod = 1; 
  i = 0;  
  do {
    i++; 
    prod *= r;
    printf ("\t%6.2lf", prod);
  }
  while (i < 10);                        
  printf("\n");

This approach illustrates a different meaning for the variables i and prod. Here, at the top of the loop, i represents an exponent and prod represents the ri value that has most recently been printed. Thus, in this approach, i and prod are initialized to 0 and 1=r0, and these values are printed before the loop. Then, within the loop, the i and prod are updated before the new values are printed. With this perspective of i, processing continues until i=10, since this is the last desired output value.

As with the previous code segments, we can summarize why the code works correctly with four statements.

  1. At the start of each time through the loop, i represents a current exponent of r and prod represents ri — the value that has been printed most recently.
  2. i and prod are correctly initialized for r0, and this value of r0 is printed, so statement A is true when the loop first begins.
  3. Both i and prod are updated correctly during each time through the loop, so statement A is true whenever the loop starts again.
  4. The loop-continue condition (i<10) is consistent with the values i represents, so the loop terminates at the correct time.

Jargon, Revisited

Here, once again, Statement A is called a loop invariant, and that statement is true at the start, each time through the loop (at the top of the loop), and at the end. This notion of a loop invariant, therefore, applies to any type of loop construct, not just for while loops. In the current context, for a do-while loop, a loop invariant is a statement that is true every time the computer gets to the do and the statement is also true when execution of the loop is over.

Code Segment 3


  printf ("Third Solution\n");
  printf ("\t%6.2lf", 1.0);
  prod = r;
  printf ("\t%6.2lf", prod);
  i = 0;
  while (i < 9) {
    i++;
    prod *= r;  
    printf ("\t%6.2lf", prod);
  }
  printf("\n");

A loop invariant for this Code Segment might be described as follows:

  1. At the start of each time through the loop, i represents the number of multiplications of r with itself to obtain the product prod — thus prod = ri+1. Further, prod is the value that has been printed most recently.

From this perspective, the first two cases, r0 and r1, do not require any multiplications of r by itself and so are handled as part of initialization. Also, the final desired value, r10, requires only 9 multiplications, so processing should halt when this number of multiplications has been performed.

Highlights

In developing correct code, our discussion has emphasized four points.

  1. We write a statement of what each variable represents at the top of the loop. Such statements are called loop invariants. For example, "i represents a current exponent of r" could be a loop invariant.
  2. We initialize variables before a loop, so that the loop invariants are true at the start of the loop.
  3. We check the loop body updates variables appropriately, so the loop invariant remains true each time through the loop. I.e., if the variables have values prescribed by loop invariant statements at the start of the loop, then the loop body should update variables so the loop variant statements remain true when execution returns the next time to the beginning of the loop.
  4. We check that the loop-continue condition stops the loop at the appropriate time -- using the loop invariants to understand clearly what the variables represent.

This laboratory exercise is based on part of an on-going project of introducing the concepts of assertions and loop invariants informally in CS1 and CS2 courses. Early funding for this work came, in part, from NSF Grant CDA 9214874, "Integrating Object-Oriented Programming and Formal Methods into the Computer Science Curriculum". Henry M. Walker worked as Senior Investigator on this portion of that effort.


This document is available on the World Wide Web as

http://www.cs.grinnell.edu/~walker/courses/161.sp10/readings/reading-loop-invariants.shtml

created 25 October 2007
last revised 27 February 2010
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu.