Dafny, triggers in forall assignment - dafny

in my method that converts a sequence to an array, I get a recommendation by debugger of dafny for VSCode that I can not understand what it is.
method toArrayConvert(s:seq<int>) returns(res:array<int>)
requires |s|>0;
ensures |s| == res.Length;
ensures forall i::0<=i<res.Length ==> s[i] == res[i];
{
res :=new int[|s|];
forall i|0<=i && i<|s| {res[i]:=s[i];} /*on this line I get the following*/
// rewrite: forall i#inv: int {:trigger res[i#inv]} | 0 <= i#inv && i#inv < |s| { res[i#inv] := s[i#inv]; }
//Not generating triggers for "res[i#inv] == s[i#inv]".
return res;
}

This is not a warning or error, but just a diagnostic message from Dafny telling you how it plans to encode the forall assignment. You can safely ignore it.
I agree that the message is a little bit confusing, since it contains the string "Not generating triggers", when, in fact, it has already generated a trigger. This message is due to some internal technical details of how Dafny handles forall statements. I will file an issue to look at it.

Related

Why does Dafny think there might be a problem with this precondition when using a ghost variable?

Let's say I have the following class:
class Testing {
ghost var myGhostVar: int;
method Init()
modifies this
ensures this.myGhostVar == -1
{
this.myGhostVar := -1;
assert this.myGhostVar == -1;
}
method MyTestingMethod(list: array<int>, t: int)
modifies this
requires list.Length > 1
requires this.myGhostVar == -1
requires t == -1
ensures MyPredicate(list, myGhostVar)
ensures this.myGhostVar < list.Length
{
this.Init();
assert this.myGhostVar < 0;
assert list.Length > 0;
assert this.myGhostVar < list.Length;
}
predicate MyPredicate(list: array<int>, startIndex: int)
requires startIndex < list.Length
{
true
}
}
For some reason, Dafny say that the call to MyPredicate(...) might not hold. But if I instead use t as the argument instead of myGhostVar; Dafny has no complaints.
Both have the same requires predicate which makes it all a bit confusing. Is it something that I am missing when using ghost variables?
It's not an issue with ghost variables - you could check and see that you'd have the same issue if you removed the ghost keyword.
The issue is that to call MyPredicate(list, myGhostVar), you need to satisfy the pre-condition, which here would be myGhostVar < list.Length.
You actually have this condition in your ensures clause, which is great!
ensures MyPredicate(list, myGhostVar)
ensures this.myGhostVar < list.Length
But your call to MyPredicate is before the condition you need. Try flipping around the order:
ensures this.myGhostVar < list.Length
ensures MyPredicate(list, myGhostVar)
And you should see that Dafny stops complaining.
In general, Dafny will try to prove that the pre-conditions within an ensures clauses hold using the previous ensures clauses.
Both have the same requires predicate which makes it all a bit confusing. Is it something that I am missing when using ghost variables?
Here, I think you're asking about the clauses
requires this.myGhostVar == -1
requires t == -1
and wondering why it can't use the this.myGhostVar == -1 pre-condition to prove this.myGhostVar < list.Length.
The answer is that the this.myGhostVar == -1 is a pre-condition, meaning Dafny knows that it holds on entry, but the value of this.myGhostVar might change during the execution of the method. So that doesn't help Dafny when checking the post-condition.
Note that Dafny doesn't look at the body of its methods when checking the well-formedness of its post-conditions. For that purpose, Dafny only knows what you tell it in the method signature.

Dafny iterator: precondition and modifes clause violated

Dafny shows multiple errors when calling MoveNext() on an iterator that does nothing:
iterator Iter()
{}
method main()
decreases *
{
var iter := new Iter();
while (true)
decreases *
{
var more := iter.MoveNext();
if (!more) { break; }
}
}
The errors are on the call to iter.MoveNext():
call may violate context's modifies clause
A precondition for this call might not hold.
There is no modifies clause for main or Iter, and there is no precondition for Iter. Why is this program incorrect?
You need the following invariant on the loop
invariant iter.Valid() && fresh(iter._new)
Then your program verifies. As usual, there's nothing wrong (dynamically) with your program, but you can have false positives at verification time due to missing annotations.
As far as I know, this invariant is always required when using iterators.
(A little) More information about iterators can be found in the Dafny Reference, in Chapter 16. (At least, enough information for me to remember the answer to this question.)

Assertion fails after modifying another array in Dafny

