In the "Draft Dafny Reference Manual" 4.0.2 it describes defining decreases clauses for mutually recursive functions but where the variables decreasing in both functions are of the type nat. I have tried to do the same thing but it has not worked. One difference is that the variables are not of the same type.
datatype Trie = Trie(letters : map<char,Trie>, word : bool)
function size(t:Trie) :(r:nat)
decreases t
{
1 + sum_setT(t.letters.Values)
}
function sum_setT(xs: set<Trie>) : (z:nat)
decreases xs
{
var working := xs; //Needed!
if (|working| == 0) then 0
else (
var x:Trie :| x in working;
var sofar:nat := sum_setT(working-{x});
sofar + size(x)
)
}
Any idea how to define the decreases clause much appreciated.
If two functions (possibly the same function) call each other recursively, then each call needs to be shown to decrease the termination metric given by the
decreasesfunctions. More precisely, if on entry to a functionF, thedecreasesclause ofFevaluates toX, and whenFcalls functionGat a time whenG'sdecreasesclause evaluates toY, thenXmust be shown to exceedY.The "exceeds" relation is a built-in well-founded order, but you have control over the
decreasesclauses that give rise to the valuesXandY. In your example, the easiest way to define these is to use lexicographic tuples. In the "outer" function,size, uset. In the "inner" function,sum_setT, uset, xsfor the samet. To get this to work out, you'll need to addtas a parameter tosum_setTas well.In the call from
sizetosum_setT,XandYaretandt, t.letters.Values, which is smaller because the built-in well-founded order in Dafny considers shorterdecreasestuples to be larger.In the recursive call of
sum_setT,XandYhave the same first component (t) and the set is strictly smaller inY.In the call from
sum_setTback tosize, the valuexis structurally included int, sotexceedsxas required. For the verifier to know this fact (that is, for it to know that parameterxshas some relation tot), you'll need to add a precondition tosum_setT.So, the final program is