CSC195, Class 51: Loop Invariants Overview: * Smallest in an array, continued * Some general principles * Detour: Gries's infinite loop principle * Gries's balloon picture * Designing invariants Notes: * Devin presents cool graphics stuff at 4:15/4:30. Show up and support her (and get extra credit). * I expect to have prospective grades for you on Friday of 14th week. * Are there questions on exam 2? + Essay should be ten-twelve point, 1.5 space, 1 inch margins. Word is okay. PDF is better. RTF is okay. + How do we store symbols? As char *. * We'll start talking about Unix processes on Friday. ---------------------------------------- Precondition: C = { a = A and n >= 1} Postcondition: P = { (exists 1 <= i <= n, s = a[i]) and (for all 1 <= i <= n, s <= a[i]) and (a = A) } Invariant I = { (exists 1 <= i <= j, s = a[i]) and (for all 1 <= i <= j, s <= a[i]) and (a = A) } Introducing a new variable, j What should we say about j and s before the loop starts? j should be 1 Precondition: C = { a = A and n >= 1 and j = 1 and s=a[1]} Reminder: Check that C => I Does C imply I? Yes. What do we want when the loop finishes? I and (not GG) => P I and (j = n) => P Observation: guard should be j!=n { Precondition: C } { Invariant: I } { Bound: n-j } do { (exists 1 <= i <= K, s = a[i]) and (for all 1 <= i <= K, s <= a[i]) and (a = A) } j != n: if s <= a[j+1]: skip | s > a[j+1]: s = a[j+1] fi j = j+1; ; Either s stayed the same or s got set to a[K+1] ; If s stays the same, what do we need to know about ; s so that the new version of the invariant holds? ; We need to know s <= a[K+1] { (exists 1 <= i <= K+1, s = a[i]) and (for all 1 <= i <= K+1, s <= a[i]) and (a = A) } od { Postcondition: P } Yay! The invariant is invariant. The do loop guarantees that j=n when the loop terminates. We've already decided that termination plus I yields postcondition. Will this terminate? Does the bound start out non-negative and always decrease while remaining non-negative? Informal analysis: Yes. Interesting design decision: We used j != n rather than j < n. Gries says "Yay" (that is, use j != n) Your training says "Boo" (that is, use j < n) Morals? * If you know I and FOO => P, then your guard should start out as (not FOO). * Infinite loops are good ways of indicating errors. * You can often puzzle out the body of the loop by figuring out how to get from one I to the next. + Guess a statement and use wp + Other techniques work too. * Everything always boils down to trial and error + But good design can lead to better first trials and fewer errors + If there wasn't trial and error, we could write programs that wrote programs based only on postconditions. How do you build invariants? Think about "the balloon model" How do we translate this picture into "something useful". * Need a technique for gradually expanding the postconditions * Need to think about how you reverse that technique How do you "expand" a predicate? * Eliminate some of the conjuncts A and B goes to B I.e., P = A and B I = B what should the guard in the loop be? (not A) * Add a disjunct I.e. P = A I = A or B What should the guard be? B * Replace constants with variables P: foo(constant) I: foo(v) What should the guard be? v != constant * Expand ranges From 5 <= i <= 10 to 0 <= i <= 10 Generalize P: lb <= i <= ub I: lb-x <= i <= ub+y Think of a practical example without looking at Gries