I'm trying to prove a simple program in Dafny that finds the maximum element of an integer array. Dafny succeeds in a few seconds proving the program below. When I remove the comments from the last two ensures specifications, Dafny fires error messages saying that
a postcondition might not hold on this return path
This is probably caused by the fact that index is guaranteed to be <= a.Length. However, max_index < a.Length is correct, and I'm having a hard time proving it. I tried writing a nested invariant in the if statement, but Dafny rejected that syntax. Any possible solution?
Here is my code:
method FindMax(a: array<int>) returns (max: int, max_index : int)
requires a.Length > 0
ensures forall k :: 0 <= k < a.Length ==> a[k] <= max
ensures 0 <= max_index
// ensures max_index < a.Length
// ensures a[max_index] == max
{
max := 0;
var index := 0;
max_index := 0;
while index < a.Length
invariant 0 <= index <= a.Length
invariant forall k :: 0 <= k < index ==> a[k] <= max
{
if (max < a[index])
// invariant 0 <= index < a.Length
{
max := a[index];
max_index := index;
}
index := index + 1;
}
}
It turns out my loop invariants needed more careful planning. Here is the correct version:
method FindMax(a: array<int>) returns (max: int, max_index : int)
requires a.Length > 0
ensures forall k :: 0 <= k < a.Length ==> a[k] <= max
ensures 0 <= max_index
ensures max_index < a.Length
ensures a[max_index] == max
{
var index := 0;
max_index := 0;
max := a[max_index];
while index < a.Length
invariant max_index < a.Length
invariant 0 <= index <= a.Length
invariant forall k :: 0 <= k < index ==> a[k] <= max
invariant a[max_index] == max
{
if (max < a[index])
{
max := a[index];
max_index := index;
}
index := index + 1;
}
}
And it takes Dafny a little over than 10 seconds to prove.
Related
I would like to prove in Dafny that variance(x) (i.e., covariance(x,x)) is >=0. Note that we define covariance(x,y) as: 1/N*Summation{i=1 to N}{(x_i-x_mean)*(y_i-y_mean)}, where N is the number of elements of x and y.
Let us define covariance in Dafny as in Proving a covariance inequality in Dafny, use contradiction?:
//calculates the sum of all elements of a sequence
function method sum_seq(s:seq<real>): (res:real)
ensures (forall i :: 0 <= i < |s| ==> s[i] >= 0.0) ==> res>=0.0
decreases s;
{
if s == [] then 0.0 else s[0] + sum_seq(s[1..])
}
//calculates the mean of a sequence
function method mean_fun(s:seq<real>): (res:real)
requires |s| >= 1;
decreases |s|;
ensures (forall i :: 0 <= i < |s| ==> s[i] >= 0.0) ==> res>=0.0
{
sum_seq(s) / (|s| as real)
}
//from a sequence x, it constructs a=[x[0]-x_mean, x[1]-x_mean...]
function construct_list (x:seq<real>, m:real) : (a:seq<real>)
requires |x| >= 1
ensures |x|==|a|
{
if |x| == 1 then [x[0]-m]
else [x[0]-m] + construct_list(x[1..],m)
}
//it performs the Summation of the covariance
//note that a=[x[0]-x_mean, x[1]-x_mean...] and b=[y[0]-y_mean, y[1]-y_mean...]
function {:fuel 2} product(a: seq<real>, b: seq<real>) : real
requires |a| == |b|
{
if |a| == 0 then 0.0
else a[0] * b[0] + product(a[1..], b[1..])
}
//covariance is the Summation divided by the number of elements
function cov(x: seq<real>, y: seq<real>) : (res:real)
requires |x| == |y|
requires |x| >= 1
ensures cov(x,y) == product(construct_list(x, mean_fun(x)),construct_list(y, mean_fun(y))) / (|x| as real)
//i.e., ensures cov(x,y) == product(a,b) / (|x| as real)
{
var x_mean := mean_fun(x);
var y_mean := mean_fun(y);
var a := construct_list(x, x_mean);
var b := construct_list(y, y_mean);
product(a,b) / (|a| as real)
}
Thus, to prove cov(x,y)>=0, I directly try the following:
//variance (i.e., Cov(x,x)) is always positive
lemma covarianceItself_positive(a:seq<real>)
requires |a| >= 1
requires forall i :: 0 <= i < |a| ==> a[i] >= 0.0
ensures cov(a,a) >= 0.0
{}
Which does not verify on its own. So I verify its base case and then realize that is suffices to prove that product(a,a)>=0.0, which is stated in Lemma productItself_positive(a):
lemma covarianceItself_positive(a:seq<real>)
requires |a| >= 1
requires forall i :: 0 <= i < |a| ==> a[i] >= 0.0
ensures cov(a,a) >= 0.0
{
if (|a|==1){
assert cov(a,a) >= 0.0;
}
else{
productItself_positive(a);
}
}
Where productItself_positive is the following:
lemma productItself_positive(a:seq<real>)
requires |a| >= 1
requires forall i :: 0 <= i < |a| ==> a[i] >= 0.0
ensures product(construct_list(a, mean_fun(a)),construct_list(a, mean_fun(a))) >= 0.0
{}
I am trying to make a proof for this Lemma, so I started a calculation. My problems are that (1) Dafny reports that a calculation step might not hold; and (2) Dafny is easily getting stuck while verifying, so I do not know whether I am following the a right idea. My advances so far are as follows:
lemma productItself_positive(a:seq<real>)
requires |a| >= 1
requires forall i :: 0 <= i < |a| ==> a[i] >= 0.0
ensures product(construct_list(a, mean_fun(a)),construct_list(a, mean_fun(a))) >= 0.0
{
if (|a|==1){
assert product(construct_list(a, mean_fun(a)),construct_list(a, mean_fun(a))) >= 0.0;
}
else {
calc >= {
product(construct_list(a, mean_fun(a)),construct_list(a, mean_fun(a)));
{
assert forall x:real :: forall y:real :: (x>=0.0 && y>=0.0) ==> (x*y>=0.0);
assert forall x:real :: forall y:real :: (x>=0.0 && y>=0.0) ==> (x+y>=0.0);
assert construct_list(a, mean_fun(a))[0] * construct_list(a, mean_fun(a))[0] >= 0.0;
productItself_positive(a[1..]);
//assert product(a[1..],a[1..]) >= 0.0; //Loops forever
}
//construct_list(a, mean_fun(a))[0] * construct_list(a, mean_fun(a))[0] + product(a[1..],a[1..]); //This should hold, but says that previous calculation does not hold
//{assume construct_list(a, mean_fun(a))[0] * construct_list(a, mean_fun(a))[0] + product(a[1..],a[1..]) >= 0.0;}
//construct_list(a, mean_fun(a))[0] * construct_list(a, mean_fun(a))[0] + product(a[1..],a[1..]) >= 0.0;
//Knowing that construct_list(a, mean_fun(a))[0] * construct_list(a, mean_fun(a))[0] >= 0.0 and that product(a[1..],a[1..]), their sum should be >=0.0
0.0;
}
}
}
Any help?
There is straight forward way to do this. First add postcondition in product that it is positive if both array are same, dafny able to verify it without any help
function {:fuel 2} product(a: seq<real>, b: seq<real>) : real
requires |a| == |b|
ensures a == b ==> product(a, b) >= 0.0
{
if |a| == 0 then 0.0
else a[0] * b[0] + product(a[1..], b[1..])
}
Then use the fact that covariance is product of two equal array
lemma self_cov_is_positive(a: seq<real>)
requires |a| >= 1
ensures cov(a, a) >= 0.0
{
var a_list := construct_list(a, mean_fun(a));
assert cov(a, a) == product(a_list, a_list) / (|a| as real);
}
method atoi(a:array<char>) returns(r:int)
requires a.Length>0
requires forall k :: 0<= k <a.Length ==> (a[k] as int) - ('0' as int) <= 9
ensures ??
{
var j:int := 0;
while j < a.Length
invariant ??
{
r := r*10 + (a[j] as int) - ('0' as int);
j := j + 1;
}
}
How to write "ensures" for the atoi method and "invariant" for the while loops in dafny?
I express the idea "each bit of the return value corresponds to each bit of the character array" as following:
// Ten to the NTH power
// e.g.: ten_pos_pow(2) == 10*10 == 100
function ten_pos_pow(p:int):int
requires p>=0
ensures ten_pos_pow(p) >= 1
{
if p==0 then 1 else
10*ten_pos_pow(p-1)
}
// Count from right to left, the ith digit of integer v (i starts from zero)
// e.g.: num_in_int(123,0) == 3 num_in_int(123,1) == 2 num_in_int(123,2) == 1
function num_in_int(v:int,i:int) : int
requires i>=0
{
(v % ten_pos_pow(i+1))/ten_pos_pow(i)
}
method atoi(a:array<char>) returns(r:int)
requires a.Length>0
requires forall k :: 0<= k <a.Length ==> (a[k] as int) - ('0' as int) <= 9
ensures forall k :: 0<= k < a.Length ==> ((a[k] as int) - ('0' as int)) == num_in_int(r,a.Length-k-1)
{
var i:int := 0;
r := 0;
while i < a.Length
invariant 0<= i <= a.Length
invariant forall k :: 0<= k < i ==> ((a[k] as int) - ('0' as int)) == num_in_int(r,i-k-1) // loop invariant violation
{
r := r*10 + (a[i] as int) - ('0' as int);
i := i + 1;
}
}
But the loops invariant violation. How to write a correct and provable specification?
This lemma verifies, but it raises the warning Not triggers found:
lemma multisetPreservesGreater (a:seq<int>, b:seq<int>, c:int, f:int, x:int)
requires |a|==|b| && 0 <= c <= f + 1 <= |b|
requires (forall j :: c <= j <= f ==> a[j] >= x)
requires multiset(a[c..f+1]) == multiset(b[c..f+1])
ensures (forall j :: c <= j <= f ==> b[j] >= x)
{
assert (forall j :: j in multiset(a[c..f+1]) ==> j in multiset(b[c..f+1]));
}
I do not know how to instantiate this trigger (cannot instantiate it as a function, or can I?). Any help?
Edit: Maybe I can instantiate a method f such that takes an array and inserts it in a multiset, and therefore I can trigger f(a), but that does not mention i. I will try.
Here's one way to transform the program so that there are no trigger warnings.
function SeqRangeToMultiSet(a: seq<int>, c: int, f: int): multiset<int>
requires 0 <= c <= f + 1 <= |a|
{
multiset(a[c..f+1])
}
lemma multisetPreservesGreater (a:seq<int>, b:seq<int>, c:int, f:int, x:int)
requires |a|==|b| && 0 <= c <= f + 1 <= |b|
requires (forall j :: c <= j <= f ==> a[j] >= x)
requires multiset(a[c..f+1]) == multiset(b[c..f+1])
ensures (forall j :: c <= j <= f ==> b[j] >= x)
{
assert forall j :: j in SeqRangeToMultiSet(a, c, f) ==> j in SeqRangeToMultiSet(b, c, f);
forall j | c <= j <= f
ensures b[j] >= x
{
assert b[j] in SeqRangeToMultiSet(b, c, f);
}
}
The point is that we introduce the function SeqRangeToMultiSet to stand for a subexpression that is not a valid trigger (because it contains arithmetic). Then SeqRangeToMultiSet itself can be the trigger.
The downside of this approach is that it decreases automation. You can see that we had to add a forall statement to prove the postcondition. The reason is that we need to mention the trigger, which does not appear in the post condition.
I am passing Logical Foundations course and became stuck upon the last excersize of Basics:
Having binary number write a converter to it's unary representation:
Inductive bin : Type :=
| Z
| A (n : bin)
| B (n : bin).
Fixpoint bin_to_nat (m:bin) : nat :=
(* What to do here? *)
I solved the problem with a recursive function in C. The only thing, I used "0" istead of "A" and "1" instead of "B".
#include <stdio.h>
unsigned int pow2(unsigned int power)
{
if(power != 0)
return 2 << (power - 1);
else
return 1;
}
void rec_converter(char str[], size_t i)
{
if(str[i] == 'Z')
printf("%c", 'Z');
else if(str[i] == '0')
rec_converter(str, ++i);
else if(str[i] == '1')
{
unsigned int n = pow2(i);
for (size_t j = 0; j < n; j++)
{
printf("%c", 'S');
}
rec_converter(str, ++i);
}
}
int main(void)
{
char str[] = "11Z";
rec_converter(str, 0);
printf("\n");
return 0;
}
My problem now is how to write this code in coq:
unsigned int n = pow2(i);
for (size_t j = 0; j < n; j++)
{
printf("%c", 'S');
}
rec_converter(str, ++i);
The main difference between your code and the Coq code is that the Coq code ought to return the natural number, rather than printing it. That means we'll need to keep track of everything that your solution printed and return the result all at once.
Since printing an S means that the answer is the successor of whatever else is printed, we'll need a function that can take the 2^(n)th successor of a natural number. There are various ways to do this, but I'd suggest recursion on n and noting that the 2^(n + 1)th successor of x is the 2^(n)th successor of the 2^(n)th successor of x.
That should be enough to get what you want.
unsigned int n = pow2(i);
for (size_t j = 0; j < n; j++)
{
printf("%c", 'S');
}
rec_converter(str, ++i);
can be written (in pseudo-Coq) as
pow2_succ i (rec_converter str (S i)).
However, one other thing to note: you may not be able to directly access the ith "character" of the input, but this shouldn't be a problem. When you write your function as a Fixpoint
Fixpoint rec_converter (n: bin) (i: nat): nat :=
match n with
| Z => 0
| A m => ...
| B m => ...
end.
the first "character" of m will be the second "character" of the original input. So you'll just need to access the first "character", which is exactly what a Fixpoint does.
For the question on computing powers of 2, you should look at the following file, provided in the Coq libraries (at least up to version 8.9):
https://coq.inria.fr/distrib/current/stdlib/Coq.Init.Nat.html
This file contains a host of functions around the natural numbers, they could all be used as illustrations about how to program with Coq and this datatype.
Fixpoint bin_to_nat (m:bin) : nat :=
match m with
| Z => O
| A n =>2 * (bin_to_nat n)
| B n =>2 * (bin_to_nat n) + 1
end.
see: coq art's 2004. P167-P168. ( How to understand 'positive' type in Coq)
Is the a better functional idiom alternative to the code below? ie Is there a neater way to get the value j without having to use a var?
var j = i + 1
while (j < idxs.length && idxs(j) == x) j += 1
val j = idxs.drop(i).indexWhere(_ != x) + i
Or, as suggested by #kosii in the comments, use the indexWhere overload that takes an index from where to start searching:
val j = idxs.indexWhere(_ != x, i)
Edit
Since j must equal the length of idxs in case all items following i are equal to x:
val index = idxs.indexWhere(_ != x, i)
val j = if(index < 0) idxs.length else index
// or
val j = if (idxs.drop(i).forall(_ == x)) idxs.length
else idxs.indexWhere(_ != x, i)
Maybe with streams, something like:
((i + 1) to idxs.length).toStream.takeWhile(j => idxs(j) == x).last