Dafny: stronger assertion passes while weaker assertion doesn't - verification

The first assertion says that all the values in missing array are 0. The other says at least 1 value in missing is 0. If the first assertion is true, the second must also be true.
If anyone wants the full code, it is given below. It is essentially a program that finds the missing number in the given array.
method FindMissing(n: int, a: array<int>) returns (m: int)
requires 2 <= n <= 2 * 100000
requires a.Length == n - 1
requires forall j, k :: 0 <= j < k < a.Length ==> a[j] != a[k]
requires forall k :: 0 <= k < a.Length ==> 1 <= a[k] <= n
ensures 1 <= m <= n
ensures forall k :: 0 <= k < a.Length ==> a[k] != m
{
var missing := new int[n];
var i := 0;
while i < missing.Length
invariant 0 <= i <= missing.Length
invariant forall k :: 0 <= k < i ==> missing[k] == 0
{
missing[i] := 0;
i := i + 1;
}
assert forall k :: 0 <= k < missing.Length ==> missing[k] == 0;
assert exists k :: 0 <= k < missing.Length && missing[k] == 0;
i := 0;
while i < a.Length
invariant 0 <= i <= a.Length
invariant forall k :: 0 <= k < i ==> missing[a[k] - 1] == 1
invariant forall k :: i <= k < a.Length ==> missing[a[k] - 1] == 0
invariant exists k :: 0 <= k < missing.Length && missing[k] == 0
{
missing[a[i] - 1] := 1;
i := i + 1;
}
assert exists k :: 0 <= k < missing.Length && missing[k] == 0;
i := 0;
while i < missing.Length {
if missing[i] == 0 {
m := i + 1;
break;
}
i := i + 1;
}
}

To prove an existential, you often have to supply a witness. To do that for the assertion, add another assertion with the witness in front of it. Like this:
assert missing[0] == 0;
assert exists k :: 0 <= k < missing.Length && missing[k] == 0;
For the existential quantifier in the loop invariant, I suggest you introduce another variable to hold the witness. If that variable is only used in the proof, you can make it a ghost. You code will look something like:
ghost var indexOfMissing := 0;
i := 0;
while i < a.Length
...
invariant 0 <= indexOfMissing < missing.Length && missing[indexOfMissing] == 0
You'll have to manually update indexOfMissing inside the loop to maintain the invariant.
Here is one other point about logic and two points about Dafny:
You started by saying the forall implies the exists. This is not true if the range of the quantifiers is empty. Luckily, in your case, do you have missing.Length != 0.
Your first loop initializes the elements of missing to 0. There are two simpler ways to do that in Dafny. One is to use an aggregate statement that performs a bunch of simultaneous assignments:
forall i | 0 <= i < missing.Length {
missing[i] := 0;
}
The other is to give new a function that says how to initialize the elements.
var missing := new int[n](i => 0);
The beauty with both of these is that they are not loops, and that means you don't need to maintain a loop index and write various loop invariants.
You can also eliminate the final loop if you use an assign-such-that statement:
m :| 0 <= m < missing.Length && missing[m] == 0;

Related

Dafny question: How to sort the Dutch Flag problem with four colors?

