SE 504: Proving Correctness of Recursive Programs

Example 0: Sum of [0..N).

/* Returns the sum of the natural numbers in range [0..n]
** pre: n≥0
*/
public static int sumUpTo(int n) {
   if (n == 0) { return 0; }
   else { 
      int prevSum = sumUpTo(n-1); 
      // assert prevSum = 0 + 1 + ... + (n-1)
      return n + prevSum;
   }
} 


Example 1: Selection Sort

/* Rearranges the elements of the given array 
** so that they are in ascending order.
*/
public static void selectSort(int[] a) 
   { selectSortAux(a, a.length); }

/* Rearranges the elements of the given array 
** segment (a[0..n)) so that they are ascending.
** so that they are in ascending order.
*/
private static void selectSortAux(int[] a, int n) { 
   if (n > 1) {
      int locOfMax = locOfMax(a, n);
      // assert (∀i | 0 ≤ i < n : a[locOfMax] ≥ a[i])
      swap(a, locOfMax, n-1);
      // assert (∀i | 0 ≤ i < n : a[n-1] ≥ a[i])
      selectSortAux(a, n-1);
      // assert isAscending(a,n-1) ∧ (∀i | 0 ≤ i < n : a[n-1] ≥ a[i]);
      //    therefore isAscending(a,n)
   }
   else {
      // assert isAscending(a,n)  (vacuously)
   }
}

/* Returns k such that b[k] is the largest value
** in the array segment b[0..n).
** pre: n > 0
*/
private static int locOfMax(int[] b, int n) {
   if (n == 1) { return 0; }
   else { 
      int k = locOfMax(b, n-1);
      // assert (∀i | 0≤i<n-1 : b[k] ≥ b[i])
      if (b[k] >= b[n-1]) { 
         // assert (∀i | 0≤i<n-1 : b[k] ≥ b[i]) ∧  b[k] >= b[n-1];
         //    therefore, (∀i | 0≤i<n : b[k] ≥ b[i])
         return k;
      }
      else { 
         // assert b[n-1] > b[k] ∧ (∀i | 0≤i<n-1 : b[k] ≥ b[i]);
         //    therefore, (∀i | 0≤i<n : b[n-1] ≥ b[i])
         return n-1;
      }
   }
}



Example 2: HeapSort.

The predicate isRootOfMaxHeap(a,k,n) says that, within array a[], interpreted as a complete binary tree, the descendants of node k, up to but not including node n, form a max-heap, meaning that no child node has a value exceeding the value in its parent node.

public static void heapSort(int[] a) {
   heapify(a);
   deconstructHeap(a);
}

private static void heapify(int[] b) {
   final int N = b.length;
   int k = (N-1)/2;
   // loop invariant: (∀i | k < i < N : isRootOfMaxHeap(b,i,N))
   while (k != -1) {
      siftDown(b, k, N);
      k = k-1;
   }
   // assert (∀i | -1 < i < N : isRootOfMaxHeap(b,i,N))
}

/* pre: isRootOfMaxHeap(b,2k+1,n) ∧ isRootOfMaxHeap(b,2k+2,n)
** post: isRootOfMaxHeap(k,n)
*/
private static void siftDown(int[] b, int k, int n) {
   int leftChildLoc = 2*k + 1;
   if (leftChildLoc >= n) { }  // node k is a leaf
   else {
      int m;   // id of child node of k having larger value
      if (leftChildLoc == b.length-1  ||  b[leftChildLoc] > b[leftChildLoc+1])
         m = leftChildLoc;
      }
      else 
         m = leftChildLoc + 1;
      }
      if (b[k] < b[m]) { 
         swap(b,k,m);
         siftDown(b, m, n);
      }
   }
}

/* pre: isRootOfMaxHeap(b,0,N)
*/
private static void deconstructHeap(int[] b) {
   final int N = b.length;
   int k = N;
   // loop invariant: isAscending(b[k..N)) ∧ 
   //                 (∀i,j | 0≤i<k≤j : b[i] ≤ b[j])
   while (k != 1) {
      k = k-1;
      swap(b,0,k);
      siftDown(b,0,k);
   }
}