I have a function to find the minimun value of an array
method arrayMin(a: array<int>) returns (m: int)
requires a.Length > 0;
ensures forall k :: 0 <= k < a.Length ==> a[k] >= m;
{
var i: nat := 1 ;
m := a[0] ;
while (i < a.Length)
invariant 1 <= i <= a.Length && forall k :: 0 <= k < i ==> a[k] >= m;
decreases a.Length - i;
{
if (a[i] < m) { m := a[i] ; }
i := i + 1 ;
}
}
When I try to call
var a := new int[5];
a[0], a[1], a[2], a[3], a[4] := 9, 4, 6, 3, 8;
var min := arrayMin(a);
assert min == 3;
Dafny is to able to verfiy the assertion. Are the post conditions not sufficient?
You are correct that the postcondition is not sufficient. In English, the postcondition says the following:
No element in the array a is below the value m returned.
But, this does not mean m has to be a value from the original array! For example, we can safely modify this line:
if (a[i] < m) { m := a[i] ; }
To be this:
if (a[i] < m) { m := a[i] - 1; }
And this program will still meet the postcondition.
Therefore to get your assertion to pass, you will a stronger postcondition. In particular, it needs to ensure that m is one of the elements contained in a.
Attempting to verify formally the following problem. https://leetcode.com/problems/count-equal-and-divisible-pairs-in-an-array/
Given a 0-indexed integer array nums of length n and an integer k, return the number of pairs (i, j) where 0 <= i < j < n, such that nums[i] == nums[j] and (i * j) is divisible by k.
function countPairs(nums: number[], k: number): number {
let count = 0;
for(let i = 0; i < nums.length-1; i++) {
for(let j = i+1; j < nums.length; j++) {
if(nums[i] == nums[j] && (i*j) % k == 0) {
count++;
}
}
}
return count;
};
I cannot figure out how to verify this silly thing. Maybe I'm missing a super simple description of the problem and I'm too focused on irrelevant details.
My strategy started with trying to compare the result to the cardinality of a matching set. However, getting dafny to believe the cardinality of the set matches during the two loops seems impossible.
function method satPairs(nums: seq<nat>, k: nat, a: nat, b: nat): bool
requires k > 0
requires a <= b < |nums|
{
nums[a] == nums[b] && (a*b) % k == 0
}
function matchPairs(nums: seq<nat>, k: nat): nat
requires k > 0
{
|set x,y | 0 <= x < y < |nums| && nums[x] == nums[y] && (x*y) % k == 0 :: (x,y)|
}
function method pairsI(nums: seq<nat>, k: nat, i: nat): set<(nat, nat)>
requires k > 0
requires 0 <= i < |nums|
ensures forall x,y :: 0 <= x < i && x <= y < |nums| && satPairs(nums, k, x, y) ==> (x,y) in pairsI(nums, k, i)
{
set x: nat,y:nat | 0 <= x < i && x <= y < |nums| && satPairs(nums, k, x, y) :: (x,y)
}
I also tried to setup invariants based on counts using methods which could count the matching pairs using a column at a time. However, I ran into no end of incompatible conditions maintaining the invariants before and after the while loop. I was hoping these helper functions could be defined recursively allowing some induction on the result to be used inside the two loops for each invariant, but it didn't work.
function countSeqPairs(nums: seq<nat>, k: nat, start: nat, stop: nat): nat
requires k > 0
requires start <= stop <= |nums|
decreases |nums|-start, |nums|-stop
{
if start > stop || stop >= |nums| || start >= |nums| then 0 else
if stop < |nums| then (if satPairs(nums, k, start, stop) then 1 + countSeqPairs(nums, k, start, stop+1) else countSeqPairs(nums, k, start, stop+1)) else countSeqPairs(nums, k, start+1, stop+2)
}
function countSeqSlice(nums: seq<nat>, k: nat, start: nat, stop: nat): nat
requires k > 0
requires start <= stop <= |nums|
decreases |nums| - stop
{
if start > stop || stop >= |nums| then 0
else if satPairs(nums, k, start, stop) then 1 + countSeqSlice(nums, k, start, stop+1) else countSeqSlice(nums, k, start, stop+1)
}
Here is the main method, with various non-working attempts at invariants.
method countPairs(nums: seq<nat>, k: nat) returns (count: nat)
requires k > 0
requires |nums| >= 2;
{
count := 0;
//ghost var cpairs: set<(nat, nat)> := {};
for i : nat := 0 to |nums|-2
invariant count >= 0
//invariant cpairs == pairsI(nums, k, i)
{
// ghost var occount := count;
// ghost var increment := 0;
for j : nat := i+1 to |nums|-1
invariant count >= 0
// invariant count == occount + increment
// invariant satPairs(nums, k, i, j) ==> increment == increment + 1
// invariant count == 0 || satPairs(nums, k, i, j) ==> count == count + 1
//invariant cpairs == pairsI(nums, k, i) + set z: nat | i+1 <= z <= j && satPairs(nums, k, i, z) :: (i, z)
{
// ghost var currcount := count;
// if nums[i] == nums[j] && (i*j)% k == 0 {
if i+1 <= j <= j && satPairs(nums, k, i, j) {
// increment := increment + 1;
//cpairs := {(i,j)}+cpairs;
count := count + 1;
}
}
}
}
It seems like there is no shorter description than the method itself for what is to be ensured. In addition to help with the above, I have three questions, generally how do you describe an invariant for something which is sort of manifestly arbitrary like this?
Secondly, what strategy can be used to handle loop invariants which are not true before the loop is run but are afterwards? It tends to be the initial condition is set to 0 or some other empty value, but then after the 0-th iteration of the loop it will be set to some value, and then the invariant fails. I keep running into this situation and it feels like there should be some sort of standard guard for it.
Finally, can or should ghost variables be used in method ensure statements?
Here is one way to do it.
function method satPairs(nums: seq<nat>, k: nat, a: nat, b: nat): bool
requires k > 0
requires a <= b < |nums|
{
nums[a] == nums[b] && (a*b) % k == 0
}
function matchPairsHelper(nums: seq<nat>, k: nat, bound: int): set<(int, int)>
requires k > 0
requires bound <= |nums|
{
set x,y | 0 <= x < bound && x < y < |nums| && satPairs(nums, k, x, y) :: (x,y)
}
function matchPairs(nums: seq<nat>, k: nat): set<(int, int)>
requires k > 0
{
matchPairsHelper(nums, k, |nums|)
}
function innerMatchPairsHelper(nums: seq<nat>, k: nat, outer: int, inner_bound: int): set<(int, int)>
requires k > 0
requires inner_bound <= |nums|
{
set y | 0 <= outer < y < inner_bound && satPairs(nums, k, outer, y) :: (outer,y)
}
method countPairs(nums: seq<nat>, k: nat) returns (count: nat)
requires k > 0
requires |nums| >= 2
ensures count == |matchPairs(nums, k)|
{
count := 0;
for i : nat := 0 to |nums|
invariant count == |matchPairsHelper(nums, k, i)|
{
for j : nat := i+1 to |nums|
invariant count == |matchPairsHelper(nums, k, i)| + |innerMatchPairsHelper(nums, k, i, j)|
{
assert innerMatchPairsHelper(nums, k, i, j+1) ==
(if satPairs(nums, k, i, j) then {(i, j)} else {}) + innerMatchPairsHelper(nums, k, i, j);
if satPairs(nums, k, i, j) {
count := count + 1;
}
}
assert matchPairsHelper(nums, k, i+1) == matchPairsHelper(nums, k, i) + innerMatchPairsHelper(nums, k, i, |nums|);
}
}
A few notes:
James's rule of set comprehensions: never use a set comprehension as part of any larger expression, but only as the body of a function that returns that set. This facilitates referring to the set multiple times in assertions without confusing Dafny.
James's rule of cardinalities: Dafny will never prove two cardinalities equal. You must manually ask it to prove two sets equal, and from there, it will conclude the cardinalities are equal.
I didn't really look at your invariants. I just tried to write down what the loops are doing. The outer loop is a loop over the x coordinate. So the invariant is that all the "right" pairs have been counted for all x coordinates smaller than i (for all values of y). Then for the inner loop, the invariant is that all the pairs for the exact x coordinate i have been counted up to j. I define two functions for these notions.
Other than that, just need to assert some set equalities in a few places.
To your other questions:
how do you describe an invariant for something which is sort of
manifestly arbitrary like this?
I'm not sure I understand the question. Are you asking "how do I discover the right loop invariants for this postcondition?" or "how do I state the postcondition when it seems like it is just as long as the code itself?"
what strategy can be used to handle loop invariants which are
not true before the loop is run but are afterwards?
I didn't need this in my solution, but if you do need it then the easiest way is something like i == 0 || <invariant that is true only after loop starts>. Generally I consider such invariants to have a "bad smell" and try to refactor to avoid them. Sometimes they are unavoidable though.
can or should ghost variables be used in method ensure statements?
Not sure I understand this one either. You cannot refer to any local variables of a method in an ensures clause except those that are returned by the method. If needed you can return a ghost variable as in
method Foo() returns (bar: int, ghost baz: int)
ensures ... mentions bar and baz just fine ...
Does that answer this one?
I'm following the tutorials here and the code seems correct but when I test using assertions I get an error!
Running the program prints the correct answer, but the assertions seem to be paradoxical. When a show the counter examples it seems that -1 is considered even though it shouldn't be.
method binarySearch(a:array<int>, key:int) returns (r:int)
requires forall i,j :: 0 <= i <= j < a.Length ==> a[i] <= a[j]
ensures 0 <= r ==> r < a.Length && a[r] == key
ensures r < 0 ==> forall i :: 0 <= i < a.Length ==> a[i] != key
{
var lo, hi := 0, a.Length;
while (lo < hi)
invariant 0 <= lo <= hi <= a.Length
invariant forall i :: 0 <= i < lo ==> a[i] < key
invariant forall i :: hi <= i < a.Length ==> a[i] > key
decreases hi - lo;
{
var mid := (lo + hi) / 2;
if key < a[mid]
{
hi := mid;
}
else if key > a[mid]
{
lo := mid + 1;
}
else
{
return mid;
}
}
return -1;
}
// tests
method Main()
{
var a := new int[6][1,2,3,4,5,6];
var r := binarySearch(a, 5);
assert r == 4; // fails
assert r != 4; // also fails
}
Is this a bug or am I missing something?
Dafny uses post-condition of method to reason about result of method call.
Here post-condition is
If r is between 0 to array length, element at r is equal to key
If r is less than 0, it is not in array.
Dafny doesn't know which of these is vacuous, but you can hint it.
Guarding assert r == 4 with if r >= 0 && r < a.Length will make it verify.
Alternatively after adding assert a[4] == 5 before assert r == 4, verification will go through.
Reason for strange error is after call to binary search, these are facts known to dafny
assert (r < 0) || (0 <= r < 6)
assert (r < 0) ==> forall i :: 0 <= i < a.Length ==> a[i] != 5
assert (0 <= r < 6) ==> a[r] == 5
Using these it can neither prove r == 4 nor r != 4. Dafny doesn't seem to propagate information like assert a[0] == 1 etc by default to prover, you have to explicitly ask for it.
Right, so I am trying to verify the following fill() method. Currently the first and third invariant clauses fail, and I'm not entirely surely why. Any thoughts appreciated!
class List {
var data : int;
var next : List?;
ghost var rep : set<List>;
constructor(d : int)
ensures this.valid();
{
this.data := d;
this.next := null;
this.rep := {this};
}
predicate valid()
reads this, rep;
decreases rep + {this};
{
this in rep
&& (next != null ==> (
next in rep
&& next.rep <= rep
&& this !in next.rep
&& next.valid()
))
}
}
method fill(ol : List, on : int)
requires ol.valid();
requires on >= 0;
modifies ol.rep;
{
assert ol in ol.rep;
var n := on;
var l : List? := ol;
//
//
while(n >= 0 && l != null)
invariant ol.valid();
invariant (l != null) ==> l.valid();
invariant (l != null) ==> (l in ol.rep);
modifies l.rep;
{
l.data := n;
l := l.next;
n := n - 1;
}
}
Here's one way to do it.
class List {
var data : int;
var next : List?;
ghost var rep : set<List>;
constructor(d : int)
ensures valid()
{
data := d;
next := null;
rep := {this};
}
predicate valid()
reads this, rep
decreases rep + {this}
{
&& this in rep
&& (next != null ==>
&& next in rep
&& next.rep <= rep
&& this !in next.rep
&& next.valid())
}
static twostate lemma valid_frame(a: List)
requires old(a.valid())
requires forall x | x in old(a.rep) :: unchanged(x`next)
requires forall x | x in old(a.rep) :: unchanged(x`rep)
decreases old(a.rep)
ensures a.valid()
{}
}
method fill(ol : List, on : int)
requires ol.valid()
requires on >= 0
modifies ol.rep
ensures ol.valid()
{
var n := on;
var l : List? := ol;
label L:
while(n >= 0 && l != null)
invariant l != null ==> l.valid()
invariant l != null ==> l.rep <= old(ol.rep)
modifies ol.rep`data
{
l.data := n;
l := l.next;
n := n - 1;
}
List.valid_frame#L(ol);
}
The basic idea of this proof is that the valid predicate only depends on the next and rep fields of List. Since fill only writes to the data field, it must preserve validity.
To implement the idea, we can use a twostate lemma in Dafny. The way to "pass" a particular old state to such a lemma uses a combination of the label feature and #.
Trying to implement a fairly simple method, where you pass an empty array and place values into it (natural numbers).
The code runs fine, but a simple postcondition that ought to pass in my mind is throwing me errors.
method Main() {
var a := new int[5];
initialise(a);
}
method initialise(a: array<int>)
modifies a
requires a.Length > 0
ensures forall i :: 0 <= i < a.Length ==> a[i] == i
{
var i := 0;
while i < a.Length
invariant 0 <= i <= a.Length
decreases a.Length - i
{
a[i] := i;
i := i + 1;
}
}
Error:
A postcondition might not hold on this return path. Related location 1: Line: 10, Col: 8
You need to tell Dafny about the invariant maintained by the loop.
Once you add
invariant forall j :: 0 <= j < i ==> a[j] == j
the proof goes through.