0

Hi for teaching I am setting up a mass of simple dafny questions. Mostly going fine, but... Either I have missed some detail about loop invariants in Dafny or this is a weakness/bug?

method whS(a:int) returns ()
  {   var i:int := 0;
       while (i<a ) 
       decreases a-i     
       invariant i<= a
       {   assert i<= a;
            i:=i+1;
           assert i<= a;
       }  
   }  

The method fails to verify with error "invariant might not hold on entry" Yet with the invariant commented out the method verifies even with the assertions.

david streader
  • 589
  • 2
  • 7

2 Answers2

0

A good way to remember the answer to the question "when must the loop invariant be true?" in Dafny is "whenever the loop condition would be evaluated".

So the loop invariant needs to be true before the first iteration of the loop, even if the body would never execute, because the loop condition will be evaluated to determine whether to enter the loop at all. The invariant also needs to be true after the last iteration, because again, the loop condition will be evaluated to determine whether to execute another iteration.

In your example, if the argument a to the method is negative, then the loop invariant is false before the first time the loop condition is evaluated. An example of an invariant that would work for this loop would be something like a >= 0 ==> i <= a.

James Wilcox
  • 5,307
  • 16
  • 25
  • Trying to understand why dafny has made the design decision to check the loop invariant even when the loop is not entered. I assume that `if (g) { while (g) { b..}}` is observationally equivalent to `while (g) { b..}` hence it is not necessary to check the loop invariant when the loop is not entered. For me at least this design decision is counter intuitive and I know some student will ask me to explain. So is there some pragmatic reason for this design that I can not see? – david streader Aug 01 '21 at 20:06
0

many thanks James I can see that I misunderstood how dafny implemented loop invariants. Wrapping the while in an if statement now verifies and gives me the semantics that I thought while on its own had.

method whS(a:int) returns ()
  {   var i:int := 0;
       if (i<a) {
         while (i<a ) 
           decreases a-i     
           invariant i<= a 
          {  i:=i+1;
          }  
       }
   }

Thanks again james . I will avoid this mistake when I give my lecture on Tuesday.

david streader
  • 589
  • 2
  • 7