假设我们有一个序列 s,并且所有元素都与其他元素不同。我将这个属性描述如下
predicate all_element_different(s: seq<int>)
{
forall i,j :: 0 <= i < j < |s| ==> s[i] != s[j]
}
当然,另一种等价的方式是
forall i,j :: 0 <= i < |s| && 0 <= j < |s| && i != j ==> s[i] != s[j]
所以我在这里写一个引理
lemma different_properties(s: seq<int>)
requires all_element_different(s)
ensures forall i,j :: 0 <= i < |s| && 0 <= j < |s| && i != j ==> s[i] != s[j]
{
}
由于某种原因,我需要对这个序列进行排序,并且我想得到另一个新序列而不是直接修改旧序列。类似的东西
function insertionSort(s: seq<int>): (r: seq<int>)
ensures multiset(s) == multiset(r)
ensures sorted(r)
ensures forall x :: x in s ==> x in r
ensures |s| == |r|
忽略
insertionSort
的实现即可。无论如何,最后我们得到另一个序列r
,具有这样的属性:
var r := insertionSort(s);
assert multiset(s) == multiset(r);
assert |s| == |r|;
//assert sorted(r); This property is not used here
assert forall x :: x in s ==> x in r;
assert all_element_different(s);
显然,谓词
all_element_different(r)
应该成立,但我无法证明它。我尝试提取过程:
lemma sequence_properties(s: seq<int>, r: seq<int>)
requires multiset(s) == multiset(r)
requires |s| == |r|
requires all_element_different(s)
ensures all_element_different(r)
{
}
有人对这个引理的证明有一些想法吗?
下面的证明背后的想法如下
predicate UniqueElements(s: seq<int>)
{
forall i, j :: 0 <= i < j < |s| ==> s[i] != s[j]
}
lemma pigeonhole(m : int, n: int, f : int -> int)
requires 0 <= m < n
requires forall i :: 0 <= i < n ==> 0 <= f(i) < m
ensures exists j, k :: (0 <= j < k < n) && f(j) == f(k)
{
if m <= 0 {
assert 0 <= f(0) < 0;
}
else {
var i : int := 0;
while i < n
invariant forall k :: 0 <= k < i ==> 0 <= f(k) < m - 1
invariant i <= n
{
if f(i) == m-1 {
var j : int := i + 1;
while j < n
invariant forall k :: i < k < j ==> 0 <= f(k) < m - 1
{
if f(j) == m-1 { return; }
j := j + 1;
}
var g : int -> int := x => if x < i then f(x) else f(x+1);
pigeonhole(m-1, n-1, g);
return;
}
i := i + 1;
}
pigeonhole(m-1, n, f);
}
}
lemma UniqueMultiSet(s: seq<int>, r: seq<int>)
requires UniqueElements(s)
requires |s| == |r|
requires multiset(s) == multiset(r)
ensures UniqueElements(r)
{
assert |multiset(s)| == |multiset(r)|;
if !UniqueElements(r){
var m, n :| 0 <= m < n < |r| && r[m] == r[n];
forall idx | 0 <= idx < |s| ensures exists ridx :: 0 <= ridx < |r| && r[ridx] == s[idx]
{
assert s[idx] in multiset(r);
}
var f : int -> int :=
x => if 0 <= x < |s|
then
var idx :| 0 <= idx < |r| && r[idx] == s[x];
if idx < n then idx else if idx == n then m else idx - 1
else -1;
pigeonhole(|s|-1, |s|, f);
var k, l :| 0 <= k < l < |s| && f(k) == f(l);
assert s[k] == s[l];
}
}