by Yu Feng
{ I ∧ b } C { I }──────────────────{ I } while b do C { I ∧ ¬b }
// Goal: y = 3 * x
i := 0; y := 0;
while i < x do {
y := y + 3;
i := i + 1;
}i := 0;
sum := 0;
while i < 5 do {
sum := sum + i;
i := i + 1;
}wp(x := E, Q) = Q[x/E]x := x + 1
{x = 2}wp(x := x + 1, x = 2)
= (x = 2)[x/x+1] // Substitute x+1 for x
= (x+1 = 2) // Apply substitution
= (x = 1) // Simplifywp(skip, Q) = Qskip {x = 5}, the VC is: wp(skip, x = 5) = (x = 5)wp(C₁; C₂, Q) = wp(C₁, wp(C₂, Q))x := 1; y := x + 1
{y = 2}wp(x := 1; y := x + 1, y = 2)
= wp(x := 1, wp(y := x + 1, y = 2))
= wp(x := 1, (y = 2)[y/x+1])
= wp(x := 1, x + 1 = 2)
= (x + 1 = 2)[x/1]
= 1 + 1 = 2
= truewp(if B then C₁ else C₂, Q) = (B ⇒ wp(C₁, Q)) ∧ (¬B ⇒ wp(C₂, Q))if x > 0 then
y := 1
else
y := -1
{y * x > 0}wp(if x > 0 then y := 1 else y := -1, y * x > 0)
= (x > 0 ⇒ wp(y := 1, y * x > 0)) ∧
(x ≤ 0 ⇒ wp(y := -1, y * x > 0))
= (x > 0 ⇒ 1 * x > 0) ∧ (x ≤ 0 ⇒ -1 * x > 0)wp(while b do c, Q) generates these verification conditions:while b do c with Invariant I and Post-condition Q, we verify the three conditions abovex := 0;
if x < 1 then
x := x + 1
else
skip;
Post: x = 1
1. Start with the postcondition: x = 1
2. For the if-statement (working backwards):
wp(if x < 1 then x := x + 1 else skip, x = 1)
= (x < 1 ⇒ wp(x := x + 1, x = 1)) ∧ (x ≥ 1 ⇒ wp(skip, x = 1))
= (x < 1 ⇒ (x + 1) = 1) ∧ (x ≥ 1 ⇒ x = 1)
= (x < 1 ⇒ x = 0) ∧ (x ≥ 1 ⇒ x = 1)
3. For the first assignment:
wp(x := 0, (x < 1 ⇒ x = 0) ∧ (x ≥ 1 ⇒ x = 1))
= ((0 < 1 ⇒ 0 = 0) ∧ (0 ≥ 1 ⇒ 0 = 1))
= (true ⇒ true) ∧ (false ⇒ 0 = 1)
= true ∧ true
= true
4. Therefore, the verification condition is: truee ::= n | x | e₁ + e₂ | e₁ - e₂ | e₁ * e₂b ::= true | false | e₁ = e₂ | e₁ < e₂ | ¬b | b₁ ∧ b₂ | b₁ ∨ b₂S ::= skip | x := e | S₁; S₂ | if b then S₁ else S₂ | while b do SS ::= skip // no operation
| havoc x // nondeterministically assigns any value to x
| assume b // restricts control flow to paths where b holds
| assert b // declares that b must hold (generates VC for b)
| S ; S // sequential composition
| S ★ S // nondeterministic compositionGC(skip) = assume true
GC(x := e) = assume tmp = x; havoc x; assume (x = e[tmp/x])
GC(c1 ; c2) = GC(c1) ; GC(c2)
GC(c1 ★ c2) = GC(c1) ∧ GC(c2)
GC(if b then c1 else c2) =
(assume b; GC(c1)) ∧ (assume ¬b; GC(c2))
[Loop rule omitted - will be covered later]GC(x := e) = assume tmp = x; havoc x; assume (x = e[tmp/x])GC({I} while b do c) =
assert I;
havoc x₁; ...; havoc xₙ; // vars modified in c
assume I;
(assume b;
GC(c);
assert I;
assume false)
★
assume ¬bwp(skip, Q) = Q
wp(assert C, Q) = C ∧ Q
wp(assume C, Q) = C → Q
wp(havoc x, Q) = ∃a. Q[a/x] (a is fresh)
wp(S₁; S₂, Q) = wp(S₁, wp(S₂, Q))
wp(S1 ★ S2, Q) = wp(S1, Q) ∧ wp(S2, Q)
{n ≥ 0}
p := 0;
x := 0;
{p = x * m ∧ x ≤ n}
while x < n do
x := x + 1;
p := p + m
{p = n * m}
assume p₀ = p; havoc p; assume p = 0;
assume x₀ = x; havoc x; assume x = 0;
assert p = x * m ∧ x ≤ n; // Check loop invariant initially
havoc x; havoc p; // Abstract loop execution
assume p = x * m ∧ x ≤ n; // Assume invariant holds
(assume x < n; // Loop condition holds
assume x₁ = x; havoc x; assume x = x₁ + 1; // x := x + 1
assume p₁ = p; havoc p; assume p = p₁ + m; // p := p + m
assert p = x * m ∧ x ≤ n; // Invariant preserved
assume false) // No fall-through
★
assume ¬(x < n) // Loop exit condition