Understanding how to use post- condition and loop-invariant correctly with Frama-c - functional-testing

I am trying to prove on this example that the return value will be either 0(if 8 is not in array) or 1(if 8 in array).
int fi8(int *array, int size) {
int fi8 = 0;
int i = 0;
for(i = 0; i < length; ++i)
{
if(array[i] == 8)
fi8 = 1;
}
return fi8;
}
And I created pre- and post conditions:
/*# requires 0 <= size <= 100;
# requires \valid(array+(0..size-1));
# assigns \nothing;
# ensures (\forall integer i; 0<= i < size && array[i] != 8) ==> (\result == 0);
# ensures (\exists integer i; (0<= i < size && array[i] == 8)) && (\result == 1);
#*/
and loop invariants, because Frama-C is based on Hoare Logic:
/*# loop invariant 0 <= i <= length;
# loop invariant fi8 == 0 || fi8 == 1;
# loop invariant (\forall integer i; 0<= i < size && array[i] != 8)
==> (fi8 == 0);
# loop invariant (\exists integer i; (0<= i < size && array[i] == 8))
&& (fi8 == 1);
# loop assigns i, fi8;
#*/
I'm pretty sure that I'm missing something on the lines, where I'm trying to use forall
and exists.
I spend hours trying to understand, how can I check correctly, if any value is assigned on array or not, but I feel like I'm stuck here.
I really appreciate your help :)

There are a few issues with your code. First, you seem to have mixed size and length. I've taken the liberty to use size everywhere, otherwise this code won't even be accepted by a C compiler, let alone by Frama-C. Second, \forall integer i; 0<= i < size && array[i] != 8 (and the corresponding loop invariant) is incorrect. Literally, it means that any integer i verifies both that i is between 0 and size and array[i] is not 8. Taking 101 for i gives a trivial counter-example to this proposition. What you want to express is that for any integer i, if i is between 0 and size, then array[i] is not 8, which is expressed as \forall integer i; 0<= i < size ==> array[i] != 8. On the other hand, the && connector is correct when used under the \exists: this time we indeed want to find an i such that i is within the bounds of the array and for which array[i]==8. However, the second && in your last ensures is not correct: what you want to say is that if there is such an i, then \result == 1, hence you must have an implication here: (\exists integer i; 0<= i < size && array[i] == 8) ==> (fi8 == 1)
The last issue is with your loop invariants. You are re-using as a quantified variable while it is already a C variable, which is often not a good idea. In fact, it is a real problem, since the property you want to express is that as long as we have not seen an 8 between 0 and i, fi8==0 (and dually that if if have seen an 8, fi8==1), i being the C variable. If you use j in your quantification, as in
loop invariant (\forall integer j; 0<= j < i ==> array[j] != 8) ==> (fi8 == 0);
loop invariant (\exists integer j; 0<= j < i && array[j] == 8) ==> (fi8 == 1);
all proof obligations are discharged.

Related

Difference between the implementation?

So recently I stumbled across a query i.e.
code 1:
for(long i = 1; i <= m; i++) {
long j = (fullsum - 2*(sum -i))/2;
if(j >= m+1 && j <=n) {
swaps++;
}
}
code 2:
for(long i = 1; i <= m; i++) {
for(long j = m+1; j <=n ; j++) {
if(sum - i + j == fullsum - sum -j + i) {
swaps++;
break;
}
}
}
Where fullsum = n*(n+1)/2, sum = m*(m+1)/2
1 <= N <= 10^9
1 <= M < N
Now my question here is that both the codes seem identical to me(logic wise) but Code 2 is giving correct output while code 1 is not.
Can anyone please tell me the difference between the codes, further why code2 is giving the correct output while code1 is not and what is the correct way of implementing code 1?
Rewriting if(sum - i + j == fullsum - sum -j + i), we get
if(2*j == fullsum - 2*(sum-i))
In the first code, the value you are assigning to j is
long j = (fullsum - 2*(sum -i))/2;
The issue is pretty clear: division truncation is causing the incorrect results. Let's say that fullsum - 2*(sum-i) = 45 for some case, and j=22. Now, the second condition will be false, since 2*j != fullsum - 2*(sum-i).
However, for the first condition, (fullsum - 2*(sum -i))/2 has a value of 45/2 = 22 (floor division), so the condition j = (fullsum - 2*(sum -i))/2 will be counted as a valid result when it shouldn't have been.