I ran into a weird problem in Dafny. I tried to extract it as much as possible here: https://rise4fun.com/Dafny/F7sK
The thing is, after the modification of truthAssignment, stack.valid fails even if stack.valid doesn't know about truthAssignment.
assert stack.valid();
truthAssignment[variable] := 1;
assert stack.valid(); // assertion violation
The reason Dafny fails to verify the assertion assert stack.valid(); is the last conjunct in the body of valid():
(forall c :: c in contents ==>
exists i,j :: 0 <= i < stack.Length
&& 0 <= j < |stack[i]|
&& stack[i][j] == c)
It has the form forall ... exists ..., and proving such a condition to be invariant is difficult for the verifier. Once you have figured out that this is the part of valid() that the verifier cannot prove (which you can do by, for example, manually inlining the definition of valid() in place of your assertion), then the solution is to give the verifier some assistance.
When the verifier--or a human, for that matter--tries to prove something for the form forall c :: P(c), then it makes up an arbitrary c and then tries to prove the "P(c)" for it. (Logicians call this rule "universal introduction".) Easy. Then, to prove something of the form exists i,j :: Q(i,j), the verifier looks for a witness to the "Q(i,j)". (This is known as "existential introduction".) Here, the verifier is not particularly creative and often needs help. Sometimes, you have to figure out some i and j yourself and then assert Q(i,j). Other times, it suffices to just mention some component of the needed Q(i,j) and the verifier will then figure out the rest. Exactly what to do can be a trial-and-error process.
What makes James's remedy above work is the fact that it mentions stack.stack[..] after the update truthAssignment[variable] := 1;. This tickles the verifier in a way that lets it see the light. Just writing the trivially proved assertion:
assert 0 <= |stack.stack[..]|; // mentioning stack.stack[..] helps the verifier in the next line
after the update also works in this case.
Rustan
The following verifies for me:
assert stack.valid();
ghost var old_stack := stack.stack[..];
truthAssignment[variable] := 1;
assert stack.stack[..] == old_stack;
assert stack.valid();
I don't really understand why this works, but it falls under the general category of "extentional equality for sequences is hard for Dafny".

Why this Dafny example verification fails?

This is an example to learn Dafny.
method test5(x:array<int>,y:array<int>,n:int)
requires 0<=n
requires 0< x.Length
requires 0< y.Length
requires x[0]==y[0];
requires (x[0]>=0 ==> y[0]>=0)
requires (y[0]>= 0 ==> x[0]>= 0)
requires (x[0]+y[0]==0 || x[0]+y[0]>0);
modifies y;
modifies x;
ensures (x[0]==y[0]);
ensures (x[0]>0 ==> y[0]>0)
ensures (y[0] > 0 ==> x[0] > 0)
ensures (x[0]+y[0]==0 || x[0]+y[0]>0)
{ if (x[0]>0)
{x[0]:=x[0]- 1;
y[0]:=y[0]- 1;
}
}
Why does the verification fails?
Can Dafny show a counterexample?
Yes, you can get a counterexample. If you're using Visual Studio, simply click on the red circle where the error is. This brings up the Verification Debugger. If you're using VS Code, then press F7 (see https://marketplace.visualstudio.com/items?itemName=correctnessLab.dafny-vscode). That will reverify your program and show you some information from the counterexample.
In your case, these counterexamples show x and y as being equal and with x[0]==y[0]==1 initially. Indeed, starting from that initial state, test5 will not establish its declared postcondition.
Rustan

Sorted post-condition doesn't hold

What I want to do in the method is simply to overwrite the previous array and fill it with number that are sorted, however dafny says that the post-condition does not hold and I can't for the life of me figure out why.
I'm guessing I need to add some invariant to the loop but since they are checked before entering the loop I don't know how to put a valid invariant.
method sort2(a : array<int>)
modifies a;
requires a != null && a.Length >= 2;
ensures sorted2(a[..]);
{
var i := a.Length - 1;
while (i >= 0)
decreases i
{
a[i] := i;
i := i - 1;
}
}
predicate sorted2(s: seq<int>)
{
forall i :: 1 <= i < |s| ==> s[i] >= s[i-1]
}
My previous attempt was just to reinitialize a but dafny apparently doesn't allow that inside methods.
You do need a loop invariant in order to prove this program correct.
See Section 6 of the Dafny Tutorial for a general introduction to loop invariants and how to come up with them.
In this case, a good loop invariant will be something like sorted(a[i+1..]), which says that the part of the array after index i is sorted. That way, when the loop terminates and i is zero, you'll know that the whole array is sorted.
You will also need one or two more loop invariants describing bounds on i and the elements of the array itself.

Resources