300 likes | 309 Views
Loop correctness & Termination proff. Init; Invariant Loop. A correctness proof. 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;
E N D
Loop correctness & Termination proff Init; Invariant Loop
A correctness proof • 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; and • the variant decreases by at least one in every pass through the loop body.
horner (c: ARRAY[NUMBER]; x: NUMBER): NUMBER is require c.lower = 0; c.upper >= 0 local i: INTEGER do from i := 0 Result := c @ 0 invariant -- ? variant -- ? until i >=c.upper loop i := i + 1 Result := Result * x+ c @ i end ensure -- Result = end
horner (c: ARRAY[NUMBER]; x: NUMBER): NUMBER is require c.lower = 0; c.upper >= 0 local i: INTEGER do from i := 0 Result := c @ 0 invariant 0 <= i <=c.upper -- Result = variant c.upper - i until i >=c.upper loop i := i + 1 Result := Result * x+ c @ i end ensure -- Result = end
(a) The invariant is true at the beginning of the first loop iteration • On entering the loop for the first time, iis initialized to 0. • Since the precondition requires thatc.upper >= 0, it follows that0 <= i <= c.upper. • The second requirement is Result = Which is the value the Result is initialized to.
(b) The invariant is maintained by one pass through the loop body • Let i' = old i, Result' = old Result.By the loop invariant we can assume thati' >= 0, i' <=c.upper, Result' = • Since the loop was entered, we know thati' < c.upper.At the end of the loop, we have i = i' + 1, and Result = Result' + c @ i.Substituting into the last equation, we get:
(b) contd. As required. Also, i=i’+1>=0 since i’<c.upper, i=i’+1<=c.upper
(c) The postcondition follows from the invariant and the exit condition • The exit condition is i >= c.upper.Since the invariant states that i <= c.upper, it follows that i = c.upper. • Substituting this into the second part of the invariant immediately yields the postcondition.
(d) The variant is always non-negative • By the invariant, i <= c.upper,and thereforec.upper – i >=0.
(e) The variant decreases by at least one in every pass through the loop body • Since iincreases by one in every pass and c.upperis constant, the invariant decreases by exactly one in every pass.
(f) The array reference in the loop is always within bounds • By the first part of the invariant,0 <=i <=c.upper, and by the precondition c.lower = 0. • Therefore iis always within the bounds of the array.
merge (a: ARRAY[G]; b: ARRAY[G]): ARRAY[G] is require a is not Void; b is not Void a.lower = 1; b.lower = 1 -- for all i: 1 i a.upper – 1 implies a @ i a @ (i + 1) -- for all j: 1 j b.upper – 1 implies b @ j b @ (j + 1) local i, j, k: INTEGER do Result.make(1, a.upper + b.upper) from i := 1; j := 1; k := 1 invariant -- ? -- variant -- ? -- until i > a.upper and j > b.upper loop if i > a.upper or else (j b.upper and then b @ j a @ i) then Result.put(b @ j, k) j := j + 1 else Result.put(a @ i, k) i := i + 1 end k := k + 1 end ensure -- mset(Result) = mset(a) mset(b) -- for all l: 1 l a.upper + b.upper – 1 implies Result @ l Result @ (l + 1) end
merge (a: ARRAY[G]; b: ARRAY[G]): ARRAY[G] is require a is not Void; b is not Void a.lower = 1; b.lower = 1 -- for all i: 1 i a.upper – 1 implies a @ i a @ (i + 1) -- for all j: 1 j b.upper – 1 implies b @ j b @ (j + 1) local i, j, k: INTEGER do Result.make(1, a.upper + b.upper) from i := 1; j := 1; k := 1 invariant 1 i a.upper + 1; 1 j b.upper + 1 k = i + j – 1 -- mset(Result[1 .. k – 1]) = mset(a[1 .. i – 1]) mset(b[1 .. j – 1]) -- for all l: 1 l k – 2 implies Result @ l Result @ (l + 1) 2 k a.upper + b.upper and 1 i a.upper implies Result @ (k – 1) a @ i 2 k a.upper + b.upper and 1 j b.upper implies Result @ (k – 1) b @ j variant a.upper + b.upper + 1 – k until i > a.upper and j > b.upper loop if i > a.upper or else (j b.upper and then b @ j a @ i) then Result.put(b @ j, k) j := j + 1 else Result.put(a @ i, k) i := i + 1 end k := k + 1 end ensure -- mset(Result) = mset(a) mset(b) -- for all l: 1 l a.upper + b.upper – 1 implies Result @ l Result @ (l + 1) end -1- -2- -3- -4- -5- -6-
merge (a: ARRAY[G]; b: ARRAY[G]): ARRAY[G] is require a is not Void; b is not Void a.lower = 1; b.lower = 1 -- for all i: 1 i a.upper – 1 implies a @ i a @ (i + 1) -- for all j: 1 j b.upper – 1 implies b @ j b @ (j + 1) local i, j, k: INTEGER do Result.make(1, a.upper + b.upper) from i := 1; j := 1; k := 1 invariant 1 i a.upper + 1; 1 j b.upper + 1 -- 1 k = i + j – 1 -- 2 -- mset(Result[1 .. k – 1]) = mset(a[1 .. i – 1]) mset(b[1 .. j – 1]) -- 3 -- for all l: 1 l k – 2 implies Result @ l Result @ (l + 1) -- 4 2 k a.upper + b.upper and 1 i a.upper implies Result @ (k – 1) a @ i -- 5 2 k a.upper + b.upper and 1 j b.upper implies Result @ (k – 1) b @ j -- 6 variant a.upper + b.upper + 1 – k
until i > a.upper and j > b.upper loop if i > a.upper or else (j b.upper and then b @ j a @ i) then Result.put(b @ j, k) j := j + 1 else Result.put(a @ i, k) i := i + 1 end k := k + 1 end ensure -- mset(Result) = mset(a) mset(b) -- for all l: 1 l a.upper + b.upper – 1 implies Result @ l Result @ (l + 1) end
(a) The invariant is true at the beginning of the first loop iteration • Line (1) of the invariant follows from the initialization of the variables, the precondition, and the invariant of ARRAY[G] that states that a.upper a.lower – 1. • Line (2) follows from the initialization. • In line (3) all multisets are empty. • Lines (4–6) are vacuously true.
(b) The invariant is maintained by one pass through the loop body • Denote the values of the variables at the beginning of the pass using primes ('). First note that by the loop exit condition together with line (1) we know that (*) i' + j' a.upper + b.upper +1. • From this, together with line (2), we get (**) k' a.upper + b.upper.
(b) contd. : Line (1) • Line (1): By the inductive hypothesis, 1i' a.upper + 1;inside the loop, ieither remains the same or is incremented by one, but only under the condition that i' a.upper.In any case, at the end of the pass,1i a.upper + 1. • The argument for jis identical.
(b) contd. : Lines (2) + (3) • Line (2): k = k' + 1, and either i = i'and j = j' + 1 or i = i' + 1 and j = j'. The invariant is maintained in both cases. • Line (3): There are two cases. • Case (a): the condition in the if statement was true. In this case, the element b @ j'has been added to the multiset on the left-hand side, and also to the second multiset on the right-hand side (because jwas incremented). Therefore the equation still holds. • Case (b): the condition was false. The argument is similar.
(b) contd. : Line (4) • Line (4): If k 2 the assertion is vacuously true. Assume therefore that k > 2, so that k' 2. • By the induction assumption, the assertion holds for all lbetween 1 and k' – 2, so we need only prove that Result @ (k' – 1) Result @ k'.Again there are two cases. • The first case is when the condition in the if statement was true. In this case, Result @ k' = b @ j', and by line (6) we know that Result @ (k' – 1) b @ j'. • The condition 2 k' a.upper + b.upperof line (6) is true by the other initial assumption that k' 2 and by (**). • The condition 1 j' b.upperis true by line (1), the exit condition, and the if condition. • The second case is similar.
(b) contd. : Line (5) • Line (5): Assume that the antecedents of the implication hold. Again there are two cases. • Case (a): the condition in the if statement was true. In this case, Result @ k' = b @ j', and by the if condition we know that b @ j' a @ i'. (The case i' > a.upper cannot be true by the antecedents of the implication and the fact that in this case i = i'.)Therefore Result @ (k – 1) = Result @ k' = = b @ j' a @ i' = a @ i. • Case (b): the condition in the if statement was false.
(b) contd. : Line (5) case (b) • In this case, Result @ k' = a @ i' and i = i' + 1. By line (1) and the antecedents of the implication we know that i' is between 1 and a.upper – 1, and from the precondition it now follows that a @ i' a @ (i' + 1).Therefore Result @ (k – 1) = Result @ k' = = a @ i' a @ (i' + 1) = a @ i.
(b) contd. : Line (6) • Line (6): Similar to line (5), exchanging iand jand the two cases.
(c) The postcondition follows from the invariant and the exit condition • By line (1) of the invariant together with the exit condition we know that on exit from the loop i = a.upper + 1,j = b.upper + 1, and k = a.upper + b.upper + 1. • The first line of the postcondition follows immediately from the initialization of the Resultarray and line (3) of the invariant. • The second line of the postcondition follows from line (4) of the invariant.
(d) The variant is always non-negative • From lines (1–2) of the invariant it follows that k a.upper + b.upper + 1 • Therefore the variant is non-negative.
(e) The variant decreases by at least one in every pass through the loop body • The quantity a.upper + b.upper + 1 is constant, and kincreases by exactly one in every pass through the loop body. • The variant therefore decreases by exactly one in each pass.
(f) There are no array-out-of-bounds error during the computation • From the invariant we can conclude that inside the loop (except after the last line) 1k a.upper + b.upper(see (**)).Therefore the assignment to the element of Resultat index kis correct. • The indexes iand jare never too low because of line (1) of the invariant.
(f) contd. • The comparison b @ j a @ iin the if condition is correct because of the preceding conditions, which ensure that i a.upperand j b.upper. • The reference to b @ jin the then part is correct because if i > a.upperthen j b.upper(by the exit condition), and otherwise by the second part of the condition. • Because of the if condition, the reference to a @ iin the else part will never happen when i > a.upper, and is therefore also correct.
(f) contd. • It is easy to see that the conditions in the various invariant assertions ensure that there will be no array-out-of-bounds error even when computing the invariants (and this holds also for the commented-out assertions).