I saw an example program which sets every value in an array to 0:
int a[n]; int i = 0;
while(i < n) {
a[i] = 0;
i++;
}
It said that part of the loop invariant was 0<=i<n. However, after the loop is finished terminating, i will equal n. Am i correct in saying that this is then not part of the loop invariant? If so, what should it be replaced with?
The full invariant was For All j (0<= j < i --> a[i] = 0) & 0 <= i < n)
The loop invariant must hold on loop entry and be preserved by every iteration, including the last iteration.
Therefore the loop invariant should be 0 <= i <= n
To support my claim, I offer as evidence your program translated into the automatically verified language Microsoft Dafny:
method Main(a:array<int>)
requires a != null
modifies a
ensures forall j :: 0 <= j < a.Length ==> a[j] == 0
{
var i:int := 0;
while(i < a.Length)
invariant 0 <= i <= a.Length
invariant forall j :: (0 <= j < i ==> a[j] == 0)
{
a[i] := 0;
i := i+1;
}
}
You can check that this program does indeed verify by running it in the online version of Dafny.
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 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.
while(1)
{
k = j + d;
if (k >= n)
k = k - n;
if (k == i)
break;
arr[j] = arr[k];
j = k;
}
I was going through "Juggling Algorithm" for Array Rotation and saw this piece of code there. Now i am confusing about which statement of code will terminate while loop.Is while(1) here making condition true for ever ?
It will will run forever unless it hits the break statement - which will exit the loop and in this case this happens when (k == i)
See here
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..];
}
I don't understand what exactly does the continue statement inside this for loop do. How is code any different if I remove it? Which lines does it skip if it's placed at the end of for loop?
int sum = 0, i, j, stop = 0;
for( i = 1; i <= 5 && !stop; i++)
{
for( j = 1; j <= 5 ; j++)
{
if (j%4 == 0)
{
stop = 1;
continue;
}
sum += i+j;
}
}
printf("%d\n", sum);
If you run this program the sum is going to be 15, and if you comment out countinue line then it's going to be 20.
It would be more clear if you would format the code. Let's consider the inner loop
for( j = 1; j <= 5 ; j++)
{
if ( j % 4 == 0)
{
stop = 1;
continue;
}
sum += i+j;
}
Thus as you see if j % 4 == 0 then statement
sum += i+j;
is skipped.
As for the code in whole then it has no any sense.:) It is a silly code.
In fact your code is equivalent to the following
int sum = 0, j;
for( j = 1; j <= 5 ; j++ )
{
if ( j != 4 ) sum += j + 1
}
printf("%d\n", sum);
So you will get sum 2 + 3 + 4 + 6 that is equal to 15.:)
The continue statement skips the remainder of the current loop. In the case of nested loops, it skips to the next iteration of the innermost loop.
In this case, if you didn't continue, you would execute sum += i+j; in every iteration, where it appears you only want it sometimes.
That being said, this is a very awkward loop to begin with. The whole stop variable is rather ill conceived from the get-go anyway.
The continue statement is used to start the next iteration of a loop,skipping everything in the loop,after the continue. In your case,once the execution of the program reaches the continue statement,then the next iteration of your inner loop starts,skipping whatever there was after the continue. It skips sum += i+j; as it is after the continue and the sum will not be added when j is 4 as j%4 will be 0. This is why you get 20 when you comment the continue and 15 when you uncomment it.
P.S: Your outer loop will execute only once as stop will be changed inside the if in your inner loop.
continue causes the enclosing for loop to begin the next iteration. As a more basic example, take the following code:
for(int i = 0; i < 50; i++)
{
if(i % 2 == 1) // If it's odd
continue;
printf("%d\n", i);
}
In this case, the continue statement will cause the for loop to immediately begin the next iteration if i is odd, hence this code will print the even numbers between 0 and 50.
int sum = 0, i, j, stop = 0;
for( i = 1; i <= 5 && !stop; i++)
{
for( j = 1; j <= 5 ; j++)
{
if (j%4 == 0) <===== is j divisible by 4 ?
{
stop = 1; <=== set stop flag, will continue for J loop
but stop next I loop and end the routine
continue; <==== skip the rest of the J loop for this itteration
}
sum += i+j;
}
}
printf("%d\n", sum);
http://msdn.microsoft.com/en-us/library/0ceyyskb.aspx explains the continue statement