I'm trying to sort the Dutch Flag problem with 4 colors instead of 3, it seems that Dafny does not really verify and I could not fix it as well. This is my code:
datatype Colour = RED | WHITE | PINK | BLUE
method FlagSort(flag: array<Colour>) returns (w:int, p:int, b:int)
ensures 0 <= w <= p <= b < flag.Length
ensures forall i :: 0 <= i < w ==> flag[i] == RED
ensures forall i :: w <= i < p ==> flag[i] == WHITE
ensures forall i :: p <= i < b ==> flag[i] == PINK
ensures forall i :: b <= i < flag.Length ==> flag[i] == BLUE
ensures multiset(flag[..]) == multiset(old(flag[..]))
modifies flag
{
var next := 0;
w, p := 0, 0;
b := flag.Length;
while next <= b
invariant 0 <= w <= p <= next <= b <= flag.Length
invariant forall i :: 0 <= i < w ==> flag[i] == RED
invariant forall i :: w <= i < p ==> flag[i] == WHITE
invariant forall i :: p <= i < next ==> flag[i] == PINK
invariant forall i :: b <= i < flag.Length ==> flag[i] == BLUE
invariant multiset(flag[..]) == multiset(old(flag[..]))
{
if flag[next] == RED {
flag[next], flag[w] := flag[w], flag[next];
w := w + 1;
if p < w {
p := p + 1;
}
if next < w {
next := next + 1;
}
} else if flag[next] == WHITE {
flag[next], flag[p] := flag[p], flag[next];
p := p + 1;
next := next + 1;
} else if flag[next] == PINK {
next := next + 1;
} else if flag[next] == BLUE {
b := b - 1;
flag[next], flag[b] := flag[b], flag[next];
}
}
}
Can anyone help me with this please, thank you!
I don't know the solution to this problem (you might be solving a hard problem !), but here is some relevant advice for each of the three errors Dafny found in your code.
Error 1
When you see this:
flag[next], flag[b] := flag[b], flag[next];
^^^ index out of range
you can add an assertion before like this:
assert 0 <= b;
assert b < |flags|;
flag[next], flag[b] := flag[b], flag[next];
Magically, the index out of range will go away, and in your case, the first assertion will fail. You can then apply verification debugging techniques to move the assertion up..
Error 2
while next <= b
^^^^^ cannot prove termination, try supplying a decreases clause
the problem is that it tried to insert the decrease clause b - next, which should always be decreasing and bounded below by zero. If you make it explicit, and hover the decreases expression, it will tell you "the decreases expression is always bounded below by zero", but you get a new error:
while next <= b
^^^^^ decreases expression might not decrease
decreases b - next
What you can do is add this line at the beginning of your while loop.
ghost var b_saved,next_saved := b, next;
and at the end of your while loop, add the decreases check explicitly:
assert b - next < b_saved-next_saved;
You'll see that now the decreases clause is verified, and you have an error on an assert, on which you can apply regular verification debugging techniques.
Error 3
if flag[next] == RED {
^^^^^^^^^^ index out of range.
Similarly, you can insert the implicit assertions there:
assert 0 <= next < flag.Length;
if flag[next] == RED { // No error there
You'll see an underline on next < flag.Length. What can you do to ensure this? Perhaps change an invariant?

What will be the decreases value for multiply two integer in Dafny

Basically, my target is to learn dafny basics. But I am confused about invariant and decreases. In this code, my first while loop decreases by one so I have set decreases b but in my inner loop it is divided by 10, so when I was trying to set up b%10 as a decreases value, it always showed me an error. here I need some expert suggestions. What will be the decreases value for the second while loop in this code in this code invariant and decreases values are right?
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
decreases b
{
while (b % 10 != 0)
invariant M * N == a * b + x
decreases ?? // what will be the value here ??
{
x := x + a;
b := b - 1;
}
a := 10 * a;
b := b / 10;
}
Res := x;
}
Here is a verification debugging technique: you should first write the assertion that, if proven, would make your previous failing assertions to verify. Since you have two errors, one on the postcondition, and one on the outer decrease clause, here are two assertions you could insert.
If you want to see the solution, skip the steps and go to the end of this post.
Steps to solution
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
decreases b
{
var oldB := b;
while (b % 10 != 0)
invariant M * N == a * b + x
{
x := x + a;
b := b - 1;
}
a := 10 * a;
b := b / 10;
assert b < oldB; // Just added: If proven, the decreases condition holds
}
Res := x;
assert Res == M*N; // Just added: If proven, the postcondition would be ok
}
Now you see the two errors are on these assert. It's time to "move the asserts up" by applying weakest precondition rules. That means we keep the assert, but we write assert before their preceding statement such that, if these new assertions held, the old assertions would be verified:
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
decreases b
{
var oldB := b;
while (b % 10 != 0)
invariant M * N == a * b + x
{
x := x + a;
b := b - 1;
}
a := 10 * a;
assert b / 10 < oldB; // Just added. The next assert conditionally verify
b := b / 10;
assert b < oldB;
}
assert x == M * N; // Just added. The next assert conditionally verify.
Res := x;
assert Res == M*N;
}
See in your IDE how the error is now on the two most recent asserts.
Let's consider the second assert x == M * N;. Why is it wrong? There is an invariant that says M * N == a * b + x. So, if x == M * N;, it probably means that b should be equal to zero.
However, when we exit the while loop, we only know the negation of the guard, which is !(b > 0), or b <= 0. That's why we could not conclude!
Since we never intended b to be non-positive, we either need to add the invariant b >= 0 to the outer loop, or simply change the guard to b != 0 - but if you do that, then it will complain that with decreases b, b is not bounded by zero anymore. So the invariant is better.
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
invariant b >= 0 // Just added
decreases b
{
var oldB := b;
while (b % 10 != 0)
invariant M * N == a * b + x
{
x := x + a;
b := b - 1;
}
a := 10 * a;
assert b / 10 < oldB;
b := b / 10;
assert b < oldB;
}
assert x == M * N;
Res := x;
assert Res == M*N;
}
Now the invariant b >= 0 might not be maintained by the loop. This is because the inner while loop modifies b and does not give invariant on the value of b. Of course, we want b >= 0. So we add the invariant in the inner loop.
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
invariant b >= 0
decreases b
{
var oldB := b;
while (b % 10 != 0)
invariant M * N == a * b + x
invariant b >= 0 // Just added
{
x := x + a;
b := b - 1;
}
a := 10 * a;
assert b / 10 < oldB;
b := b / 10;
assert b < oldB;
}
assert x == M * N;
Res := x;
assert Res == M*N;
}
Ok, now the only assertion remaining is assert b / 10 < oldB;
Note that you don't need to write decreases in the inner clause because the default decreases for E > 0 is inferred to be decreases E, and in this case, Dafny can prove that b % 10 decreases.
However, knowing that b%10 == 0 at the end is not useful to prove that b itself decreased. If b was 7, it could be that the inner loop was increasing b to 10 before exiting...
The most basic strategy would be to convert the assertion b / 10 < oldB as an invariant. If you add it like that, everything verifies!
Solution
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
invariant b >= 0
decreases b
{
var oldB := b;
while (b % 10 != 0)
invariant M * N == a * b + x
invariant b >= 0
invariant b / 10 < oldB
{
x := x + a;
b := b - 1;
}
a := 10 * a;
assert b / 10 < oldB;
b := b / 10;
assert b < oldB;
}
assert x == M * N;
Res := x;
assert Res == M*N;
}
Now, you can experiment a bit about other invariant and observe that the following clauses would solve this last problem as well:
invariant b <= oldB
decreases b
Take some time to remove the asserts now because they were only used for scaffolding, but keep the invariant :-)

