Reputation: 589
I am used to loops
while Grd
invariant Inv
{ ..}
assert Inv && !Grd;
with out any break Dafny knows that Inv && ! Grd
is true but:
Dafny does not check the loop invariant after a break;
command. Hence
method tester(s:seq<int>) returns (r:int)
ensures r <= 0
{ var i:nat := |s|;
r := 0;
while (i > 0)
decreases i
invariant r == 0;
{ i := i -1;
if s[i]< 0 { r:= s[i]; break;}
}
// assert r == 0; // invariant dose not hold
}
method Main() {
var x:int := tester([1,-9,0]);
print x,"\n";
}
Clearly Dafny understands that the invariant no longer holds. Could anyone tell me what dafny actually knows.
Upvotes: 2
Views: 682
Reputation: 2087
If there are break
statements, the condition after the loop is
the disjunction of Inv && !Grd
and the conditions that hold at
the respective break
statements.
Here's a more formal answer:
In the absence of any abrupt exits (like break
) from a loop, the familiar
way to prove the Hoare triple
{{ P }}
while Grd
invariant Inv
{
Body
}
{{ Q }}
is to prove the following three conditions (I'm ignore termination):
P ==> Inv
{{ Inv && Grd }}
Body
{{ Inv }}
Inv && !Grd ==> Q
Let me rephrase conditions 1 and 2. To do that, I will start by rewriting the while loop into a repeat-forever loop with breaks:
loop
invariant Inv
{
if !Grd {
break;
}
Body
}
(In other words, I'm using loop
as while true
.) Proof obligation 1 above
can now be rephrased as proving
{{ Inv }}
if !Grd {
break;
}
Body
{{ Inv }}
where you don't have to prove anything further along any path that reaches
a break
.
Proof obligation 2 can be rephrased in a sort of dual way:
{{ Inv }}
if !Grd {
break;
}
Body
{{ break: Q }}
by which I mean you don't have to prove anything if you reach the end of ...Body
,
but you do have to prove Q
at any break
.
What I just said also applies when Body
contains other break
statements. That's how Dafny treats loops (that is, condition 0 plus the rephrased conditions 1 and 2, plus termination checking).
Upvotes: 5