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

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

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.

Verifying a Loop Modifies Clause

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

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;
}

Using methods inside loop invariants in Dafny

I'm trying to prove the simple gcd algorithm in Dafny, so I wrote the following, but it seems I can not use the method divides inside the loop invariants:
method divides(d: int, x: int) returns (result: bool)
requires d > 0
requires x > 0
ensures (result == true ) ==> (exists q : int :: (d * q == x))
ensures (result == false) ==> (forall q : int :: (d * q != x))
{
// code omitted
}
method gcd(a: int, b: int) returns (result: int)
requires a > 0
requires b > 0
ensures (forall d : int :: ((exists q1 : int :: q1 * d == a) && (exists q2 :: (q2 * d == b))) ==>
(exists q3 : int :: (q3 * d == result)))
{
var x := a;
var y := b;
var fuel := a+b;
while ((x != y) && (fuel > 0))
decreases fuel
invariant x > 0
invariant y > 0
invariant (forall d : int :: (divides(d,x) && divides(d,y)) ==> (divides(d,a) && divides(d,b)))
{
// code omitted
}
return x;
}
Is there anyway to use a divides method/function/macro inside invariants?
Unlike methods, functions can appear in expressions. You can create a function:
function div(d: int, x: int): bool
{
if (d != 0 && x % d == 0) then true else false
}
Then in your method divides, you can have
ensures result == div(d,x)
and in your method gcd you can use the function div in your invariant.
Note, from the Dafny guide: One caveat of functions is that not only can they appear in annotations, they can only appear in annotations. Functions are never part of the final compiled program, they are just tools to help us verify our code.

Dafny. Cannot establish the existence of LHS ... for sequences

For the following code I get that it cannot establish the existence of LHS values that satisfy the such-that predicate. How could I prove the right side holds and such an x exists?
method Main() {
var n : int := 10;
var x : seq<int> :| n == |x| && forall i :: 0 <= i < |x| ==> -1 <= x[i] <= 1;
}
https://rise4fun.com/Dafny/TiO5
You need to provide a witness. The following assertion does the trick:
method Main() {
var n : int := 10;
assert |[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]| == 10;
var x : seq<int> :| n == |x| && forall i :: 0 <= i < |x| ==> -1 <= x[i] <= 1;
}
However, this brings you to the next point, which is that
It seems that even something trivial like this is not supported at the moment:
method Main() {
var n : int := 10;
var y : seq<int> :| y == [3];
var x : seq<int> :| x == y;
var z : seq<int> :| |z| == |y|;
}
Dafny manages to instantiate x, but not z.
Maybe post it in their GitHub/Issues?

Resources