Is the Time Complexity of this function O(n * (n * log n² ))

What is the Time Complexity of the function below? n > 0
Function fun(n){
Let count = 0;
For( I = 0; I < n; I++){
For(j = 0; j < n; j /= 2) {
For(h = 0; h < n; h /= 2) {
Count = count + 1;
}
}
}
Return count;
}
I have O(n * (n * log n² )) , but something tells me i might be wrong.
The above loop is an infinite loop. time complexity for this cannot be determined, unless the problem statement is updated properly!
Function fun(n){
Let count = 0;
For( I = 0; I < n; I++){
// will run infinitely even if you change j /= 2 to j *= 2, because initial value is 0
For(j = 0; j < n; j /= 2) {
// will run infinitely even if you change h /= 2 to h *= 2, because initial value is 0
For(h = 0; h < n; h /= 2) {
Count = count + 1;
}
}
}
Return count;
}

Dafny: Why is this assertion failing and how to fix it

Trying to prove a simple algorithm on Dafny, but I just get an "assertion violation" on the last assertion with no extra details. Can anybody spot what is wrong and how to fix it? Formal methods is not my specialty.
method BubbleSort(a: array?<int>)
modifies a
requires a != null
ensures sorted(a, 0, a.Length -1)
{
var i := a.Length - 1;
while(i > 0)
decreases i
invariant i < 0 ==> a.Length == 0
invariant -1 <= i < a.Length
invariant sorted(a, i, a.Length -1)
invariant partitioned(a, i)
{
var j := 0;
while(j < i)
decreases i - j
invariant 0 < i < a.Length && 0 <= j <= i
invariant sorted(a, i, a.Length -1)
invariant partitioned(a, i)
invariant forall k :: 0 <= k <= j ==> a[k] <= a[j]
{
if(a[j] > a[j+1])
{
a[j], a[j+1] := a[j+1], a[j];
}
j := j + 1;
}
i := i - 1;
}
}
predicate sorted(a: array?<int>, l: int , u: int)
reads a //Sintaxe do Dafny. PRECISA disso para dizer que vai ler o array
requires a != null
{
forall i, j :: 0 <= l <= i <= j <= u < a.Length ==> a[i] <= a[j]
}
predicate partitioned(a: array?<int>, i: int)
reads a
requires a != null
{
forall k, k' :: 0 <= k <= i < k' < a.Length ==> a[k] <= a[k']
}
method testSort()
{
var b := new int[2];
b[0], b[1] := 2, 1;
assert b[0] == 2 && b[1] == 1;
BubbleSort(b);
assert b[0] == 1 && b[1] == 2;
}
The problem is that the postcondition (ensures clause) of Sort gives no information about the state of A. When Dafny does verification, it verifies each method independently, using only the specifications (not the bodies) of other methods. So when Dafny verifies testSort, it doesn't look at the definition of Sort, but only its postcondition true, which isn't enough to prove your assertions.
For more information, see the FAQ and the section on assertions in the tutorial.

Summation on 1 <= i < j < k <= n in GLPK

I have been trying to solve seriation problem by using GNU. But I couldn't write a summation like the following.
param n, integer, >= 3;
set O := 1..n;
param d{i in O,j in O};
var x{i in O,j in O}, binary, i < j;
var v{i in O,j in O,k in O}, binary, i < j < k;
maximize total: sum{i in O,j in O, i<j}(d[i,j] - d[j,i])* x[i,j] + sum{i in O,j in O, i<j}d[j,i];
s.t. tran{i in O,j in O,k in O, i<j<k}: x[i,j] + x[j,i] - x[i,k] + v[i,j,k] = 1;
Thanks
You should use : instead of , in the "such that" clause i < j:
sum{i in O,j in O: i < j} ...
# ^ note ':' here