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.
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):
Check that the loop invariant holds on entry to the loop:
P ==> Inv
Check that the loop invariant is maintained by the loop body:
{{ Inv && Grd }}
Body
{{ Inv }}
Check that the invariant and negated guard prove Q:
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).
Related
Hi I have simplified the problem to a method that simply copies the elements of one array to another array. My problem is that the final assert verifies yet the initial assert fails to verify even though I have a guard to ensure that initial assert only applies after the first time the loop is entered. Hence I think the final assert should imply the initial assert.
Any help much appreciated.
method simpImp(a:array<int>) returns (r:array<int>)
{
print "a ",a[..],"\n";
r := new int[a.Length];
var i:nat := 0;
while (i< a.Length)
decreases a.Length - i
invariant a.Length >= i
{
if (i> 0) { print " bool ",r[i-1] == a[i-1],"\n";}
else {print "*i ",i,"\n";}
//if (i> 0) { assert r[i-1] == a[i-1]; } //Fail
//assert (i>0) ==> r[i-1] == a[i-1]; //Fail
r[i] := a[i];
i:= i +1;
assert r[i-1] == a[i-1];
}
}
method Main() {
var a:array<int> := new int[5];
a[0],a[1],a[2],a[3],a[4] := 10,2,30,4,3;
var iny:= simpImp(a);
print "r ",iny[..],"\n";
}
The issue is that you need to add something to your loop invariant to "remember" any facts you need to carry between iterations. Dafny analyzes the loop body in isolation, assuming only the loop invariants at the beginning of the body. So unless you add the fact to the loop invariant, it will be "forgotten" by Dafny.
In your simplified example, adding
invariant i > 0 ==> r[i-1] == a[i-1]
to the loop causes the program to verify.
You can read more about loop invariants in the second half of this answer. Note that that discussion is phrased in terms of establishing that loop invariants are preserved, but the reasoning is mostly identical to trying to establish that an assertion inside the loop body is valid. Please feel free to ask further questions!
I have a dafny defined graph ADT (from this SO question) brought here again for completeness:
class Graph
{
var adjList : seq<seq<int>>;
constructor (adjListInput : seq<seq<int>>)
ensures adjList == adjListInput
{
adjList := adjListInput;
}
}
function ValidGraph(G : Graph) : bool
reads G
{
(forall u :: 0 <= u < |G.adjList| ==> forall v :: 0 <= v < |G.adjList[u]| ==> 0 <= G.adjList[u][v] < |G.adjList|) &&
(forall u :: 0 <= u < |G.adjList| ==> forall v,w :: 0 <= v < w < |G.adjList[u]| ==> G.adjList[u][v] != G.adjList[u][w])
}
method main()
{
var G : Graph := new Graph([[1,2],[0,2],[0,1]]);
var nonRelatedArray := new int[8];
var i := 0; while (i < 14)
{
// nonRelatedArray[3] := 55;
i := i + 1;
}
assert (ValidGraph(G));
}
If I remove the write comment to nonRelatedArray at index 3, I get an assertion violation, which is a bit weird because it seems reasonable that the memory model would be able to determine that nonRelatedArray is (well) non related to G.
You can fix this by adding modifies nonRelatedArray to the loop. The key to this modifies clause is that it does not mention G. So then Dafny knows that G will not be modified by the loop, so it will still be a valid graph.
It is a little confusing what happens if you leave off a modifies clause from a loop. If you don't do any writes to the heap (like when you comment out the write above), then Dafny (actually, Boogie) is able to automatically see that nothing is changed at all. But if you do any writes into the heap, Dafny's default modifies clause all of a sudden becomes "anything the surrounding scope is allowed to modify". If you want something other than these two defaults, you need to ask for it explicitly by giving a modifies clause.
datatype CACHE_STATE = I| S| E
datatype MSG_CMD = Empty| ReqS| ReqE| Inv| InvAck| GntS| GntE
type NODE=nat
type DATA=nat
type boolean=bool
class class_0 {
var
Data : DATA,
Cmd : MSG_CMD
}
class class_1 {
var
Data : DATA,
State : CACHE_STATE
}
method n_RecvGntSinv__1_2(
Chan2 : array<class_0 > ,
Cache : array<class_1 > ,i:nat, N1:nat ,p__Inv0:nat,p__Inv2:nat)
modifies Chan2[i]
modifies Cache[i]
requires 0<= i<N1
requires Cache.Length ==N1
requires N1>0
requires Chan2.Length ==N1
requires p__Inv0!=p__Inv2&&p__Inv2<N1&& p__Inv0<N1
requires Chan2[i] != null
requires Cache[i] !=null
requires i!=p__Inv0&&i!=p__Inv2
requires (!((Cache[p__Inv2].State == E) && (!(Cache[p__Inv0].State == I))))
requires (Chan2[i].Cmd == GntS)
ensures Cache==old(Cache)
ensures Chan2==old(Chan2)
ensures (!((Cache[p__Inv2].State == E) && (!(Cache[p__Inv0].State == I))))
{
Cache[i].State := S;
Cache[i].Data := Chan2[i].Data;
Chan2[i].Cmd := Empty;
}
I have placed the requirement i is different from p__Inv2 and p_Inv0, thus the assignments should not disturb the evaluation of the invariant.
It is obvious that the invariant (!((Cache[p__Inv2].State == E) && (!(Cache[p__Inv0].State == I)))) should hold if it holds before execution.
Dafny shows my assertions fail and gives a counterexample I cann't understand.
Your precondition allows the possibility that Cache[i] references the same object as Cache[p__Inv0] or Cache[p__Inv2]. If that's what you intended, then the method body is indeed incorrect, as reported by the verifier. If that's not what you intended, then a precondition like
requires forall j,k :: 0 <= j < k < Cache.Length ==> Cache[j] != Cache[k]
will make your method verify.
In the following method, Dafny reports that the postcondition might not hold, even though I am quite sure that it does.
method toArrayConvert(s:seq<int>) returns (a:array<int>)
requires |s| > 0
ensures |s| == a.Length
ensures forall i :: 0 <= i < a.Length ==> s[i] == a[i] // This is the postcondition that might not hold.
{
a := new int[|s|];
var i:int := 0;
while i < |s|
decreases |s| - i
invariant 0 <= i <= |s|
{
a[i] := s[i];
i := i + 1;
}
return a; // A postcondition might not hold on this return path.
}
Indeed, the postcondition does always hold, but Dafny cannot tell!
That's because you're missing a loop invariant annotation such as
invariant forall j :: 0 <= j < i ==> s[j] == a[j]
After adding that line to the loop, the method verifies.
For more explanation about why Dafny sometimes reports errors on correct programs, see the (brand new) FAQ. For more about loop invariants, see the corresponding section in the rise4fun guide.
I'm currently learning Dafny. I'm totally comfused by lemma and I dont know how to use it. The tutorial is not that helpful. What if I want to prove
count(a) <= |a|
how should I do it. Thanks for helping.
function count(a: seq<bool>): nat
ensures count(a) <= |a|;
{
if |a| == 0 then 0 else
(if a[0] then 1 else 0) + count(a[1..])
}
You've already proved it! You wrote the property you wanted as a postcondition of the function and Dafny verifies it without complaints. That's it.
You can also use a lemma to prove the property. Here's an example:
function count(a: seq<bool>): nat
{
if |a| == 0 then 0 else
(if a[0] then 1 else 0) + count(a[1..])
}
lemma CountProperty(a: seq<bool>)
ensures count(a) <= |a|
{
}
Again, Dafny verifies the lemma without issuing any complaints, so you have proved it!
It is not correct to assume that Dafny will always prove things for you automatically. Therefore, it's a good idea to learn how to write proofs manually, too. Here's a manual proof of this property. Just to make sure Dafny doesn't try to do induction automatically, I used a directive to turn it off (thus making our lives harder than Dafny normally would):
lemma {:induction false} CountProperty(a: seq<bool>)
ensures count(a) <= |a|
{
// Let's consider two cases, just like the definition of "count"
// considers two cases.
if |a| == 0 {
// In this case, we have:
assert count(a) == 0 && |a| == 0;
// so the postcondition follows easily.
} else {
// By the definition of "count", we have:
assert count(a) == (if a[0] then 1 else 0) + count(a[1..]);
// We know an upper bound on the first term of the addition:
assert (if a[0] then 1 else 0) <= 1;
// We can also obtain an upper bound on the second term by
// calling the lemma recursively. We do that here:
CountProperty(a[1..]);
// The call we just did gives us the following property:
assert count(a[1..]) <= |a[1..]|;
// Putting these two upper bounds together, we have:
assert count(a) <= 1 + |a[1..]|;
// We're almost done. We just need to relate |a[1..]| to |a|.
// This is easy:
assert |a[1..]| == |a| - 1;
// By the last two assertions, we now have:
assert count(a) <= 1 + |a| - 1;
// which is the postcondition we have to prove.
}
}
A nicer way to write a proof like this is to use a verified calculation, which Dafny calls "the calc statement":
lemma {:induction false} CountProperty(a: seq<bool>)
ensures count(a) <= |a|
{
if |a| == 0 {
// trivial
} else {
calc {
count(a);
== // def. count
(if a[0] then 1 else 0) + count(a[1..]);
<= // left term is bounded by 1
1 + count(a[1..]);
<= { CountProperty(a[1..]); } // induction hypothesis gives a bound for the right term
1 + |a[1..]|;
== { assert |a[1..]| == |a| - 1; }
|a|;
}
}
}
I hope that this gets you started.
Program safely,
Rustan