I'm trying to prove this program in dafny but I still get an error with the last invariant and I can't see why it's not working.
The program consists on a method which inserts an int into a sorted array. The int will be inserted in the correct position ie: inserting 5 into 1,2,3,4,5,6,7 will return: 1,2,3,4,5,5,6,7
function sorted (a: array<int>): bool
requires a != null ;
reads a;
{
forall i :: 0 <= i < (a.Length - 1) ==> a[i] <= a[ i+1]
}
method InsertSorted(a: array<int>, key: int ) returns (b: array<int>)
requires a != null && sorted(a);
ensures b != null ;
ensures sorted(b);
{
var i:= 0;
b:= new int[a.Length + 1];
if(a.Length > 0){
while (i < a.Length)
invariant 0<= i;
invariant i <= a.Length;
invariant b.Length == a.Length + 1;
invariant sorted(a);
invariant forall j :: 0 <= j < i ==> b[j] <= b[j+1];
{
if(a[i]<=key)
{
b[i]:= a[i];
b [i+1] := key;
assert b[i] <= b[i+1];
}
else if (key > a[i])
{
if(i==0)
{
b[i] := key;
}
b [i+1] := a[i];
assert key > a[i];
assert b[i]<= b[i+1];
}
else{
b[i]:= a[i];
b [i+1] := a[i];
assert sorted(a);
assert b[i] <= b[i+1];
}
assert b[i]<= b[i+1];
i := i+1;
}
}
else{
b[0] := key;
}
}
Thanks
I think that perhaps you algorithm is not correct. In any case, I find the conditionals hard to understand, if the first branch is not taken then we know that !(a[i] <= key) or more simply a[i] > key which implies that the second branch guarded by key > a[i] is unreachable.
!(a[i]<=key) && a[i] < key ==> false
In any case, I suspect the loop invariant isn't strong enough to prove even a correct version since you are not keeping track of the state of b in sufficient detail.
Below is a proof of an algorithm that is similar to yours, showing a stronger loop invariant. I keep track of where in the array key is inserted using a ghost variable (a variable that is just used for verification and will not appear in the compiler output).
http://rise4fun.com/Dafny/RqGi
predicate sorted (a: seq<int>)
{
forall i,j :: 0 <= i < j < |a| ==> a[i] <= a[j]
}
predicate lessThan(a:seq<int>, key:int) {
forall i :: 0 <= i < |a| ==> a[i] < key
}
predicate greaterEqualThan(a:seq<int>, key:int) {
forall i :: 0 <= i < |a| ==> a[i] >= key
}
method InsertSorted(a: array<int>, key: int ) returns (b: array<int>)
requires a != null && sorted(a[..])
ensures b != null && sorted(b[..]);
{
b:= new int[a.Length + 1];
ghost var k := 0;
b[0] := key;
ghost var a' := a[..];
var i:= 0;
while (i < a.Length)
modifies b;
invariant 0 <= k <= i <= a.Length
invariant b.Length == a.Length + 1
invariant a[..] == a'
invariant lessThan(a[..i], key) ==> i == k;
invariant lessThan(a[..k], key)
invariant b[..k] == a[..k]
invariant b[k] == key
invariant k < i ==> b[k+1..i+1] == a[k..i]
invariant k < i ==> greaterEqualThan(b[k+1..i+1], key)
invariant 0 <= k < b.Length && b[k] == key
{
if(a[i]<key)
{
b[i]:= a[i];
b[i+1] := key;
k := i+1;
}
else if (a[i] >= key)
{
b[i+1] := a[i];
}
i := i+1;
}
assert b[..] == a[..k] + [key] + a[k..];
}
Related
So I've tried implementing a program for a simplified Dutch flag problem in Dafny where all indices 0 <= n < k are red and all indices k <= n < arr.Length are blue, except it keeps saying that k might go out of bounds even though it should be at most arr.Length based on how I coded it. What am I doing wrong here?
method dutch(arr: array?<char>) returns (k: int)
requires arr != null && forall x :: 0 <= x < arr.Length ==> arr[x] == 'r' || arr[x] == 'b'
ensures k <= arr.Length //postcondition might not hold
ensures forall n :: 0 <= n < k ==> arr[n] == 'r' //out of range
ensures forall n :: k <= n < arr.Length ==> arr[n] == 'b' //out of range
modifies arr
{
var x := 0;
k := 0;
while(x < arr.Length)
invariant k <= x
invariant forall n :: 0 <= n < k ==> arr[n] == 'r' //out of range
invariant forall n :: k <= n < x ==> arr[n] == 'b' //invariant might not be maintained by loop
{
if(arr[x] == 'r')
{
arr[x] := arr[k];
arr[k] := 'r';
k := k + 1;
}
x := x + 1;
}
}
After the loop, all that is known is the invariant and the negation of the loop guard. So, arr.Length <= x holds and so does k <= x. So, according to your loop specification, x might be arr.Length + 10 and k might be arr.Length + 2.
To verify the program, you need to turn your belief that k "should be at most arr.Length based on how I coded it" into a loop specification. So, add
invariant k <= arr.Length
I'm trying to prove the correctness of a method that determines whether
a sequence of size n is a permutation of 0,1,...,n-1. I managed to prove that whenever the method returns true then the sequence is indeed a valid permutation. Still, proving the converse is much harder (for me). I think I have the right loop invariants and triggers, but Dafny fires an assert error I can not understand. Here is the permalink, and here is the code for completeness:
method perm_imperative(s: seq<int>) returns (status : bool)
requires |s| > 0
ensures (status == true ) ==> (forall i :: 0 <= i < |s| ==> 0 <= s[i] < |s|)
ensures (status == true ) ==> (forall i, j :: 0 <= i < j < |s| ==> (s[i] != s[j]))
ensures (status == false) ==> (exists i, j :: 0 <= i <= j < |s| && (
(s[i] < 0 ) ||
(s[i] >= |s| ) ||
(s[i] == s[j] && (i != j))))
{
var i := 0;
var used := new int[|s|];
while (i < |s|)
invariant 0 <= i <= |s|
invariant forall k :: 0 <= k < i ==> used[k] == -1;
{
used[i] := -1;
i := i + 1;
}
assert (forall k :: 0 <= k < |s| ==> used[k] == -1);
i := 0;
while (i < |s|)
invariant 0 <= i <= |s|
invariant forall k :: 0 <= k < i ==> 0 <= s[k] < |s|
invariant forall k :: 0 <= k < i ==> 0 <= used[s[k]] < i
invariant forall k, m :: 0 <= k < m < i ==> s[k] != s[m]
invariant forall k :: 0 <= k < i ==> used[s[k]] == k
invariant forall k :: 0 <= k < i ==> s[used[s[k]]] == s[k]
invariant forall k, m :: 0 <= k < m < i ==> used[s[k]] != used[s[m]]
invariant forall k :: 0 <= k < |s| ==> (0 <= used[k] < i) || (used[k] == -1)
{
if (s[i] < 0)
{
// assert (s[i] < 0);
return false;
}
else if (s[i] >= |s|)
{
// assert (s[i] >= |s|);
return false;
}
else if (used[s[i]] != -1)
{
assert (0 <= s[i] < |s|);
assert (0 <= used[s[i]] < i );
//////////////////
// //
// ASSERT ERROR //
// | //
// V //
//////////////////
assert (s[used[s[i]]] == s[i]);
return false;
}
assert (used[s[i]] == -1);
used[s[i]] := i;
i := i + 1;
}
return true;
}
The proof goes through if you add the following loop invariant:
invariant forall n | 0 <= n < |s| :: used[n] != -1 ==> exists k | 0 <= k < i :: s[k] == n
This basically states that used correctly records all of the numbers seen in s in previous iterations.
If you add this loop invariant, you can get rid of the previous four loop invariants, as well as all the assertions in the body of the while loop:
method perm_imperative(s: seq<int>) returns (status : bool)
requires |s| > 0
ensures (status == true ) ==> (forall i :: 0 <= i < |s| ==> 0 <= s[i] < |s|)
ensures (status == true ) ==> (forall i, j :: 0 <= i < j < |s| ==> (s[i] != s[j]))
ensures (status == false) ==> (exists i, j :: 0 <= i <= j < |s| && (
(s[i] < 0 ) ||
(s[i] >= |s| ) ||
(s[i] == s[j] && (i != j))))
{
var i := 0;
var used := new int[|s|];
while (i < |s|)
invariant 0 <= i <= |s|
invariant forall k :: 0 <= k < i ==> used[k] == -1;
{
used[i] := -1;
i := i + 1;
}
assert (forall k :: 0 <= k < |s| ==> used[k] == -1);
i := 0;
while (i < |s|)
invariant 0 <= i <= |s|
invariant forall k :: 0 <= k < i ==> 0 <= s[k] < |s|
invariant forall k :: 0 <= k < i ==> 0 <= used[s[k]] < i
invariant forall k, m :: 0 <= k < m < i ==> s[k] != s[m]
// invariant forall k :: 0 <= k < i ==> used[s[k]] == k
// invariant forall k :: 0 <= k < i ==> s[used[s[k]]] == s[k]
// invariant forall k, m :: 0 <= k < m < i ==> used[s[k]] != used[s[m]]
// invariant forall k :: 0 <= k < |s| ==> (0 <= used[k] < i) || (used[k] == -1)
invariant forall n | 0 <= n < |s| :: used[n] != -1 ==> exists k | 0 <= k < i :: s[k] == n
{
if (s[i] < 0)
{
// assert (s[i] < 0);
return false;
}
else if (s[i] >= |s|)
{
// assert (s[i] >= |s|);
return false;
}
else if (used[s[i]] != -1)
{
// assert (0 <= s[i] < |s|);
// assert (0 <= used[s[i]] < i );
// assert (s[used[s[i]]] == s[i]);
return false;
}
// assert (used[s[i]] == -1);
used[s[i]] := i;
i := i + 1;
}
return true;
}
I have the following method for performing selection sort in descending order. However, the very first invariant in the while loop is said to be not maintained by the loop, why is that the case?
method sortDesc (a : array<int>)
modifies a;
requires a != null;
ensures forall m,n :: 0 <= m < n < a.Length ==> a[m] >= a[n];
requires a.Length > 1;
ensures multiset(a[..]) == multiset(old(a[..]));
{
var index := a.Length - 1;
while(index > -1)
invariant forall m,n :: 0 <= m <= index && index < n < a.Length ==> a[m] >= a[n]; // all elements that we have not sorted are bigger than any element we have sorted !!!!!!!!!!!!
invariant a.Length > index > -1;
invariant forall k,l :: index < k < l < a.Length ==> a[k] >= a[l]; //the part we have gone through is already sorted!!
invariant multiset(a[..]) == multiset(old(a[..])); // USED TO MAKE SURE ALL THE STARTING ELEMENTS ARE STILL THERE!!!!!
decreases index;
{
var minIndex := findMinBetween(a, index, a.Length);
if (a[index] < a[minIndex])
{
a[index], a[minIndex] := a[minIndex],a[index]; //SWAP ELEMENTS!!!
}
if (index == 0)
{
return;
}
index := index - 1;
}
}
Perhaps the comparison a[index] < a[minIndex] is the wrong way around. You are trying to move the small stuff to the right, so if a[minindex] is smaller than a[index] you need to move it (a[minindex]) to the right.
this proof gives an infinite loop in Dafnys' verifier:
// Status: verifier infinite loop
// rotates a region of the array by one place forward
method displace(arr: array<int>, start: nat, len: nat) returns (r: array<int>)
requires arr != null
requires start + len <= arr.Length
// returned array is the same size as input arr
ensures r != null && r.Length == arr.Length
// elements before the start of the region are unchanged
ensures arr[..start] == r[..start]
// elements after the end of the rhe region are unchanged
ensures arr[(start + len)..] == r[(start + len)..]
// elements in the region are skewed by one in a positive direction and wrap
// around
ensures forall k :: 0 <= k < len
==> r[start + ((k + 1) % len)] == arr[start + k]
{
var i: nat := 0;
r := new int[arr.Length];
// just make a copy of the array
while i < arr.Length
invariant i <= arr.Length
invariant forall k: nat :: k < i ==> r[k] == arr[k]
{
r[i] := arr[i];
i := i + 1;
}
i := 0;
// rotate the region
while i < len
invariant 0 <= i <= len
invariant arr[..start] == r[..start]
invariant arr[(start + len)..] == r[(start + len)..]
invariant forall k :: 0 <= k < i
==> r[start + ((k + 1) % len)] == arr[start + k]
{
r[start + ((i + 1) % len)] := arr[start + i];
i := i + 1;
}
}
which points to some sort of undecidability issue or is it? Is there a better way to present this problem to avoid the infinite loop?
previous version:
method displace(arr: array<int>, start: nat, len: nat) returns (r: array<int>)
requires arr != null
requires start + len <= arr.Length
// returned array is the same size as input arr
ensures r != null && r.Length == arr.Length
// elements before the start of the region are unchanged
ensures arr[..start] == r[..start]
// elements after the end of the rhe region are unchanged
ensures arr[(start + len)..] == r[(start + len)..]
// elements in the region are skewed by one in a positive direction and wrap around
ensures forall k :: start <= k < (start + len)
==> r[start + (((k + 1) - start) % len)] == arr[k]
{
var i: nat := 0;
r := new int[arr.Length];
while i < arr.Length
invariant i <= arr.Length
invariant forall k: nat :: k < i ==> r[k] == arr[k]
{
r[i] := arr[i];
i := i + 1;
}
i := start;
while i < (start + len)
invariant start <= i <= (start + len)
invariant arr[..start] == r[..start]
invariant arr[(start + len)..] == r[(start + len)..]
invariant forall k :: start <= k < i
==> r[start + (((k + 1) - start) % len)] == arr[k]
{
r[start + (((i + 1) - start) % len)] := arr[i];
i := i + 1;
}
}
Non-linear arithmetic is not decidable. So I suspect that using the % operator to define rotation is the root cause of your problem. Below is a version, that does verify, that defines rotation using only linear integer arithmetic.
See also How does Z3 handle non-linear integer arithmetic?
predicate rotated(o:seq<int>, r:seq<int>)
requires |o| == |r|
{
(forall i :: 1 <= i < |o| ==> r[i] == o[i-1]) &&
(|o| > 0 ==> r[0] == o[|o|-1])
}
// Status: verifier infinite loop
// rotates a region of the array by one place forward
method displace(arr: array<int>, start: nat, len: nat) returns (r: array<int>)
requires arr != null
requires start + len <= arr.Length
ensures r != null && r.Length == arr.Length
ensures arr[..start] == r[..start]
ensures arr[(start + len)..] == r[(start + len)..]
ensures rotated(arr[start .. start+len], r[start .. start+len])
{
var i: nat := 0;
r := new int[arr.Length];
while i < start
invariant i <= start
invariant forall k: nat :: k < i ==> r[k] == arr[k]
{
r[i] := arr[i];
i := i + 1;
}
assert arr[..start] == r[..start];
if len > 0 {
r[start] := arr[start+len-1];
assert r[start] == arr[start+len-1];
i := start+1;
while i < start+len
invariant start < i <= start+len
invariant arr[..start] == r[..start]
invariant r[start] == arr[start+len-1]
invariant forall k: nat :: start < k < i ==> r[k] == arr[k-1]
{
r[i] := arr[i-1];
i := i + 1;
}
}
assert rotated(arr[start .. start+len], r[start .. start+len]);
i := start+len;
while i < arr.Length
invariant start+len <= i <= arr.Length
invariant arr[..start] == r[..start]
invariant rotated(arr[start .. start+len], r[start .. start+len])
invariant forall k: nat :: start+len <= k < i ==> r[k] == arr[k]
{
r[i] := arr[i];
i := i + 1;
}
}
http://rise4fun.com/Dafny/aysI
I am working on a verified implementation of gaussian elimination and I am having problems verifying this super simple method that adds the contents of the array b to the contents of the array a. Here is the code.
method addAssign(a: array<real>, b: array<real>)
requires a != null && b != null && a.Length == b.Length;
modifies a
ensures forall k:: 0 <= k < a.Length ==> a[k] == old(a[k]) + b[k];
{
var i := 0;
assert a == old(a);
while(i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k:: i <= k < a.Length ==> a[k] == old(a[k])
invariant forall k:: 0 <= k < i ==> a[k] == old(a[k]) + b[k];
{
assert a[i] == old(a[i]); // dafny verifies this
a[i] := a[i] + b[i];
assert a[i] == old(a[i]) + b[i]; // dafny says this is an assertion violation
i := i + 1;
}
}
(I deleted my first answer since it didn't work).
It seems that the problem is that Dafny detects potential aliasing problems. As an experiment, I first modified your code to get an even easier function which does verify:
method addOne(a: array<real>)
requires a != null;
modifies a;
ensures forall k:: 0 <= k < a.Length ==> a[k] == old(a[k]) + 1.0;
{
var i := 0;
assert a == old(a);
while(i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k:: i <= k < a.Length ==> a[k] == old(a[k])
invariant forall k:: 0 <= k < i ==> a[k] == old(a[k]) + 1.0;
{
assert a[i] == old(a[i]); // dafny verifies this
a[i] := a[i] + 1.0;
assert a[i] == old(a[i]) + 1.0; // dafny *doesn't* say this is an assertion violation
i := i + 1;
}
}
The only difference is that I am using a literal real (1.0) rather than a real drawn from b. Why should that make a difference?
Well suppose that you invoke your method with a call which looks like
addAssign(a,a)
then in the body of the function b and a both refer to the same array. Suppose, for example, that a[0] is 1.0. Then in the first pass through the loop you execute a[0] := a[0] + b[0].
This sets a[0] to 2.0. But -- it also sets b[0] to 2.0.
But in this situation assert a[0] == old(a[0]) + b[0] is equivalent to
assert 2.0 == 1.0 + 2.0 -- which should fail.
By the way -- the following does verify:
method addAssign(a: array<real>, b: array<real>)
requires a != null && b != null && a.Length == b.Length;
modifies a;
ensures forall k:: 0 <= k < a.Length ==> a[k] == old(a[k]) + old(b[k]);
{
var i := 0;
assert a == old(a);
while(i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k:: i <= k < a.Length ==> a[k] == old(a[k])
invariant forall k:: 0 <= k < i ==> a[k] == old(a[k]) + old(b[k]);
{
assert a[i] == old(a[i]); // dafny verifies this
a[i] := a[i] + b[i];
assert a[i] == old(a[i]) + old(b[i]); // and also this!
i := i + 1;
}
}