Use semantics to prove that the postcondition is true following the execution of the program assuming the precondition is true

I am trying to study for a test in my programming language concepts class.
I am trying to understand how to solve this problem. Our professor said we don't need to use formal notation to prove the problem as long as he can understand what we are saying.
I missed the lecture where he solved the problem and I'm having a very hard time finding resources to help me solve it on my own.
Would be so thankful for an explanation.
Problem
Use axiomatic semantics to prove that the postcondition is true following the execution of the program assuming the precondition is true
Precondition: n ≥ 0 and A contains n elements indexed from 0
bound = n;
while (bound > 0) {
t = 0;
for (i = 0; i < bound-1; i++) {
if (A[i] > A[i+1]) {
swap = A[i];
A[i] = A[i+1];
A[i+1] = swap;
t = i+1;
}
}
bound = t;
}
Postcondition: A[0] ≤ A[1] ≤ ...≤ A[n-1]
Lets number the lines for reference:
1. bound = n;
2. while (bound > 0) {
3. t = 0;
4. for (i = 0; i < bound-1; i++) {
5. if (A[i] > A[i+1]) {
6. swap = A[i];
7. A[i] = A[i+1];
8. A[i+1] = swap;
9. t = i+1;
10. }
11. }
12. bound = t;
13. }
Consider the following assertions:
Before entering 12
t < bound
Before entering 11
A[i] <= A[t] for all i such that 0 <= i < t
Before entering 13
A[k] <= A[j] for all indexes k and j such that bound <= k <= j <= n-1
After leaving 12
bound has decreased
Let's see now why the assertions are true
This is true because t=0 before the loop and if set inside the if it is
t = i + 1 < (bound - 1) + 1 = bound.
This is true because otherwise a swap would have happened.
This is true because of 2 and because the for doesn't change entries with indexes j from bound to n-1.
This is true because of 1.
From assertion 4 we deduce that the while loop, and so the algorithm, finishes in n steps at most, when bound = 0.
The postcondition now follows from assertion 3 for bound = 0.

Nested Loops in C programming

I was wondering how the line "if(!(i%j)) break;" in the code below would be interpreted. Since the "!" symbol is an inverter, does it mean that the bold line in the code below would interpret to saying that "if i mod j is equal to zero, invert and then break out of the loop"
Many thanks
int main ()
{
/* local variable definition */
int i, j;
for (i = 2; i < 100; i++) {
for (j = 2; j <= (i / j); j++)
if (!(i % j))
break;
if (j > (i / j)) printf("%d is prime\n", i);
}
return 0;
}
"if i mod j is equal to zero, invert and then break out of the loop"
Close: if i mod j equals zero then break.
if ( ! (i % j) ) break;
In C, 0 is false and anything else is true. So, when i % j is 0, ! (i % j) is 1, and thus true.
In C, an if (number) always evaluates to true, unless the number is 0. Therefore, that would evaluate to: if i mod j is equal to 0, basically, if i is a multiple of j.

dafny implementation of insertionsort

