Skip to main content

vstd/
set.rs

1#[allow(unused_imports)]
2use super::iset::*;
3#[allow(unused_imports)]
4use super::map::*;
5#[allow(unused_imports)]
6use super::pervasive::*;
7#[allow(unused_imports)]
8use super::prelude::*;
9
10verus! {
11
12/// `Set<A>` is a finite set type for specifications.
13///
14/// An object `set: Set<A>` is a subset of the set of all values `a: A`.
15/// Equivalently, it can be thought of as a boolean predicate on `A`.
16///
17/// Sets can be constructed in a few different ways:
18///  * [`Set::empty`] gives an empty set
19///  * [`Set::new`] constructs a set from a boolean predicate
20///  * The [`set!`] macro, to construct small sets of a fixed size
21///  * By manipulating an existing sequence with [`Set::union`], [`Set::intersect`],
22///    [`Set::difference`], [`Set::complement`], [`Set::filter`], [`Set::insert`],
23///    or [`Set::remove`].
24///
25/// To prove that two sequences are equal, it is usually easiest to use the extensionality
26/// operator `=~=`.
27///
28/// `Set` only holds finite sets, so it can be used in recursive types.
29/// For instance, a type `T` can contain a `Set<T>`.
30#[verifier::ext_equal]
31#[verifier::external_body]
32#[verifier::accept_recursive_types(A)]
33#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::set::Set")]
34pub struct Set<A> {
35    // To prevent Verus's internal checks from rejecting recursive types,
36    // we use an artificial definition of `Set` that hides its inclusion
37    // of a function from `A` to `bool`.
38    //
39    // To make sure that proofs in this file don't take advantage of
40    // this artificial structure (e.g., to prove that any two `Set`s are
41    // equal), we mark this definition as `external_body`.
42    //
43    // For future work, we may figure out how to have `Set` use a
44    // `Seq`-like representation that is inherently finite, to eliminate
45    // the need for this. We haven't done this yet, though, because it would
46    // introduce the problem of multiple representations of equivalent
47    // sets, which creates a different problem with extensional equality.
48    dummy: core::marker::PhantomData<A>,
49}
50
51impl<A> Set<A> {
52    /// Generates an `ISet` with the same elements
53    pub uninterp spec fn to_iset(self) -> ISet<A>;
54
55    /// Generates a `Set` from the given `ISet`, governed by
56    /// `axiom_make_set`. Thanks to the axiom `axiom_make_set`, this
57    /// function is known to produce a `Set` with the same elements as
58    /// the given `ISet`, provided that `ISet` is finite. If the given
59    /// `ISet` is infinite, it produces an arbitrary finite set.
60    uninterp spec fn make_set(s: ISet<A>) -> Set<A>;
61
62    /// This axiom says that `make_set` produces a `Set` with the same
63    /// elements as the given `ISet`, provided that `ISet` is finite.
64    /// (If the given `ISet` is infinite, `make_set` produces an
65    /// arbitrary finite set.)
66    broadcast axiom fn axiom_make_set(s: ISet<A>)
67        requires
68            s.finite(),
69        ensures
70            #![trigger Self::make_set(s).to_iset()]
71            Self::make_set(s).to_iset() == s,
72    ;
73
74    /// This axiom says that the set represented by a `Set` is always
75    /// finite.
76    broadcast axiom fn axiom_is_finite(self)
77        ensures
78            #![trigger self.to_iset().finite()]
79            self.to_iset().finite(),
80    ;
81
82    /// The "empty" set.
83    ///
84    /// Usage Example: <br>
85    /// ```rust
86    /// let empty_set = Set::<A>::empty();
87    ///
88    /// assert(empty_set.is_empty());
89    /// assert(empty_set.complement() =~= Set::<A>::full());
90    /// assert(Set::<A>::empty().finite());
91    /// assert(Set::<A>::empty().len() == 0);
92    /// assert(forall |x: A| !Set::<A>::empty().contains(x));
93    /// ```
94    /// Axioms around the empty set are: <br>
95    /// * [`lemma_set_empty_len`] <br>
96    /// * [`lemma_set_empty`]
97    #[rustc_diagnostic_item = "verus::vstd::set::Set::empty"]
98    pub closed spec fn empty() -> Set<A> {
99        Self::make_set(ISet::<A>::empty())
100    }
101
102    /// Set whose membership is determined by the given `ISet`,
103    /// but only if that `ISet` is finite.
104    ///
105    /// Usage Examples:
106    /// ```rust
107    /// let iset_a = ISet::new(|x : nat| x < 42);
108    /// let option_set_b = Set::<A>::new(iset_a);
109    /// assert(iset_a.finite() ==>
110    ///        option_set_b matches Some(s) &&
111    ///        forall|x| x < 42 <==> s.contains(x));
112    /// ```
113    pub closed spec fn new_from_iset(s: ISet<A>) -> Option<Set<A>> {
114        if s.finite() {
115            Some(Self::make_set(s))
116        } else {
117            None
118        }
119    }
120
121    /// Set whose membership is determined by the given boolean predicate,
122    /// but only if the predicate produces a finite set. (If it produces an
123    /// infinite set, the result of this function is None.)
124    ///
125    /// Usage Examples:
126    /// ```rust
127    /// let option_set_a = Set::new(|x : nat| x < 42);
128    /// let option_set_b = Set::<A>::new(|x| some_predicate(x));
129    /// assert(ISet::new(|x| some_predicate(x)).finite()) ==>
130    ///        option_set_b matches Some(s) &&
131    ///        forall|x| some_predicate(x) <==> s.contains(x));
132    /// ```
133    pub closed spec fn new(f: spec_fn(A) -> bool) -> Option<Set<A>> {
134        Self::new_from_iset(ISet::new(f))
135    }
136
137    /// The "full" set, i.e., set containing every element of type `A`.
138    /// Note that if `A` is infinite, then this produces None.
139    #[rustc_diagnostic_item = "verus::vstd::set::Set::full"]
140    pub open spec fn full() -> Option<Set<A>> {
141        Set::new(|a: A| true)
142    }
143
144    /// Predicate indicating if the set contains the given element.
145    #[rustc_diagnostic_item = "verus::vstd::set::Set::contains"]
146    #[verifier::inline]
147    pub open spec fn contains(self, a: A) -> bool {
148        self.to_iset().contains(a)
149    }
150
151    /// Predicate indicating if the set contains the given element: supports `self has a` syntax.
152    #[verifier::inline]
153    pub open spec fn spec_has(self, a: A) -> bool {
154        self.contains(a)
155    }
156
157    /// Returns `true` if the first argument is a subset of the second.
158    #[rustc_diagnostic_item = "verus::vstd::set::Set::subset_of"]
159    pub open spec fn subset_of(self, s2: Set<A>) -> bool {
160        forall|a: A| self.contains(a) ==> s2.contains(a)
161    }
162
163    #[verifier::inline]
164    pub open spec fn spec_le(self, s2: Set<A>) -> bool {
165        self.subset_of(s2)
166    }
167
168    /// Returns a new set with the given element inserted.
169    /// If that element is already in the set, then an identical set is returned.
170    #[rustc_diagnostic_item = "verus::vstd::set::Set::insert"]
171    pub closed spec fn insert(self, a: A) -> Set<A> {
172        Self::make_set(self.to_iset().insert(a))
173    }
174
175    /// Returns a new set with the given element removed.
176    /// If that element is already absent from the set, then an identical set is returned.
177    #[rustc_diagnostic_item = "verus::vstd::set::Set::remove"]
178    pub closed spec fn remove(self, a: A) -> Set<A> {
179        Self::make_set(self.to_iset().remove(a))
180    }
181
182    /// Union of two sets.
183    pub closed spec fn union(self, s2: Set<A>) -> Set<A> {
184        Self::make_set(self.to_iset().union(s2.to_iset()))
185    }
186
187    /// `+` operator, synonymous with `union`
188    #[verifier::inline]
189    pub open spec fn spec_add(self, s2: Set<A>) -> Set<A> {
190        self.union(s2)
191    }
192
193    /// Intersection of two sets.
194    pub closed spec fn intersect(self, s2: Set<A>) -> Set<A> {
195        Self::make_set(self.to_iset().intersect(s2.to_iset()))
196    }
197
198    /// `*` operator, synonymous with `intersect`
199    #[verifier::inline]
200    pub open spec fn spec_mul(self, s2: Set<A>) -> Set<A> {
201        self.intersect(s2)
202    }
203
204    /// Set difference, i.e., the set of all elements in the first one but not in the second.
205    pub closed spec fn difference(self, s2: Set<A>) -> Set<A> {
206        Self::make_set(self.to_iset().difference(s2.to_iset()))
207    }
208
209    /// `-` operator, synonymous with `difference`
210    #[verifier::inline]
211    pub open spec fn spec_sub(self, s2: Set<A>) -> Set<A> {
212        self.difference(s2)
213    }
214
215    /// Set complement (within the space of all possible elements in `A`).
216    /// Returns None if this would be an infinite set.
217    pub open spec fn complement(self) -> Option<Set<A>> {
218        Set::new(|a| !self.contains(a))
219    }
220
221    /// Set of all elements in the given set which satisfy the predicate `f`.
222    pub closed spec fn filter(self, f: spec_fn(A) -> bool) -> Set<A> {
223        Self::make_set(self.to_iset().filter(f))
224    }
225
226    /// Returns `true` if the set is finite.
227    #[deprecated(note = "Every Set is always finite, so this is always true.")]
228    pub open spec fn finite(self) -> bool {
229        true
230    }
231
232    /// Returns `true` if this set is congruent to (contains the same elements as)
233    /// a given ISet.
234    pub open spec fn congruent(self, s2: ISet<A>) -> bool {
235        forall|a: A| #![all_triggers] self.contains(a) <==> s2.contains(a)
236    }
237
238    /// Cardinality of the set.
239    pub closed spec fn len(self) -> nat {
240        self.to_iset().len()
241    }
242
243    /// Chooses an arbitrary element of the set.
244    ///
245    /// This is often useful for proofs by induction.
246    ///
247    /// (Note that, although the result is arbitrary, it is still a _deterministic_ function
248    /// like any other `spec` function.)
249    pub open spec fn choose(self) -> A {
250        choose|a: A| self.contains(a)
251    }
252
253    /// Returns `true` if the sets are disjoint, i.e., if their interesection is
254    /// the empty set.
255    pub open spec fn disjoint(self, s2: Self) -> bool {
256        forall|a: A| self.contains(a) ==> !s2.contains(a)
257    }
258}
259
260/// Sets `s1` and `s2` are considered equal if and only if they contain all of the same elements.
261/// This has to be an axiom because `Set` is `external_body`.
262pub broadcast proof fn axiom_set_ext_equal<A>(s1: Set<A>, s2: Set<A>)
263    ensures
264        #[trigger] (s1 =~= s2) <==> (forall|a: A| s1.contains(a) == s2.contains(a)),
265{
266    admit();
267}
268
269/// Sets `s1` and `s2` are considered equal if and only if they contain all of the same elements.
270/// This has to be an axiom because `Set` is `external_body`.
271pub broadcast proof fn axiom_set_ext_equal_deep<A>(s1: Set<A>, s2: Set<A>)
272    ensures
273        #[trigger] (s1 =~~= s2) <==> s1 =~= s2,
274{
275    admit();
276}
277
278/// A member of a `Set` is less than that `Set`.
279pub broadcast axiom fn axiom_set_decreases_to_member<A>(s: Set<A>, a: A)
280    requires
281        #[trigger] s.contains(a),
282    ensures
283        #[trigger] (decreases_to!(s => a)),
284;
285
286broadcast use super::iset::group_iset_lemmas;
287
288pub mod fold {
289    use super::*;
290
291    impl<A> Set<A> {
292        /// Folds the set, applying `f` to perform the fold. The next element for the fold is chosen by
293        /// the choose operator.
294        ///
295        /// Given a set `s = {x0, x1, x2, ..., xn}`, applying this function `s.fold(init, f)`
296        /// returns `f(...f(f(init, x0), x1), ..., xn)`.
297        #[verifier::inline]
298        pub open spec fn fold<B>(self, z: B, f: spec_fn(B, A) -> B) -> B
299            recommends
300                super::super::iset::fold::is_fun_commutative(f),
301        {
302            self.to_iset().fold(z, f)
303        }
304    }
305
306}
307
308/// The empty set contains no elements
309pub broadcast proof fn lemma_set_empty<A>(a: A)
310    ensures
311        !(#[trigger] Set::empty().contains(a)),
312{
313    broadcast use Set::axiom_make_set;
314
315}
316
317/// If `Set::<A>::new(f)` produces `Some(s)`, then `s` contains `a`
318/// if and only if `f(a)` is true.
319pub broadcast proof fn lemma_set_new<A>(f: spec_fn(A) -> bool, a: A)
320    requires
321        Set::<A>::new(f) is Some,
322    ensures
323        #[trigger] Set::<A>::new(f).unwrap().contains(a) == f(a),
324{
325    broadcast use Set::axiom_make_set;
326
327}
328
329/// If `ISet::<A>::new(f)` is finite, then `Set::<A>::new(f)`
330/// produces `Some(s)`. Useful for triggering the `lemma_set_new`
331/// to show that `s` contains `a` if and only if `f(a)` is true.
332pub broadcast proof fn lemma_set_new_some<A>(f: spec_fn(A) -> bool)
333    requires
334        ISet::<A>::new(f).finite(),
335    ensures
336        #[trigger] Set::<A>::new(f) is Some,
337{
338    broadcast use Set::axiom_make_set;
339
340}
341
342/// If an iset `s` is finite, then `Set::new_from_iset(s)` has the same
343/// contents as `s`.
344pub broadcast proof fn lemma_set_new_from_iset<A>(s: ISet<A>)
345    requires
346        s.finite(),
347    ensures
348        #![trigger Set::<A>::new_from_iset(s)]
349        Set::<A>::new_from_iset(s) is Some,
350        Set::<A>::new_from_iset(s).unwrap().to_iset() == s,
351{
352    broadcast use Set::axiom_make_set;
353
354    assert(ISet::new(|a: A| s.contains(a)) =~= s);
355}
356
357/// The result of inserting element `a` into set `s` must contains `a`.
358pub broadcast proof fn lemma_set_insert_same<A>(s: Set<A>, a: A)
359    ensures
360        #[trigger] s.insert(a).contains(a),
361{
362    broadcast use Set::axiom_make_set;
363    broadcast use Set::axiom_is_finite;
364
365}
366
367/// If `a1` does not equal `a2`, then the result of inserting element `a2` into set `s`
368/// must contain `a1` if and only if the set contained `a1` before the insertion of `a2`.
369pub broadcast proof fn lemma_set_insert_different<A>(s: Set<A>, a1: A, a2: A)
370    requires
371        a1 != a2,
372    ensures
373        #[trigger] s.insert(a2).contains(a1) == s.contains(a1),
374{
375    broadcast use Set::axiom_make_set;
376    broadcast use Set::axiom_is_finite;
377
378}
379
380/// The result of removing element `a` from set `s` must not contain `a`.
381pub broadcast proof fn lemma_set_remove_same<A>(s: Set<A>, a: A)
382    ensures
383        !(#[trigger] s.remove(a).contains(a)),
384{
385    broadcast use Set::axiom_make_set;
386    broadcast use Set::axiom_is_finite;
387
388}
389
390/// Removing an element `a` from a set `s` and then inserting `a` back into the set`
391/// is equivalent to the original set `s`.
392pub broadcast proof fn lemma_set_remove_insert<A>(s: Set<A>, a: A)
393    requires
394        s.contains(a),
395    ensures
396        (#[trigger] s.remove(a)).insert(a) == s,
397{
398    assert forall|aa| #![all_triggers] s.remove(a).insert(a).contains(aa) implies s.contains(
399        aa,
400    ) by {
401        if a == aa {
402        } else {
403            lemma_set_remove_different(s, aa, a);
404            lemma_set_insert_different(s.remove(a), aa, a);
405        }
406    };
407    assert forall|aa| #![all_triggers] s.contains(aa) implies s.remove(a).insert(a).contains(
408        aa,
409    ) by {
410        if a == aa {
411            lemma_set_insert_same(s.remove(a), a);
412        } else {
413            lemma_set_remove_different(s, aa, a);
414            lemma_set_insert_different(s.remove(a), aa, a);
415        }
416    };
417    axiom_set_ext_equal(s.remove(a).insert(a), s);
418}
419
420/// If `a1` does not equal `a2`, then the result of removing element `a2` from set `s`
421/// must contain `a1` if and only if the set contained `a1` before the removal of `a2`.
422pub broadcast proof fn lemma_set_remove_different<A>(s: Set<A>, a1: A, a2: A)
423    requires
424        a1 != a2,
425    ensures
426        #[trigger] s.remove(a2).contains(a1) == s.contains(a1),
427{
428    broadcast use axiom_set_ext_equal;
429    broadcast use Set::axiom_make_set;
430    broadcast use Set::axiom_is_finite;
431
432}
433
434/// The union of sets `s1` and `s2` contains element `a` if and only if
435/// `s1` contains `a` and/or `s2` contains `a`.
436pub broadcast proof fn lemma_set_union<A>(s1: Set<A>, s2: Set<A>, a: A)
437    ensures
438        #[trigger] s1.union(s2).contains(a) == (s1.contains(a) || s2.contains(a)),
439{
440    broadcast use axiom_set_ext_equal;
441    broadcast use Set::axiom_make_set;
442    broadcast use Set::axiom_is_finite;
443
444}
445
446/// The intersection of sets `s1` and `s2` contains element `a` if and only if
447/// both `s1` and `s2` contain `a`.
448pub broadcast proof fn lemma_set_intersect<A>(s1: Set<A>, s2: Set<A>, a: A)
449    ensures
450        #[trigger] s1.intersect(s2).contains(a) == (s1.contains(a) && s2.contains(a)),
451{
452    broadcast use axiom_set_ext_equal;
453    broadcast use Set::axiom_make_set;
454    broadcast use Set::axiom_is_finite;
455
456}
457
458/// The set difference between `s1` and `s2` contains element `a` if and only if
459/// `s1` contains `a` and `s2` does not contain `a`.
460pub broadcast proof fn lemma_set_difference<A>(s1: Set<A>, s2: Set<A>, a: A)
461    ensures
462        #[trigger] s1.difference(s2).contains(a) == (s1.contains(a) && !s2.contains(a)),
463{
464    broadcast use Set::axiom_make_set;
465    broadcast use Set::axiom_is_finite;
466
467}
468
469/// The complement of set `s` contains element `a` if and only if `s` does not contain `a`.
470pub broadcast proof fn lemma_set_complement<A>(s: Set<A>, a: A)
471    requires
472        ISet::new(|a| !s.contains(a)).finite(),
473    ensures
474        #[trigger] s.complement().unwrap().contains(a) == !s.contains(a),
475{
476    broadcast use Set::axiom_make_set;
477
478}
479
480/// The filter of set `s` using function `f` contains element `a` if and only if `s` contains `a`
481/// and `f(a)` is true.
482pub broadcast proof fn lemma_set_filter<A>(s: Set<A>, f: spec_fn(A) -> bool, a: A)
483    ensures
484        #[trigger] s.filter(f).contains(a) == (s.contains(a) && f(a)),
485{
486    broadcast use Set::axiom_make_set;
487    broadcast use Set::axiom_is_finite;
488
489}
490
491// Lemmas about len
492// The following, with lemma_set_ext_equal, are enough to build libraries about len.
493/// The empty set has length 0.
494pub broadcast proof fn lemma_set_empty_len<A>()
495    ensures
496        #[trigger] Set::<A>::empty().len() == 0,
497{
498    broadcast use Set::axiom_make_set;
499
500}
501
502/// The result of inserting an element `a` into a finite set `s` has length
503/// `s.len() + 1` if `a` is not already in `s` and length `s.len()` otherwise.
504pub broadcast proof fn lemma_set_insert_len<A>(s: Set<A>, a: A)
505    ensures
506        #[trigger] s.insert(a).len() == s.len() + (if s.contains(a) {
507            0int
508        } else {
509            1
510        }),
511{
512    broadcast use Set::axiom_make_set;
513    broadcast use Set::axiom_is_finite;
514
515}
516
517/// The result of removing an element `a` from a finite set `s` has length
518/// `s.len() - 1` if `a` is in `s` and length `s.len()` otherwise.
519pub broadcast proof fn lemma_set_remove_len<A>(s: Set<A>, a: A)
520    ensures
521        s.len() == #[trigger] s.remove(a).len() + (if s.contains(a) {
522            1int
523        } else {
524            0
525        }),
526{
527    broadcast use Set::axiom_make_set;
528    broadcast use Set::axiom_is_finite;
529
530}
531
532/// If a finite set `s` contains any element, it has length greater than 0.
533pub broadcast proof fn lemma_set_contains_len<A>(s: Set<A>, a: A)
534    requires
535        #[trigger] s.contains(a),
536    ensures
537        #[trigger] s.len() != 0,
538{
539    broadcast use Set::axiom_make_set;
540    broadcast use Set::axiom_is_finite;
541
542}
543
544/// A finite set `s` contains the element `s.choose()` if it has length greater than 0.
545pub broadcast proof fn lemma_set_choose_len<A>(s: Set<A>)
546    requires
547        #[trigger] s.len() != 0,
548    ensures
549        #[trigger] s.contains(s.choose()),
550{
551    assert(s.to_iset().contains(s.to_iset().choose()));
552}
553
554/// Converting a `Set` to an `ISet` produces a finite result.
555pub broadcast proof fn lemma_to_iset_finite<A>(s: Set<A>)
556    ensures
557        #[trigger] s.to_iset().finite(),
558{
559    broadcast use Set::axiom_make_set;
560    broadcast use Set::axiom_is_finite;
561
562}
563
564/// Converting a `Set` to an `ISet` produces a result with the same
565/// length.
566pub broadcast proof fn lemma_to_iset_len<A>(s: Set<A>)
567    ensures
568        #[trigger] s.to_iset().len() == s.len(),
569{
570    broadcast use Set::axiom_make_set;
571    broadcast use Set::axiom_is_finite;
572
573}
574
575pub broadcast group group_set_lemmas {
576    axiom_set_ext_equal,
577    axiom_set_ext_equal_deep,
578    axiom_set_decreases_to_member,
579    lemma_set_empty,
580    lemma_set_new,
581    lemma_set_new_from_iset,
582    lemma_set_new_some,
583    lemma_set_insert_same,
584    lemma_set_insert_different,
585    lemma_set_remove_same,
586    lemma_set_remove_insert,
587    lemma_set_remove_different,
588    lemma_set_union,
589    lemma_set_intersect,
590    lemma_set_difference,
591    lemma_set_complement,
592    lemma_set_filter,
593    lemma_set_empty_len,
594    lemma_set_insert_len,
595    lemma_set_remove_len,
596    lemma_set_contains_len,
597    lemma_set_choose_len,
598    lemma_set_new,
599    lemma_to_iset_finite,
600    lemma_to_iset_len,
601}
602
603// Macros
604#[doc(hidden)]
605#[macro_export]
606macro_rules! set_internal {
607    [$($elem:expr),* $(,)?] => {
608        $crate::vstd::set::Set::empty()
609            $(.insert($elem))*
610    };
611}
612
613#[macro_export]
614macro_rules! set {
615    [$($tail:tt)*] => {
616        $crate::vstd::prelude::verus_proof_macro_exprs!($crate::vstd::set::set_internal!($($tail)*))
617    };
618}
619
620pub use set_internal;
621pub use set;
622
623} // verus!