how do I write a dafny function that checks if an array is sorted? - dafny

I want to write a dafny function, the same as the predicate below, so that I can call it from another function (in the code). However, I am not sure how I would go about doing this.
predicate sorted(s: seq<char>)
{
forall i,j :: 0 <= i < j < |s| ==> s[i] <= s[j]
}
EDIT: So I tried the below, and got the error: stdin.dfy(8,8): Error: Assignment to non-ghost variable is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)
in reference to the line b := a
method sortString(a: string) returns (b: string)
{
if (sorted(a)){
b := a;
}
}
function sorted(s: seq<char>):bool
{
if forall i,j :: 0 <= i < j < |s| ==> s[i] <= s[j] then true else false
}

If you want to be able to call sorted from a method, just mark it as a predicate method, like this
predicate method sorted(s: seq<char>)
{
forall i,j :: 0 <= i < j < |s| ==> s[i] <= s[j]
}
Then you can call it from a method like this
method sortString(a: string) returns (b: string)
{
if (sorted(a)){
b := a;
}
}
Also, in general, a predicate is just a function that returns bool. There is no difference between the two.

Related

dafny assertion violation when using the result of a method

I have written the program below to verify that an array is 'clean' of any particular element or not. I am having trouble asserting the result of the method. I keep getting an assertion violation when trying to assert the result of the method.
method Main (){
var a:= new int[3];
a[0], a[1], a[2] := 1,2,3;
var v := isClean (a, 1);
assert v == false;
}
method isClean (a : array <int>, key : int) returns (clean : bool)
requires a.Length > 0
{
var i := 0;
while (i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k :: 0 <= k < i ==> a[k] != key
{
if (a[i] == key) {
clean := false;
return;
}
i := i + 1;
}
clean := true;
}
Dafny 2.3.0.10506
stdin.dfy(8,11): Error: assertion violation
Dafny program verifier finished with 2 verified, 1 error
You need to give an ensures clause on isClean. When Dafny verifies a program, it only looks at one method at a time. So when Dafny verifies Main, it does not look at the definition of isClean at all. Instead, it only looks at the requires and ensures clauses.
You already have the hard part of the proof done in the loop invariant. Basically you just need to modify a copy of that invariant so that it makes sense in the context of the caller, as an ensures clause, like this:
ensures clean <==> (forall k :: 0 <= k < a.Length ==> a[k] != key)
(Add that right below the requires clause on isClean.) In this ensures clause, clean refers to the named return value of the isClean method. If you add this clause, Dafny will still complain, because you are asking it to prove that a forall quantifier is false. That is equivalent to trying to prove an exists quantifier true, and requires an explicit "witness", which is a value of k that makes the body of the formula turn out true/false.
In this case, the intuitive reason why isClean returns false is because a[0] has the value 1, so a is not "clean" of 1. We can demonstrate this "witness" to Dafny by adding the assertion
assert a[0] == 1;
to the body of Main, right after the call to isClean.
For clarity, here is a complete version of the program that verifies:
method Main() {
var a := new int[3];
a[0], a[1], a[2] := 1,2,3;
var v := isClean (a, 1);
assert a[0] == 1;
assert v == false;
}
method isClean(a: array <int>, key: int) returns (clean: bool)
requires a.Length > 0
ensures clean <==> (forall k :: 0 <= k < a.Length ==> a[k] != key)
{
var i := 0;
while (i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k :: 0 <= k < i ==> a[k] != key
{
if (a[i] == key) {
clean := false;
return;
}
i := i + 1;
}
clean := true;
}

dafny pre-condition failure

I'm trying to run a dafny verified version of BFS (from here)
My input graph is perfectly fine, but for some reason it fails the pre-condition check.
Here is the permalink
And for self completeness here is the graph definition + validity conditions
class Graph
{
var adjList : seq<seq<int>>;
constructor (adjListInput : seq<seq<int>>)
{
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]]);
assert (ValidGraph(G));
}
dafny's response is Error: assertion violation
You just need to add ensures adjList == adjListInput to the constructor. Because Dafny treats a constructor basically just like a method, and because Dafny analyzes each method in isolation, when Dafny analyzes main, it only uses the specification of the constructor, not the body of the constructor. So the reason the assert was failing was because from the perspective of main, the constructor was setting the field adjList to an arbitrary value that did not necessarily correspond to its argument.

Dafny copy multiset data into array

