I am having a problem with getting an invariant to be be maintained in dafny. The invariant is trying to maintain that a total is equal to the a recursive sum of elements in a sequence that match a given condition. What do i need to add/change to get this to verify. Here is my attempt:
datatype MovieTitle = A | B | C
class Movie {
var title: MovieTitle;
var run_time: int;
predicate Valid()
reads this
{
run_time >= 0
}
constructor(mt: MovieTitle, rt: int)
requires rt >= 0;
ensures Valid();
modifies this;
{
title := mt;
run_time := rt;
}
}
function movieSum(s: seq<Movie>, mt: MovieTitle, i: int): int
requires 0 <= i <= |s|;
decreases s, i;
reads s;
reads set x | x in s[..];
{
if |s| == 0 || i == 0 then 0
else if s[0].title == mt then s[0].run_time + movieSum(s[1..], mt, i - 1)
else movieSum(s[1..], mt, i - 1)
}
lemma {:induction s, mt, i} movieSumLemma(s: seq<Movie>, mt: MovieTitle, i: int)
requires 0 <= i < |s|;
ensures s[i].title == mt ==> (movieSum(s, mt, i) + s[i].run_time == movieSum(s, mt, i + 1)) &&
s[i].title != mt ==> (movieSum(s, mt, i) == movieSum(s, mt, i + 1));
decreases s;
{
}
method SumRuntimes(s: seq<Movie>)
{
var total := 0;
var i := 0;
while i < |s|
invariant 0 <= i <= |s|;
invariant total == movieSum(s, A, i);
decreases |s| - i;
{
if s[i].title == A {
total := total + s[i].run_time;
movieSumLemma(s, A, i);
}
i := i + 1;
}
}
Here invariant total == movieSum(s, A, i); won't hold. Any help in getting this to verify is appreciated. Thank you!
The problem is in function movieSum. You're both chopping off the initial element of s in the recursive call and decrementing i. That will not produce the sum of all the mt-movie elements.
You don't need the lemma. But its postcondition doesn't say what you may think it says. It currently has the form
ensures A ==> B && !A ==> C
The 2-character-wide && has higher binding power than the 3-character-wide ==>. So, your postcondition is saying
ensures A ==> ((B && !A) ==> C)
which simplifies to true. Instead, you want
ensures (A ==> B) && (!A ==> C)
which you can also write on two lines (for better readability):
ensures A ==> B
ensures !A ==> C
Your program also has a number of redundant decreases clauses and :induction attributes. I'm guessing you have added these from the blue information squiggles in the IDE. The blue squiggles are just FYI--Dafny is just trying to tell you what its default settings are.
It seems you may be using a very version of Dafny, or I expected you should have got a warning about the deprecated modifies this on the constructor.
Related
I have 2 functions, all is for checking how many values that are the same values and same index in 2 sequences, example:
requires there's no duplicates in the sequence
s:= [1,3,2,5,6]
u:= [2,3,4,5,1]
==> bullspec(s,u) = 2
So both my 2 functions return the right value but the assertion of one is true, other is false
Here are my 2 functions:
function bullspec(s:seq<nat>, u:seq<nat>): nat
requires 0 < |s| <= 10
requires 0 < |u| <= 10
requires |s| <= |u|
// Remove duplicates
requires forall i, j | 0 <= i < |s| && 0 <= j < |s| && i != j :: s[i] != s[j] && s[i] <= 10
requires forall i, j | 0 <= i < |u| && 0 <= j < |u| && i != j :: u[i] != u[j] && u[i] <= 10
{
if |s| == 1 then (
if s[0] in u && s[0] == u[0]
then 1 else 0
) else (
if s[|s|-1] in u && s[|s|-1]==u[|s|-1]
then (1 + bullspec(s[..|s|-1], u))
else bullspec(s[..|s|-1],u)
)
}
and
function bullspec2(s:seq<nat>, u:seq<nat>): nat
requires 0 < |s| <= 10
requires 0 < |u| <= 10
requires |s| <= |u|
// Remove duplicates
requires forall i, j | 0 <= i < |s| && 0 <= j < |s| && i != j :: s[i] != s[j] && s[i] <= 10
requires forall i, j | 0 <= i < |u| && 0 <= j < |u| && i != j :: u[i] != u[j] && u[i] <= 10
{
if |s| == 1 then (
if s[0] in u && s[0] == u[0]
then 1 else 0
) else (
if s[0] in u && s[0] == u[0]
then (1 + bullspec2(s[1..], u))
else bullspec2(s[1..], u)
)
}
I have a method Main below:
method Main()
{
var sys:seq<nat> := [4,2,9,3,1];
var usr:seq<nat> := [1,2,3,4,5];
assert bullspec(sys, usr) == 1; //Assertion might not hold
assert bullspec2(sys, usr) == 1; //This is good
}
The difference between 2 functions is the loop recusive, one start from the beginning, other start from the end, and somehow the backward make assertion works well
I try to write some ensures statements but there's no working.
First, please be aware that you are using a static analyzer, not a run-time tester. So the assertion might hold at run-time, but the static analyzer can't prove it.
The fact that the static analyzer can prove the second one is pretty astounding already. But I would always advise you switch the order of assertions, because an assertion after a first unproven one is always proved with the condition that the unproven one is true. In your case, it's still bullspec that can't be resolved, no matter what.
The reason why it currently fail to verify is that the axiom that indirectly serves at evaluating a sequence's length in the presence of a sequence literal without consuming fuel is not implemented yet. See this similar issue. That means that, for your second example, "evaluating" the function using axioms does not consume "fuel" (I'll go back to that later), but for the first failing example, it cannot unroll the function enough to do the computation.
What you can do for now is:
Create a lemma and prove it (hard)
lemma bullspec2equalsBullspec(s:seq<nat>, u:seq<nat>): nat
ensures bullspec2(sys, usr) == bullspec(sys, usr)
{
// TODO
}
and then write:
assert bullspec2(sys, usr) == 1;
assert bullspec(sys, usr) == 1 by {
bullspec2equalsBullspec(sys, usr);
}
Pass the sequence's length as a ghost parameter in bullspec
function bullspec(s:seq<nat>, u:seq<nat>, length: nat): nat
requires |s| == length
requires 0 < |s| <= 10
requires 0 < |u| <= 10
requires |s| <= |u|
// Remove duplicates
requires forall i, j | 0 <= i < |s| && 0 <= j < |s| && i != j :: s[i] != s[j] && s[i] <= 10
requires forall i, j | 0 <= i < |u| && 0 <= j < |u| && i != j :: u[i] != u[j] && u[i] <= 10
{
if length == 1 then (
if s[0] in u && s[0] == u[0]
then 1 else 0
) else (
if s[length-1] in u && s[length-1]==u[length-1]
then (1 + bullspec(s[..length-1], u,length-1))
else bullspec(s[..length-1],u,length-1)
)
}
/// ...
method Main()
{
var sys:seq<nat> := [4,2,9,3,1];
var usr:seq<nat> := [1,2,3,4,5];
assert bullspec2(sys, usr) == 1; //This is good
assert bullspec(sys, usr, 5) == 1; //This is good
}
verifies because now it can unroll the function applied to literals without fuel.
Unroll bullspec by verification debugging to see where it blocks.
If this assertion should hold, what should hold before? You can unroll the function's definition and assert intermediate results. If you assert something non-trivial that Dafny can finally prove, all the rest will be proven. I unrolled the function for 3 steps only.
method Main()
{
var sys:seq<nat> := [4,2,9,3,1];
var usr:seq<nat> := [1,2,3,4,5];
assert bullspec2(sys, usr) == 1; //This is good
var sys1 := sys[..|sys|-1];
var sys2 := sys1[..|sys1|-1];
var sys3 := sys2[..|sys2|-1];
var sys4 := sys3[..|sys3|-1];
var sys5 := sys4[..|sys4|-1];
assert bullspec(sys3, usr) == 1;
assert bullspec(sys2, usr) == 1;
assert bullspec(sys1, usr) == 1;
assert bullspec(sys, usr) == 1; //Assertion might not hold
}
Give more fuel to your function (best in your case)
By just changing the definition of your function, you can give it more fuel for the verifier to instantiate it. For your case, a fuel of 3 is sufficient.
function {:fuel 10} bullspec(s:seq<nat>, u:seq<nat>): nat
I have a dafny defined graph ADT (from this SO question) brought here again for completeness:
class Graph
{
var adjList : seq<seq<int>>;
constructor (adjListInput : seq<seq<int>>)
ensures adjList == adjListInput
{
adjList := adjListInput;
}
}
function ValidGraph(G : Graph) : bool
reads G
{
(forall u :: 0 <= u < |G.adjList| ==> forall v :: 0 <= v < |G.adjList[u]| ==> 0 <= G.adjList[u][v] < |G.adjList|) &&
(forall u :: 0 <= u < |G.adjList| ==> forall v,w :: 0 <= v < w < |G.adjList[u]| ==> G.adjList[u][v] != G.adjList[u][w])
}
method main()
{
var G : Graph := new Graph([[1,2],[0,2],[0,1]]);
var nonRelatedArray := new int[8];
var i := 0; while (i < 14)
{
// nonRelatedArray[3] := 55;
i := i + 1;
}
assert (ValidGraph(G));
}
If I remove the write comment to nonRelatedArray at index 3, I get an assertion violation, which is a bit weird because it seems reasonable that the memory model would be able to determine that nonRelatedArray is (well) non related to G.
You can fix this by adding modifies nonRelatedArray to the loop. The key to this modifies clause is that it does not mention G. So then Dafny knows that G will not be modified by the loop, so it will still be a valid graph.
It is a little confusing what happens if you leave off a modifies clause from a loop. If you don't do any writes to the heap (like when you comment out the write above), then Dafny (actually, Boogie) is able to automatically see that nothing is changed at all. But if you do any writes into the heap, Dafny's default modifies clause all of a sudden becomes "anything the surrounding scope is allowed to modify". If you want something other than these two defaults, you need to ask for it explicitly by giving a modifies clause.
I have tried many thing involving this, >=, >==, =>, ==>.i can not find one that works. hey all return either primary expression needed or expected initializer before '>'. I am creating a IR receiver latch switch and thus have to create parameters for the code because the receiver is not constant in all conditions. Full code below. Any suggestions to fix the code please reply and don't DM me. Thank you.
code:
int LEDState = 0;
int LEDPin = 8;
int dt = 100;
int recieverOld ==> 500 and recieverOld ==< 2000;
int recieverNew;
int recieverPin = 12;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(LEDPin, OUTPUT);
pinMode(recieverPin, INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
recieverNew = digitalRead(recieverPin);
if((recieverOld >== 0 && recieverOld <== 10) && (recieverNew >== 500 && recieverNew <== 2000) {
if(LEDState == 0) {
digitalWrite(LEDPin, HIGH);
LEDState = 1;
}
}
recieverOld = recieverNew;
delay(dt);
}
error:
expected initializer before '==' token
if one = used line 4 and related, return error expected primary-expression before '>' token
if > before = line 4 and related, return error expected initializer before '>=' token
Any solutions or suggestions welcome.
TL;DR
Operators that do no exist, and that you should NOT use:
==>, ==<, >==, <==
Operators that works and you can use them:
>= - MORE THAN OR EQUAL, compare operator, for example X >= 5
<= - LESS THAN OR EQUAL, compare operator, for example X <= 5
> - MORE THAN, compare operator, for example X > 5
< - LESS THAN, compare operator, for example X < 5
== - compare operator, when you want to compare values of the variables if they have the same value, for example X == 5, Y == X, 10 == 7
=== - equality operator, similar to compare operator ==, but aditionally checks the type of a variable. for example X === Y, '10' === 10
= - assign operator, when you want to assign something to the variable, for example X = 5
<> OR != - NOT EQUAL, compare operator, for example X != 5, Y <> 10
!== - similar to != or <>, but also checks the type of a value. For example 10 !== '10', and will return opposite result of the equality operator ===
I'm currently learning Dafny. I'm totally comfused by lemma and I dont know how to use it. The tutorial is not that helpful. What if I want to prove
count(a) <= |a|
how should I do it. Thanks for helping.
function count(a: seq<bool>): nat
ensures count(a) <= |a|;
{
if |a| == 0 then 0 else
(if a[0] then 1 else 0) + count(a[1..])
}
You've already proved it! You wrote the property you wanted as a postcondition of the function and Dafny verifies it without complaints. That's it.
You can also use a lemma to prove the property. Here's an example:
function count(a: seq<bool>): nat
{
if |a| == 0 then 0 else
(if a[0] then 1 else 0) + count(a[1..])
}
lemma CountProperty(a: seq<bool>)
ensures count(a) <= |a|
{
}
Again, Dafny verifies the lemma without issuing any complaints, so you have proved it!
It is not correct to assume that Dafny will always prove things for you automatically. Therefore, it's a good idea to learn how to write proofs manually, too. Here's a manual proof of this property. Just to make sure Dafny doesn't try to do induction automatically, I used a directive to turn it off (thus making our lives harder than Dafny normally would):
lemma {:induction false} CountProperty(a: seq<bool>)
ensures count(a) <= |a|
{
// Let's consider two cases, just like the definition of "count"
// considers two cases.
if |a| == 0 {
// In this case, we have:
assert count(a) == 0 && |a| == 0;
// so the postcondition follows easily.
} else {
// By the definition of "count", we have:
assert count(a) == (if a[0] then 1 else 0) + count(a[1..]);
// We know an upper bound on the first term of the addition:
assert (if a[0] then 1 else 0) <= 1;
// We can also obtain an upper bound on the second term by
// calling the lemma recursively. We do that here:
CountProperty(a[1..]);
// The call we just did gives us the following property:
assert count(a[1..]) <= |a[1..]|;
// Putting these two upper bounds together, we have:
assert count(a) <= 1 + |a[1..]|;
// We're almost done. We just need to relate |a[1..]| to |a|.
// This is easy:
assert |a[1..]| == |a| - 1;
// By the last two assertions, we now have:
assert count(a) <= 1 + |a| - 1;
// which is the postcondition we have to prove.
}
}
A nicer way to write a proof like this is to use a verified calculation, which Dafny calls "the calc statement":
lemma {:induction false} CountProperty(a: seq<bool>)
ensures count(a) <= |a|
{
if |a| == 0 {
// trivial
} else {
calc {
count(a);
== // def. count
(if a[0] then 1 else 0) + count(a[1..]);
<= // left term is bounded by 1
1 + count(a[1..]);
<= { CountProperty(a[1..]); } // induction hypothesis gives a bound for the right term
1 + |a[1..]|;
== { assert |a[1..]| == |a| - 1; }
|a|;
}
}
}
I hope that this gets you started.
Program safely,
Rustan
int i = 0
boolean answer = false
while (i < a.length) {
if a[i] == 0
answer = true
i = i + 1
where 'a' is an array of integers.
I'm doing a question paper where it has asked me what the loop invariant of this is, I have already established that the code works out whether the array contains a 0. But so far I can only think of the invariant as being
i <= a.length
and the question states to include variables i, a and answer in the invariant so I know this can't be right. I have not come across loop invariants involving booleans before and am confused, could anyone help explaining?
Here is an implementation of your loop in Microsoft Dafny with appropriate loop invariants specified:
method Main(a:array<int>) returns (answer:bool)
requires a != null
ensures answer <==> (exists i :: 0 <= i < a.Length && a[i] == 0)
{
var i:int := 0;
answer := false;
while (i < a.Length)
invariant 0 <= i <= a.Length;
invariant !answer ==> !(exists j :: 0 <= j < i && a[j] == 0)
invariant answer ==> (exists j :: 0 <= j < i && a[j] == 0)
{
if a[i] == 0 {
answer := true;
}
i := i + 1;
}
}
You can verify its correctness automatically in the online version of Dafny