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