I am new to Dafny. I am writing a programme to FindMax. By going through this tutorial, I am able to write the verified programme for arrays.
method FindMax(a: array<int>) returns (i: int)
requires 0<a.Length
ensures 0<= i < a.Length
ensures forall k :: 0 <= k < a.Length ==> a[k] <= a[i]
// Annotate this method with pre- and postconditions
// that ensure it behaves as described.
{
// Fill in the body that calculates the INDEX of the maximum.
i:=0;
var index := 0;
while index < a.Length
invariant 0 <= index <= a.Length
invariant 0 <= i < a.Length
invariant forall k :: 0 <= k < index ==> a[k] <= a[i]
{
if a[index] > a[i] {
i := index;
}
index := index + 1;
}
}
Now I want to write a similar programme when data is in the form of Multiset. As .length function is not allowed in multiset, it's giving error.
Another approach I thought is to convert multiset data into arrays -> apply operation and convert back.
Now I am stuck into writing function to convert multiset data into arrays.
I read this tutorial but still facing difficulties due to limited documentation and being new to Dafny.
Any help or resource link will be highly appreciated.
For all those who might visit this answer later - all you need to do is use |a| at the place of a.length and the same method would correctly work for multiset

Modifying an array in Dafny with postconditions

Trying to implement a fairly simple method, where you pass an empty array and place values into it (natural numbers).
The code runs fine, but a simple postcondition that ought to pass in my mind is throwing me errors.
method Main() {
var a := new int[5];
initialise(a);
}
method initialise(a: array<int>)
modifies a
requires a.Length > 0
ensures forall i :: 0 <= i < a.Length ==> a[i] == i
{
var i := 0;
while i < a.Length
invariant 0 <= i <= a.Length
decreases a.Length - i
{
a[i] := i;
i := i + 1;
}
}
Error:
A postcondition might not hold on this return path. Related location 1: Line: 10, Col: 8
You need to tell Dafny about the invariant maintained by the loop.
Once you add
invariant forall j :: 0 <= j < i ==> a[j] == j
the proof goes through.

Dafny program can't prove this binary search implementation?

We are trying to write a binary search algorithm using Dafny and it seems that Dafny doesn't prove the correctness of the program.
can someone please assist?
These are the errors we are getting:
On INV: This loop invariant might not be maintained by the loop.Dafny VSCode
On Guard1: decreases expression might not decreaseDafny VSCode
predicate Sorted(q: seq<int>)
{
forall i,j :: 0 <= i <= j < |q| ==> q[i] <= q[j]
}
method BinarySearch(q: seq<int>, key: int) returns (j: nat)
requires Sorted(q) && key in q
ensures j < |q| && q[j] == key
{
var i: nat, k: nat;
i,j,k := Init(q,key);
while Guard1(q,key,j)
invariant Inv(q,key,i,j,k)
decreases V(i,k)
{
if Guard2(q,key,j)
{
i := UpdateI(q,key,i,j,k);
}
else
{
k := UpdateK(q,key,i,j,k);
}
j := (i+k)/2;
}
}
predicate Inv(q: seq<int>, key: int, i: nat, j: nat, k: nat)
{
i <= j <= k < |q| &&
key in q[i..k+1]
}
predicate method Guard1(q: seq<int>, key: int, j: nat)
requires Sorted(q) && key in q
{
0 <= j < |q| && q[j] != key
}
method Init(q: seq<int>, key: int) returns (i: nat, j: nat, k: nat)
requires Sorted(q) && key in q
ensures 0 <= i <= j <= k < |q| && key in q[i..k+1]
{
i, k := 0, |q|-1;
j := (k+i) / 2;
}
function V(i: nat, k: nat): int
{
if (k > i) then k-i
else 0
}
predicate method Guard2(q: seq<int>, key: int, j: nat)
{
0 <= j < |q| && q[j] < key
}
method UpdateI(q: seq<int>, key: int, i0: nat, j: nat, k: nat) returns (i: nat)
requires Guard2(q,key,j) && Inv(q,key,i0,j,k)
ensures i0 <= i
{
if(j < |q|-1 ){
i:= j + 1;
}
else {
i:= j;
}
}
method UpdateK(q: seq<int>, key: int, i: nat, j: nat, k0: nat) returns (k: nat)
requires (!Guard2(q,key,j)) && Inv(q,key,i,j,k0)
ensures k <= k0
{
if(j > 0){
k:= j - 1;
}
else {
k:= j;
}
}
The Dafny verifier reasons about the calls to methods UpdateI and UpdateK only in terms of their specifications. The postcondition you have given those two methods are not strong enough to prove termination. In particular, UpdateI(..., i, ...) may return i and UpdateK(..., k, ...) may return k, in which case your loop would make no progress.
I have two more suggestions.
One is perhaps a matter of taste, but I find it simplifies expressions. Use k as the lowest index that's not used, rather than as the highest index that's used. So, initialize k to |q|, not to |q|-1. This way, each iteration of the loop looks at the k-i (not k-i+1) elements starting at index i. That is, it looks at q[i..k] (not q[i..k+1]).
The other is that your program is really hard to read, because you needlessly have separate functions and methods for so many things. Furthermore, those things have meaningless names, like Guard1 and V and UpdateI. I think you'd be better off just writing those expressions and statements directly in method BinarySearch.
A final remark. Perhaps you will find the following episode of Verification Corner helpful: https://www.youtube.com/watch?v=-_tx3lk7yn4
Rustan

Resources