Reputation: 1
The code below, also at https://rise4fun.com/Dafny/I4wM ,
function abst(bits: array<int>,low:int,high: int): int
requires 0<=low<=high<=8
requires bits.Length==8
decreases high-low
reads bits
{ if low==high
then 0
else 2*abst(bits,low+1,high) + bits[low]
}
method M() {
var byte: int;
var bits:= new int[8];
bits[0]:= 1;
bits[1]:= 1;
bits[2]:= 1;
bits[3]:= 1;
bits[4]:= 1;
bits[5]:= 1;
bits[6]:= 1;
bits[7]:= 1;
// assert abst(bits,2,2) == 0; // Why is this needed?
assert abst(bits,0,2) == 3;
}
fails to verify the assertion on the last line. (I'm using the on-line Dafny at Rise4Fun.) If the assertion just before is uncommented, the verification succeeds.
I'd be grateful for help. Thanks!
Upvotes: 0
Views: 332
Reputation: 2087
The Dafny verifier unrolls functions only once or twice. Specifically, if the function occurs in an assertion you're trying to prove (like abst
does in your example), then the function gets unrolled twice. However, to prove your assertion, the definition of abst
needs to be unrolled 3 times. Therefore, the verifier can't prove it automatically. You'll have to help it along.
When you uncomment the first assertion, it gets used in the proof of the second assertion. Since the first assertion provides the last instantiation of abst
that you need, it helps prove the second assertion. The first assertion itself is also proved, but that's automatic, since it only requires one unrolling of abst
.
If you write out the proof in detail, it looks like:
calc {
abst(bits,0,2);
== // def. abst
2*abst(bits,1,2) + bits[0];
== // def. abst
2*(2*abst(bits,2,2) + bits[1]) + bits[0];
== // def. abst
2*(2*0 + bits[1]) + bits[0];
== // def. bits[0] and bits[1]
2*(2*0 + 1) + 1;
== // arithmetic
3;
}
In this proof, you can see the needed instantiations of the function.
Do you really need arrays in your application? Arrays are allocated on the heap and are mutable (which means you need the reads
clause and other complications). If you only need an immutable sequence, then I would recommend you change array<int>
to seq<int>
. This will make things easier (again--if you don't need the mutable qualities of arrays). Moreover, for your assertion above, it brings another benefit: All the arguments you then pass to abst
are literals. For literals, Dafny is willing to unroll functions (more or less) without limits. So, then your original assertion verifies automatically.
Rustan
Upvotes: 1