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