=========================================================================== CSC 236 Extra Example of Iterative Correctness Winter 2008 =========================================================================== selection_sort(A): # Pre: A is a list whose elements are comparable with each other # Loop Inv: A[0..i-1] sorted and A[0..i-1] <= A[i..len(A)-1] for i in [0..len(A)-1]: s = i # Loop Inv: A[s] <= A[i..j-1] for j in [i+1..len(A)-1]: if A[j] < A[s]: s = j A[i], A[s] = A[s], A[i] # Post: A contains same elements as before, sorted in # non-decreasing order Plan: First, prove loop invariant for inside loop (assume arbitrary iteration of the outside loop). Next, use this to prove loop invariant for outside loop. Finally, use outside loop invariant to prove partial correctness, and prove termination. Inside loop: - Loop invariant: LI = "A[s] <= A[i..j-1]". - Proof by induction on number of iterations: Base Case: s_0 = i and j_0 = i+1 so A[s_0] = A[i] <= A[i..j_0-1]. Ind. Hyp.: Let k >= 0 and suppose LI_k. Ind. Step: To prove LI_{k+1} consider two cases. Case 1: If there is no iteration number k+1, then LI_{k+1} is equivalent to LI_k so it is true by the IH Case 2: If there is an iteration number k+1, then from loop condition, j_k < len(A). Also, A[s_k] <= A[i..j_k-1] from IH. Consider two subcases, based on if-statement. Subcase A: If A[j_k] < A[s_k], then A[j_k] <= A[i..j_k] and algo sets s_{k+1}=j_k. Subcase B: If A[j_k] >= A[s_k], then A[s_k] <= A[i..j_k] and s_{k+1} = s_k. In all cases, A[s_{k+1}] <= A[i..j_k] = A[i..j_{k+1}-1] since j_{k+1} = j_k + 1. In all cases, LI_{k+1} is true. Hence, by induction, LI holds for any number of iterations. - Termination: use E = len(A)-j. . For all k, E_k >= 0 because j <= len(A) from LI. . For some k >= 0, if there is an iteration number k+1, then from code we know j_{k+1} = j_k+1, so E_{k+1} = len(A)-j_{k+1} = len(A)-(j_k+1) = len(A)-j_k-1 = E_k-1 < E_k. . Therefore, E_0 > E_1 > ... is a decreasing sequence of natural numbers and must be finite by the well-ordering principle, i.e., the inside loop terminates. Outside loop: - Loop invariant: LI' = "A[0..i-1] sorted and A[0..i-1] <= A[i..len(A)-1]". - Proof by induction on number of iterations: Base Case: i_0 = 0, so A[0..i_0-1] = A[0..-1] is sorted (trivially because empty), and A[0..i_0-1] = A[0..-1] <= A[0..len(A)-1] = A[i_0..len(A)-1] (vacuously because A[0..-1] is empty). Ind. Hyp.: Let k >= 0 and suppose LI'_k. Ind. Step: To prove LI'_{k+1} consider two cases. Case 1: If there is no iteration number k+1, then LI'_{k+1} is equivalent to LI'_k so it is true by the IH Case 2: If there is an iteration number k+1, then from the loop condition we know that i_k < len(A). Also, IH tells us that A[0..i_k-1] is sorted and A[0..i_k-1] <= A[i_k..len(A)-1]. After inside loop runs, we know from LI (for inside loop) that A[s] <= A[i_k..len(A)-1] (since final value of j is len(A)). Next, algo swaps A[s], A[i_k], so A[i_k] <= A[i_k+1..len(A)-1], and since A[i_k-1] <= A[i_k..len(A)-1] (from IH) we know that A[i_k-1] <= A[i_k], i.e., A[0..i_k] is sorted. Since i_{k+1} = i_k+1, this proves LI'_{k+1}. In all cases, LI'_{k+1} is true. Hence, by induction, LI' holds for any number of iterations. - Termination: use E = len(A)-i, just like for inside loop. Partial correctness: - When outside loop terminates, we know i = len(A) so LI' tells us that A[0..len(A)-1] is sorted (and A[0..len(A)-1] <= A[len(A)..len(A)-1], which is vacuoucly true because A[len(A)..len(A)-1] is empty). This is exaclty the postcondition for selection sort.