我试图证明以下引理。看起来确实很琐碎,但我无法证明这一点。预先谢谢你!
lemma test(x : seq<int>)
// if the values from x are margined by an interval
// the values are different
// and the number of values equals the size of the interval
// then all values from the interval appear in x
requires forall i :: 0 <= i < |x| ==>
0 <= x[i] < |x|;
requires forall i :: 0 <= i < |x| ==>
forall i' :: 0 <= i' < |x| && i != i' ==>
x[i] != x[i'];
ensures forall v :: 0 <= v < |x| ==>
exists i :: 0 <= i < |x| && x[i] == v;
{
}
答案 0 :(得分:1)
使用有关设置基数的一些事实,这是一种方法。
lemma test(x : seq<int>)
// if the values from x are margined by an interval
// the values are different
// and the number of values equals the size of the interval
// then all values from the interval appear in x
requires forall i :: 0 <= i < |x| ==>
0 <= x[i] < |x|;
requires forall i :: 0 <= i < |x| ==>
forall i' :: 0 <= i' < |x| && i != i' ==>
x[i] != x[i'];
ensures forall v :: 0 <= v < |x| ==> v in x
{
var L: set<int>, R: set<int> := {}, RangeSet(0, |x|);
var i := 0;
CardinalityRangeSet(0, |x|);
while i < |x|
invariant 0 <= i <= |x|
invariant L == set j | 0 <= j < i :: x[j]
invariant forall v | v in L :: v in x
invariant forall v | 0 <= v < |x| :: v in L || v in R
invariant |R| == |x| - i
{
L, R := L + {x[i]}, R - {x[i]};
i := i + 1;
}
}
predicate InRange(lo: int, hi: int, i: int)
{
lo <= i < hi
}
function RangeSet(lo: int, hi: int): set<int>
{
set i | lo <= i < hi && InRange(lo, hi, i)
}
lemma CardinalityRangeSet(lo: int, hi: int)
decreases hi - lo
ensures |RangeSet(lo, hi)| == if lo >= hi then 0 else hi - lo
{
if lo < hi {
assert RangeSet(lo, hi) == {lo} + RangeSet(lo + 1, hi);
CardinalityRangeSet(lo + 1, hi);
}
}
我使用Dafny语法v in x
略微更改了您的规范,该语法与您所写的相同,并且Dafny可以更轻松地进行推理。
证明的基本思想是从元素R
的范围0..|x|
开始,然后迭代地从x[i]
中删除元素R
并将其添加到{{ 1}}。这样就保持不变,即L
范围内的每个数字都在0..|x|
或L
中,而R
的基数在每次迭代中都减小。因此,在循环结束时R
为空,因此范围中的每个数字都必须在R
中,因此必须在L
中。
我还用归纳法证明的一个辅助引理来证明x
具有预期的大小。
(已编辑,以消除RangeSet
中的“找不到触发词条”警告。引入谓词RangeSet
可以触发它,但是您仍然需要在其中包含显式范围InRange
,因为否则无法确定集合是有限的。)