1 / 29

Loop correctness & Termination proff

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;

mcarlotta
Download Presentation

Loop correctness & Termination proff

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Loop correctness & Termination proff Init; Invariant Loop

  2. 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.

  3. 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

  4. 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

  5. (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.

  6. (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:

  7. (b) contd. As required. Also, i=i’+1>=0 since i’<c.upper, i=i’+1<=c.upper

  8. (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.

  9. (d) The variant is always non-negative • By the invariant, i <= c.upper,and thereforec.upper – i >=0.

  10. (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.

  11. (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.

  12. 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

  13. 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-

  14. 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

  15. 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

  16. (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.

  17. (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.

  18. (b) contd. : Line (1) • Line (1): By the inductive hypothesis, 1i' 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,1i a.upper + 1. • The argument for jis identical.

  19. (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.

  20. (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.

  21. (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.

  22. (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.

  23. (b) contd. : Line (6) • Line (6): Similar to line (5), exchanging iand jand the two cases.

  24. (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.

  25. (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.

  26. (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.

  27. (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) 1k 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.

  28. (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.

  29. (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).

More Related