Verifying a Loop Modifies Clause - dafny

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 #.

Related

Postcondition for method to find min value of an array

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.

How do I describe the invariants for this simple algorithm in Dafny?

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?

dafny assertion violation when using the result of a method

I have written the program below to verify that an array is 'clean' of any particular element or not. I am having trouble asserting the result of the method. I keep getting an assertion violation when trying to assert the result of the method.
method Main (){
var a:= new int[3];
a[0], a[1], a[2] := 1,2,3;
var v := isClean (a, 1);
assert v == false;
}
method isClean (a : array <int>, key : int) returns (clean : bool)
requires a.Length > 0
{
var i := 0;
while (i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k :: 0 <= k < i ==> a[k] != key
{
if (a[i] == key) {
clean := false;
return;
}
i := i + 1;
}
clean := true;
}
Dafny 2.3.0.10506
stdin.dfy(8,11): Error: assertion violation
Dafny program verifier finished with 2 verified, 1 error
You need to give an ensures clause on isClean. When Dafny verifies a program, it only looks at one method at a time. So when Dafny verifies Main, it does not look at the definition of isClean at all. Instead, it only looks at the requires and ensures clauses.
You already have the hard part of the proof done in the loop invariant. Basically you just need to modify a copy of that invariant so that it makes sense in the context of the caller, as an ensures clause, like this:
ensures clean <==> (forall k :: 0 <= k < a.Length ==> a[k] != key)
(Add that right below the requires clause on isClean.) In this ensures clause, clean refers to the named return value of the isClean method. If you add this clause, Dafny will still complain, because you are asking it to prove that a forall quantifier is false. That is equivalent to trying to prove an exists quantifier true, and requires an explicit "witness", which is a value of k that makes the body of the formula turn out true/false.
In this case, the intuitive reason why isClean returns false is because a[0] has the value 1, so a is not "clean" of 1. We can demonstrate this "witness" to Dafny by adding the assertion
assert a[0] == 1;
to the body of Main, right after the call to isClean.
For clarity, here is a complete version of the program that verifies:
method Main() {
var a := new int[3];
a[0], a[1], a[2] := 1,2,3;
var v := isClean (a, 1);
assert a[0] == 1;
assert v == false;
}
method isClean(a: array <int>, key: int) returns (clean: bool)
requires a.Length > 0
ensures clean <==> (forall k :: 0 <= k < a.Length ==> a[k] != key)
{
var i := 0;
while (i < a.Length)
invariant 0 <= i <= a.Length
invariant forall k :: 0 <= k < i ==> a[k] != key
{
if (a[i] == key) {
clean := false;
return;
}
i := i + 1;
}
clean := true;
}

What is the relation between Dafny's Hilbert epsilon operator and apparently redundant code?

In the Dafny code below the var notUsed := t; line seems redundant as notUsed is, as the name suggests, not used. But, with out this line the var e :| e in t line becomes not unique. Why has this assignment changed the uniqueness?
predicate setIsSeq<T>(t : set<T>, q : seq<T>)
{ (|t| == |q|) ==>
(forall i :: (0 <= i < |q|) ==> (q[i] in t)) &&
(forall x :: x in t ==> (x in q))
}
function method fSetToSeq<T>(t : set<T>) : (r : seq<T>)
decreases t
ensures setIsSeq(t,r);
{
var notUsed := t;//with out this var e:|e in t; is not unique
if (|t| == 0) then []
else (
var e :| e in t;
var tx := t - {e};
var qx := fSetToSeq(tx);
[e] + qx //part of the var e:|e in t expression and is unique
)
}
This is a bug. Please report it on github: https://github.com/dafny-lang/dafny/issues

Dafny program can't prove this binary search implementation?

We are trying to write a binary search algorithm using Dafny and it seems that Dafny doesn't prove the correctness of the program.
can someone please assist?
These are the errors we are getting:
On INV: This loop invariant might not be maintained by the loop.Dafny VSCode
On Guard1: decreases expression might not decreaseDafny VSCode
predicate Sorted(q: seq<int>)
{
forall i,j :: 0 <= i <= j < |q| ==> q[i] <= q[j]
}
method BinarySearch(q: seq<int>, key: int) returns (j: nat)
requires Sorted(q) && key in q
ensures j < |q| && q[j] == key
{
var i: nat, k: nat;
i,j,k := Init(q,key);
while Guard1(q,key,j)
invariant Inv(q,key,i,j,k)
decreases V(i,k)
{
if Guard2(q,key,j)
{
i := UpdateI(q,key,i,j,k);
}
else
{
k := UpdateK(q,key,i,j,k);
}
j := (i+k)/2;
}
}
predicate Inv(q: seq<int>, key: int, i: nat, j: nat, k: nat)
{
i <= j <= k < |q| &&
key in q[i..k+1]
}
predicate method Guard1(q: seq<int>, key: int, j: nat)
requires Sorted(q) && key in q
{
0 <= j < |q| && q[j] != key
}
method Init(q: seq<int>, key: int) returns (i: nat, j: nat, k: nat)
requires Sorted(q) && key in q
ensures 0 <= i <= j <= k < |q| && key in q[i..k+1]
{
i, k := 0, |q|-1;
j := (k+i) / 2;
}
function V(i: nat, k: nat): int
{
if (k > i) then k-i
else 0
}
predicate method Guard2(q: seq<int>, key: int, j: nat)
{
0 <= j < |q| && q[j] < key
}
method UpdateI(q: seq<int>, key: int, i0: nat, j: nat, k: nat) returns (i: nat)
requires Guard2(q,key,j) && Inv(q,key,i0,j,k)
ensures i0 <= i
{
if(j < |q|-1 ){
i:= j + 1;
}
else {
i:= j;
}
}
method UpdateK(q: seq<int>, key: int, i: nat, j: nat, k0: nat) returns (k: nat)
requires (!Guard2(q,key,j)) && Inv(q,key,i,j,k0)
ensures k <= k0
{
if(j > 0){
k:= j - 1;
}
else {
k:= j;
}
}
The Dafny verifier reasons about the calls to methods UpdateI and UpdateK only in terms of their specifications. The postcondition you have given those two methods are not strong enough to prove termination. In particular, UpdateI(..., i, ...) may return i and UpdateK(..., k, ...) may return k, in which case your loop would make no progress.
I have two more suggestions.
One is perhaps a matter of taste, but I find it simplifies expressions. Use k as the lowest index that's not used, rather than as the highest index that's used. So, initialize k to |q|, not to |q|-1. This way, each iteration of the loop looks at the k-i (not k-i+1) elements starting at index i. That is, it looks at q[i..k] (not q[i..k+1]).
The other is that your program is really hard to read, because you needlessly have separate functions and methods for so many things. Furthermore, those things have meaningless names, like Guard1 and V and UpdateI. I think you'd be better off just writing those expressions and statements directly in method BinarySearch.
A final remark. Perhaps you will find the following episode of Verification Corner helpful: https://www.youtube.com/watch?v=-_tx3lk7yn4
Rustan

Resources