Is there a bound in Dafny on the number of recursive calls? - dafny

The following code verifies:
function stepMany(i : int, steps : int) : int
requires steps >= 0;
decreases steps;
{
if steps > 0 then
stepMany(i + 1, steps - 1)
else
i
}
lemma ex2()
{
ghost var ex1 := 10;
ghost var ex1Done := stepMany(ex1, 33);
assert ex1Done == 43; // assertion verifies successfully
}
However, the following code does not verify:
function stepMany(i : int, steps : int) : int
requires steps >= 0;
decreases steps;
{
if steps > 0 then
stepMany(i + 1, steps - 1)
else
i
}
lemma ex2()
{
ghost var ex1 := 10;
ghost var ex1Done := stepMany(ex1, 34); <-- only differences here
assert ex1Done == 44; <-- and here
// assertion DOES NOT verify
}
The only difference is the second parameter of stepMany. The assertion works for all arguments up to 33 and fails for all arguments exceeding 34.
Is there a maximum number of recursive calls Dafny can handle? I have tried searching the documentation and found nothing. There appears to be a command-line argument "/recursionBound", but it does not influence the results.

The limit isn't so much on levels of recursion, but on levels of unfolding. When Dafny has a recursive definition it will unfold it a bit. But not without limit.
What you want is for Dafny to realize that stepMany is just an add function. One way to do that is to write a lemma. Then you need to remind Dafny of what you told it by invoking the lemma. Like this:
// Hey Dafny, the stepMany functions adds its arguments and returns the result.
lemma stepManyAddsItsArguments(i : int, steps : int)
requires steps >= 0
ensures stepMany(i, steps) == i+steps
decreases steps
{} // Hey Dafny, would you mind proving that?
lemma ex2()
{
ghost var ex1 := 10;
ghost var ex1Done := stepMany(ex1, 34);
stepManyAddsItsArguments( ex1, 34) ; // Heh Dafny, remember what I told you about stepMany!
assert ex1Done == 44;
}

Related

How to check this sequence element is equal to that sequence element in Dafny

I have 2 sequences a:seq and b:seq, I wonder if we use the function, how we can determine that the element at this index in seq a is equal to element at this index in seq b
function test(s:seq<nat>, u:seq<nat>): nat
ensures |s|>0
ensures |u|>0
ensures |s| == |u|
{
// Code
}
method Testing()
{
var sys:seq<nat> := [4,2,9,3,1];
var usr:seq<nat> := [1,2,3,4,5];
assert test(sys, usr) == 1
// The element at the index 2 of sys and usr are equal, so it have 1 element that match in both 2 sequence
}
Because of the function I could not create a while loop, so I can not do the basic logic on that, so I wonder if there's something that fit the requirement.
After researching and working by Python to find the recursion in Python, finally I found the answer for this:
function bullspec(s:seq<nat>, u:seq<nat>): nat
requires |s| > 0
requires |u| > 0
requires |s| == |u|
{
var index:=0;
if |s| == 1 then (
if s[0]==u[0]
then 1 else 0
) else (
if s[index] != u[index]
then bullspec(s[index+1..],u[index+1..])
else 1+bullspec(s[index+1..],u[index+1..])
)
}
This is a wonderful problem to solve with Dafny.
Let me state the problem in clear:
Given two sequences of the same length, find the first index at which these sequences are equal. Otherwise return the length of the sequences.
That formulation makes it possible to not require that sequences are non-empty.
Thus, we can start with the following definition
function bullspec(s:seq<nat>, u:seq<nat>): (r: nat)
requires |s| == |u|
// Ensures r is either a sequence index or the sequence length
ensures r <= |s|
// All the elements before r are different
ensures forall i: nat | i < r :: s[i] != u[i]
// Either r is the sequence length or the elements at index r are equal
ensures r == |s| || s[r] == u[r]
{
Now, if you manage to prove this function, you will have prove that this function does what you want it to do.
To obtain the body of the function, you usually have to check whether the sequence if empty. In our case, we can return 0, which is the length of the sequence.
if |s| == 0 then 0 else
If the sequence is not empty, then we can compare the first elements. If they are equal, then we return the index 0
if s[0] == u[0] then 0 else
Otherwise, what happens if we recurse into bullspec(s[1..],u[1..])? We will obtain an index that is offset by 1 ! So we only need to add 1 to it.
1 + bullspec(s[1..],u[1..])
}
With this, you can verify that your function does exactly what you intended it to do.

