[UMN logo]

CSCI 5106: Programming Languages
Spring 2006, University of Minnesota
Homework 4


Posted: Feb 23, 2006
Due: March 9, 2006

You have been given two weeks for this assignment because of an intervening midterm. However, solving the problem in substance before the midterm will help you prepare for the exam as well.


The requirement in this assignment is to develop a program in C or Pascal involving loops that is based on a given invariant and a method for making progress while maintaining this invariant. The resulting program is intended to carry out a particular task. However, to receive a grade for this assignment, it is critical that you design the program based on the given invariant--simply writing any program that does the task will not suffice.

In addition to developing the program, you should also do the following:

  1. Provide a convincing argument for its (total) correctness using the methods discussed in class and in the text and as illustrated in the paper by Bentley that was given to you. The best style for this is probably one that interleaves the program design and the correctness argument.

  2. Devise a set of tests for checking that your program does work as expected, explain the choice of tests and provide the results of applying these tests to your program.
Along with your written work, you should turn in a hard copy of your program together with the test runs. In addition you should, as usual, submit an electronic version of the program code in the manner described in the course web page.

The programming task is the one described in the text in Exercise 3.11 and can be restated as follows: to write a function that, given a (sub)array A[m..n] and a value v, rearranges the elements in A[m..n] into two subparts A[m..i] and A[i+1..n] such that all the elements in the first subpart are less than or equal to a given value v and all the elements in the second subpart are greater than or equal to v. Specifically, you should think of m, n and v as being the input arguments to this function, i as being the output and the modifications to the array cells being a side effect. The correctness argument can then be boiled down to one for the body of the function. In particular, for the partial condition part, you should start out by stating a suitable precondition for the point before the body of the function and a postcondition for the point at its end. Clearly, these conditions should involve the program variables A, m, n, v and i.

To keep the assignment simple, assume that the values that you are dealing with are integers. A pictorial depiction of the desired state of affairs when the function finishes its execution appears as part of Exercise 3.11 on page 97. This picture is only suggestive and not a complete description as is made clear below. As explained in Exercise 3.11, this function, which I will refer to as partition, finds utility in a sorting algorithm referred to as quicksort: the quicksort algorithm, that you are not required to implement, consists of partitioning arrays in the manner outlined and then calling quicksort recursively on the two partitions.

As is to be expected, the main part of the partition function will be a loop. You may use one of two loop invariants and an associated method for progressing towards the desired goal while preserving this invariant. These two possibilities are described below. The second one is more involved than the first and so will carry an extra credit of 10%. Of course, there is a hazard in doing it the second way in that you may have more difficulty in getting things right. For this reason, you should choose to do it the second way only if you know what you are doing.

You must clearly state which of the two invariants and method of progress you decide to base your program on.


First Loop Invariant

This loop invariant, and the method for progressing towards the desired goal while preserving this invariant, is the one described in Exercise 3.11. This invariant refers to the values in the array A and to two variables i and k that are indices into the array and whose values may change in the course of executing the program. The relevant invariant can be restated in mathematical notation as follows:

m <= (i + 1) <= k <= (n + 1) and, for all j such that m <= j <= i, it is the case that A[j] < v and for all l such that (i + 1) <= l < k it is the case that A[l] => v and the values in A[m..n] are some permutation of the values in these cells at the beginning of the function body.
Read <= as ``less than or equal to'' and => as ``greater than or equal to'' in the above display. Notice that, in this description, m, n and v are intended to represent certain fixed input values and that we have assumed that we have some way of referring to the original values in A[m..n]. The method for making progress is described fairly clearly in the mentioned exercise in the book and I will let you look this up for yourself.


Second Loop Invariant

This loop invariant, and the method of progressing towards the desired goal while preserving this invariant, is the one described in Exercise 3.12. This invariant refers to the array A and to the variables i and j that are indices into this array and whose values, again, change during program execution. The invariant can be stated in mathematical notation as follows:

m <= i,j <= n and, for all k such that m <= k <= i it is the case that A[k] <= v and for all l such that j <= l <= n it is the case that A[l] => v and the values in A[m..n] are some permutation of the original values in these cells.
Read <= as ``less than or equal to'' and => as ``greater than or equal to'' in the above display. You should assume that, at the outset, A[m] <= v and A[n] => v. This assumption is satisfied in the context that the function partition is to be used. (If you are curious as to why this is the case, post an article to HyperNews and I will answer it if nobody else does.) If you use this approach, then your function body will most likely have two additional loops and this assumption will also be useful in simplifying the termination condition for these loops. Once again, the method for making progress is described quite clearly in the book and I will let you look this up for yourself.

One thing that you might feel the need for when doing this problem is a looping construct that has a single input-single output character but that exits from the middle of the loop's body. There have been proposals for such a construct in the past with the following kind of syntax:

 
loop  <First-Half> 
exit if <Exit-Cond>
      <Second-Half>
end
Unfortunately, such a construct is not directly supported in C or Pascal. However, if you use C for this homework, can simulate it: use a while with a condition that is always true and a break at a suitable place in its body. If you use such a `construct', you should first explain its associated proof rule by thinking of its abstract syntax as that corresponding to the one for the loop exit-if construct.


In arguing the partial correctness of your program, you are expected only to use the spirit of the proof rules discussed in class and not to provide a detailed derivation based on them. You may assume that Xiaochu and I, as humans rather than machines, will accept the truth of simple and self-evident assertions. However, we will have to be convinced through a sequence of steps of the truth of more complicated ones. Use the paper by Bentley and our discussions in class as a guide to deciding the level of detail and also the best presentation. You can use devices other than mathematical notation in describing the assertions that you want to attach to different program points if you feel that this would simplify your presentation. Two specific alternative devices that you might find useful are descriptions in English and pictures. Combinations of these three devices are also possible and perhaps the most desirable. However, whatever device you use, you must not sacrifice accuracy in your presentation. As an example of how accuracy can be sacrificed, consider the pictures ``describing'' the invariants in the book. One fact that is left out of this description and that is, in any case, difficult to capture in a picture is that the all the original values in the array must be preserved and only their order of appearance may be changed. This is a crucial requirement of partition and the use of the pictorial description should not cause you to overlook the need to show that it is met.

Some final comments: First, while efficiency is an important attribute for your program, do not focus on this to the extent that clarity and the ease of presenting a convincing argument of its correctness is sacrificed. Second, you should not write too much in arguing for the correctness of your program since this usually takes away from the argument. What you will have to do is think clearly of the important steps in the argument and of simple ways of presenting these steps before you start writing anything down.


Last updated on Feb 23, 2006 by gopalan@cs.umn.edu