250 likes | 564 Views
Loop variant and invariant. Recitation on OOSC Ohad Barzilay IDC, May 2004. (1). (2). (3). Breaking the Loop: Generating the Verification Conditions. Start. “Precondition”. Init. Invariant. Exit?. YES. NO. “Postcondition”. Body. End. Loop Computations. Loop outline. from init
E N D
Loop variant and invariant Recitation on OOSC Ohad Barzilay IDC, May 2004
(1) (2) (3) Breaking the Loop: Generating the Verification Conditions Start “Precondition” Init Invariant Exit? YES NO “Postcondition” Body End
Loop outline from init invariant inv variant var until exit loop body end
Loop outline • A loop invariant inv— an assertion. • An exit condition exit, whose conjunction with invachieves the desired goal. • A variant var— an integer expression. • A set of initialization instructions init, which always produces a state that satisfies invand makes varnon-negative.
Loop outline • A set of body instructions bodywhich, • when started in a state where invholds and • varis non-negative, • preserves the invariant and decreases the variant while keeping it non-negative (so that the resulting state still satisfies invand has for vara value that is less than before but has not gone below zero).
Proving Loop Correctness • Step 1: The invariant follows from the loop precondition and the initialization. Loop-precond Init Invariant • Step 2: The invariant is maintained by one pass through the loop. Invariant Exit Invariant • Step 3: The loop postcondition follows from the invariant. Invariant Exit Loop-postcond
Proving Loop Termination • Step 4: The variant is always non-negative (should follow from the invariant). Invariant Variant 0 • Step 5: The variant decreases by at least 1 in every pass through the loop. Invariant Variant < Previous-Variant
proof steps (in other words) • The invariant is true at the beginning of the first loop iteration; • The invariant is maintained by one pass through the loop body; • The postcondition follows from the invariant and the exit condition; • The variant is always non-negative; • The variant decreases by at least one in every pass through the loop body;
maxarray maxarray (t: ARRAY [INTEGER]): INTEGER is -- The highest of the values in the entries of t require t.capacity >= 1 local i: INTEGER do -- See next page end
maxarray – loop body from i := t.lower Result := t @ lower until i = t.upper loop i := i + 1 Result := Result.max (t @ i) end
Loop invariant • The invariant property is that at each stage through the loop Result is the maximum of the current approximation of the array. • This is true after the initialization, since the instructions in the from clause ensure that Result is the maximum of the first approximation, the trivial slice [lower, lower] consisting of just one element.
Loop invariant • Then on each iteration we extend the slice by one element — improving our approximation of the array — and make sure to maintain the invariant by updating Result if the new value is higher than the previous maximum. • At the end, the approximation covers the entire array, and since we have maintained invariant the property that Result is the maximum of the current approximation we know that it now is the maximum of the array as a whole.
Loop variant • The variant is: t.upper – i • This satisfies both conditions: • Because the routine precondition requires t.capacity to be positive (that is to say, the routine is only applicable to non-empty arrays) and the invariant of class ARRAY indicates that capacity = upper – lower + 1, the property i <= t.upper (part of the loop’s invariant) will always be satisfied when i is initialized to t.lower. • Any execution of the loop body performs the instruction i := i + 1, reducing the variant by one.
maxarray from i := t.lower; Result := t @ lower invariant -- Result is the maximum of the elements of t at indices t.lower -- to i. variant t.lower – i until i = t.upper loop i := i + 1 Result := Result.max (t @ i) end
GCD gcd(a,b: INTEGER): INTEGER is -- Greatest common divisor of a and b require a>0; b>0 local x, y : INTEGER do …. -- see next slide ensure -- Result is the gcd of a and b end
GCD – loop body from x:=a; y:=b until x=y loop if x>y then x:=x-y else y:=y-x end end
Loop invariant x > 0; y > 0 -- The pair <x, y> has the same greatest common divisor as the -- pair <a, b> • Clearly, INV is satisfied after execution of the from clause. • Also, if inv is satisfied before an execution of the loop body under the loop continuation condition x /= y, then inv will still be satisfied after execution of this instruction; this is because replacing the greater of two positive non-equal numbers by their difference leaves them positive and does not change their gcd.
Loop postcondition • We have shown inv to be satisfied before the first iteration and preserved by every iteration. • It follows that on loop exit, when x = y becomes true, inv still holds; that is to say: x = y and “The pair <x, y> has the same greatest common divisor as the pair <a, b>” • which implies that the gcd is x because of the mathematical property that the gcd of any integer x and itself is x.
Loop variant • How do we know that the loop will always terminate? We need a variant. • We cannot choose x as a variant, because we cannot be sure that an arbitrary loop iteration will decrease x; • nor can we be sure that it will decrease y, so y is also not an appropriate variant. But we can be sure that it will decrease either x or y. • hence their maximum x.max (y); this maximum will never become negative.
GCD from x:=a; y:=b invariant x>0;y>0 --(x,y) have same GCD as (a,b) variant x.max(y) until x=y loop if x > y then x := x – y else y := y – x end end