Skip to main content

vstd_extra/
seq_extra.rs

1//! Extra properties of [`vstd::seq::Seq`](https://verus-lang.github.io/verus/verusdoc/vstd/seq/struct.Seq.html).
2use vstd::prelude::*;
3use vstd::seq::*;
4use vstd::seq_lib::*;
5
6verus! {
7
8broadcast use {group_seq_axioms, group_seq_lib_default};
9
10/// Splits a tracked sequence at position `n`, leaving `[0, n)` in `s`
11/// and returning `[n, len)`.
12pub proof fn seq_tracked_split_at<T>(tracked s: &mut Seq<T>, n: int) -> (tracked result: Seq<T>)
13    requires
14        0 <= n <= old(s).len(),
15    ensures
16        *final(s) =~= old(s).subrange(0, n),
17        result =~= old(s).subrange(n, old(s).len() as int),
18    decreases
19        old(s).len() - n,
20{
21    if n == s.len() {
22        Seq::tracked_empty()
23    } else {
24        let ghost orig = *s;
25        let ghost orig_len = orig.len() as int;
26        let tracked last = s.tracked_pop();
27        let tracked mut result = seq_tracked_split_at(s, n);
28        result.tracked_push(last);
29        result
30    }
31}
32
33pub broadcast proof fn lemma_seq_add_head_back<T>(s: Seq<T>)
34    requires
35        s.len() > 0,
36    ensures
37        s =~= #[trigger] seq![s[0]].add(s.drop_first()),
38{
39}
40
41pub broadcast proof fn lemma_seq_push_head<T>(s: Seq<T>, hd: T)
42    ensures
43        #[trigger] seq![hd].add(s) =~= s.reverse().push(hd).reverse(),
44{
45}
46
47pub broadcast proof fn lemma_seq_drop_pushed_head<T>(s: Seq<T>, hd: T)
48    ensures
49        #[trigger] seq![hd].add(s).drop_first() =~= s,
50{
51}
52
53pub broadcast proof fn lemma_seq_push_head_take_head<T>(s: Seq<T>, hd: T)
54    ensures
55        #[trigger] seq![hd].add(s)[0] == hd,
56{
57}
58
59} // verus!
60verus! {
61
62/// The result of pushing element `needle` into the sequence `s` contains `needle`.
63pub proof fn lemma_push_contains_same<T>(s: Seq<T>, needle: T)
64    ensures
65        #[trigger] s.push(needle).contains(needle),
66{
67    assert(s.push(needle).last() == needle);
68}
69
70/// If element `needle` is different from `new_elem`, then whether the sequence `s` contains `needle`
71/// after pushing `new_elem` depends on whether `s` contains `needle` before the push.
72pub proof fn lemma_push_contains_different<T>(s: Seq<T>, new_elem: T, needle: T)
73    requires
74        new_elem != needle,
75    ensures
76        #[trigger] s.push(new_elem).contains(needle) == s.contains(needle),
77{
78    if s.contains(needle) {
79        let i = choose|i: int| 0 <= i < s.len() && s[i] == needle;
80        axiom_seq_push_index_different(s, needle, i);
81        assert(0 <= i < s.push(new_elem).len() && s.push(new_elem)[i] == needle);
82    }
83}
84
85/// If the last element of the sequence `s` is different from `needle`, then whether the sequence
86/// `s` contains `needle` after dropping the last element depends on whether `s` contains `needle`
87/// before the drop.
88pub proof fn lemma_drop_last_contains_different<T>(s: Seq<T>, needle: T)
89    requires
90        s.len() > 0,
91        s.last() != needle,
92    ensures
93        #[trigger] s.drop_last().contains(needle) == s.contains(needle),
94{
95    if s.contains(needle) {
96        let i = choose|i: int| 0 <= i < s.len() && s[i] == needle;
97        assert(0 <= i < s.drop_last().len() && s.drop_last()[i] == needle);
98    }
99}
100
101} // verus!
102verus! {
103
104/// Returns true if predicate `f(i,seq[i])` holds for all indices `i`.
105pub open spec fn forall_seq<T>(seq: Seq<T>, f: spec_fn(int, T) -> bool) -> bool {
106    forall|i| #![trigger seq[i]] 0 <= i < seq.len() ==> f(i, seq[i])
107}
108
109pub broadcast group group_forall_seq_lemmas {
110    lemma_forall_seq_push,
111    lemma_seq_all_push,
112    lemma_forall_seq_drop_last,
113    lemma_seq_all_drop_last,
114    lemma_seq_all_add,
115    lemma_seq_all_index,
116}
117
118/// Index `i` of the sequence `s` satisfies `f(i,s[i])` if `forall_seq(s,f)` holds.
119pub proof fn lemma_forall_seq_index<T>(s: Seq<T>, f: spec_fn(int, T) -> bool, i: int)
120    requires
121        forall_seq(s, f),
122        0 <= i < s.len(),
123    ensures
124        f(i, s[i]),
125{
126}
127
128/// Index `i` of the sequence `s` satisfies `f(s[i])` if `s.all(f)` holds.
129/// This proof is required due to the change of trigger by replacing the original `forall_seq_values` with `Seq::all`.
130pub broadcast proof fn lemma_seq_all_index<T>(s: Seq<T>, f: spec_fn(T) -> bool, i: int)
131    requires
132        0 <= i < s.len(),
133        #[trigger] s.all(f),
134    ensures
135        f(#[trigger] (s[i])),
136{
137}
138
139/// `forall_seq(s.push(v),f)` is equivalent to `forall_seq(s,f)` and `f(s.len(),v)`.
140pub broadcast proof fn lemma_forall_seq_push<T>(s: Seq<T>, f: spec_fn(int, T) -> bool, v: T)
141    ensures
142        forall_seq(s, f) && f(s.len() as int, v) <==> #[trigger] forall_seq(s.push(v), f),
143{
144    if forall_seq(s.push(v), f) {
145        assert forall|i| 0 <= i < s.len() implies f(i, s[i]) by {
146            assert(s[i] === s.push(v)[i]);
147        }
148        assert(s.push(v)[s.len() as int] == v);
149    }
150}
151
152/// s.push(v).all(f)` is equivalent to `s.all(f)` and `f(v)`.
153pub broadcast proof fn lemma_seq_all_push<T>(s: Seq<T>, f: spec_fn(T) -> bool, v: T)
154    ensures
155        #[trigger] s.push(v).all(f) <==> s.all(f) && f(v),
156{
157    if s.push(v).all(f) {
158        assert forall|i| 0 <= i < s.len() implies f(s[i]) by {
159            assert(s[i] === s.push(v)[i]);
160        }
161        assert(s.push(v)[s.len() as int] == v);
162    }
163}
164
165/// `forall_seq(s,f)` is equivalent to `forall_seq(s.drop_last(),f)` and `f(s.len() as int - 1, s.last())`.
166pub broadcast proof fn lemma_forall_seq_drop_last<T>(s: Seq<T>, f: spec_fn(int, T) -> bool)
167    requires
168        s.len() > 0,
169    ensures
170        forall_seq(s, f) <==> #[trigger] forall_seq(s.drop_last(), f) && f(
171            s.len() as int - 1,
172            s.last(),
173        ),
174{
175    assert(s == s.drop_last().push(s.last()));
176}
177
178/// `s.all(f)` is equivalent to `s.drop_last().all(f)` and `f(s.last())`.
179pub broadcast proof fn lemma_seq_all_drop_last<T>(s: Seq<T>, f: spec_fn(T) -> bool)
180    requires
181        s.len() > 0,
182    ensures
183        s.all(f) <==> #[trigger] s.drop_last().all(f) && f(s.last()),
184{
185    assert(s == s.drop_last().push(s.last()));
186}
187
188pub broadcast proof fn lemma_seq_all_add<T>(s1: Seq<T>, s2: Seq<T>, f: spec_fn(T) -> bool)
189    ensures
190        s1.all(f) && s2.all(f) <==> #[trigger] (s1 + s2).all(f),
191    decreases s2.len(),
192// Induction proof on the length of s2
193
194{
195    if s2.len() == 0 {
196        assert(s1 + s2 == s1);
197    } else {
198        // Induction step: assume the lemma holds for s2.drop_last() and show that s2==s2.drop_last().push(s2.last()).
199        lemma_seq_all_add(s1, s2.drop_last(), f);
200        if s1.all(f) && s2.all(f) {
201            assert((s1 + s2).all(f));
202        }
203        if (s1 + s2).all(f) {
204            assert((s1 + s2).drop_last() == s1 + s2.drop_last());
205            assert(s2 == s2.drop_last().push(s2.last()));
206            assert((s1 + s2).last() == s2.last());
207        }
208    }
209}
210
211/// If `source1` and `source2` are prefixes of `child`, then either `source1` is equal to `source2` or
212/// one of them is a prefix of the other.
213pub proof fn lemma_prefix_of_common_sequence(source1: Seq<nat>, source2: Seq<nat>, child: Seq<nat>)
214    requires
215        source1.is_prefix_of(child),
216        source2.is_prefix_of(child),
217    ensures
218        source1 == source2 || source1.len() < source2.len() && source1.is_prefix_of(source2)
219            || source2.len() < source1.len() && source2.is_prefix_of(source1),
220{
221}
222
223pub broadcast proof fn lemma_seq_to_set_map_contains<T, U>(s: Seq<T>, f: spec_fn(T) -> U, i: int)
224    requires
225        0 <= i < s.len(),
226    ensures
227        #![trigger s.map_values(f), s[i]]
228        (s.map_values(f)).to_set().contains(f(s[i])),
229{
230    assert(s.contains(s[i]));
231    assert(f(s[i]) == s.map_values(f)[i]);
232}
233
234pub broadcast group group_seq_extra_lemmas {
235    lemma_seq_add_head_back,
236    lemma_seq_push_head,
237    lemma_seq_drop_pushed_head,
238    lemma_seq_push_head_take_head,
239    lemma_seq_to_set_map_contains,
240}
241
242} // verus!