dafny assertion fails is hard to explain - permutation

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;
}

Related

Keep Getting "Index Out of Range"

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

give the location of matrix cell with 0 around

i need to input 6 on 6 matrix and to out put the location of the
cell that all the cells around him has the value 0.
let's say:
1 1 1 1 1 1
1 1 1 1 1 1
0 0 1 1 1 1
2 0 1 1 1 1
0 0 1 1 1 1
1 1 1 1 1 1
the out put will be row 3 col 0
this is the code i made.. how i solve this ?
i tried a lot please help me
#include<stdio.h>
#define N 6
int main()
{
int arr[N][N] = { 0 }, i = 0, j = 0, x = 0, y = 0, counter = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)//input//
{
scanf("%5d", &arr[i][j]);
}
printf("\n");
}
for (i = 0; i < N; i++)//output//
{
for (j = 0; j < N; j++)
{
printf("%5d", arr[i][j]);
}
printf("\n");
}
for (i = 0; i < N; j++)
{
for (j = 0; j < N; j++)
{
for (x = i - 1; x <= i + 1; x + 2)
{
for (y = j - 1; y <= j + 1; y + 2)
{
if (x >= 0 && x < N &&y >= 0 && y < N&&arr[x][y] == 0)
{
counter++;
}
}
}
if (i == 0 && j == 0 || i == 0 && j == N - 1 || i == N - 1 && j == 0
|| i == N - 1 && j == N - 1)
{
if (counter == 3)
{
printf("the row is %d the col is %d\n", i, j);
}
}
else if (i == 0 && j >= 1 && j < N - 1 || i == N - 1 && j >= 1 && j
< N - 1 && j == 0 && i >= 1 && i <= N - 1 && j == N - 1 && i >= 1 && i<N -1)
{
if (counter == 5)
{
printf("the row is %d the col is %d\n ", i, j);
}
}
else
{
if (counter == 8)
{
printf("the row is %d the col is %d\n ", i, j);
}
}
}
}
}
There are problems with your x and y loops:
for (x = i - 1; x <= i + 1; x + 2)
{
for (y = j - 1; y <= j + 1; y + 2)
{
You aren't incrementing x or y in these loops. The expression x + 2 merely evaluates the value x + 2. It doesn't do anything with it. If you want to actually set x to x + 2, then you need to use x = x + 2, or more concisely, x += 2.
Incrementing x and y by 2 is incorrect. It will only examine 4 points: (i-1,i-1), (i-1,i+1), (i+1,i-1), and (i+1,i+1). It will skip the following 4 points: (i-1,i), (i,i-1), (i,i+1), (i+1,i). You need to increment x and y by 1 each time, i.e. use x++ and y++ in the loop incremement instead of adding 2. The, inside the loop, add an additional test for x == i && y == i and skip that point (the center point).
I believe this is what you want (note that you can do eveything in two loops if you nest the conditionals in a smart way to avoid checking areas outside the matrix):
#include <stdio.h>
#define ROWS 5
#define COLS 5
void printBlockeds(int M[ROWS][COLS])
{
int i, j;
for(i = 0; i < ROWS; ++i)
{
for(j = 0; j < COLS; ++j)
{
int isBlocked = 1;
if(i > 0)
{
isBlocked = isBlocked && !M[i-1][j];
if(j > 0) isBlocked = isBlocked && !M[i-1][j-1];
if(j < COLS-1) isBlocked = isBlocked && !M[i-1][j+1];
}
if(j > 0) isBlocked = isBlocked && !M[i][j-1];
if(j < COLS-1) isBlocked = isBlocked && !M[i][j+1];
if(i < ROWS-1)
{
isBlocked = isBlocked && !M[i+1][j];
if(j > 0) isBlocked = isBlocked && !M[i+1][j-1];
if(j < COLS-1) isBlocked = isBlocked && !M[i+1][j+1];
}
if(isBlocked) printf("(%d, %d)\n", i, j);
}
}
}
int main()
{
int M[ROWS][COLS] = {{1, 1, 1, 0, 1},
{1, 0, 0, 0, 0},
{1, 0, 1, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 1, 0, 1}};
printBlockeds(M);
return 0;
}
Output for the case above:
(0, 4)
(2, 2)
(4, 2)

Dafny Insert int into Sorted Array method

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..];
}

Dafny: rotated region of an array method verification

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

Why does this Dafny assertion involving arrays fail?

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;
}
}

Resources