Analyzing the invariants
Let's analyze each of the invariants to see that they hold for the loop
in binary search.
Clearly, the invariants are true just before the loop condition is
tested for the first time:
Know: lower = 0, upper = n, and 0 <= n (from precondition).
Invariants:
0 <= lower && lower <= upper && upper <= n
0 <= 0 && 0 <= n && n <= n
true && true && true = true
lower == 0 || A[lower-1] < x
0 == 0 || A[lower-1] < x
true, using short circuit evaluation
upper == n || A[upper] > x
n == n || A[upper] > x
true, using short circuit evaluation
Now, if the invariants are true at the start of an iteration, are they
true at the end of an iteration?
Assume:
0 <= lower && lower <= upper && upper <= n;
(lower == 0 || A[lower-1] < x);
(upper == n || A[upper] > x);
Know:
mid' = lower + (upper-lower)/2;
Show:
0 <= lower' && lower' <= upper' && upper' <= n;
(lower' == 0 || A[lower'-1] < x);
(upper' == n || A[upper'] > x);
Case 1: A[mid] > x
Also know:
A[mid'] > x
upper' = mid'
lower' = lower
lower <= mid' && mid' < upper
0 <= lower' && lower' <= upper' && upper' <= n;
0 <= lower && lower <= mid' && mid' <= n;
true && true && true (since mid' < upper <= n)
lower' == 0 || A[lower'-1] < x
Since lower doesn't change in this iteration:
lower == 0 || A[lower-1] < x which is true by our assumption.
upper' == n || A[upper'] > x
mid' == n || A[mid'] > x == true since we only have to satisfy one condition
in an or condition to get true as a result
Exercise: Case 2: Show that the invariants hold if A[mid] < x.
Assuming the invariants hold, how can we show that we get the desired
postcondition as specified?
Case 1: x is not in the array
This means that when the loop terminates and returns -1, we know that
lower >= upper. But the loop invariant says lower <= upper also.
Thus, lower == upper. So plugging into the other invariants:
(lower == 0 || A[lower-1 < x]) && (upper == n || A[upper] > x)
(upper == 0 || A[upper-1 < x]) && (upper == n || A[upper] > x)
If upper == 0, then A[0] > x which means x is not in the array
(since the array is sorted).
If upper == n, then A[n-1] < x which means x is not in the array (same reason).
If upper is not equal to 0 or n, then:
A[upper-1 < x] && A[upper] > x
Since the array is sorted, x is not in the array.
So we return -1 correctly.
Case 2: x is in the array
If x is in the array, A[mid] == x and we return mid,
satisfying A[\result] == x. Also, we should make sure mid
satisfies (0 <= \result && \result < n). This can be shown
since right before we return mid, we know:
0 <= lower && lower <= upper && upper <= n
and
lower <= mid && mid < upper
So mid must also be in the range [0,n).
written by Tom Cortina, 1/27/11