210 likes | 298 Vues
Stay informed about invariants in coding, class invariants, loop invariants, and axiomatic semantics. Learn about pre/post conditions, weakest preconditions, and correctness proofs. Get insights into assignment statements, inference, and rule of consequence.
E N D
Announcements • We are done with homeworks • Second coding exam this week, in recitation • Times will be posted later today • If in doubt, show up for your regular recitation time
Invariants • Invariants: properties which must always hold • Class invariants hold between (but not necessarily during) method invocations • Loop invariants hold before, during and after execution of a loop • Pre/post conditions • Post-conditions of a method spell out what must be true after a method execution completes, if preconditions are satisfied • Pre-conditions of a method spell out what must be true at method invocation in order for method to perform as promised
Class invariant Recall our Bag<E> implementation: publicclass Bag<E> implements Collection<E> { private E [] _values; /* CLASS INVARIANTS * _size denotes the number of elements in the bag, and also * the first available position within the array _values */ privateint_size; public Bag() { _values = (E[]) (new Object[10]); _size = 0; } // POST: _values is initialized, _size is zero publicbooleanadd(E item) { … } // POST: item is in Bag publicvoid clear() { … }// POST: _size is zero publicbooleanremove(Object item){ … }// POST: one fewer item is in Bag … }
Axiomatic semantics • Basic idea: you make assertions about statements in a program. • A precondition is an assertion about what is true prior to execution of a statement. • A postcondition is an assertion about what is true after execution of a statement. For example: sum = 2*sum + 1 {sum > 1} • Quotes on upcoming slides are from Concepts of Programming Languages, by Robert Sebesta.
Weakest precondition • “The weakest precondition is the least restrictive precondition that will guarantee the validity of the associated postcondition.” [p. 151] • In example above {sum>10} is a valid precondition but {sum>0} is the weakest precondition: {sum > 0} sum = 2*sum + 1 {sum > 1}
Correctness proofs • “If the weakest precondition can be computed from the given postconditions for each statement of a language, then correctness proofs can be constructed for programs in that language.” [p. 151] • To do this, start with output specifications for the program as the postcondition for the program as a whole.
Next, work backwards, computing weakest preconditions one statement at a time, to derive the weakest precondition for the program as a whole: stmt1 {c0} stmt1 {c1} stmt2 {c1} stmt2 {c2} . . . . . . stmtN {cN} {cN-1} stmtN {cN}
If the input specification for the program satisfies the program’s weakest precondition, then the program will (provably) produce the correct result.
Assignment statements • The axiomatic semantics of an assignment statement x=E is written as P=QxE • This means that the precondition is the postcondition with all instances of x replaced by E. • Example: a = b/2-1 {a<10} To compute precondition, replace all instances of a in postcondition a<10 by b/2–1: b/2-1 < 10, or b < 22 • Semantics: {b<22} a = b/2-1 {a<10} • In general: {QxE} x=E {Q}
Inference • Suppose we wanted to prove the following: {sum > 5} sum = 2*sum + 1 {sum > 3} • Starting with the postcondition, we derive as the weakest precondition something different: 2*sum + 1 > 3 2*sum > 2 sum > 1 (weakest precondition) • Clearly this is OK, because the actual precondition {sum>5} implies the weakest precondition {sum>1}: sum>5 => sum>1 • We use an inference rule, the rule of consequence, to prove this.
Rule of consequence • General form: S1, S2, …, Sn S • Precondition strengthening: P=>P’, {P’} C {Q} {P} C {Q} • Postcondition weakening: Q’=>Q, {P} C {Q’} {P} C {Q}
Precondition strengthening applied • Recall our example. We want to prove the following: {sum > 5} sum = 2*sum + 1 {sum > 3} • The weakest precondition we derive is: sum > 1 • Apply precondition strengthening to finish proof: P=>P’, {P’} C {Q} {P} C {Q} sum>5 => sum>1, {sum>1} sum=2*sum+1 {sum>3} {sum>5} sum=2*sum+1 {sum>3}
Hang on! • Why get so formal? • Because this way correctness proofs can be (partially) automated.
{P} S1 {Q}, {Q} S2 {R} • {P} S1 S2 {R} Sequences:S1 S2 Start with a sequence of statements: y = 3*x+1; x = y+3; {x<10} Compute weakest precondition for 2nd stmt: {y+3<10} or {y<7}, use as postcondition for 1st stmt: y = 3*x+1; {y<7} {y<7} x = y+3; {x<10} Compute weakest precondition for 1st stmt: {3x+1<7} or {x<2} {x<2} y = 3*x+1; {y<7} {y<7} x = y+3; {x<10} Conclude, applying sequence rule: {x<2} y = 3*x+1; x = y+3; {x<10}
{B & P} S1 {Q}, {!B & P} S2 {Q} • {P} if B then S1 else S2 {Q} Selection:if B then S1 else S2 Start with a conditional statement: if (x>0) then y=y-1 else y=y+1 {y>0} Deal with arms of the conditional one at a time, first the then-arm: y = y-1 {y>0} {y>1} y = y-1; {y>0} Now the else-arm: y = y+1 {y>0} {y>-1} y = y+1; {y>0} Use rule of precondition strengthening on the else-arm result (to make both arms uniform): {y>1} y = y+1; {y>0} Now strengthen both arms’ preconditions by imposing a constraint on x: { x>0 & y>1} y = y-1; {y>0} {!(x>0) & y>1} y = y+1; {y>0} Conclude, applying selection rule: {y>1} if (x>0) then y=y-1 else y=y+1 {y>0}
{B & I} S {I} _ • {I} while B do S end {I and !B} While:while B do S end Let’s prove the following: {true} r=x; q=0; while y<=r do r=r-y; q=q+1; end {y>r & x=r+y*q} Start by proving loop body: {y<=r & x=r+y*q} r=r-y; q=q+1;{x=r+y*q} Start with last statement: q=q+1 {x=r+y*q} {x=r+y*(q+1)} q=q+1 {x=r+y*q} {x=r+y+y*q} q=q+1 {x=r+y*q} Continue with second-to-last statement: r=r-y {x=r+y+y*q} {x=r-y+y+y*q} r=r-y {x=r+y+y*q} {x=r+y*q} r=r-y {x=r+y+y*q} Use rule for sequence to get: {x=r+y*q} r=r-y; q=q+1; {x=r+y*q} Now strengthen precondition to conclude proof of loop body: {y<=r & x=r+y*q} r=r-y; q=q+1; {x=r+y*q} This lets us derive a weakest precondition for the while loop: {x=r+y*q} while y<=r do r=r-y; q=q+1; end {x=r+y*q & !(y<=r)}
{B & I} S {I} _ • {I} while B do S end {I and !B} While:while B do S end The next step is to prove the sequence {true} r=x; q=0; while y<=r do r=r-y; q=q+1; end {x=r+y*q & y>r)} Start by moving backwards from the while loop (since we derived a weakest precondition from its postcondition already): {true} r=x; q=0; {x=r+y*q} Start with last statement: q=0; {x=r+y*q} {x=r+y*0} q=0 {x=r+y*q} {x=r} q=0 {x=r+y*q} Continue with second-to-last statement: r=x {x=r} {x=x} r=x {x=r} Precondition strengthening: {true} r=x {x=r} Sequence rule (applied in general form): {true} r=x; q=0; while y<=r do r=r-y; q=q+1; end {x=r+y*q & !(y<=r)} Finally, postcondition weakening because !(y<=r) => y>r : {true} r=x; q=0; while y<=r do r=r-y; q=q+1; end {x=r+y*q & y>r} We're done!
Loop invariant • Recall the While rule: {B & I} S {I} _ {I} while B do S end {I and !B} • I is called the loop invariant: • "…if executing [the body] once preserves the truth of [the invariant], then executing [the body] any number of times also preserves the truth of [the invariant]." [Gordon, Programming Language Theory and its Implementation, paraphrased from page 24]
Importance of loop invariants • Developing loop invariants are a powerful way to design and understand algorithms. • Consider selection sort: selectionSort(int[] array) { int min, temp, bar=0; while (bar < array.length - 1) { min = indexOfSmallest(array, bar); // find min temp = array[bar]; // swap array[bar] = array[min]; array[min] = temp; bar = bar + 1; // Loop invariant: region before bar is sorted: // for all i,j<=bar, i<jarray[i] <= array[j]} }
Example [ 7 4 6 8 3 2 ] [ 24 6 8 3 7 ] [ 2 36 8 4 7 ] [ 2 3 48 6 7 ] [ 2 3 4 68 7 ] [ 2 3 4 6 7 8 ] region not known to be sorted region known to be sorted
Priority queues • Queue • Ordered by some priority • Regular queue – ordered by time of arrival • Think of ER queue • Implementation • List • Heap (a heap-ordered tree)