i am new in Dafny and i have problems verifying my insertionSort-implementation.
Dafny tells me the the multiset invariants are not holding, anything else is working fine. After Hours of searching the mistake i could need some help :)
Would be nice if somebody could tell me the trick!
My Code:
predicate sorted(a:array<int>, min:int, max:int)
requires a != null;
requires 0<= min <= max <= a.Length;
reads a;
{
forall j, k :: min <= j < k < max ==> a[j] <= a[k]
}
/*
*
*/
method insertionSort(a: array<int>)
requires a != null;
requires a.Length > 0;
ensures sorted(a, 0, a.Length);
ensures multiset(a[..]) == multiset(old(a[..]));
modifies a;
{
var i := 1;
while(i < a.Length)
invariant 1 <= i <= a.Length;
invariant sorted(a, 0, i);
invariant a != null;
invariant multiset(old(a[..])) == multiset(a[..]);
decreases a.Length-i;
{
var j := i - 1;
var key := a[i];
while(j >= 0 && key < a[j])
invariant -1 <= j <= i - 1 <= a.Length;
invariant (j == i-1 && sorted(a, 0, i)) || (sorted(a, 0, i+1));
invariant forall k :: j < k < i ==> a[k] >= key;
invariant -1 < j == i - 1 ==> multiset(old(a[..])) == multiset(a[..]);
invariant |multiset(old(a[..]))| == |multiset(a[..])|;
invariant -1 < j < i - 1 && key < a[j] ==> multiset(old(a[..])) == multiset(a[..]) - multiset({a[j+1]}) + multiset({key});
invariant -1 == j ==> multiset(old(a[..])) == multiset(a[..]) + multiset({key}) - multiset({a[j+1]});
decreases j;
{
a[j + 1] := a[j];
j := j - 1;
}
a[j + 1] := key;
i := i + 1;
}
}
It produces
1 This loop invariant might not be maintained by the loop. 29,38
2 This loop invariant might not be maintained by the loop. 42,73
3 This loop invariant might not be maintained by the loop. 43,52
Link: http://rise4fun.com/Dafny/3R5
Here is a slightly modified algorithm that does verify. It shifts the elements up by doing a swap. I think with a bit more work it could be adapted to your algorithm. It just needs a slightly more complex multiset invariant (which would require a lemma about adding and removing things from multisets).
predicate sorted(a:array<int>, min:int, max:int)
requires a != null;
requires 0<= min <= max <= a.Length;
reads a;
{
forall j, k :: min <= j < k < max ==> a[j] <= a[k]
}
predicate sortedSeq(a:seq<int>)
{
forall j, k :: 0 <= j < k < |a| ==> a[j] <= a[k]
}
lemma sortedSeqSubsequenceSorted(a:seq<int>, min:int, max:int)
requires 0<= min <= max <= |a|
requires sortedSeq(a)
ensures sortedSeq(a[min .. max])
{ }
method swap(a: array<int>, i:int, j:int)
modifies a;
requires a != null && 0 <= i < j < a.Length
requires i + 1 == j
ensures a[..i] == old(a[..i])
ensures a[j+1..] == old(a[j+1..])
ensures a[j] == old(a[i])
ensures a[i] == old(a[j])
ensures multiset(a[..]) == multiset(old(a[..]))
{
var tmp := a[i];
a[i] := a[j];
a[j] := tmp;
}
method insertionSort(a: array<int>)
modifies a;
requires a != null;
requires a.Length > 0;
ensures sorted(a, 0, a.Length);
ensures multiset(a[..]) == multiset(old(a[..]));
{
var i := 0;
while(i < a.Length)
invariant 0 <= i <= a.Length
invariant sorted(a, 0, i)
invariant multiset(old(a[..])) == multiset(a[..]);
{
var key := a[i];
var j := i - 1;
ghost var a' := a[..];
assert sortedSeq(a'[0..i]);
while(j >= 0 && key < a[j])
invariant -1 <= j <= i - 1
invariant a[0 .. j+1] == a'[0 .. j+1]
invariant sorted(a, 0, j+1);
invariant a[j+1] == key == a'[i];
invariant a[j+2 .. i+1] == a'[j+1 .. i]
invariant sorted(a, j+2, i+1);
invariant multiset(old(a[..])) == multiset(a[..])
invariant forall k :: j+1 < k <= i ==> key < a[k]
{
ghost var a'' := a[..];
swap(a, j, j+1);
assert a[0..j] == a''[0..j];
assert a[0..j] == a'[0..j];
assert a[j] == a''[j+1] == a'[i] == key;
assert a[j+2..] == a''[j+2..];
assert a[j+2..i+1] == a''[j+2..i+1] == a'[j+1..i];
j := j - 1;
sortedSeqSubsequenceSorted(a'[0..i], j+1, i);
assert sortedSeq(a'[j+1..i]);
assert a[j+2 .. i+1] == a'[j+1 .. i];
assert sortedSeq(a[j+2..i+1]);
}
i := i + 1;
}
}
http://rise4fun.com/Dafny/Gplux

Selection Sort in Dafny

I am trying to implement selection sort in Dafny.
My sorted and FindMin functions do work, but selectionsort itself contains assertions which Dafny will not prove, even if they are correct.
Here is my program:
predicate sorted(a:array<int>,i:int)
requires a != null;
requires 0 <= i <= a.Length;
reads a;
{
forall k :: 0 < k < i ==> a[k-1] < a[k]
}
method FindMin(a:array<int>,i:int) returns(m:int)
requires a != null;
requires 0 <= i < a.Length;
ensures i <= m < a.Length;
ensures forall k :: i <= k < a.Length ==> a[k] >= a[m];
{
var j := i;
m := i;
while(j < a.Length)
decreases a.Length - j;
invariant i <= j <= a.Length;
invariant i <= m < a.Length;
invariant forall k :: i <= k < j ==> a[k] >= a[m];
{
if(a[j] < a[m]){m := j;}
j := j + 1;
}
}
method selectionsort(a:array<int>) returns(s:array<int>)
requires a != null;
modifies a;
ensures s != null;
ensures sorted(s,s.Length);
{
var c,m := 0,0;
var t;
s := a;
assert s != null;
assert s.Length == a.Length;
while(c<s.Length)
decreases s.Length-c;
invariant 0 <= c <= s.Length;
invariant c-1 <= m <= s.Length;
invariant sorted(s,c);
{
m := FindMin(s,c);
assert forall k :: c <= k < s.Length ==> s[k] >= s[m];
assert forall k :: 0 <= k < c ==> s[k] <= s[m];
assert s[c] >= s[m];
t := s[c];
s[m] := t;
s[c] := s[m];
assert s[m] >= s[c];
assert forall k :: c <= k < s.Length ==> s[k] >= s[c];
c := c+1;
assert c+1 < s.Length ==> s[c-1] <= s[c];
}
}
Why is this wrong? What does "postcondtion may not hold" mean? Could Dafny give an counter-example?
You seem to understand the basic idea behind loop invariants, which is needed to verify programs using Dafny.
Your program is not correct. One way to discover this is to use the verification debugger inside the Dafny IDE in Visual Studio. Click on the last error reported (the assertion on the line before the increment of c) and you will see that the upper half of the array contains an element that is smaller than both s[c] and s[m]. Then select the program points around your 3-statement swap operation and you will notice that your swap does not actually swap.
To fix the swap, exchange the second and third statement of the 3-statement swap. Better yet, make use of Dafny's multiple assignment statement, which makes the code easier to get right:
s[c], s[m] := s[m], s[c];
There are two other problems. One is that the second assertion inside the loop does not verify:
assert forall k :: 0 <= k < c ==> s[k] <= s[m];
While s[m] is the smallest element in the upper part of the array, the loop invariant needs to document that the elements in the lower part of the array are no greater than the elements in the upper part--an essential property of the selection sort algorithm. The following loop invariant does the trick:
invariant forall k, l :: 0 <= k < c <= l < a.Length ==> s[k] <= s[l];
Finally, the complaint about the property sorted(s,c) not being maintained by the loop stems from the fact that you defined sorted as strictly increasing, which swapping will never achieve unless the array's elements are initially all distinct. Dafny thus points out a design decision that you have to make about your sorting routine. You can either decide that your selectionsort method will apply only to arrays with no duplicate elements, which you do by adding
forall k, l :: 0 <= k < l < a.Length ==> a[k] != a[l];
as a precondition to (and loop invariant in) selectionsort. Or, more conventionally, you can fix your definition of sorted to replace a[k] > a[m] with a[k] >= a[m].
To clean up your code a little, you can now delete all assert statements and the declaration of t. Since m is used only inside the loop, you can move the declaration of m to the statement that calls FindMin, which also makes it evident that the loop invariant c-1 <= m <= s.Length is not needed. The two decreases clauses can be omitted; for your program, Dafny will supply these automatically. Lastly, your selectionsort method modifies the given array in place, so there is no real reason to return the reference a in the out-parameter s; instead, you can just omit the out-parameter and replace s by a everywhere.

Resources