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