decreases_to!
The expression decreases_to!(e1, e2, …, en => f1, f2, …, fn) is a bool indicating
if the left-hand sequence
e1, e2, …, en
lexicographically-decreases-to
the right-hand sequence
f1, f2, …, fn
The lexicographic-decreases-to
is used to check the decreases measure for spec functions.
See this tutorial chapter for an introductory discussion of lexicographic-decreases.
Definition
We say that
e1, e2, …, en
lexicographically-decreases-to
f1, f2, …, fn
if there exists a k where 1 <= k <= n such that:
ekdecreases-tofk.- For each
iwhere1 <= i < k,ei == fi.
The decreases-to relation is a partial order on all values; values of different types are comparable. The relation permits, but is not necessarily limited to:
- If
xandyare integers, wherex > y >= 0, thenxdecreases-toy. - If
ais a datatype (struct, tuple, or enum) andfis one of its “potentially recursive” fields, thenadecreases-toa.f.- For a datatype
X, a field is considered “potentially recursive” if it either mentionsXor a generic type parameter ofX.
- For a datatype
- If
fis aspec_fn, thenfdecreases-tof(i). - If
sis aSeq, thensdecreases-tos[i]. - If
sis aSeq, thensdecreases-tos.subrange(i, j)if the given range is strictly smaller than0 .. s.len().axiom_seq_len_decreasesprovides a more general axiom; it must be invoked explicitly.
- If
vis aVec, thenvdecreases-tov@.
These axioms are triggered when the relevant expression (e.g., x.f, x->f, s[i], v@) is used as part of a decreases-to expression.
Notes
-
Tuples are not compared lexicographically; tuples are datatypes, which are compared as explained above, e.g.,
adecreases_toa.0. Only the “top level” sequences in adecreases_to!expression are compared lexicographically. -
Sequences are not compared on
len()alone. However, you can always uses.len()as a decreases-measure instead ofs.
Examples
proof fn example_decreases_to(s: Seq<int>)
requires s.len() == 5
{
assert(decreases_to!(8int => 4int));
// fails: can't decrease to negative number
// assert(decreases_to!(8 => -2));
// Comma-separated elements are treated lexicographically:
assert(decreases_to!(12int, 8int, 1int => 12int, 4int, 50000int));
// Datatypes decrease-to their fields:
let x = Some(8int);
assert(decreases_to!(x => x->0));
let y = (true, false);
assert(decreases_to!(y => y.0));
// fails: tuples are not treated lexicographically
// assert(decreases_to!((20, 9) => (11, 15)));
// sequence decreases-to an element of the sequence
assert(decreases_to!(s => s[2]));
// sequence decreases-to a subrange of the sequence
assert(decreases_to!(s => s.subrange(1, 3)));
}