# CSC 301.01, Class 24: Program verification (1)

Overview

• Preliminaries
• Notes and news
• Upcoming work
• Extra credit
• Goals for this unit
• Verifying imperative code
• Example - binary search
• Example - binary search, revised
• Verifying recursive procedures
• Example - Efficient exponentiation with recursion
• Example - Efficient exponentiation with iteration
• Loop invariants, revisited [if time]
• Example - Dutch national flag [if time]

### Upcoming work

• Saving Brinton, Talk at 2pm TODAY in Harris.
• Saving Brinton, Wednesday at 7pm TODAY in the Strand.
• Gates Lecture, TONIGHT at 7:00 p.m. in JRC 101.
• Convocation Thursday (11 am in JRC 101).
• Strange Escape Room Challenge.
• Protest BOT workshop, Friday 4pm in Burling 1st.

### Extra credit (Peer)

• Scarlet and Black Swim and Dive Meeting Saturday. (One hour suffices.)
• Tailgate for football team Saturday at 11:30 a.m. on the grassy knoll.
• German movie in Strand 4pm Sunday.

### Other good things

• Support the football team on Saturday.
• Grinnell Singers Sunday at 2pm.

## Goals for this unit

• Think about / practice a common technique for “proving” that a program or algorithm is correct.
• Practice thinking about the “state” of an imperative program.
• Values associated with local variables (and parameters).
• Values associated with global variables.
• The “stuff” on the stack.
• The “stuff” on the heap.
• Use program verification techniques to improve your algorithm design.

## Verifying imperative code

• Annotate the code with information about appropriate parts of the state of the system.
• Ideally, you have state info after every instruction (or set of related instructions).
• It should be provable that an instruction brings you from one state to the next state.
• Simplest instruction: assignment statement. ` {…} // may include “x = ?” x = 5; {… - “x = ?” + “x = 5”}

• Tests {S0} if TEST {S0 and TEST} consequent {S1} else {S0 and (not TEST)} alternate {S2} end {S1 or S2} or {S1 intersect S2}

• Loops: Traditionally we both look at the state and put limitations on the state. (“Loop invariants.”) A loop invariant is (a) a useful statement about the state of the system that (b) we know is true when we enter loop, (c) we know is true at the end of the body
• Invariants plus “loop termination argument” go hand in hand
• You can then guarantee that the invariant holds at the end of the loop.
• Function calls
{S}
call(f)
{postconditions of f + things we know that f did not affect}

Detour fun with C

printf ("%d", x); // 5
foo(y);
printf ("%d", x); // 6

What are some ways that a call that does not seem to involve x modifies x?

• y is a pointer to x.
• x is a global.
• Some other global contains a pointer to x.
• Someone wrote beyond the bounds of an array.

Verification is harder with pointers and with globals. More system state information is necessary.

Here’s a slightly modified version of Bentley’s Figure 1. We’ll walk through it together.

Procedure: Binary search
Input: X, array of size N
Input: N
Input: T, a value (target)
Output: P, which is the index of T if T is in the array, and 0 o/w.
1. { MustBe(1,N) }
{ This means that if X is anywhere in the array, it is between
indices 1 and N, inclusive }
2. L := 1; U := N
3. { MustBE(L,U) }
{ Note: We know that L is 1 and U is N, but we're not including
them in the statement about the state because it's not relevant. }
{ However, because we know those two things, we know the MustBe. }
{ This is also the loop invariant. }
4. loop
5.   { MustBe(L,U) }
6.   if L>U then
7.     { L>U and MustBE(L,U) }
8.     { T is not in the array }
9.     P := 0; break
else
10.     { MustBe(L,U) and L<=U }
11.     M := (L+U) div 2
12.     { MustBe(L,U) and L<=M<=U }
13.     case
14.       X[M] < T:
15.         { MustBe(L,U) and CantBe(1,M) and L<=M<=U }
16.         { MustBe(M+1,U) }
17.         L := M+1
18.         { MustBe(L,U) }
19.       X[M] = T:
20.       { MustBe(L,U) and X[M] = T }
21.         P := M; break
22.       X[M] > T:
23.         { MustBe(L,U) and CantBe(M,N) }
24.         { MustBe(L,M-1) }
25.         U := M-1
26.         { MustBe(L,U) }
end case
27.   { MustBe(L,U) }
end if
28. end loop

Note: A proof would also involve ensuring that the loop terminates. We should argue that U-L shrinks at every iteration.

## Example - binary search, revised

Write an O(logn) binary search that finds the *first* instance of a value in an array. (Note that because it’s O(logn), you can’t just find an instance and then look left.)

## Verifying recursive procedures

Trust the magic recursion fairy + good preconditions/postconditions.

You can also do nice proofs by induction.