#[allow(unused_imports)]
use super::multiset::Multiset;
#[allow(unused_imports)]
use super::pervasive::*;
#[allow(unused_imports)]
use super::prelude::*;
#[allow(unused_imports)]
use super::relations::*;
#[allow(unused_imports)]
use super::seq::*;
#[allow(unused_imports)]
use super::set::Set;
#[cfg(verus_keep_ghost)]
use super::set_lib::lemma_set_properties;
verus! {
broadcast use group_seq_axioms;
impl<A> Seq<A> {
pub open spec fn map<B>(self, f: spec_fn(int, A) -> B) -> Seq<B> {
Seq::new(self.len(), |i: int| f(i, self[i]))
}
pub open spec fn map_values<B>(self, f: spec_fn(A) -> B) -> Seq<B> {
Seq::new(self.len(), |i: int| f(self[i]))
}
pub open spec fn is_prefix_of(self, other: Self) -> bool {
self.len() <= other.len() && self =~= other.subrange(0, self.len() as int)
}
pub open spec fn is_suffix_of(self, other: Self) -> bool {
self.len() <= other.len() && self =~= other.subrange(
(other.len() - self.len()) as int,
other.len() as int,
)
}
pub closed spec fn sort_by(self, leq: spec_fn(A, A) -> bool) -> Seq<A>
recommends
total_ordering(leq),
decreases self.len(),
{
if self.len() <= 1 {
self
} else {
let split_index = self.len() / 2;
let left = self.subrange(0, split_index as int);
let right = self.subrange(split_index as int, self.len() as int);
let left_sorted = left.sort_by(leq);
let right_sorted = right.sort_by(leq);
merge_sorted_with(left_sorted, right_sorted, leq)
}
}
pub proof fn lemma_sort_by_ensures(self, leq: spec_fn(A, A) -> bool)
requires
total_ordering(leq),
ensures
self.to_multiset() =~= self.sort_by(leq).to_multiset(),
sorted_by(self.sort_by(leq), leq),
forall|x: A| !self.contains(x) ==> !(#[trigger] self.sort_by(leq).contains(x)),
decreases self.len(),
{
if self.len() <= 1 {
} else {
let split_index = self.len() / 2;
let left = self.subrange(0, split_index as int);
let right = self.subrange(split_index as int, self.len() as int);
assert(self =~= left + right);
let left_sorted = left.sort_by(leq);
left.lemma_sort_by_ensures(leq);
let right_sorted = right.sort_by(leq);
right.lemma_sort_by_ensures(leq);
lemma_merge_sorted_with_ensures(left_sorted, right_sorted, leq);
lemma_multiset_commutative(left, right);
lemma_multiset_commutative(left_sorted, right_sorted);
assert forall|x: A| !self.contains(x) implies !(#[trigger] self.sort_by(leq).contains(
x,
)) by {
self.to_multiset_ensures();
self.sort_by(leq).to_multiset_ensures();
assert(!self.contains(x) ==> self.to_multiset().count(x) == 0);
}
}
}
#[verifier::opaque]
pub open spec fn filter(self, pred: spec_fn(A) -> bool) -> Self
decreases self.len(),
{
if self.len() == 0 {
self
} else {
let subseq = self.drop_last().filter(pred);
if pred(self.last()) {
subseq.push(self.last())
} else {
subseq
}
}
}
pub broadcast proof fn filter_lemma(self, pred: spec_fn(A) -> bool)
ensures
forall|i: int|
0 <= i < self.filter(pred).len() ==> pred(#[trigger] self.filter(pred)[i]),
forall|i: int|
0 <= i < self.len() && pred(self[i]) ==> #[trigger] self.filter(pred).contains(
self[i],
),
#[trigger] self.filter(pred).len() <= self.len(),
decreases self.len(),
{
reveal(Seq::filter);
let out = self.filter(pred);
if 0 < self.len() {
self.drop_last().filter_lemma(pred);
assert forall|i: int| 0 <= i < out.len() implies pred(out[i]) by {
if i < out.len() - 1 {
assert(self.drop_last().filter(pred)[i] == out.drop_last()[i]); assert(pred(out[i])); }
}
assert forall|i: int|
0 <= i < self.len() && pred(self[i]) implies #[trigger] out.contains(self[i]) by {
if i == self.len() - 1 {
assert(self[i] == out[out.len() - 1]); } else {
let subseq = self.drop_last().filter(pred);
assert(subseq.contains(self.drop_last()[i])); let j = choose|j| 0 <= j < subseq.len() && subseq[j] == self[i];
assert(out[j] == self[i]); }
}
}
}
pub broadcast proof fn filter_distributes_over_add(a: Self, b: Self, pred: spec_fn(A) -> bool)
ensures
#[trigger] (a + b).filter(pred) == a.filter(pred) + b.filter(pred),
decreases b.len(),
{
reveal(Seq::filter);
if 0 < b.len() {
Self::drop_last_distributes_over_add(a, b);
Self::filter_distributes_over_add(a, b.drop_last(), pred);
if pred(b.last()) {
Self::push_distributes_over_add(
a.filter(pred),
b.drop_last().filter(pred),
b.last(),
);
}
} else {
Self::add_empty_right(a, b);
Self::add_empty_right(a.filter(pred), b.filter(pred));
}
}
pub broadcast proof fn add_empty_left(a: Self, b: Self)
requires
a.len() == 0,
ensures
#[trigger] (a + b) == b,
{
assert(a + b =~= b);
}
pub broadcast proof fn add_empty_right(a: Self, b: Self)
requires
b.len() == 0,
ensures
#[trigger] (a + b) == a,
{
assert(a + b =~= a);
}
pub broadcast proof fn push_distributes_over_add(a: Self, b: Self, elt: A)
ensures
#[trigger] (a + b).push(elt) == a + b.push(elt),
{
assert((a + b).push(elt) =~= a + b.push(elt));
}
pub open spec fn max_via(self, leq: spec_fn(A, A) -> bool) -> A
recommends
self.len() > 0,
decreases self.len(),
{
if self.len() > 1 {
if leq(self[0], self.subrange(1, self.len() as int).max_via(leq)) {
self.subrange(1, self.len() as int).max_via(leq)
} else {
self[0]
}
} else {
self[0]
}
}
pub open spec fn min_via(self, leq: spec_fn(A, A) -> bool) -> A
recommends
self.len() > 0,
decreases self.len(),
{
if self.len() > 1 {
let subseq = self.subrange(1, self.len() as int);
let elt = subseq.min_via(leq);
if leq(elt, self[0]) {
elt
} else {
self[0]
}
} else {
self[0]
}
}
pub open spec fn contains(self, needle: A) -> bool {
exists|i: int| 0 <= i < self.len() && self[i] == needle
}
pub open spec fn index_of(self, needle: A) -> int {
choose|i: int| 0 <= i < self.len() && self[i] == needle
}
pub closed spec fn index_of_first(self, needle: A) -> (result: Option<int>) {
if self.contains(needle) {
Some(self.first_index_helper(needle))
} else {
None
}
}
spec fn first_index_helper(self, needle: A) -> int
recommends
self.contains(needle),
decreases self.len(),
{
if self.len() <= 0 {
-1 } else if self[0] == needle {
0
} else {
1 + self.subrange(1, self.len() as int).first_index_helper(needle)
}
}
pub proof fn index_of_first_ensures(self, needle: A)
ensures
match self.index_of_first(needle) {
Some(index) => {
&&& self.contains(needle)
&&& 0 <= index < self.len()
&&& self[index] == needle
&&& forall|j: int| 0 <= j < index < self.len() ==> self[j] != needle
},
None => { !self.contains(needle) },
},
decreases self.len(),
{
if self.contains(needle) {
let index = self.index_of_first(needle).unwrap();
if self.len() <= 0 {
} else if self[0] == needle {
} else {
assert(Seq::empty().push(self.first()).add(self.drop_first()) =~= self);
self.drop_first().index_of_first_ensures(needle);
}
}
}
pub closed spec fn index_of_last(self, needle: A) -> Option<int> {
if self.contains(needle) {
Some(self.last_index_helper(needle))
} else {
None
}
}
spec fn last_index_helper(self, needle: A) -> int
recommends
self.contains(needle),
decreases self.len(),
{
if self.len() <= 0 {
-1 } else if self.last() == needle {
self.len() - 1
} else {
self.drop_last().last_index_helper(needle)
}
}
pub proof fn index_of_last_ensures(self, needle: A)
ensures
match self.index_of_last(needle) {
Some(index) => {
&&& self.contains(needle)
&&& 0 <= index < self.len()
&&& self[index] == needle
&&& forall|j: int| 0 <= index < j < self.len() ==> self[j] != needle
},
None => { !self.contains(needle) },
},
decreases self.len(),
{
if self.contains(needle) {
let index = self.index_of_last(needle).unwrap();
if self.len() <= 0 {
} else if self.last() == needle {
} else {
assert(self.drop_last().push(self.last()) =~= self);
self.drop_last().index_of_last_ensures(needle);
}
}
}
pub open spec fn drop_last(self) -> Seq<A>
recommends
self.len() >= 1,
{
self.subrange(0, self.len() as int - 1)
}
pub proof fn drop_last_distributes_over_add(a: Self, b: Self)
requires
0 < b.len(),
ensures
(a + b).drop_last() == a + b.drop_last(),
{
assert_seqs_equal!((a+b).drop_last(), a+b.drop_last());
}
pub open spec fn drop_first(self) -> Seq<A>
recommends
self.len() >= 1,
{
self.subrange(1, self.len() as int)
}
pub open spec fn no_duplicates(self) -> bool {
forall|i, j| (0 <= i < self.len() && 0 <= j < self.len() && i != j) ==> self[i] != self[j]
}
pub open spec fn disjoint(self, other: Self) -> bool {
forall|i: int, j: int| 0 <= i < self.len() && 0 <= j < other.len() ==> self[i] != other[j]
}
pub open spec fn to_set(self) -> Set<A> {
Set::new(|a: A| self.contains(a))
}
pub closed spec fn to_multiset(self) -> Multiset<A>
decreases self.len(),
{
if self.len() == 0 {
Multiset::<A>::empty()
} else {
Multiset::<A>::empty().insert(self.first()).add(self.drop_first().to_multiset())
}
}
pub proof fn to_multiset_ensures(self)
ensures
forall|a: A| #[trigger] (self.push(a).to_multiset()) =~= self.to_multiset().insert(a),
forall|i: int|
0 <= i < self.len() ==> #[trigger] (self.remove(i).to_multiset())
=~= self.to_multiset().remove(self[i]),
self.len() == self.to_multiset().len(),
forall|a: A| self.contains(a) <==> #[trigger] self.to_multiset().count(a) > 0,
{
assert forall|a: A| #[trigger]
(self.push(a).to_multiset()) =~= self.to_multiset().insert(a) by {
to_multiset_build(self, a);
}
assert forall|i: int| 0 <= i < self.len() implies #[trigger] (self.remove(i).to_multiset())
=~= self.to_multiset().remove(self[i]) by {
to_multiset_remove(self, i);
}
to_multiset_len(self);
assert forall|a: A| self.contains(a) <==> #[trigger] self.to_multiset().count(a) > 0 by {
to_multiset_contains(self, a);
}
}
pub open spec fn insert(self, i: int, a: A) -> Seq<A>
recommends
0 <= i <= self.len(),
{
self.subrange(0, i).push(a) + self.subrange(i, self.len() as int)
}
pub proof fn insert_ensures(self, pos: int, elt: A)
requires
0 <= pos <= self.len(),
ensures
self.insert(pos, elt).len() == self.len() + 1,
forall|i: int| 0 <= i < pos ==> #[trigger] self.insert(pos, elt)[i] == self[i],
forall|i: int| pos <= i < self.len() ==> self.insert(pos, elt)[i + 1] == self[i],
self.insert(pos, elt)[pos] == elt,
{
}
pub open spec fn remove(self, i: int) -> Seq<A>
recommends
0 <= i < self.len(),
{
self.subrange(0, i) + self.subrange(i + 1, self.len() as int)
}
pub proof fn remove_ensures(self, i: int)
requires
0 <= i < self.len(),
ensures
self.remove(i).len() == self.len() - 1,
forall|index: int| 0 <= index < i ==> #[trigger] self.remove(i)[index] == self[index],
forall|index: int|
i <= index < self.len() - 1 ==> #[trigger] self.remove(i)[index] == self[index + 1],
{
}
pub open spec fn remove_value(self, val: A) -> Seq<A> {
let index = self.index_of_first(val);
match index {
Some(i) => self.remove(i),
None => self,
}
}
pub open spec fn reverse(self) -> Seq<A>
decreases self.len(),
{
if self.len() == 0 {
Seq::empty()
} else {
Seq::new(self.len(), |i: int| self[self.len() - 1 - i])
}
}
pub open spec fn zip_with<B>(self, other: Seq<B>) -> Seq<(A, B)>
recommends
self.len() == other.len(),
decreases self.len(),
{
if self.len() != other.len() {
Seq::empty()
} else if self.len() == 0 {
Seq::empty()
} else {
Seq::new(self.len(), |i: int| (self[i], other[i]))
}
}
pub open spec fn fold_left<B>(self, b: B, f: spec_fn(B, A) -> B) -> (res: B)
decreases self.len(),
{
if self.len() == 0 {
b
} else {
f(self.drop_last().fold_left(b, f), self.last())
}
}
pub open spec fn fold_left_alt<B>(self, b: B, f: spec_fn(B, A) -> B) -> (res: B)
decreases self.len(),
{
if self.len() == 0 {
b
} else {
self.subrange(1, self.len() as int).fold_left_alt(f(b, self[0]), f)
}
}
proof fn aux_lemma_fold_left_alt<B>(self, b: B, f: spec_fn(B, A) -> B, k: int)
requires
0 < k <= self.len(),
ensures
self.subrange(k, self.len() as int).fold_left_alt(
self.subrange(0, k).fold_left_alt(b, f),
f,
) == self.fold_left_alt(b, f),
decreases k,
{
reveal_with_fuel(Seq::fold_left_alt, 2);
if k == 1 {
} else {
self.subrange(1, self.len() as int).aux_lemma_fold_left_alt(f(b, self[0]), f, k - 1);
assert_seqs_equal!(
self.subrange(1, self.len() as int)
.subrange(k - 1, self.subrange(1, self.len() as int).len() as int) ==
self.subrange(k, self.len() as int)
);
assert_seqs_equal!(
self.subrange(1, self.len() as int).subrange(0, k - 1) ==
self.subrange(1, k)
);
assert_seqs_equal!(
self.subrange(0, k).subrange(1, self.subrange(0, k).len() as int) ==
self.subrange(1, k)
);
}
}
pub proof fn lemma_fold_left_alt<B>(self, b: B, f: spec_fn(B, A) -> B)
ensures
self.fold_left(b, f) == self.fold_left_alt(b, f),
decreases self.len(),
{
reveal_with_fuel(Seq::fold_left, 2);
reveal_with_fuel(Seq::fold_left_alt, 2);
if self.len() <= 1 {
} else {
self.aux_lemma_fold_left_alt(b, f, self.len() - 1);
self.subrange(self.len() - 1, self.len() as int).lemma_fold_left_alt(
self.drop_last().fold_left_alt(b, f),
f,
);
self.subrange(0, self.len() - 1).lemma_fold_left_alt(b, f);
}
}
pub open spec fn fold_right<B>(self, f: spec_fn(A, B) -> B, b: B) -> (res: B)
decreases self.len(),
{
if self.len() == 0 {
b
} else {
self.drop_last().fold_right(f, f(self.last(), b))
}
}
pub open spec fn fold_right_alt<B>(self, f: spec_fn(A, B) -> B, b: B) -> (res: B)
decreases self.len(),
{
if self.len() == 0 {
b
} else {
f(self[0], self.subrange(1, self.len() as int).fold_right_alt(f, b))
}
}
pub proof fn lemma_fold_right_split<B>(self, f: spec_fn(A, B) -> B, b: B, k: int)
requires
0 <= k <= self.len(),
ensures
self.subrange(0, k).fold_right(f, self.subrange(k, self.len() as int).fold_right(f, b))
== self.fold_right(f, b),
decreases self.len(),
{
reveal_with_fuel(Seq::fold_right, 2);
if k == self.len() {
assert(self.subrange(0, k) == self);
} else if k == self.len() - 1 {
} else {
self.subrange(0, self.len() - 1).lemma_fold_right_split(f, f(self.last(), b), k);
assert_seqs_equal!(
self.subrange(0, self.len() - 1).subrange(0, k) ==
self.subrange(0, k)
);
assert_seqs_equal!(
self.subrange(0, self.len() - 1).subrange(k, self.subrange(0, self.len() - 1).len() as int) ==
self.subrange(k, self.len() - 1)
);
assert_seqs_equal!(
self.subrange(k, self.len() as int).drop_last() ==
self.subrange(k, self.len() - 1)
);
}
}
pub proof fn lemma_fold_right_commute_one<B>(self, a: A, f: spec_fn(A, B) -> B, v: B)
requires
commutative_foldr(f),
ensures
self.fold_right(f, f(a, v)) == f(a, self.fold_right(f, v)),
decreases self.len(),
{
if self.len() > 0 {
self.drop_last().lemma_fold_right_commute_one(a, f, f(self.last(), v));
}
}
pub proof fn lemma_fold_right_alt<B>(self, f: spec_fn(A, B) -> B, b: B)
ensures
self.fold_right(f, b) == self.fold_right_alt(f, b),
decreases self.len(),
{
reveal_with_fuel(Seq::fold_right, 2);
reveal_with_fuel(Seq::fold_right_alt, 2);
if self.len() <= 1 {
} else {
self.subrange(1, self.len() as int).lemma_fold_right_alt(f, b);
self.lemma_fold_right_split(f, b, 1);
}
}
pub proof fn lemma_multiset_has_no_duplicates(self)
requires
self.no_duplicates(),
ensures
forall|x: A| self.to_multiset().contains(x) ==> self.to_multiset().count(x) == 1,
decreases self.len(),
{
broadcast use super::multiset::group_multiset_axioms;
if self.len() == 0 {
assert(forall|x: A|
self.to_multiset().contains(x) ==> self.to_multiset().count(x) == 1);
} else {
lemma_seq_properties::<A>();
assert(self.drop_last().push(self.last()) =~= self);
self.drop_last().lemma_multiset_has_no_duplicates();
}
}
pub proof fn lemma_multiset_has_no_duplicates_conv(self)
requires
forall|x: A| self.to_multiset().contains(x) ==> self.to_multiset().count(x) == 1,
ensures
self.no_duplicates(),
{
broadcast use super::multiset::group_multiset_axioms;
assert forall|i, j| (0 <= i < self.len() && 0 <= j < self.len() && i != j) implies self[i]
!= self[j] by {
let mut a = if (i < j) {
i
} else {
j
};
let mut b = if (i < j) {
j
} else {
i
};
if (self[a] == self[b]) {
let s0 = self.subrange(0, b);
let s1 = self.subrange(b, self.len() as int);
assert(self == s0 + s1);
s0.to_multiset_ensures();
s1.to_multiset_ensures();
lemma_multiset_commutative(s0, s1);
assert(self.to_multiset().count(self[a]) >= 2);
}
}
}
pub proof fn lemma_add_last_back(self)
requires
0 < self.len(),
ensures
#[trigger] self.drop_last().push(self.last()) =~= self,
{
}
pub proof fn lemma_indexing_implies_membership(self, f: spec_fn(A) -> bool)
requires
forall|i: int| 0 <= i < self.len() ==> #[trigger] f(#[trigger] self[i]),
ensures
forall|x: A| #[trigger] self.contains(x) ==> #[trigger] f(x),
{
assert(forall|i: int| 0 <= i < self.len() ==> #[trigger] self.contains(self[i]));
}
pub proof fn lemma_membership_implies_indexing(self, f: spec_fn(A) -> bool)
requires
forall|x: A| #[trigger] self.contains(x) ==> #[trigger] f(x),
ensures
forall|i: int| 0 <= i < self.len() ==> #[trigger] f(self[i]),
{
assert forall|i: int| 0 <= i < self.len() implies #[trigger] f(self[i]) by {
assert(self.contains(self[i]));
}
}
pub proof fn lemma_split_at(self, pos: int)
requires
0 <= pos <= self.len(),
ensures
self.subrange(0, pos) + self.subrange(pos, self.len() as int) =~= self,
{
}
pub proof fn lemma_element_from_slice(self, new: Seq<A>, a: int, b: int, pos: int)
requires
0 <= a <= b <= self.len(),
new == self.subrange(a, b),
a <= pos < b,
ensures
pos - a < new.len(),
new[pos - a] == self[pos],
{
}
pub proof fn lemma_slice_of_slice(self, s1: int, e1: int, s2: int, e2: int)
requires
0 <= s1 <= e1 <= self.len(),
0 <= s2 <= e2 <= e1 - s1,
ensures
self.subrange(s1, e1).subrange(s2, e2) =~= self.subrange(s1 + s2, s1 + e2),
{
}
pub proof fn unique_seq_to_set(self)
requires
self.no_duplicates(),
ensures
self.len() == self.to_set().len(),
decreases self.len(),
{
broadcast use super::set::group_set_axioms;
seq_to_set_equal_rec::<A>(self);
if self.len() == 0 {
} else {
let rest = self.drop_last();
rest.unique_seq_to_set();
seq_to_set_equal_rec::<A>(rest);
seq_to_set_rec_is_finite::<A>(rest);
assert(!seq_to_set_rec(rest).contains(self.last()));
assert(seq_to_set_rec(rest).insert(self.last()).len() == seq_to_set_rec(rest).len()
+ 1);
}
}
pub proof fn lemma_cardinality_of_set(self)
ensures
self.to_set().len() <= self.len(),
decreases self.len(),
{
broadcast use super::set::group_set_axioms, seq_to_set_is_finite;
lemma_seq_properties::<A>();
lemma_set_properties::<A>();
if self.len() == 0 {
} else {
assert(self.drop_last().to_set().insert(self.last()) =~= self.to_set());
self.drop_last().lemma_cardinality_of_set();
}
}
pub proof fn lemma_cardinality_of_empty_set_is_0(self)
ensures
self.to_set().len() == 0 <==> self.len() == 0,
{
broadcast use super::set::group_set_axioms, seq_to_set_is_finite;
assert(self.len() == 0 ==> self.to_set().len() == 0) by { self.lemma_cardinality_of_set() }
assert(!(self.len() == 0) ==> !(self.to_set().len() == 0)) by {
if self.len() > 0 {
assert(self.to_set().contains(self[0]));
assert(self.to_set().remove(self[0]).len() <= self.to_set().len());
}
}
}
pub proof fn lemma_no_dup_set_cardinality(self)
requires
self.to_set().len() == self.len(),
ensures
self.no_duplicates(),
decreases self.len(),
{
broadcast use super::set::group_set_axioms, seq_to_set_is_finite;
lemma_seq_properties::<A>();
if self.len() == 0 {
} else {
assert(self =~= Seq::empty().push(self.first()).add(self.drop_first()));
if self.drop_first().contains(self.first()) {
assert(self.to_set() =~= self.drop_first().to_set());
assert(self.to_set().len() <= self.drop_first().len()) by {
self.drop_first().lemma_cardinality_of_set()
}
} else {
assert(self.to_set().len() == 1 + self.drop_first().to_set().len()) by {
assert(self.drop_first().to_set().insert(self.first()) =~= self.to_set());
}
self.drop_first().lemma_no_dup_set_cardinality();
}
}
}
}
impl<A, B> Seq<(A, B)> {
pub closed spec fn unzip(self) -> (Seq<A>, Seq<B>) {
(Seq::new(self.len(), |i: int| self[i].0), Seq::new(self.len(), |i: int| self[i].1))
}
pub proof fn unzip_ensures(self)
ensures
self.unzip().0.len() == self.unzip().1.len(),
self.unzip().0.len() == self.len(),
self.unzip().1.len() == self.len(),
forall|i: int|
0 <= i < self.len() ==> (#[trigger] self.unzip().0[i], #[trigger] self.unzip().1[i])
== self[i],
decreases self.len(),
{
if self.len() > 0 {
self.drop_last().unzip_ensures();
}
}
pub proof fn lemma_zip_of_unzip(self)
ensures
self.unzip().0.zip_with(self.unzip().1) =~= self,
{
}
}
impl<A> Seq<Seq<A>> {
pub open spec fn flatten(self) -> Seq<A>
decreases self.len(),
{
if self.len() == 0 {
Seq::empty()
} else {
self.first().add(self.drop_first().flatten())
}
}
pub open spec fn flatten_alt(self) -> Seq<A>
decreases self.len(),
{
if self.len() == 0 {
Seq::empty()
} else {
self.drop_last().flatten_alt().add(self.last())
}
}
pub proof fn lemma_flatten_one_element(self)
ensures
self.len() == 1 ==> self.flatten() == self.first(),
{
broadcast use Seq::add_empty_right;
if self.len() == 1 {
assert(self.flatten() =~= self.first().add(self.drop_first().flatten()));
}
}
pub proof fn lemma_flatten_length_ge_single_element_length(self, i: int)
requires
0 <= i < self.len(),
ensures
self.flatten_alt().len() >= self[i].len(),
decreases self.len(),
{
if self.len() == 1 {
self.lemma_flatten_one_element();
self.lemma_flatten_and_flatten_alt_are_equivalent();
} else if i < self.len() - 1 {
self.drop_last().lemma_flatten_length_ge_single_element_length(i);
} else {
assert(self.flatten_alt() == self.drop_last().flatten_alt().add(self.last()));
}
}
pub proof fn lemma_flatten_length_le_mul(self, j: int)
requires
forall|i: int| 0 <= i < self.len() ==> (#[trigger] self[i]).len() <= j,
ensures
self.flatten_alt().len() <= self.len() * j,
decreases self.len(),
{
lemma_seq_properties::<A>();
lemma_seq_properties::<Seq<A>>();
if self.len() == 0 {
} else {
self.drop_last().lemma_flatten_length_le_mul(j);
assert((self.len() - 1) * j == (self.len() * j) - (1 * j)) by (nonlinear_arith); }
}
pub proof fn lemma_flatten_and_flatten_alt_are_equivalent(self)
ensures
self.flatten() =~= self.flatten_alt(),
decreases self.len(),
{
broadcast use Seq::add_empty_right, Seq::push_distributes_over_add;
if self.len() != 0 {
self.drop_last().lemma_flatten_and_flatten_alt_are_equivalent();
seq![self.last()].lemma_flatten_one_element();
assert(seq![self.last()].flatten() == self.last());
lemma_flatten_concat(self.drop_last(), seq![self.last()]);
assert((self.drop_last() + seq![self.last()]).flatten() == self.drop_last().flatten()
+ self.last());
assert(self.drop_last() + seq![self.last()] =~= self);
assert(self.flatten_alt() == self.drop_last().flatten_alt() + self.last());
}
}
}
impl Seq<int> {
pub open spec fn max(self) -> int
recommends
0 < self.len(),
decreases self.len(),
{
if self.len() == 1 {
self[0]
} else if self.len() == 0 {
0
} else {
let later_max = self.drop_first().max();
if self[0] >= later_max {
self[0]
} else {
later_max
}
}
}
pub proof fn max_ensures(self)
ensures
forall|x: int| self.contains(x) ==> x <= self.max(),
forall|i: int| 0 <= i < self.len() ==> self[i] <= self.max(),
self.len() == 0 || self.contains(self.max()),
decreases self.len(),
{
if self.len() <= 1 {
} else {
let elt = self.drop_first().max();
assert(self.drop_first().contains(elt)) by { self.drop_first().max_ensures() }
assert forall|i: int| 0 <= i < self.len() implies self[i] <= self.max() by {
assert(i == 0 || self[i] == self.drop_first()[i - 1]);
assert(forall|j: int|
0 <= j < self.drop_first().len() ==> self.drop_first()[j]
<= self.drop_first().max()) by { self.drop_first().max_ensures() }
}
}
}
pub open spec fn min(self) -> int
recommends
0 < self.len(),
decreases self.len(),
{
if self.len() == 1 {
self[0]
} else if self.len() == 0 {
0
} else {
let later_min = self.drop_first().min();
if self[0] <= later_min {
self[0]
} else {
later_min
}
}
}
pub proof fn min_ensures(self)
ensures
forall|x: int| self.contains(x) ==> self.min() <= x,
forall|i: int| 0 <= i < self.len() ==> self.min() <= self[i],
self.len() == 0 || self.contains(self.min()),
decreases self.len(),
{
if self.len() <= 1 {
} else {
let elt = self.drop_first().min();
assert(self.subrange(1, self.len() as int).contains(elt)) by {
self.drop_first().min_ensures()
}
assert forall|i: int| 0 <= i < self.len() implies self.min() <= self[i] by {
assert(i == 0 || self[i] == self.drop_first()[i - 1]);
assert(forall|j: int|
0 <= j < self.drop_first().len() ==> self.drop_first().min()
<= self.drop_first()[j]) by { self.drop_first().min_ensures() }
}
}
}
pub closed spec fn sort(self) -> Self {
self.sort_by(|x: int, y: int| x <= y)
}
pub proof fn lemma_sort_ensures(self)
ensures
self.to_multiset() =~= self.sort().to_multiset(),
sorted_by(self.sort(), |x: int, y: int| x <= y),
{
self.lemma_sort_by_ensures(|x: int, y: int| x <= y);
}
pub proof fn lemma_subrange_max(self, from: int, to: int)
requires
0 <= from < to <= self.len(),
ensures
self.subrange(from, to).max() <= self.max(),
{
self.max_ensures();
self.subrange(from, to).max_ensures();
}
pub proof fn lemma_subrange_min(self, from: int, to: int)
requires
0 <= from < to <= self.len(),
ensures
self.subrange(from, to).min() >= self.min(),
{
self.min_ensures();
self.subrange(from, to).min_ensures();
}
}
spec fn merge_sorted_with<A>(left: Seq<A>, right: Seq<A>, leq: spec_fn(A, A) -> bool) -> Seq<A>
recommends
sorted_by(left, leq),
sorted_by(right, leq),
total_ordering(leq),
decreases left.len(), right.len(),
{
if left.len() == 0 {
right
} else if right.len() == 0 {
left
} else if leq(left.first(), right.first()) {
Seq::<A>::empty().push(left.first()) + merge_sorted_with(left.drop_first(), right, leq)
} else {
Seq::<A>::empty().push(right.first()) + merge_sorted_with(left, right.drop_first(), leq)
}
}
proof fn lemma_merge_sorted_with_ensures<A>(left: Seq<A>, right: Seq<A>, leq: spec_fn(A, A) -> bool)
requires
sorted_by(left, leq),
sorted_by(right, leq),
total_ordering(leq),
ensures
(left + right).to_multiset() =~= merge_sorted_with(left, right, leq).to_multiset(),
sorted_by(merge_sorted_with(left, right, leq), leq),
decreases left.len(), right.len(),
{
lemma_seq_properties::<A>();
if left.len() == 0 {
assert(left + right =~= right);
} else if right.len() == 0 {
assert(left + right =~= left);
} else if leq(left.first(), right.first()) {
let result = Seq::<A>::empty().push(left.first()) + merge_sorted_with(
left.drop_first(),
right,
leq,
);
lemma_merge_sorted_with_ensures(left.drop_first(), right, leq);
let rest = merge_sorted_with(left.drop_first(), right, leq);
assert(rest.len() == 0 || rest.first() == left.drop_first().first() || rest.first()
== right.first()) by {
if left.drop_first().len() == 0 {
} else if leq(left.drop_first().first(), right.first()) {
assert(rest =~= Seq::<A>::empty().push(left.drop_first().first())
+ merge_sorted_with(left.drop_first().drop_first(), right, leq));
} else {
assert(rest =~= Seq::<A>::empty().push(right.first()) + merge_sorted_with(
left.drop_first(),
right.drop_first(),
leq,
));
}
}
lemma_new_first_element_still_sorted_by(left.first(), rest, leq);
assert((left.drop_first() + right) =~= (left + right).drop_first());
} else {
let result = Seq::<A>::empty().push(right.first()) + merge_sorted_with(
left,
right.drop_first(),
leq,
);
lemma_merge_sorted_with_ensures(left, right.drop_first(), leq);
let rest = merge_sorted_with(left, right.drop_first(), leq);
assert(rest.len() == 0 || rest.first() == left.first() || rest.first()
== right.drop_first().first()) by {
assert(left.len() > 0);
if right.drop_first().len() == 0 { } else if leq(left.first(), right.drop_first().first()) { assert(rest =~= Seq::<A>::empty().push(left.first()) + merge_sorted_with(
left.drop_first(),
right.drop_first(),
leq,
));
} else {
assert(rest =~= Seq::<A>::empty().push(right.drop_first().first())
+ merge_sorted_with(left, right.drop_first().drop_first(), leq));
}
}
lemma_new_first_element_still_sorted_by(
right.first(),
merge_sorted_with(left, right.drop_first(), leq),
leq,
);
lemma_seq_union_to_multiset_commutative(left, right);
assert((right.drop_first() + left) =~= (right + left).drop_first());
lemma_seq_union_to_multiset_commutative(right.drop_first(), left);
}
}
pub proof fn lemma_max_of_concat(x: Seq<int>, y: Seq<int>)
requires
0 < x.len() && 0 < y.len(),
ensures
x.max() <= (x + y).max(),
y.max() <= (x + y).max(),
forall|elt: int| (x + y).contains(elt) ==> elt <= (x + y).max(),
decreases x.len(),
{
lemma_seq_properties::<int>();
x.max_ensures();
y.max_ensures();
(x + y).max_ensures();
assert(x.drop_first().len() == x.len() - 1);
if x.len() == 1 {
assert(y.max() <= (x + y).max()) by {
assert((x + y).contains(y.max()));
}
} else {
assert(x.max() <= (x + y).max()) by {
assert(x.contains(x.max()));
assert((x + y).contains(x.max()));
}
assert(x.drop_first() + y =~= (x + y).drop_first());
lemma_max_of_concat(x.drop_first(), y);
}
}
pub proof fn lemma_min_of_concat(x: Seq<int>, y: Seq<int>)
requires
0 < x.len() && 0 < y.len(),
ensures
(x + y).min() <= x.min(),
(x + y).min() <= y.min(),
forall|elt: int| (x + y).contains(elt) ==> (x + y).min() <= elt,
decreases x.len(),
{
x.min_ensures();
y.min_ensures();
(x + y).min_ensures();
lemma_seq_properties::<int>();
if x.len() == 1 {
assert((x + y).min() <= y.min()) by {
assert((x + y).contains(y.min()));
}
} else {
assert((x + y).min() <= x.min()) by {
assert((x + y).contains(x.min()));
}
assert((x + y).min() <= y.min()) by {
assert((x + y).contains(y.min()));
}
assert(x.drop_first() + y =~= (x + y).drop_first());
lemma_max_of_concat(x.drop_first(), y)
}
}
proof fn to_multiset_build<A>(s: Seq<A>, a: A)
ensures
s.push(a).to_multiset() =~= s.to_multiset().insert(a),
decreases s.len(),
{
broadcast use super::multiset::group_multiset_axioms;
if s.len() == 0 {
assert(s.to_multiset() =~= Multiset::<A>::empty());
assert(s.push(a).drop_first() =~= Seq::<A>::empty());
assert(s.push(a).to_multiset() =~= Multiset::<A>::empty().insert(a).add(
Seq::<A>::empty().to_multiset(),
));
} else {
to_multiset_build(s.drop_first(), a);
assert(s.drop_first().push(a).to_multiset() =~= s.drop_first().to_multiset().insert(a));
assert(s.push(a).drop_first() =~= s.drop_first().push(a));
}
}
proof fn to_multiset_remove<A>(s: Seq<A>, i: int)
requires
0 <= i < s.len(),
ensures
s.remove(i).to_multiset() =~= s.to_multiset().remove(s[i]),
{
broadcast use super::multiset::group_multiset_axioms;
let s0 = s.subrange(0, i);
let s1 = s.subrange(i, s.len() as int);
let s2 = s.subrange(i + 1, s.len() as int);
lemma_seq_union_to_multiset_commutative(s0, s2);
lemma_seq_union_to_multiset_commutative(s0, s1);
assert(s == s0 + s1);
assert(s2 + s0 == (s1 + s0).drop_first());
}
proof fn to_multiset_len<A>(s: Seq<A>)
ensures
s.len() == s.to_multiset().len(),
decreases s.len(),
{
broadcast use super::multiset::group_multiset_axioms;
if s.len() == 0 {
assert(s.to_multiset() =~= Multiset::<A>::empty());
assert(s.len() == 0);
} else {
to_multiset_len(s.drop_first());
assert(s.len() == s.drop_first().len() + 1);
assert(s.to_multiset().len() == s.drop_first().to_multiset().len() + 1);
}
}
proof fn to_multiset_contains<A>(s: Seq<A>, a: A)
ensures
s.contains(a) <==> s.to_multiset().count(a) > 0,
decreases s.len(),
{
broadcast use super::multiset::group_multiset_axioms;
if s.len() != 0 {
if s.contains(a) {
if s.first() == a {
to_multiset_build(s, a);
assert(s.to_multiset() =~= Multiset::<A>::empty().insert(s.first()).add(
s.drop_first().to_multiset(),
));
assert(Multiset::<A>::empty().insert(s.first()).contains(s.first()));
} else {
to_multiset_contains(s.drop_first(), a);
assert(s.skip(1) =~= s.drop_first());
lemma_seq_skip_contains(s, 1, a);
assert(s.to_multiset().count(a) == s.drop_first().to_multiset().count(a));
assert(s.contains(a) <==> s.to_multiset().count(a) > 0);
}
}
if s.to_multiset().count(a) > 0 {
to_multiset_contains(s.drop_first(), a);
assert(s.contains(a) <==> s.to_multiset().count(a) > 0);
} else {
assert(s.contains(a) <==> s.to_multiset().count(a) > 0);
}
}
}
pub proof fn lemma_append_last<A>(s1: Seq<A>, s2: Seq<A>)
requires
0 < s2.len(),
ensures
(s1 + s2).last() == s2.last(),
{
}
pub proof fn lemma_concat_associative<A>(s1: Seq<A>, s2: Seq<A>, s3: Seq<A>)
ensures
s1.add(s2.add(s3)) =~= s1.add(s2).add(s3),
{
}
spec fn seq_to_set_rec<A>(seq: Seq<A>) -> Set<A>
decreases seq.len(),
{
if seq.len() == 0 {
Set::empty()
} else {
seq_to_set_rec(seq.drop_last()).insert(seq.last())
}
}
proof fn seq_to_set_rec_is_finite<A>(seq: Seq<A>)
ensures
seq_to_set_rec(seq).finite(),
decreases seq.len(),
{
broadcast use super::set::group_set_axioms;
if seq.len() > 0 {
let sub_seq = seq.drop_last();
assert(seq_to_set_rec(sub_seq).finite()) by {
seq_to_set_rec_is_finite(sub_seq);
}
}
}
proof fn seq_to_set_rec_contains<A>(seq: Seq<A>)
ensures
forall|a| #[trigger] seq.contains(a) <==> seq_to_set_rec(seq).contains(a),
decreases seq.len(),
{
broadcast use super::set::group_set_axioms;
if seq.len() > 0 {
assert(forall|a| #[trigger]
seq.drop_last().contains(a) <==> seq_to_set_rec(seq.drop_last()).contains(a)) by {
seq_to_set_rec_contains(seq.drop_last());
}
assert(seq =~= seq.drop_last().push(seq.last()));
assert forall|a| #[trigger] seq.contains(a) <==> seq_to_set_rec(seq).contains(a) by {
if !seq.drop_last().contains(a) {
if a == seq.last() {
assert(seq.contains(a));
assert(seq_to_set_rec(seq).contains(a));
} else {
assert(!seq_to_set_rec(seq).contains(a));
}
}
}
}
}
proof fn seq_to_set_equal_rec<A>(seq: Seq<A>)
ensures
seq.to_set() == seq_to_set_rec(seq),
{
broadcast use super::set::group_set_axioms;
assert(forall|n| #[trigger] seq.contains(n) <==> seq_to_set_rec(seq).contains(n)) by {
seq_to_set_rec_contains(seq);
}
assert(forall|n| #[trigger] seq.contains(n) <==> seq.to_set().contains(n));
assert(seq.to_set() =~= seq_to_set_rec(seq));
}
pub broadcast proof fn seq_to_set_is_finite<A>(seq: Seq<A>)
ensures
#[trigger] seq.to_set().finite(),
{
broadcast use super::set::group_set_axioms;
assert(seq.to_set().finite()) by {
seq_to_set_equal_rec(seq);
seq_to_set_rec_is_finite(seq);
}
}
pub proof fn lemma_no_dup_in_concat<A>(a: Seq<A>, b: Seq<A>)
requires
a.no_duplicates(),
b.no_duplicates(),
forall|i: int, j: int| 0 <= i < a.len() && 0 <= j < b.len() ==> a[i] != b[j],
ensures
#[trigger] (a + b).no_duplicates(),
{
}
pub proof fn lemma_flatten_concat<A>(x: Seq<Seq<A>>, y: Seq<Seq<A>>)
ensures
(x + y).flatten() =~= x.flatten() + y.flatten(),
decreases x.len(),
{
if x.len() == 0 {
assert(x + y =~= y);
} else {
assert((x + y).drop_first() =~= x.drop_first() + y);
assert(x.first() + (x.drop_first() + y).flatten() =~= x.first() + x.drop_first().flatten()
+ y.flatten()) by {
lemma_flatten_concat(x.drop_first(), y);
}
}
}
pub proof fn lemma_flatten_alt_concat<A>(x: Seq<Seq<A>>, y: Seq<Seq<A>>)
ensures
(x + y).flatten_alt() =~= x.flatten_alt() + y.flatten_alt(),
decreases y.len(),
{
if y.len() == 0 {
assert(x + y =~= x);
} else {
assert((x + y).drop_last() =~= x + y.drop_last());
assert((x + y.drop_last()).flatten_alt() + y.last() =~= x.flatten_alt()
+ y.drop_last().flatten_alt() + y.last()) by {
lemma_flatten_alt_concat(x, y.drop_last());
}
}
}
pub proof fn lemma_seq_union_to_multiset_commutative<A>(a: Seq<A>, b: Seq<A>)
ensures
(a + b).to_multiset() =~= (b + a).to_multiset(),
{
broadcast use super::multiset::group_multiset_axioms;
lemma_multiset_commutative(a, b);
lemma_multiset_commutative(b, a);
}
pub proof fn lemma_multiset_commutative<A>(a: Seq<A>, b: Seq<A>)
ensures
(a + b).to_multiset() =~= a.to_multiset().add(b.to_multiset()),
decreases a.len(),
{
broadcast use super::multiset::group_multiset_axioms;
if a.len() == 0 {
assert(a + b =~= b);
} else {
lemma_multiset_commutative(a.drop_first(), b);
assert(a.drop_first() + b =~= (a + b).drop_first());
}
}
pub proof fn lemma_sorted_unique<A>(x: Seq<A>, y: Seq<A>, leq: spec_fn(A, A) -> bool)
requires
sorted_by(x, leq),
sorted_by(y, leq),
total_ordering(leq),
x.to_multiset() == y.to_multiset(),
ensures
x =~= y,
decreases x.len(), y.len(),
{
broadcast use super::multiset::group_multiset_axioms;
x.to_multiset_ensures();
y.to_multiset_ensures();
if x.len() == 0 || y.len() == 0 {
} else {
assert(x.to_multiset().contains(x[0]));
assert(x.to_multiset().contains(y[0]));
let i = choose|i: int| #![trigger x.spec_index(i) ] 0 <= i < x.len() && x[i] == y[0];
assert(leq(x[i], x[0]));
assert(leq(x[0], x[i]));
assert(x.drop_first().to_multiset() =~= x.to_multiset().remove(x[0]));
assert(y.drop_first().to_multiset() =~= y.to_multiset().remove(y[0]));
lemma_sorted_unique(x.drop_first(), y.drop_first(), leq);
assert(x.drop_first() =~= y.drop_first());
assert(x.first() == y.first());
assert(x =~= Seq::<A>::empty().push(x.first()).add(x.drop_first()));
assert(x =~= y);
}
}
pub proof fn lemma_seq_contains<A>(s: Seq<A>, x: A)
ensures
s.contains(x) <==> exists|i: int| 0 <= i < s.len() && s[i] == x,
{
}
pub proof fn lemma_seq_empty_contains_nothing<A>(x: A)
ensures
!Seq::<A>::empty().contains(x),
{
}
pub proof fn lemma_seq_empty_equality<A>(s: Seq<A>)
ensures
s.len() == 0 ==> s =~= Seq::<A>::empty(),
{
}
pub proof fn lemma_seq_concat_contains_all_elements<A>(x: Seq<A>, y: Seq<A>, elt: A)
ensures
(x + y).contains(elt) <==> x.contains(elt) || y.contains(elt),
decreases x.len(),
{
if x.len() == 0 && y.len() > 0 {
assert((x + y) =~= y);
} else {
assert forall|elt: A| #[trigger] x.contains(elt) implies #[trigger] (x + y).contains(
elt,
) by {
let index = choose|i: int| 0 <= i < x.len() && x[i] == elt;
assert((x + y)[index] == elt);
}
assert forall|elt: A| #[trigger] y.contains(elt) implies #[trigger] (x + y).contains(
elt,
) by {
let index = choose|i: int| 0 <= i < y.len() && y[i] == elt;
assert((x + y)[index + x.len()] == elt);
}
}
}
pub proof fn lemma_seq_contains_after_push<A>(s: Seq<A>, v: A, x: A)
ensures
(s.push(v).contains(x) <==> v == x || s.contains(x)) && s.push(v).contains(v),
{
assert forall|elt: A| #[trigger] s.contains(elt) implies #[trigger] s.push(v).contains(elt) by {
let index = choose|i: int| 0 <= i < s.len() && s[i] == elt;
assert(s.push(v)[index] == elt);
}
assert(s.push(v)[s.len() as int] == v);
}
pub proof fn lemma_seq_subrange_elements<A>(s: Seq<A>, start: int, stop: int, x: A)
requires
0 <= start <= stop <= s.len(),
ensures
s.subrange(start, stop).contains(x) <==> (exists|i: int|
0 <= start <= i < stop <= s.len() && s[i] == x),
{
assert((exists|i: int| 0 <= start <= i < stop <= s.len() && s[i] == x) ==> s.subrange(
start,
stop,
).contains(x)) by {
if exists|i: int| 0 <= start <= i < stop <= s.len() && s[i] == x {
let index = choose|i: int| 0 <= start <= i < stop <= s.len() && s[i] == x;
assert(s.subrange(start, stop)[index - start] == s[index]);
}
}
}
pub open spec fn commutative_foldr<A, B>(f: spec_fn(A, B) -> B) -> bool {
forall|x: A, y: A, v: B| #[trigger] f(x, f(y, v)) == f(y, f(x, v))
}
pub proof fn lemma_fold_right_permutation<A, B>(l1: Seq<A>, l2: Seq<A>, f: spec_fn(A, B) -> B, v: B)
requires
commutative_foldr(f),
l1.to_multiset() == l2.to_multiset(),
ensures
l1.fold_right(f, v) == l2.fold_right(f, v),
decreases l1.len(),
{
l1.to_multiset_ensures();
l2.to_multiset_ensures();
if l1.len() > 0 {
let a = l1.last();
let i = l2.index_of(a);
let l2r = l2.subrange(i + 1, l2.len() as int).fold_right(f, v);
assert(l1.to_multiset().count(a) > 0);
l1.drop_last().lemma_fold_right_commute_one(a, f, v);
l2.subrange(0, i).lemma_fold_right_commute_one(a, f, l2r);
l2.lemma_fold_right_split(f, v, i + 1);
l2.remove(i).lemma_fold_right_split(f, v, i);
assert(l2.subrange(0, i + 1).drop_last() == l2.subrange(0, i));
assert(l1.drop_last() == l1.remove(l1.len() - 1));
assert(l2.remove(i).subrange(0, i) == l2.subrange(0, i));
assert(l2.remove(i).subrange(i, l2.remove(i).len() as int) == l2.subrange(
i + 1,
l2.len() as int,
));
lemma_fold_right_permutation(l1.drop_last(), l2.remove(i), f, v);
}
}
pub proof fn lemma_seq_take_len<A>(s: Seq<A>, n: int)
ensures
0 <= n <= s.len() ==> s.take(n).len() == n,
{
}
pub proof fn lemma_seq_take_contains<A>(s: Seq<A>, n: int, x: A)
requires
0 <= n <= s.len(),
ensures
s.take(n).contains(x) <==> (exists|i: int| 0 <= i < n <= s.len() && s[i] == x),
{
assert((exists|i: int| 0 <= i < n <= s.len() && #[trigger] s[i] == x) ==> s.take(n).contains(x))
by {
if exists|i: int| 0 <= i < n <= s.len() && #[trigger] s[i] == x {
let index = choose|i: int| 0 <= i < n <= s.len() && #[trigger] s[i] == x;
assert(s.take(n)[index] == s[index]);
}
}
}
pub proof fn lemma_seq_take_index<A>(s: Seq<A>, n: int, j: int)
ensures
0 <= j < n <= s.len() ==> s.take(n)[j] == s[j],
{
}
pub proof fn subrange_of_matching_take<T>(a: Seq<T>, b: Seq<T>, s: int, e: int, l: int)
requires
a.take(l) == b.take(l),
l <= a.len(),
l <= b.len(),
0 <= s <= e <= l,
ensures
a.subrange(s, e) == b.subrange(s, e),
{
assert forall|i| 0 <= i < e - s implies a.subrange(s, e)[i] == b.subrange(s, e)[i] by {
assert(a.subrange(s, e)[i] == a.take(l)[i + s]);
}
assert(a.subrange(s, e) == b.subrange(s, e));
}
pub proof fn lemma_seq_skip_len<A>(s: Seq<A>, n: int)
ensures
0 <= n <= s.len() ==> s.skip(n).len() == s.len() - n,
{
}
pub proof fn lemma_seq_skip_contains<A>(s: Seq<A>, n: int, x: A)
requires
0 <= n <= s.len(),
ensures
s.skip(n).contains(x) <==> (exists|i: int| 0 <= n <= i < s.len() && s[i] == x),
{
assert((exists|i: int| 0 <= n <= i < s.len() && #[trigger] s[i] == x) ==> s.skip(n).contains(x))
by {
let index = choose|i: int| 0 <= n <= i < s.len() && #[trigger] s[i] == x;
lemma_seq_skip_index(s, n, index - n);
}
}
pub proof fn lemma_seq_skip_index<A>(s: Seq<A>, n: int, j: int)
ensures
0 <= n && 0 <= j < (s.len() - n) ==> s.skip(n)[j] == s[j + n],
{
}
pub proof fn lemma_seq_skip_index2<A>(s: Seq<A>, n: int, k: int)
ensures
0 <= n <= k < s.len() ==> (s.skip(n))[k - n] == s[k],
{
}
pub proof fn lemma_seq_append_take_skip<A>(a: Seq<A>, b: Seq<A>, n: int)
ensures
n == a.len() ==> ((a + b).take(n) =~= a && (a + b).skip(n) =~= b),
{
}
pub proof fn lemma_seq_take_update_commut1<A>(s: Seq<A>, i: int, v: A, n: int)
ensures
0 <= i < n <= s.len() ==> #[trigger] s.update(i, v).take(n) =~= s.take(n).update(i, v),
{
}
pub proof fn lemma_seq_take_update_commut2<A>(s: Seq<A>, i: int, v: A, n: int)
ensures
0 <= n <= i < s.len() ==> #[trigger] s.update(i, v).take(n) =~= s.take(n),
{
}
pub proof fn lemma_seq_skip_update_commut1<A>(s: Seq<A>, i: int, v: A, n: int)
ensures
0 <= n <= i < s.len() ==> #[trigger] s.update(i, v).skip(n) =~= s.skip(n).update(i - n, v),
{
}
pub proof fn lemma_seq_skip_update_commut2<A>(s: Seq<A>, i: int, v: A, n: int)
ensures
0 <= i < n <= s.len() ==> s.update(i, v).skip(n) =~= s.skip(n),
{
}
pub proof fn lemma_seq_skip_build_commut<A>(s: Seq<A>, v: A, n: int)
ensures
0 <= n <= s.len() ==> s.push(v).skip(n) =~= s.skip(n).push(v),
{
}
pub proof fn lemma_seq_skip_nothing<A>(s: Seq<A>, n: int)
ensures
n == 0 ==> s.skip(n) =~= s,
{
}
pub proof fn lemma_seq_take_nothing<A>(s: Seq<A>, n: int)
ensures
n == 0 ==> s.take(n) =~= Seq::<A>::empty(),
{
}
pub proof fn lemma_seq_skip_of_skip<A>(s: Seq<A>, m: int, n: int)
ensures
(0 <= m && 0 <= n && m + n <= s.len()) ==> s.skip(m).skip(n) =~= s.skip(m + n),
{
}
pub proof fn lemma_seq_properties<A>()
ensures
forall|s: Seq<A>, x: A|
s.contains(x) <==> exists|i: int| 0 <= i < s.len() && #[trigger] s[i] == x, forall|x: A| !(#[trigger] Seq::<A>::empty().contains(x)), forall|s: Seq<A>| #[trigger] s.len() == 0 ==> s =~= Seq::<A>::empty(), forall|x: Seq<A>, y: Seq<A>, elt: A| #[trigger]
(x + y).contains(elt) <==> x.contains(elt) || y.contains(elt), forall|s: Seq<A>, v: A, x: A|
(#[trigger] s.push(v).contains(x) <==> v == x || s.contains(x)) && #[trigger] s.push(
v,
).contains(v), forall|s: Seq<A>, start: int, stop: int, x: A|
(0 <= start <= stop <= s.len() && #[trigger] s.subrange(start, stop).contains(x)) <==> (
exists|i: int| 0 <= start <= i < stop <= s.len() && #[trigger] s[i] == x), forall|s: Seq<A>, n: int| 0 <= n <= s.len() ==> #[trigger] s.take(n).len() == n, forall|s: Seq<A>, n: int, x: A|
(#[trigger] s.take(n).contains(x) && 0 <= n <= s.len()) <==> (exists|i: int|
0 <= i < n <= s.len() && #[trigger] s[i] == x), forall|s: Seq<A>, n: int, j: int| 0 <= j < n <= s.len() ==> #[trigger] s.take(n)[j] == s[j], forall|s: Seq<A>, n: int| 0 <= n <= s.len() ==> #[trigger] s.skip(n).len() == s.len() - n, forall|s: Seq<A>, n: int, x: A|
(#[trigger] s.skip(n).contains(x) && 0 <= n <= s.len()) <==> (exists|i: int|
0 <= n <= i < s.len() && #[trigger] s[i] == x), forall|s: Seq<A>, n: int, j: int|
0 <= n && 0 <= j < (s.len() - n) ==> #[trigger] s.skip(n)[j] == s[j + n], forall|a: Seq<A>, b: Seq<A>, n: int|
#![trigger (a+b).take(n)]
#![trigger (a+b).skip(n)]
n == a.len() ==> ((a + b).take(n) =~= a && (a + b).skip(n) =~= b), forall|s: Seq<A>, i: int, v: A, n: int|
0 <= i < n <= s.len() ==> #[trigger] s.update(i, v).take(n) == s.take(n).update(i, v), forall|s: Seq<A>, i: int, v: A, n: int|
0 <= n <= i < s.len() ==> #[trigger] s.update(i, v).take(n) == s.take(n), forall|s: Seq<A>, i: int, v: A, n: int|
0 <= n <= i < s.len() ==> #[trigger] s.update(i, v).skip(n) == s.skip(n).update(
i - n,
v,
), forall|s: Seq<A>, i: int, v: A, n: int|
0 <= i < n <= s.len() ==> #[trigger] s.update(i, v).skip(n) == s.skip(n), forall|s: Seq<A>, v: A, n: int|
0 <= n <= s.len() ==> #[trigger] s.push(v).skip(n) == s.skip(n).push(v), forall|s: Seq<A>, n: int| n == 0 ==> #[trigger] s.skip(n) == s, forall|s: Seq<A>, n: int| n == 0 ==> #[trigger] s.take(n) == Seq::<A>::empty(), forall|s: Seq<A>, m: int, n: int|
(0 <= m && 0 <= n && m + n <= s.len()) ==> s.skip(m).skip(n) == s.skip(m + n), forall|s: Seq<A>, a: A| #[trigger] (s.push(a).to_multiset()) =~= s.to_multiset().insert(a), forall|s: Seq<A>| s.len() == #[trigger] s.to_multiset().len(), forall|s: Seq<A>, a: A|
s.contains(a) <==> #[trigger] s.to_multiset().count(a)
> 0, {
assert forall|x: Seq<A>, y: Seq<A>, elt: A| #[trigger] (x + y).contains(elt) implies x.contains(
elt,
) || y.contains(elt) by {
lemma_seq_concat_contains_all_elements(x, y, elt);
}
assert forall|x: Seq<A>, y: Seq<A>, elt: A|
x.contains(elt) || y.contains(elt) implies #[trigger] (x + y).contains(elt) by {
lemma_seq_concat_contains_all_elements(x, y, elt);
}
assert forall|s: Seq<A>, v: A, x: A| #[trigger] s.push(v).contains(x) implies v == x
|| s.contains(x) by {
lemma_seq_contains_after_push(s, v, x);
}
assert forall|s: Seq<A>, v: A, x: A| v == x || s.contains(x) implies #[trigger] s.push(
v,
).contains(x) by {
lemma_seq_contains_after_push(s, v, x);
}
assert forall|s: Seq<A>, start: int, stop: int, x: A|
0 <= start <= stop <= s.len() && #[trigger] s.subrange(start, stop).contains(
x,
) implies exists|i: int| 0 <= start <= i < stop <= s.len() && #[trigger] s[i] == x by {
lemma_seq_subrange_elements(s, start, stop, x);
}
assert forall|s: Seq<A>, start: int, stop: int, x: A|
exists|i: int|
0 <= start <= i < stop <= s.len() && #[trigger] s[i] == x implies #[trigger] s.subrange(
start,
stop,
).contains(x) by {
lemma_seq_subrange_elements(s, start, stop, x);
}
assert forall|s: Seq<A>, n: int, x: A| #[trigger]
s.take(n).contains(x) && 0 <= n <= s.len() implies (exists|i: int|
0 <= i < n <= s.len() && #[trigger] s[i] == x) by {
lemma_seq_take_contains(s, n, x);
}
assert forall|s: Seq<A>, n: int, x: A|
(exists|i: int| 0 <= i < n <= s.len() && #[trigger] s[i] == x) implies #[trigger] s.take(
n,
).contains(x) by {
lemma_seq_take_contains(s, n, x);
}
assert forall|s: Seq<A>, n: int, j: int| 0 <= j < n <= s.len() implies #[trigger] s.take(n)[j]
== s[j] by {
lemma_seq_take_len(s, n);
assert(0 <= n <= s.len() ==> s.take(n).len() == n);
assert(0 <= n <= s.len());
assert(s.take(n).len() == n);
lemma_seq_take_index(s, n, j);
}
assert forall|s: Seq<A>, n: int, x: A| #[trigger]
s.skip(n).contains(x) && 0 <= n <= s.len() implies (exists|i: int|
0 <= n <= i < s.len() && #[trigger] s[i] == x) by {
lemma_seq_skip_contains(s, n, x);
}
assert forall|s: Seq<A>, n: int, x: A|
(exists|i: int| 0 <= n <= i < s.len() && #[trigger] s[i] == x) implies #[trigger] s.skip(
n,
).contains(x) && 0 <= n <= s.len() by {
lemma_seq_skip_contains(s, n, x);
}
assert forall|s: Seq<A>, i: int, v: A, n: int|
0 <= i < n <= s.len() implies #[trigger] s.update(i, v).take(n) == s.take(n).update(
i,
v,
) by {
lemma_seq_take_update_commut1(s, i, v, n);
}
assert forall|s: Seq<A>, i: int, v: A, n: int|
0 <= n <= i < s.len() implies #[trigger] s.update(i, v).take(n) == s.take(n) by {
lemma_seq_take_update_commut2(s, i, v, n);
}
assert forall|s: Seq<A>, i: int, v: A, n: int|
0 <= n <= i < s.len() implies #[trigger] s.update(i, v).skip(n) == s.skip(n).update(
i - n,
v,
) by {
lemma_seq_skip_update_commut1(s, i, v, n);
}
assert forall|s: Seq<A>, i: int, v: A, n: int|
0 <= i < n <= s.len() implies #[trigger] s.update(i, v).skip(n) == s.skip(n) by {
lemma_seq_skip_update_commut2(s, i, v, n);
}
assert forall|s: Seq<A>, v: A, n: int| 0 <= n <= s.len() implies #[trigger] s.push(v).skip(n)
== s.skip(n).push(v) by {
lemma_seq_skip_build_commut(s, v, n);
}
assert forall|s: Seq<A>, n: int| n == 0 implies #[trigger] s.skip(n) == s by {
lemma_seq_skip_nothing(s, n);
}
assert forall|s: Seq<A>, n: int| n == 0 implies #[trigger] s.take(n) == Seq::<A>::empty() by {
lemma_seq_take_nothing(s, n);
}
assert forall|s: Seq<A>, m: int, n: int| (0 <= m && 0 <= n && m + n <= s.len()) implies s.skip(
m,
).skip(n) == s.skip(m + n) by {
lemma_seq_skip_of_skip(s, m, n);
}
assert forall|s: Seq<A>, a: A| #[trigger]
(s.push(a).to_multiset()) =~= s.to_multiset().insert(a) by {
s.to_multiset_ensures();
}
assert forall|s: Seq<A>| s.len() == #[trigger] s.to_multiset().len() by {
s.to_multiset_ensures();
}
assert forall|s: Seq<A>, a: A| s.contains(a) implies #[trigger] s.to_multiset().count(a)
> 0 by {
s.to_multiset_ensures();
}
assert forall|s: Seq<A>, a: A| #[trigger] s.to_multiset().count(a) > 0 implies s.contains(
a,
) by {
s.to_multiset_ensures();
}
}
#[doc(hidden)]
#[verifier::inline]
pub open spec fn check_argument_is_seq<A>(s: Seq<A>) -> Seq<A> {
s
}
#[macro_export]
macro_rules! assert_seqs_equal {
[$($tail:tt)*] => {
::builtin_macros::verus_proof_macro_exprs!($crate::vstd::seq_lib::assert_seqs_equal_internal!($($tail)*))
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! assert_seqs_equal_internal {
(::builtin::spec_eq($s1:expr, $s2:expr)) => {
$crate::vstd::seq_lib::assert_seqs_equal_internal!($s1, $s2)
};
(::builtin::spec_eq($s1:expr, $s2:expr), $idx:ident => $bblock:block) => {
$crate::vstd::seq_lib::assert_seqs_equal_internal!($s1, $s2, $idx => $bblock)
};
(crate::builtin::spec_eq($s1:expr, $s2:expr)) => {
$crate::vstd::seq_lib::assert_seqs_equal_internal!($s1, $s2)
};
(crate::builtin::spec_eq($s1:expr, $s2:expr), $idx:ident => $bblock:block) => {
$crate::vstd::seq_lib::assert_seqs_equal_internal!($s1, $s2, $idx => $bblock)
};
($s1:expr, $s2:expr $(,)?) => {
$crate::vstd::seq_lib::assert_seqs_equal_internal!($s1, $s2, idx => { })
};
($s1:expr, $s2:expr, $idx:ident => $bblock:block) => {
#[verifier::spec] let s1 = $crate::vstd::seq_lib::check_argument_is_seq($s1);
#[verifier::spec] let s2 = $crate::vstd::seq_lib::check_argument_is_seq($s2);
$crate::vstd::prelude::assert_by($crate::vstd::prelude::equal(s1, s2), {
$crate::vstd::prelude::assert_(s1.len() == s2.len());
$crate::vstd::prelude::assert_forall_by(|$idx : $crate::vstd::prelude::int| {
$crate::vstd::prelude::requires(::builtin_macros::verus_proof_expr!(0 <= $idx && $idx < s1.len()));
$crate::vstd::prelude::ensures($crate::vstd::prelude::equal(s1.index($idx), s2.index($idx)));
{ $bblock }
});
$crate::vstd::prelude::assert_($crate::vstd::prelude::ext_equal(s1, s2));
});
}
}
pub broadcast group group_seq_lib_default {
Seq::filter_lemma,
Seq::add_empty_left,
Seq::add_empty_right,
Seq::push_distributes_over_add,
Seq::filter_distributes_over_add,
seq_to_set_is_finite,
}
#[doc(hidden)]
pub use assert_seqs_equal_internal;
pub use assert_seqs_equal;
}