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:
ek
decreases-tofk
.- For each
i
where1 <= 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
x
andy
are integers, wherex > y >= 0
, thenx
decreases-toy
. - If
a
is a datatype (struct, tuple, or enum) andf
is one of its “potentially recursive” fields, thena
decreases-toa.f
.- For a datatype
X
, a field is considered “potentially recursive” if it either mentionsX
or a generic type parameter ofX
.
- For a datatype
- If
f
is aspec_fn
, thenf
decreases-tof(i)
. - If
s
is aSeq
, thens
decreases-tos[i]
. - If
s
is aSeq
, thens
decreases-tos.subrange(i, j)
if the given range is strictly smaller than0 .. s.len()
.axiom_seq_len_decreases
provides a more general axiom; it must be invoked explicitly.
- If
v
is aVec
, thenv
decreases-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.,
a
decreases_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)));
}