Hi I have simplified the problem to a method that simply copies the elements of one array to another array. My problem is that the final assert verifies yet the initial assert fails to verify even though I have a guard to ensure that initial assert only applies after the first time the loop is entered. Hence I think the final assert should imply the initial assert.
Any help much appreciated.
method simpImp(a:array<int>) returns (r:array<int>)
{
print "a ",a[..],"\n";
r := new int[a.Length];
var i:nat := 0;
while (i< a.Length)
decreases a.Length - i
invariant a.Length >= i
{
if (i> 0) { print " bool ",r[i-1] == a[i-1],"\n";}
else {print "*i ",i,"\n";}
//if (i> 0) { assert r[i-1] == a[i-1]; } //Fail
//assert (i>0) ==> r[i-1] == a[i-1]; //Fail
r[i] := a[i];
i:= i +1;
assert r[i-1] == a[i-1];
}
}
method Main() {
var a:array<int> := new int[5];
a[0],a[1],a[2],a[3],a[4] := 10,2,30,4,3;
var iny:= simpImp(a);
print "r ",iny[..],"\n";
}
The issue is that you need to add something to your loop invariant to "remember" any facts you need to carry between iterations. Dafny analyzes the loop body in isolation, assuming only the loop invariants at the beginning of the body. So unless you add the fact to the loop invariant, it will be "forgotten" by Dafny.
In your simplified example, adding
invariant i > 0 ==> r[i-1] == a[i-1]
to the loop causes the program to verify.
You can read more about loop invariants in the second half of this answer. Note that that discussion is phrased in terms of establishing that loop invariants are preserved, but the reasoning is mostly identical to trying to establish that an assertion inside the loop body is valid. Please feel free to ask further questions!
Related
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.
In a for loop, a different variable is assigned a value. The variable which has already been assigned a value is getting assigned the value from next iteration. At the end, both variable have the same value.
The code is for validating data in a file. When I print the values, it prints correct value for first iteration but in the next iteration, the value assigned in first iteration is changed.
When I print the value of $value3 and $value4 in the for loop, it shows null for $value4 and some value for $value3 but in the next iteration, the value of $value3 is overwritten by the value of $value4
I have tried on rakudo perl 6.c
my $fh= $!FileName.IO.open;
my $fileObject = FileValidation.new( file => $fh );
for (3,4).list {
put "Iteration: ", $_;
if ($_ == 4) {
$value4 := $fileObject.FileValidationFunction(%.ValidationRules{4}<ValidationFunction>, %.ValidationRules{4}<Arguments>);
}
if ($_ == 3) {
$value3 := $fileObject.FileValidationFunction(%.ValidationRules{3}<ValidationFunction>, %.ValidationRules{3}<Arguments>);
}
$fh.seek: SeekFromBeginning;
}
TL;DR It's not possible to confidently answer your question as it stands. This is a nanswer -- an answer in the sense I'm writing it as one but also quite possibly not an answer in the sense of helping you fix your problem.
Is it is rw? A first look.
The is rw trait on a routine or class attribute means it returns a container that contains a value rather than just returning a value.
If you then alias that container then you can get the behavior you've described.
For example:
my $foo;
sub bar is rw { $foo = rand }
my ($value3, $value4);
$value3 := bar;
.say for $value3, $value4;
$value4 := bar;
.say for $value3, $value4;
displays:
0.14168492246366005
(Any)
0.31843665763839857
0.31843665763839857
This isn't a bug in the language or compiler. It's just P6 code doing what it's supposed to do.
A longer version of the same thing
Perhaps the above is so far from your code it's disorienting. So here's the same thing wrapped in something like the code you provided.
spurt 'junk', 'junk';
class FileValidation {
has $.file;
has $!foo;
method FileValidationFunction ($,$) is rw { $!foo = rand }
}
class bar {
has $!FileName = 'junk';
has %.ValidationRules =
{ 3 => { ValidationFunction => {;}, Arguments => () },
4 => { ValidationFunction => {;}, Arguments => () } }
my ($value3, $value4);
method baz {
my $fh= $!FileName.IO.open;
my $fileObject = FileValidation.new( file => $fh );
my ($value3, $value4);
for (3,4).list {
put "Iteration: ", $_;
if ($_ == 4) {
$value4 := $fileObject.FileValidationFunction(
%.ValidationRules{4}<ValidationFunction>, %.ValidationRules{4}<Arguments>);
}
if ($_ == 3) {
$value3 := $fileObject.FileValidationFunction(
%.ValidationRules{3}<ValidationFunction>, %.ValidationRules{3}<Arguments>);
}
$fh.seek: SeekFromBeginning;
.say for $value3, $value4
}
}
}
bar.new.baz
This outputs:
Iteration: 3
0.5779679442816953
(Any)
Iteration: 4
0.8650280000277686
0.8650280000277686
Is it is rw? A second look.
Brad and I came up with essentially the same answer (at the same time; I was a minute ahead of Brad but who's counting? I mean besides me? :)) but Brad nicely nails the fix:
One way to avoid aliasing a container is to just use =.
(This is no doubt also why #ElizabethMattijsen++ asked about trying = instead of :=.)
You've commented that changing from := to = made no difference.
But presumably you didn't change from := to = throughout your entire codebase but rather just (the equivalent of) the two in the code you've shared.
So perhaps the problem can still be fixed by switching from := to =, but in some of your code elsewhere. (That said, don't just globally replace := with =. Instead, make sure you understand their difference and then change them as appropriate. You've got a test suite, right? ;))
How to move forward if you're still stuck
Right now your question has received several upvotes and no downvotes and you've got two answers (that point to the same problem).
But maybe our answers aren't good enough.
If so...
The addition of the reddit comment, and trying = instead of :=, and trying the latest compiler, and commenting on those things, leaves me glad I didn't downvote your question, but I haven't upvoted it yet and there's a reason for that. It's because your question is still missing a Minimal Reproducible Example.
You responded to my suggestion about producing an MRE with:
The problem is that I am not able to replicate this in a simpler environment
I presumed that's your situation, but as you can imagine, that means we can't confidently replicate it at all. That may be the way you prefer to go for reasons but it goes against SO guidance (in the link above) and if the current answers aren't adequate then the sensible way forward is for you to do what it takes to share code that reproduces your problem.
If it's large, please don't just paste it into your question but instead link to it. Perhaps you can set it up on glot.io using the + button to use multiple files (up to 6 I think, plus there's a standard input too). If not, perhaps gist it via, say, gist.github.com, and if I can I'll set it up on glot.io for you.
What is probably happening is that you are returning a container rather than a value, then aliasing the container to a variable.
class Foo {
has $.a is rw;
}
my $o = Foo.new( a => 1 );
my $old := $o.a;
say $old; # 1
$o.a = 2;
say $old; # 2
One way to avoid aliasing a container is to just use =.
my $old = $o.a;
say $old; # 1
$o.a = 2;
say $old; # 1
You could also decontainerize the value using either .self or .<>
my $old := $o.a.<>;
say $old; # 1
$o.a = 2;
say $old; # 1
(Note that .<> above could be .self or just <>.)
In the following method, Dafny reports that the postcondition might not hold, even though I am quite sure that it does.
method toArrayConvert(s:seq<int>) returns (a:array<int>)
requires |s| > 0
ensures |s| == a.Length
ensures forall i :: 0 <= i < a.Length ==> s[i] == a[i] // This is the postcondition that might not hold.
{
a := new int[|s|];
var i:int := 0;
while i < |s|
decreases |s| - i
invariant 0 <= i <= |s|
{
a[i] := s[i];
i := i + 1;
}
return a; // A postcondition might not hold on this return path.
}
Indeed, the postcondition does always hold, but Dafny cannot tell!
That's because you're missing a loop invariant annotation such as
invariant forall j :: 0 <= j < i ==> s[j] == a[j]
After adding that line to the loop, the method verifies.
For more explanation about why Dafny sometimes reports errors on correct programs, see the (brand new) FAQ. For more about loop invariants, see the corresponding section in the rise4fun guide.
I am new to dafny and am trying to get this simple piece of code to work. I want to count the occurrences of a char in a string. I am receiving an assertion violation on line 4. I know my function is finding the right amount of characters, but clearly there are some holes in this assertion. I'm trying to get the basics down before I start using pre and post conditions and what not, and this should be possible without them. The function simply checks the last character in the string and returns a 1 or 0, along with calling the function again which cuts off the tail of the string until it is empty.
method Main() {
var s:string := "hello world";
print tally(s, 'l');
assert tally(s,'l') == 3;
}
function method tally(s: string, letter: char): nat
{
if |s| == 0 then 0
else if s[|s|-1] == letter then 1+tally(s[..|s|-1], letter)
else 0 + tally(s[..|s|-1], letter)
}
http://rise4fun.com/Dafny/2lvt
Here is the link to my code.
It would be natural to think that the Dafny static verifier can
evaluate any code, like the expression in your assert statement. The
verifier does try to evaluate expressions like these where the
arguments are given as constants (like your "hello world", 'l',
and 3). However, the static verifier wants to avoid recursing
forever (or even recursing for too long), so it doesn't always fully
go through these expressions. In your case, there are also limits to
what the verifier is able to do with the sequence operations. So, in
short, although the verifier tries to be helpful, it does not always
get to the bottom of the recursions.
There are two ways you can work around these limits to get the
verifier to accept your assertion.
The most reliable way to debug the situation is to start with smaller
inputs and build up to the longer inputs you're using. This is quite
tedious, however, and it makes you appreciate when Dafny is able to do
these things automatically. The following (which verifies)
illustrates what you would do:
var s := "hello world";
assert tally("he",'l') == 0;
assert tally("hel",'l') == 1;
assert "hell"[..3] == "hel";
assert tally("hell",'l') == 2;
assert "hello"[..4] == "hell";
assert tally("hello",'l') == 2;
assert "hello "[..5] == "hello";
assert tally("hello ",'l') == 2;
assert "hello w"[..6] == "hello ";
assert tally("hello w",'l') == 2;
assert "hello wo"[..7] == "hello w";
assert tally("hello wo",'l') == 2;
assert "hello wor"[..8] == "hello wo";
assert tally("hello wor",'l') == 2;
assert "hello worl"[..9] == "hello wor";
assert tally("hello worl",'l') == 3;
assert s[..10] == "hello worl";
assert tally(s,'l') == 3;
In fact, the thing that the Dafny verifier does not expand (too many
times) for you are the "take" operations (that is, the expressions of
the form s[..E]). The following intermediate assertions will also
verify themselves and will help to verify the final assertion. These
intermediate assertions show what the verifier doesn't think to do
automatically for you.
var s := "hello world";
assert "he"[..1] == "h";
assert "hel"[..2] == "he";
assert "hell"[..3] == "hel";
assert "hello"[..4] == "hell";
assert "hello "[..5] == "hello";
assert "hello w"[..6] == "hello ";
assert "hello wo"[..7] == "hello w";
assert "hello wor"[..8] == "hello wo";
assert "hello worl"[..9] == "hello wor";
assert s[..10] == "hello worl";
assert tally(s,'l') == 3;
You might wonder, "how in the world would I come up with this?". The
most systematic way would be to start like in my first example above.
Then, you could try pruning the many assertions there to see what it
is the verifier needs.
(I'm now thinking that perhaps the Dafny verifier could be enhanced to
do these operations, too. It may cause performance problems
elsewhere. I shall take a look.)
The other way to work around the verifier's limits is to define
function tally in a different way, in particular avoiding the "take"
operations, which the verifier does not want to expand a lot. It is
not clear what to change to make the verifier happy in these
situations, or if that's even possible at all, so this workaround may
not be the best. Nevertheless, I tried the following definition of
tally and it makes your assertion go through:
function method tally'(s: string, letter: char): nat
{
tally_from(s, letter, 0)
}
function method tally_from(s: string, letter: char, start: nat): nat
requires start <= |s|
decreases |s| - start
{
if start == |s| then 0
else (if s[start] == letter then 1 else 0) + tally_from(s, letter, start+1)
}
Note that these definitions do not use any "take" operations. Here,
the verifier is happy to expand all the recursive calls until the
final answer is found.
Rustan
When normally using a for-in-loop, the counter (in this case number) is a constant in each iteration:
for number in 1...10 {
// do something
}
This means I cannot change number in the loop:
for number in 1...10 {
if number == 5 {
++number
}
}
// doesn't compile, since the prefix operator '++' can't be performed on the constant 'number'
Is there a way to declare number as a variable, without declaring it before the loop, or using a normal for-loop (with initialization, condition and increment)?
To understand why i can’t be mutable involves knowing what for…in is shorthand for. for i in 0..<10 is expanded by the compiler to the following:
var g = (0..<10).generate()
while let i = g.next() {
// use i
}
Every time around the loop, i is a freshly declared variable, the value of unwrapping the next result from calling next on the generator.
Now, that while can be written like this:
while var i = g.next() {
// here you _can_ increment i:
if i == 5 { ++i }
}
but of course, it wouldn’t help – g.next() is still going to generate a 5 next time around the loop. The increment in the body was pointless.
Presumably for this reason, for…in doesn’t support the same var syntax for declaring it’s loop counter – it would be very confusing if you didn’t realize how it worked.
(unlike with where, where you can see what is going on – the var functionality is occasionally useful, similarly to how func f(var i) can be).
If what you want is to skip certain iterations of the loop, your better bet (without resorting to C-style for or while) is to use a generator that skips the relevant values:
// iterate over every other integer
for i in 0.stride(to: 10, by: 2) { print(i) }
// skip a specific number
for i in (0..<10).filter({ $0 != 5 }) { print(i) }
let a = ["one","two","three","four"]
// ok so this one’s a bit convoluted...
let everyOther = a.enumerate().filter { $0.0 % 2 == 0 }.map { $0.1 }.lazy
for s in everyOther {
print(s)
}
The answer is "no", and that's a good thing. Otherwise, a grossly confusing behavior like this would be possible:
for number in 1...10 {
if number == 5 {
// This does not work
number = 5000
}
println(number)
}
Imagine the confusion of someone looking at the number 5000 in the output of a loop that is supposedly bound to a range of 1 though 10, inclusive.
Moreover, what would Swift pick as the next value of 5000? Should it stop? Should it continue to the next number in the range before the assignment? Should it throw an exception on out-of-range assignment? All three choices have some validity to them, so there is no clear winner.
To avoid situations like that, Swift designers made loop variables in range loops immutable.
Update Swift 5
for var i in 0...10 {
print(i)
i+=1
}