Optional positional parameter in Dart

I'm studying recursion and I wrote this method to calculate the N° number of the Fibonacci series:
fibonacci(int n, Map memo) {
if (memo.containsKey(n)) return memo[n]; // Memo check
if (n <= 2) return 1; // base case
// calculation
memo[n] = fibonacci(n - 1, memo) + fibonacci((n - 2), memo);
return memo[n];
}
I think it doesn't need to be explained, my problem is just how to call this function from the main, avoiding providing an empty Map.
this is how I call the function now:
fibonacci(n, {});
But I would rather prefer to call it just like this:
fibonacci(n);
The canonical approach is to make memo optional, and use a fresh map if the memo argument is omitted. Because you want to change and update the map, you can't use a default value for the parameter, because default values must be constant, and constant maps are not mutable.
So, written very concisely:
int fibonacci(int n, [Map<int, int>? memo]) {
if (n <= 2) return 1;
return (memo ??= {})[n] ??= fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
}
The ??= operator assigns to the right-hand side if the value is null.
It's used both to initialize memo to a new map if the argument was omitted,
and to update the map if a cached value wasn't present.
I'd actually reconsider using a map. We know that the Fibonacci computation will compute a value for every prior number down to 1, so I'd just use a list instead:
int fibonacci(int n, [List<int?>? memo]) {
if (n <= 2) return 1;
return (memo ??= List<int?>.filled(n - 2))[n - 3] ??=
fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
}
That should work just like the map.
(I subtract 3 from n when doing the lookup because no value below 3 needs the list - it's handled by the prior if).
There are multiple ways to do it. This is my personal favorite, because it also limits the function that is only used for internal means and it doesn't have the need to check every recursion, as you already know there is a map provided:
int fibonacci(int n) {
return _fibonacci(n, {});
}
int _fibonacci(int n, Map<int, int> memo) {
if (n <= 2) return 1; // base case
final previouslyCalculated = memo[n]; // Memo check
if(previouslyCalculated != null) {
return previouslyCalculated;
}
// calculation
final next = _fibonacci(n - 1, memo) + _fibonacci((n - 2), memo);
memo[n] = next;
return next;
}
void main() {
print(fibonacci(4));
}
As Dart does not support overloading, if you actually need both versions to be publicly available (or want both private) you would have to pick different names.
Please note that I added proper types to your methods and cleaned them up a bit for everything that would not compile once proper types are used. Make sure you always use proper types and don't rely on dynamic to somehow works it's magic. The compiler can only help you, if you are explicit about what you want to do. Otherwise they can only nod and let you run into any mistake you may have made. Be smart, let your compiler help, it will catch a lot of errors for you at compile time that you would otherwise have to spent countless hours on debugging.
This is the solution I've found so far but looks very verbose and inelegant:
fibonacci(int n, [Map<int, int>? memo]) {
memo == null ? memo = {} : null; // null check
if (memo.containsKey(n)) return memo[n];
if (n <= 2) return 1;
memo[n] = fibonacci(n - 1, memo) + fibonacci((n - 2), memo);
return memo[n];
}
In this way I can call just:
fibonacci(n);

dafny assertion violation error, not sure what the reason is

I am very new to Dafny. It is complaining here that there is an assertion error:
method Fred () returns (result : int) {
var number : int;
result := number * number;
assert result > 0;
}
I am trying to write an assertion that expresses the following statement: the square of any integer is non-negative
The assertion passes if you change it to result >= 0. Is that what you meant? If number is 0, then result will be 0 too.

Verification involving arrays

First off, I want to thank Rustan and the whole community for the work you put on Dafny. It is an amazing language!
I am working on my Master's thesis which is about formal verification of virtual machines using Dafny.
This is how I define (a stripped version of) a virtual machine:
class VM
{
var v: array<bv8>;
var I: bv16;
var memory: array<bv8>;
predicate Valid()
reads this
{
v.Length == 16
&& memory.Length == 0x0FFF
}
constructor Init()
ensures Valid()
{
v := new bv8[16];
I := 0;
memory := new bv8[0x0FFF];
}
}
So far so good. I have a few methods that mutate the state of this machine. In particular, here's one:
method parse_opcode_registers(vm: VM, opcode: bv16)
requires vm.Valid()
modifies vm`I, vm.v
{
var i: int := 0;
var bound := ((opcode & 0x0F00) >> 8) as int;
if opcode & 0xF0FF == 0xF065
{
while i < bound && vm.I as int < vm.memory.Length
decreases bound - i
{
vm.v[i] := vm.memory[vm.I];
i := i + 1;
vm.I := vm.I + 1;
}
}
}
This passes Dafny's verification. However, the issue occurs when there exists a caller for this method. Namely, the following code will produce an error call may violate context's modifies clause:
method Main() {
var vm := new VM.Init();
parse_opcode_registers(vm, 0xF018);
}
Any hints would be appreciated.
You need to add ensures fresh(v) to the Init constructor of VM.
Basically, the problem is that Dafny is worried because parse_opcode_register claims to modify vm.v, but Dafny isn't sure where vm.v came from. Remember that Dafny analyzes the program one method at a time, so it does not look inside the constructor Init while analyzing Main. Instead, Dafny only looks at the pre/postcondition. That's why adding fresh(v) to the postcondition fixes it.
The meaning of fresh(blah) is that blah was freshly allocated during the execution of the method.
For more, see the FAQ question about modifies clauses.

Program doesn't work without an initial value

The program works fine with var dig = 0 and it doesn't work with var dig:Int I get an error: Variable "dig" used before being initialized Could you explain me why?
func myFunc(a:Int, b:Int) {
var c = a / b
var o = a % b
var v = 0
var dig = 0
if o != 0 {println("\(a)/\(b) = \(c) и \(o)/\(b)")}
else {println("\(a)/\(b) = \(c)")}
if a > b {
v = b
}
else {
v = a
}
for var i = 1; i <= v; ++i {
if a % i == 0 && b % i == 0 {dig = i}
}
println("\(dig) -  greatest common denominator of \(a) and \(b)")
}
myFunc(27,81)
The only place you set the value of dig is inside of an if statement that is inside of a for loop. The Swift compiler does not know if the body of the for loop will be executed, and it doesn't know if the if statement will ever be true, so it has to assume that there is a path in which dig is not initialized.
Consider this simpler example:
func myFunc(a:Int, b:Int) {
var dig: Int
if a >= b {
dig = 3
}
if a < b {
dig = 4
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
This example also gives the same error, because Swift considers each if separately. It is obvious to us that a is either greater than or equal to b or it is less than b, but Swift doesn't go that far in evaluating the situation. It just considers that each if may not be true, and dig is only set inside of ifs, so it is possible (as far as Swift is concerned) that dig may not be set.
func myFunc(a:Int, b:Int) {
var dig: Int
if a >= b {
dig = 3
} else {
dig = 4
}
println("\(dig) - greatest common denominator of \(a) and \(b)")
}
If you change the second condition to an else, Swift is then happy because it can reason that the if must be true or false and dig is set in each path, so it will certainly have a value before the println statement.
The compiler does not know mathematics good enough to
recognize that the statement
if a % i == 0 && b % i == 0 {dig = i}
is actually executed at least once (for i == 1). Therefore
the compiler assumes that dig might be undefined at
println("\(dig) - greatest common denominator of \(a) and \(b)")
Assigning an initial value in
var dig = 0
is the correct solution.
Btw., the Euclidean Algorithm is a much more effective method to
compute the greatest common divisor, see for example
http://rosettacode.org/wiki/Greatest_common_divisor#Swift.

Resources