Skip to main content

vstd_extra/
set_extra.rs

1//! Extra properties of [`vstd::set::Set`](https://verus-lang.github.io/verus/verusdoc/vstd/set/struct.Set.html).
2use vstd::{iset::fold::*, prelude::*, set::fold::*, set_lib::*};
3
4verus! {
5
6/// A finite `Set<int>` cannot contain every integer: there always exists
7/// an `int` outside the set. Used to prove the freshness axioms.
8pub proof fn lemma_finite_int_set_has_unused(s: Set<int>)
9    ensures
10        exists|id: int| !s.contains(id),
11{
12    let n = s.len() as int;
13    vstd::set_lib::lemma_int_range(0, n + 1);
14    if forall|i: int| 0 <= i < n + 1 ==> s.contains(i) {
15        assert(Set::range(0, n + 1).subset_of(s)) by {
16            assert forall|i: int| Set::<int>::range(0, n + 1).contains(i) implies s.contains(
17                i,
18            ) by {}
19        }
20        vstd::set_lib::lemma_len_subset(Set::range(0, n + 1), s);
21        assert(false);
22    }
23}
24
25/// If all elements in set `s` does not satisfy the predicate `f`, then the filtered set
26/// is empty.
27pub proof fn lemma_filter_all_false<T>(s: Set<T>, f: spec_fn(T) -> bool)
28    requires
29        s.all(|x: T| !f(x)),
30    ensures
31        s.filter(f).is_empty(),
32{
33}
34
35/// If `x` satisfies the predicate `f` and set `s` does not contain `x`, then first inserting `x` into
36/// the set `s` and then applying the filter is equivalent to applying the filter first and then
37/// inserting `x` into the result.
38pub proof fn lemma_insert_filter_true<T>(s: Set<T>, f: spec_fn(T) -> bool, x: T)
39    requires
40        !s.contains(x),
41        f(x),
42    ensures
43        s.insert(x).filter(f) == s.filter(f).insert(x),
44{
45}
46
47/// If `x` does not satisfy the predicate `f` and set `s` does not contain `x`, then first inserting `x` into
48/// the set `s` and then applying the filter is equivalent to directly applying the filter to the original set `s`.
49pub proof fn lemma_insert_filter_false<T>(s: Set<T>, f: spec_fn(T) -> bool, x: T)
50    requires
51        !s.contains(x),
52        !f(x),
53    ensures
54        s.insert(x).filter(f) == s.filter(f),
55{
56}
57
58/// If `x` satisfies the predicate `f` and set `s` contains `x`, then first removing `x` from
59/// the set `s` and then applying the filter is equivalent to applying the filter first and then
60/// removing `x` from the result.
61pub proof fn lemma_remove_filter_true<T>(s: Set<T>, f: spec_fn(T) -> bool, x: T)
62    requires
63        s.contains(x),
64        f(x),
65    ensures
66        s.remove(x).filter(f) == s.filter(f).remove(x),
67{
68}
69
70/// The length of a set of natural numbers between `l` and `r` equals `r - l`.
71pub proof fn lemma_nat_range_finite(l: nat, r: nat)
72    requires
73        l <= r,
74    ensures
75        Set::<nat>::range(l, r).len() == (r - l) as nat,
76{
77    broadcast use vstd::set_lib::range_set_properties;
78
79}
80
81/// A finite set can be separated by a predicate into two disjoint sets.
82pub proof fn lemma_set_separation<T>(s: Set<T>, f: spec_fn(T) -> bool)
83    ensures
84        #![trigger s.filter(f)]
85        s.filter(f).disjoint(s.filter(|x| !f(x))),
86        s == s.filter(f) + s.filter(|x| !f(x)),
87        s.filter(f).len() + s.filter(|x| !f(x)).len() == s.len(),
88    decreases s.len(),
89{
90    if s.is_empty() {
91        assert(s.filter(f) == Set::<T>::empty());
92        assert(s.filter(|x| !f(x)) == Set::<T>::empty());
93    } else {
94        let x = s.choose();
95        lemma_set_separation(s.remove(x), f);
96        if f(x) {
97            assert(s.filter(f) == s.remove(x).filter(f).insert(x));
98            assert(s.filter(|x| !f(x)) == s.remove(x).filter(|x| !f(x)));
99        } else {
100            assert(s.filter(f) == s.remove(x).filter(f));
101            assert(s.filter(|x| !f(x)) == s.remove(x).filter(|x| !f(x)).insert(x));
102        }
103    }
104}
105
106/// If the length of the filtered set is equal to the length of the original set,
107/// then the filtered set is equal to the original set.
108pub proof fn lemma_filter_len_unchanged_implies_equal<T>(s: Set<T>, f: spec_fn(T) -> bool)
109    requires
110        s.filter(f).len() == s.len(),
111    ensures
112        s.filter(f) == s,
113{
114    lemma_set_separation(s, f)
115}
116
117/// If no element in set `s` fails the predicate `q`, then all elements in `s` satisfy `q`.
118pub proof fn lemma_empty_bad_set_implies_forall<T>(s: Set<T>, q: spec_fn(T) -> bool)
119    requires
120        s.filter(|x| !q(x)).is_empty(),
121    ensures
122        forall|x: T| #[trigger] s.contains(x) ==> q(x),
123{
124    assert forall|x: T| #[trigger] s.contains(x) implies q(x) by {
125        if !q(x) {
126            assert(s.filter(|x| !q(x)).contains(x));
127        };
128    }
129}
130
131/// If all elements in the set `s` satisfy predicate `q` (i.e., the filtered set has the same length),
132/// then every element of `s` satisfies `q`.
133pub proof fn lemma_full_good_set_implies_forall<T>(s: Set<T>, q: spec_fn(T) -> bool)
134    requires
135        s.len() == s.filter(q).len(),
136    ensures
137        forall|x: T| #[trigger] s.contains(x) ==> q(x),
138{
139    lemma_set_separation(s, q);
140    assert forall|x: T| #[trigger] s.contains(x) implies q(x) by {
141        if !q(x) {
142            assert(s.filter(|x| !q(x)).contains(x));
143        };
144    }
145}
146
147/// A set of sets is pairwise disjoint if all distinct sets are disjoint.
148pub open spec fn pairwise_disjoint<A>(sets: Set<Set<A>>) -> bool {
149    forall|s1: Set<A>, s2: Set<A>|
150        #![trigger sets.contains(s1), sets.contains(s2)]
151        sets.contains(s1) && sets.contains(s2) && s1 != s2 ==> s1.disjoint(s2)
152}
153
154pub open spec fn is_partition<A>(s: Set<A>, parts: Set<Set<A>>) -> bool {
155    // Each part is non-empty and a subset of s.
156    (forall|part: Set<A>| #[trigger]
157        parts.contains(part) ==> !part.is_empty() && part
158            <= s)
159    // Parts are pairwise disjoint.
160     && pairwise_disjoint(parts)
161    // The union of the parts is s.
162     && s == parts.flatten()
163}
164
165/// With no parts, `s` is a partition exactly when it is empty.
166pub proof fn lemma_is_partition_empty_parts<A>(s: Set<A>)
167    ensures
168        is_partition(s, Set::<Set<A>>::empty()) == s.is_empty(),
169{
170    reveal(is_partition);
171    assert(Set::<Set<A>>::empty().flatten() =~= Set::<A>::empty());
172}
173
174/// If `parts` is a finite set of finite, pairwise-disjoint sets,
175/// then the cardinality of the union is the sum of cardinalities.
176pub proof fn lemma_flatten_cardinality_under_disjointness<A>(parts: Set<Set<A>>)
177    requires
178        pairwise_disjoint(parts),
179    ensures
180        parts.flatten().len() == parts.fold(0nat, |acc: nat, p: Set<A>| acc + p.len()),
181    decreases parts.len(),
182{
183    if parts.is_empty() {
184        assert(parts.flatten() == Set::<A>::empty());
185        assert(parts.to_iset() == ISet::empty());
186        lemma_fold_empty(0nat, |acc: nat, p: Set<A>| acc + p.len());
187    } else {
188        let p = parts.choose();
189        let rest = parts.remove(p);
190        assert(parts == rest.insert(p));
191        lemma_flatten_cardinality_under_disjointness(rest);
192        assert(rest.flatten().len() == rest.fold(0nat, |acc: nat, p: Set<A>| acc + p.len()));
193        assert(parts.flatten() == rest.flatten().union(p));
194        assert(parts.flatten().len() == rest.flatten().len() + p.len()) by {
195            lemma_set_disjoint_lens(rest.flatten(), p);
196        }
197        assert(parts.to_iset() == rest.to_iset().insert(p));
198        lemma_fold_insert(rest.to_iset(), 0nat, |acc: nat, p: Set<A>| acc + p.len(), p);
199    }
200}
201
202/// If `parts` is a finite set of finite, pairwise-disjoint sets, and each set has the same length `c`,
203/// then the cardinality of the union is the product of the number of sets and `c`.
204pub proof fn lemma_flatten_cardinality_under_disjointness_same_length<A>(parts: Set<Set<A>>, c: nat)
205    requires
206        pairwise_disjoint(parts),
207        parts.all(|p: Set<A>| p.len() == c),
208    ensures
209        parts.flatten().len() == parts.len() * c,
210    decreases parts.len(),
211{
212    if parts.is_empty() {
213        assert(parts.flatten() == Set::<A>::empty());
214    } else {
215        let p = parts.choose();
216        let rest = parts.remove(p);
217        assert(parts == rest.insert(p));
218        lemma_flatten_cardinality_under_disjointness_same_length(rest, c);
219        assert(parts.flatten() == rest.flatten().union(p));
220        assert(parts.flatten().len() == rest.flatten().len() + p.len()) by {
221            lemma_set_disjoint_lens(rest.flatten(), p);
222        }
223        assert(parts.flatten().len() == (rest.len() + 1) * c) by (nonlinear_arith)
224            requires
225                parts.flatten().len() == rest.len() * c + c,
226        ;
227    }
228}
229
230pub open spec fn set_prop_mutual_exclusion<A>(s: Set<A>, f: spec_fn(A) -> bool) -> bool {
231    forall|x: A, y: A| #[trigger]
232        s.contains(x) && #[trigger] s.contains(y) && x != y ==> !(f(x) && f(y))
233}
234
235proof fn lemma_set_prop_mutual_exclusion_internal<A>(s: Set<A>, f: spec_fn(A) -> bool)
236    requires
237        set_prop_mutual_exclusion(s, f),
238    ensures
239        s.filter(f).len() <= 1,
240    decreases s.len(),
241{
242    if s.len() == 0 {
243        assert(s.filter(f).is_empty());
244    } else {
245        let x = s.choose();
246        lemma_set_prop_mutual_exclusion_internal(s.remove(x), f);
247        if s.remove(x).filter(f).len() == 0 {
248            if f(x) {
249                assert(s.filter(f) == s.remove(x).filter(f).insert(x));
250            } else {
251                assert(s.filter(f) == s.remove(x).filter(f));
252            }
253        } else {
254            let a = s.remove(x).filter(f).choose();
255            assert(s.remove(x).filter(f).contains(a));
256            assert(s.filter(f) == s.remove(x).filter(f));
257        }
258    }
259}
260
261pub proof fn lemma_set_prop_mutual_exclusion<A>(s: Set<A>, f: spec_fn(A) -> bool)
262    ensures
263        set_prop_mutual_exclusion(s, f) <==> s.filter(f).len() <= 1,
264{
265    if set_prop_mutual_exclusion(s, f) {
266        lemma_set_prop_mutual_exclusion_internal(s, f);
267    }
268    if s.filter(f).len() <= 1 {
269        assert forall|x: A, y: A| #[trigger]
270            s.contains(x) && #[trigger] s.contains(y) && x != y implies !(f(x) && f(y)) by {
271            if f(x) && f(y) {
272                assert(s.filter(f).contains(x));
273                assert(s.filter(f).contains(y));
274                if s.filter(f).len() == 1 {
275                    Set::lemma_is_singleton(s.filter(f));
276                }
277            }
278        };
279    }
280}
281
282} // verus!