Basically, my target is to learn dafny basics. But I am confused about invariant and decreases. In this code, my first while loop decreases by one so I have set decreases b but in my inner loop it is divided by 10, so when I was trying to set up b%10 as a decreases value, it always showed me an error. here I need some expert suggestions. What will be the decreases value for the second while loop in this code in this code invariant and decreases values are right?
method MultiplyTheory(N: int, M: nat) returns (Res: int)
ensures Res == M*N;
requires N>=0 && M>=0;
{
var a := N;
var b := M;
var x := 0;
var i :=0;
while (b > 0)
invariant M * N == a * b + x
decreases b
{
while (b % 10 != 0)
invariant M * N == a * b + x
decreases ?? // what will be the value here ??
{
x := x + a;
b := b - 1;
}
a := 10 * a;
b := b / 10;
}
Res := x;
}
Here is a verification debugging technique: you should first write the assertion that, if proven, would make your previous failing assertions to verify. Since you have two errors, one on the postcondition, and one on the outer decrease clause, here are two assertions you could insert.
If you want to see the solution, skip the steps and go to the end of this post.
Steps to solution
Now you see the two errors are on these assert. It's time to "move the asserts up" by applying weakest precondition rules. That means we keep the assert, but we write assert before their preceding statement such that, if these new assertions held, the old assertions would be verified:
See in your IDE how the error is now on the two most recent asserts. Let's consider the second assert
x == M * N;. Why is it wrong? There is an invariant that saysM * N == a * b + x. So, ifx == M * N;, it probably means thatbshould be equal to zero. However, when we exit the while loop, we only know the negation of the guard, which is!(b > 0), orb <= 0. That's why we could not conclude! Since we never intended b to be non-positive, we either need to add theinvariant b >= 0to the outer loop, or simply change the guard tob != 0- but if you do that, then it will complain that withdecreases b,bis not bounded by zero anymore. So the invariant is better.Now the invariant
b >= 0might not be maintained by the loop. This is because the inner while loop modifiesband does not give invariant on the value ofb. Of course, we wantb >= 0. So we add the invariant in the inner loop.Ok, now the only assertion remaining is
assert b / 10 < oldB;Note that you don't need to writedecreasesin the inner clause because the defaultdecreasesforE > 0is inferred to bedecreases E, and in this case, Dafny can prove thatb % 10decreases. However, knowing thatb%10 == 0at the end is not useful to prove thatbitself decreased. Ifbwas 7, it could be that the inner loop was increasingbto 10 before exiting...The most basic strategy would be to convert the assertion
b / 10 < oldBas an invariant. If you add it like that, everything verifies!Solution
Now, you can experiment a bit about other invariant and observe that the following clauses would solve this last problem as well:
invariant b <= oldBdecreases bTake some time to remove the asserts now because they were only used for scaffolding, but keep the invariant :-)