Skip to main content

vstd/
iset.rs

1#[allow(unused_imports)]
2use super::map::*;
3#[allow(unused_imports)]
4use super::pervasive::*;
5#[allow(unused_imports)]
6use super::prelude::*;
7
8verus! {
9
10/// `ISet<A>` is a set type for specifications.
11///
12/// An object `set: ISet<A>` is a subset of the set of all values `a: A`.
13/// Equivalently, it can be thought of as a boolean predicate on `A`.
14///
15/// In general, a set might be infinite.
16/// To work specifically with finite sets, see the [`self.finite()`](ISet::finite) predicate.
17///
18/// ISets can be constructed in a few different ways:
19///  * [`ISet::empty`] gives an empty set
20///  * [`ISet::full`] gives the set of all elements in `A`
21///  * [`ISet::new`] constructs a set from a boolean predicate
22///  * The [`iset!`] macro, to construct small sets of a fixed size
23///  * By manipulating an existing sequence with [`ISet::union`], [`ISet::intersect`],
24///    [`ISet::difference`], [`ISet::complement`], [`ISet::filter`], [`ISet::insert`],
25///    or [`ISet::remove`].
26///
27/// To prove that two sequences are equal, it is usually easiest to use the extensionality
28/// operator `=~=`.
29#[verifier::ext_equal]
30#[verifier::reject_recursive_types(A)]
31#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::iset::ISet")]
32pub struct ISet<A> {
33    set: spec_fn(A) -> bool,
34}
35
36impl<A> ISet<A> {
37    /// The "empty" set.
38    ///
39    /// Usage Example: <br>
40    /// ```rust
41    /// let empty_set = ISet::<A>::empty();
42    ///
43    /// assert(empty_set.is_empty());
44    /// assert(empty_set.complement() =~= ISet::<A>::full());
45    /// assert(ISet::<A>::empty().finite());
46    /// assert(ISet::<A>::empty().len() == 0);
47    /// assert(forall |x: A| !ISet::<A>::empty().contains(x));
48    /// ```
49    /// Axioms around the empty set are: <br>
50    /// * [`lemma_iset_empty_finite`]
51    /// * [`lemma_iset_empty_len`] <br>
52    /// * [`lemma_iset_empty`]
53    #[rustc_diagnostic_item = "verus::vstd::iset::ISet::empty"]
54    pub closed spec fn empty() -> ISet<A> {
55        ISet { set: |a| false }
56    }
57
58    /// ISet whose membership is determined by the given boolean predicate.
59    ///
60    /// Usage Examples:
61    /// ```rust
62    /// let set_a = ISet::new(|x : nat| x < 42);
63    /// let set_b = ISet::<A>::new(|x| some_predicate(x));
64    /// assert(forall|x| some_predicate(x) <==> set_b.contains(x));
65    /// ```
66    pub closed spec fn new(f: spec_fn(A) -> bool) -> ISet<A> {
67        ISet { set: f }
68    }
69
70    /// The "full" set, i.e., set containing every element of type `A`.
71    #[rustc_diagnostic_item = "verus::vstd::iset::ISet::full"]
72    pub open spec fn full() -> ISet<A> {
73        ISet::empty().complement()
74    }
75
76    /// Predicate indicating if the set contains the given element.
77    #[rustc_diagnostic_item = "verus::vstd::iset::ISet::contains"]
78    pub closed spec fn contains(self, a: A) -> bool {
79        (self.set)(a)
80    }
81
82    /// Predicate indicating if the set contains the given element: supports `self has a` syntax.
83    #[verifier::inline]
84    pub open spec fn spec_has(self, a: A) -> bool {
85        self.contains(a)
86    }
87
88    /// Returns `true` if the first argument is a subset of the second.
89    #[rustc_diagnostic_item = "verus::vstd::iset::ISet::subset_of"]
90    pub open spec fn subset_of(self, s2: ISet<A>) -> bool {
91        forall|a: A| self.contains(a) ==> s2.contains(a)
92    }
93
94    #[verifier::inline]
95    pub open spec fn spec_le(self, s2: ISet<A>) -> bool {
96        self.subset_of(s2)
97    }
98
99    /// Returns a new set with the given element inserted.
100    /// If that element is already in the set, then an identical set is returned.
101    #[rustc_diagnostic_item = "verus::vstd::iset::ISet::insert"]
102    pub closed spec fn insert(self, a: A) -> ISet<A> {
103        ISet {
104            set: |a2|
105                if a2 == a {
106                    true
107                } else {
108                    (self.set)(a2)
109                },
110        }
111    }
112
113    /// Returns a new set with the given element removed.
114    /// If that element is already absent from the set, then an identical set is returned.
115    #[rustc_diagnostic_item = "verus::vstd::iset::ISet::remove"]
116    pub closed spec fn remove(self, a: A) -> ISet<A> {
117        ISet {
118            set: |a2|
119                if a2 == a {
120                    false
121                } else {
122                    (self.set)(a2)
123                },
124        }
125    }
126
127    /// Union of two sets.
128    pub closed spec fn union(self, s2: ISet<A>) -> ISet<A> {
129        ISet { set: |a| (self.set)(a) || (s2.set)(a) }
130    }
131
132    /// `+` operator, synonymous with `union`
133    #[verifier::inline]
134    pub open spec fn spec_add(self, s2: ISet<A>) -> ISet<A> {
135        self.union(s2)
136    }
137
138    /// Intersection of two sets.
139    pub closed spec fn intersect(self, s2: ISet<A>) -> ISet<A> {
140        ISet { set: |a| (self.set)(a) && (s2.set)(a) }
141    }
142
143    /// `*` operator, synonymous with `intersect`
144    #[verifier::inline]
145    pub open spec fn spec_mul(self, s2: ISet<A>) -> ISet<A> {
146        self.intersect(s2)
147    }
148
149    /// ISet difference, i.e., the set of all elements in the first one but not in the second.
150    pub closed spec fn difference(self, s2: ISet<A>) -> ISet<A> {
151        ISet { set: |a| (self.set)(a) && !(s2.set)(a) }
152    }
153
154    /// `-` operator, synonymous with `difference`
155    #[verifier::inline]
156    pub open spec fn spec_sub(self, s2: ISet<A>) -> ISet<A> {
157        self.difference(s2)
158    }
159
160    /// ISet complement (within the space of all possible elements in `A`).
161    pub closed spec fn complement(self) -> ISet<A> {
162        ISet { set: |a| !(self.set)(a) }
163    }
164
165    /// ISet of all elements in the given set which satisfy the predicate `f`.
166    pub open spec fn filter(self, f: spec_fn(A) -> bool) -> ISet<A> {
167        self.intersect(Self::new(f))
168    }
169
170    /// Returns `true` if the set is finite.
171    pub closed spec fn finite(self) -> bool {
172        exists|f: spec_fn(A) -> nat, ub: nat|
173            {
174                &&& #[trigger] trigger_finite(f, ub)
175                &&& surj_on(f, self)
176                &&& forall|a| self.contains(a) ==> f(a) < ub
177            }
178    }
179
180    pub open spec fn to_set(self) -> Option<Set<A>>
181        recommends
182            self.finite(),
183    {
184        Set::<A>::new_from_iset(self)
185    }
186
187    /// Cardinality of the set. (Only meaningful if a set is finite.)
188    pub closed spec fn len(self) -> nat {
189        self.fold(0, |acc: nat, a| acc + 1)
190    }
191
192    /// Chooses an arbitrary element of the set.
193    ///
194    /// This is often useful for proofs by induction.
195    ///
196    /// (Note that, although the result is arbitrary, it is still a _deterministic_ function
197    /// like any other `spec` function.)
198    pub open spec fn choose(self) -> A {
199        choose|a: A| self.contains(a)
200    }
201
202    /// Creates a [`Map`] whose domain is the given set.
203    /// The values of the map are given by `f`, a function of the keys.
204    pub uninterp spec fn mk_map<V>(self, f: spec_fn(A) -> V) -> IMap<A, V>;
205
206    /// Returns `true` if the sets are disjoint, i.e., if their interesection is
207    /// the empty set.
208    pub open spec fn disjoint(self, s2: Self) -> bool {
209        forall|a: A| self.contains(a) ==> !s2.contains(a)
210    }
211
212    /// Returns `true` if this set is congruent to (contains the same elements as)
213    /// a given finite Set.
214    pub open spec fn congruent(self, s2: Set<A>) -> bool {
215        forall|a: A| #![all_triggers] self.contains(a) <==> s2.contains(a)
216    }
217}
218
219// Closures make triggering finicky but using this to trigger explicitly works well.
220spec fn trigger_finite<A>(f: spec_fn(A) -> nat, ub: nat) -> bool {
221    true
222}
223
224spec fn surj_on<A, B>(f: spec_fn(A) -> B, s: ISet<A>) -> bool {
225    forall|a1, a2| #![all_triggers] s.contains(a1) && s.contains(a2) && a1 != a2 ==> f(a1) != f(a2)
226}
227
228pub mod fold {
229    //! This module defines a fold function for finite sets and proves a number of associated
230    //! lemmas.
231    //!
232    //! The module was ported (with some modifications) from Isabelle/HOL's finite set theory in:
233    //! `HOL/Finite_ISet.thy`
234    //! That file contains the following author list:
235    //!
236    //!
237    //! (*  Title:      HOL/Finite_ISet.thy
238    //!     Author:     Tobias Nipkow
239    //!     Author:     Lawrence C Paulson
240    //!     Author:     Markus Wenzel
241    //!     Author:     Jeremy Avigad
242    //!     Author:     Andrei Popescu
243    //! *)
244    //!
245    //!
246    //! The file is distributed under a 3-clause BSD license as indicated in the file `COPYRIGHT`
247    //! in Isabelle's root directory, which also carries the following copyright notice:
248    //!
249    //! Copyright (c) 1986-2024,
250    //! University of Cambridge,
251    //! Technische Universitaet Muenchen,
252    //! and contributors.
253    use super::*;
254
255    broadcast group group_iset_lemmas_early {
256        lemma_iset_empty,
257        lemma_iset_new,
258        lemma_iset_insert_same,
259        lemma_iset_insert_different,
260        lemma_iset_remove_same,
261        lemma_iset_remove_insert,
262        lemma_iset_remove_different,
263        lemma_iset_union,
264        lemma_iset_intersect,
265        lemma_iset_difference,
266        lemma_iset_complement,
267        lemma_iset_ext_equal,
268        lemma_iset_ext_equal_deep,
269        lemma_iset_empty_finite,
270        lemma_iset_insert_finite,
271        lemma_iset_remove_finite,
272    }
273
274    pub open spec fn is_fun_commutative<A, B>(f: spec_fn(B, A) -> B) -> bool {
275        forall|a1, a2, b| #[trigger] f(f(b, a2), a1) == f(f(b, a1), a2)
276    }
277
278    // This predicate is intended to be used like an inductive predicate, with the corresponding
279    // introduction, elimination and induction rules proved below.
280    #[verifier(opaque)]
281    spec fn fold_graph<A, B>(z: B, f: spec_fn(B, A) -> B, s: ISet<A>, y: B, d: nat) -> bool
282        decreases d,
283    {
284        if s === ISet::empty() {
285            &&& z == y
286            &&& d == 0
287        } else {
288            exists|yr, a|
289                {
290                    &&& #[trigger] trigger_fold_graph(yr, a)
291                    &&& d > 0
292                    &&& s.remove(a).finite()
293                    &&& s.contains(a)
294                    &&& fold_graph(z, f, s.remove(a), yr, sub(d, 1))
295                    &&& y == f(yr, a)
296                }
297        }
298    }
299
300    spec fn trigger_fold_graph<A, B>(yr: B, a: A) -> bool {
301        true
302    }
303
304    // Introduction rules
305    proof fn lemma_fold_graph_empty_intro<A, B>(z: B, f: spec_fn(B, A) -> B)
306        ensures
307            fold_graph(z, f, ISet::empty(), z, 0),
308    {
309        reveal(fold_graph);
310    }
311
312    proof fn lemma_fold_graph_insert_intro<A, B>(
313        z: B,
314        f: spec_fn(B, A) -> B,
315        s: ISet<A>,
316        y: B,
317        d: nat,
318        a: A,
319    )
320        requires
321            fold_graph(z, f, s, y, d),
322            !s.contains(a),
323        ensures
324            fold_graph(z, f, s.insert(a), f(y, a), d + 1),
325    {
326        broadcast use group_iset_lemmas_early;
327
328        reveal(fold_graph);
329        let _ = trigger_fold_graph(y, a);
330        assert(s == s.insert(a).remove(a));
331    }
332
333    // Elimination rules
334    proof fn lemma_fold_graph_empty_elim<A, B>(z: B, f: spec_fn(B, A) -> B, y: B, d: nat)
335        requires
336            fold_graph(z, f, ISet::empty(), y, d),
337        ensures
338            z == y,
339            d == 0,
340    {
341        reveal(fold_graph);
342    }
343
344    proof fn lemma_fold_graph_insert_elim<A, B>(
345        z: B,
346        f: spec_fn(B, A) -> B,
347        s: ISet<A>,
348        y: B,
349        d: nat,
350        a: A,
351    )
352        requires
353            is_fun_commutative(f),
354            fold_graph(z, f, s.insert(a), y, d),
355            !s.contains(a),
356        ensures
357            d > 0,
358            exists|yp| y == f(yp, a) && #[trigger] fold_graph(z, f, s, yp, sub(d, 1)),
359    {
360        reveal(fold_graph);
361        lemma_fold_graph_insert_elim_aux(z, f, s.insert(a), y, d, a);
362        assert(s.insert(a).remove(a) =~= s);
363        let yp = choose|yp| y == f(yp, a) && #[trigger] fold_graph(z, f, s, yp, sub(d, 1));
364    }
365
366    proof fn lemma_fold_graph_insert_elim_aux<A, B>(
367        z: B,
368        f: spec_fn(B, A) -> B,
369        s: ISet<A>,
370        y: B,
371        d: nat,
372        a: A,
373    )
374        requires
375            is_fun_commutative(f),
376            fold_graph(z, f, s, y, d),
377            s.contains(a),
378        ensures
379            exists|yp| y == f(yp, a) && #[trigger] fold_graph(z, f, s.remove(a), yp, sub(d, 1)),
380        decreases d,
381    {
382        broadcast use group_iset_lemmas_early;
383
384        reveal(fold_graph);
385        let (yr, aa): (B, A) = choose|yr, aa|
386            #![all_triggers]
387            {
388                &&& trigger_fold_graph(yr, a)
389                &&& d > 0
390                &&& s.remove(aa).finite()
391                &&& s.contains(aa)
392                &&& fold_graph(z, f, s.remove(aa), yr, sub(d, 1))
393                &&& y == f(yr, aa)
394            };
395        assert(trigger_fold_graph(yr, a));
396        if s.remove(aa) === ISet::empty() {
397        } else {
398            if a == aa {
399            } else {
400                lemma_fold_graph_insert_elim_aux(z, f, s.remove(aa), yr, sub(d, 1), a);
401                let yrp = choose|yrp|
402                    yr == f(yrp, a) && #[trigger] fold_graph(
403                        z,
404                        f,
405                        s.remove(aa).remove(a),
406                        yrp,
407                        sub(d, 2),
408                    );
409                assert(fold_graph(z, f, s.remove(aa).insert(aa).remove(a), f(yrp, aa), sub(d, 1)))
410                    by {
411                    assert(s.remove(aa).remove(a) == s.remove(aa).insert(aa).remove(a).remove(aa));
412                    assert(trigger_fold_graph(yrp, aa));
413                };
414            }
415        }
416    }
417
418    // Induction rule
419    proof fn lemma_fold_graph_induct<A, B>(
420        z: B,
421        f: spec_fn(B, A) -> B,
422        s: ISet<A>,
423        y: B,
424        d: nat,
425        pred: spec_fn(ISet<A>, B, nat) -> bool,
426    )
427        requires
428            is_fun_commutative(f),
429            fold_graph(z, f, s, y, d),
430            pred(ISet::empty(), z, 0),
431            forall|a, s, y, d|
432                pred(s, y, d) && !s.contains(a) && #[trigger] fold_graph(z, f, s, y, d) ==> pred(
433                    #[trigger] s.insert(a),
434                    f(y, a),
435                    d + 1,
436                ),
437        ensures
438            pred(s, y, d),
439        decreases d,
440    {
441        broadcast use group_iset_lemmas_early;
442
443        reveal(fold_graph);
444        if s === ISet::empty() {
445            lemma_fold_graph_empty_elim(z, f, y, d);
446        } else {
447            let a = s.choose();
448            lemma_fold_graph_insert_elim(z, f, s.remove(a), y, d, a);
449            let yp = choose|yp|
450                y == f(yp, a) && #[trigger] fold_graph(z, f, s.remove(a), yp, sub(d, 1));
451            lemma_fold_graph_induct(z, f, s.remove(a), yp, sub(d, 1), pred);
452        }
453    }
454
455    impl<A> ISet<A> {
456        /// Folds the set, applying `f` to perform the fold. The next element for the fold is chosen by
457        /// the choose operator.
458        ///
459        /// Given a set `s = {x0, x1, x2, ..., xn}`, applying this function `s.fold(init, f)`
460        /// returns `f(...f(f(init, x0), x1), ..., xn)`.
461        pub closed spec fn fold<B>(self, z: B, f: spec_fn(B, A) -> B) -> B
462            recommends
463                self.finite(),
464                is_fun_commutative(f),
465        {
466            let (y, d): (B, nat) = choose|y, d| fold_graph(z, f, self, y, d);
467            y
468        }
469    }
470
471    proof fn lemma_fold_graph_finite<A, B>(z: B, f: spec_fn(B, A) -> B, s: ISet<A>, y: B, d: nat)
472        requires
473            is_fun_commutative(f),
474            fold_graph(z, f, s, y, d),
475        ensures
476            s.finite(),
477    {
478        broadcast use group_iset_lemmas_early;
479
480        let pred = |s: ISet<A>, y, d| s.finite();
481        lemma_fold_graph_induct(z, f, s, y, d, pred);
482    }
483
484    proof fn lemma_fold_graph_deterministic<A, B>(
485        z: B,
486        f: spec_fn(B, A) -> B,
487        s: ISet<A>,
488        y1: B,
489        y2: B,
490        d1: nat,
491        d2: nat,
492    )
493        requires
494            is_fun_commutative(f),
495            fold_graph(z, f, s, y1, d1),
496            fold_graph(z, f, s, y2, d2),
497        ensures
498            y1 == y2,
499            d1 == d2,
500    {
501        let pred = |s: ISet<A>, y1: B, d1: nat|
502            forall|y2, d2| fold_graph(z, f, s, y2, d2) ==> y1 == y2 && d2 == d1;
503        // Base case
504        assert(pred(ISet::empty(), z, 0)) by {
505            assert forall|y2, d2| fold_graph(z, f, ISet::empty(), y2, d2) implies z == y2 && d2
506                == 0 by {
507                lemma_fold_graph_empty_elim(z, f, y2, d2);
508            };
509        };
510        // Step case
511        assert forall|a, s, y1, d1|
512            pred(s, y1, d1) && !s.contains(a) && #[trigger] fold_graph(
513                z,
514                f,
515                s,
516                y1,
517                d1,
518            ) implies pred(#[trigger] s.insert(a), f(y1, a), d1 + 1) by {
519            assert forall|y2, d2| fold_graph(z, f, s.insert(a), y2, d2) implies f(y1, a) == y2 && d2
520                == d1 + 1 by {
521                lemma_fold_graph_insert_elim(z, f, s, y2, d2, a);
522            };
523        };
524        lemma_fold_graph_induct(z, f, s, y2, d2, pred);
525    }
526
527    proof fn lemma_fold_is_fold_graph<A, B>(z: B, f: spec_fn(B, A) -> B, s: ISet<A>, y: B, d: nat)
528        requires
529            is_fun_commutative(f),
530            fold_graph(z, f, s, y, d),
531        ensures
532            s.fold(z, f) == y,
533    {
534        lemma_fold_graph_finite(z, f, s, y, d);
535        if s.fold(z, f) != y {
536            let (y2, d2) = choose|y2, d2| fold_graph(z, f, s, y2, d2) && y2 != y;
537            lemma_fold_graph_deterministic(z, f, s, y2, y, d2, d);
538            assert(false);
539        }
540    }
541
542    // At this point set cardinality is not yet defined, so we can't easily give a decreasing
543    // measure to prove the subsequent lemma `lemma_fold_graph_exists`. Instead, we first prove
544    // this lemma, for which we use the upper bound of a finiteness witness as the decreasing
545    // measure.
546    pub proof fn lemma_finite_set_induct<A>(s: ISet<A>, pred: spec_fn(ISet<A>) -> bool)
547        requires
548            s.finite(),
549            pred(ISet::empty()),
550            forall|s, a| pred(s) && s.finite() && !s.contains(a) ==> #[trigger] pred(s.insert(a)),
551        ensures
552            pred(s),
553    {
554        let (f, ub) = choose|f: spec_fn(A) -> nat, ub: nat| #[trigger]
555            trigger_finite(f, ub) && surj_on(f, s) && (forall|a| s.contains(a) ==> f(a) < ub);
556        lemma_finite_set_induct_aux(s, f, ub, pred);
557    }
558
559    proof fn lemma_finite_set_induct_aux<A>(
560        s: ISet<A>,
561        f: spec_fn(A) -> nat,
562        ub: nat,
563        pred: spec_fn(ISet<A>) -> bool,
564    )
565        requires
566            surj_on(f, s),
567            s.finite(),
568            forall|a| s.contains(a) ==> f(a) < ub,
569            pred(ISet::empty()),
570            forall|s, a| pred(s) && s.finite() && !s.contains(a) ==> #[trigger] pred(s.insert(a)),
571        ensures
572            pred(s),
573        decreases ub,
574    {
575        broadcast use group_iset_lemmas_early;
576
577        if s =~= ISet::empty() {
578        } else {
579            let a = s.choose();
580            // If `f` maps something to `ub - 1`, remap it to `f(a)` so we can decrease ub
581            let fp = |aa|
582                if f(aa) == ub - 1 {
583                    f(a)
584                } else {
585                    f(aa)
586                };
587            lemma_finite_set_induct_aux(s.remove(a), fp, sub(ub, 1), pred);
588        }
589    }
590
591    proof fn lemma_fold_graph_exists<A, B>(z: B, f: spec_fn(B, A) -> B, s: ISet<A>)
592        requires
593            s.finite(),
594            is_fun_commutative(f),
595        ensures
596            exists|y, d| fold_graph(z, f, s, y, d),
597    {
598        let pred = |s| exists|y, d| fold_graph(z, f, s, y, d);
599        // Base case
600        assert(fold_graph(z, f, ISet::empty(), z, 0)) by {
601            lemma_fold_graph_empty_intro(z, f);
602        };
603        // Step case
604        assert forall|s, a| pred(s) && s.finite() && !s.contains(a) implies #[trigger] pred(
605            s.insert(a),
606        ) by {
607            let (y, d): (B, nat) = choose|y, d| fold_graph(z, f, s, y, d);
608            lemma_fold_graph_insert_intro(z, f, s, y, d, a);
609        };
610        lemma_finite_set_induct(s, pred);
611    }
612
613    pub broadcast proof fn lemma_fold_insert<A, B>(s: ISet<A>, z: B, f: spec_fn(B, A) -> B, a: A)
614        requires
615            s.finite(),
616            !s.contains(a),
617            is_fun_commutative(f),
618        ensures
619            #[trigger] s.insert(a).fold(z, f) == f(s.fold(z, f), a),
620    {
621        lemma_fold_graph_exists(z, f, s);
622        let (y, d): (B, nat) = choose|y, d| fold_graph(z, f, s, y, d);
623        lemma_fold_graph_insert_intro(z, f, s, s.fold(z, f), d, a);
624        lemma_fold_is_fold_graph(z, f, s.insert(a), f(s.fold(z, f), a), d + 1);
625    }
626
627    pub broadcast proof fn lemma_fold_empty<A, B>(z: B, f: spec_fn(B, A) -> B)
628        ensures
629            #[trigger] ISet::empty().fold(z, f) == z,
630    {
631        let (y, d): (B, nat) = choose|y, d| fold_graph(z, f, ISet::empty(), y, d);
632        lemma_fold_graph_empty_intro(z, f);
633        lemma_fold_graph_empty_elim(z, f, y, d);
634    }
635
636}
637
638// Axioms
639/// The empty set contains no elements
640pub broadcast proof fn lemma_iset_empty<A>(a: A)
641    ensures
642        !(#[trigger] ISet::empty().contains(a)),
643{
644}
645
646/// A call to `ISet::new` with the predicate `f` contains `a` if and only if `f(a)` is true.
647pub broadcast proof fn lemma_iset_new<A>(f: spec_fn(A) -> bool, a: A)
648    ensures
649        #[trigger] ISet::new(f).contains(a) == f(a),
650{
651}
652
653/// The result of inserting element `a` into set `s` must contains `a`.
654pub broadcast proof fn lemma_iset_insert_same<A>(s: ISet<A>, a: A)
655    ensures
656        #[trigger] s.insert(a).contains(a),
657{
658}
659
660/// If `a1` does not equal `a2`, then the result of inserting element `a2` into set `s`
661/// must contain `a1` if and only if the set contained `a1` before the insertion of `a2`.
662pub broadcast proof fn lemma_iset_insert_different<A>(s: ISet<A>, a1: A, a2: A)
663    requires
664        a1 != a2,
665    ensures
666        #[trigger] s.insert(a2).contains(a1) == s.contains(a1),
667{
668}
669
670/// The result of removing element `a` from set `s` must not contain `a`.
671pub broadcast proof fn lemma_iset_remove_same<A>(s: ISet<A>, a: A)
672    ensures
673        !(#[trigger] s.remove(a).contains(a)),
674{
675}
676
677/// Removing an element `a` from a set `s` and then inserting `a` back into the set`
678/// is equivalent to the original set `s`.
679pub broadcast proof fn lemma_iset_remove_insert<A>(s: ISet<A>, a: A)
680    requires
681        s.contains(a),
682    ensures
683        (#[trigger] s.remove(a)).insert(a) == s,
684{
685    assert forall|aa| #![all_triggers] s.remove(a).insert(a).contains(aa) implies s.contains(
686        aa,
687    ) by {
688        if a == aa {
689        } else {
690            lemma_iset_remove_different(s, aa, a);
691            lemma_iset_insert_different(s.remove(a), aa, a);
692        }
693    };
694    assert forall|aa| #![all_triggers] s.contains(aa) implies s.remove(a).insert(a).contains(
695        aa,
696    ) by {
697        if a == aa {
698            lemma_iset_insert_same(s.remove(a), a);
699        } else {
700            lemma_iset_remove_different(s, aa, a);
701            lemma_iset_insert_different(s.remove(a), aa, a);
702        }
703    };
704    lemma_iset_ext_equal(s.remove(a).insert(a), s);
705}
706
707/// If `a1` does not equal `a2`, then the result of removing element `a2` from set `s`
708/// must contain `a1` if and only if the set contained `a1` before the removal of `a2`.
709pub broadcast proof fn lemma_iset_remove_different<A>(s: ISet<A>, a1: A, a2: A)
710    requires
711        a1 != a2,
712    ensures
713        #[trigger] s.remove(a2).contains(a1) == s.contains(a1),
714{
715}
716
717/// The union of sets `s1` and `s2` contains element `a` if and only if
718/// `s1` contains `a` and/or `s2` contains `a`.
719pub broadcast proof fn lemma_iset_union<A>(s1: ISet<A>, s2: ISet<A>, a: A)
720    ensures
721        #[trigger] s1.union(s2).contains(a) == (s1.contains(a) || s2.contains(a)),
722{
723}
724
725/// The intersection of sets `s1` and `s2` contains element `a` if and only if
726/// both `s1` and `s2` contain `a`.
727pub broadcast proof fn lemma_iset_intersect<A>(s1: ISet<A>, s2: ISet<A>, a: A)
728    ensures
729        #[trigger] s1.intersect(s2).contains(a) == (s1.contains(a) && s2.contains(a)),
730{
731}
732
733/// The set difference between `s1` and `s2` contains element `a` if and only if
734/// `s1` contains `a` and `s2` does not contain `a`.
735pub broadcast proof fn lemma_iset_difference<A>(s1: ISet<A>, s2: ISet<A>, a: A)
736    ensures
737        #[trigger] s1.difference(s2).contains(a) == (s1.contains(a) && !s2.contains(a)),
738{
739}
740
741/// The complement of set `s` contains element `a` if and only if `s` does not contain `a`.
742pub broadcast proof fn lemma_iset_complement<A>(s: ISet<A>, a: A)
743    ensures
744        #[trigger] s.complement().contains(a) == !s.contains(a),
745{
746}
747
748/// ISets `s1` and `s2` are equal if and only if they contain all of the same elements.
749pub broadcast proof fn lemma_iset_ext_equal<A>(s1: ISet<A>, s2: ISet<A>)
750    ensures
751        #[trigger] (s1 =~= s2) <==> (forall|a: A| s1.contains(a) == s2.contains(a)),
752{
753    if s1 =~= s2 {
754        assert(forall|a: A| s1.contains(a) == s2.contains(a));
755    }
756    if forall|a: A| s1.contains(a) == s2.contains(a) {
757        if !(forall|a: A| #[trigger] (s1.set)(a) <==> (s2.set)(a)) {
758            assert(exists|a: A| #[trigger] (s1.set)(a) != (s2.set)(a));
759            let a = choose|a: A| #[trigger] (s1.set)(a) != (s2.set)(a);
760            assert(s1.contains(a));
761            assert(false);
762        }
763        assert(s1 =~= s2);
764    }
765}
766
767pub broadcast proof fn lemma_iset_ext_equal_deep<A>(s1: ISet<A>, s2: ISet<A>)
768    ensures
769        #[trigger] (s1 =~~= s2) <==> s1 =~= s2,
770{
771}
772
773pub broadcast axiom fn lemma_iset_mk_map_domain<K, V>(s: ISet<K>, f: spec_fn(K) -> V)
774    ensures
775        #[trigger] s.mk_map(f).dom() == s,
776;
777
778pub broadcast axiom fn lemma_iset_mk_map_index<K, V>(s: ISet<K>, f: spec_fn(K) -> V, key: K)
779    requires
780        s.contains(key),
781    ensures
782        #[trigger] s.mk_map(f)[key] == f(key),
783;
784
785// Trusted axioms about finite
786/// The empty set is finite.
787pub broadcast proof fn lemma_iset_empty_finite<A>()
788    ensures
789        #[trigger] ISet::<A>::empty().finite(),
790{
791    let f = |a: A| 0;
792    let ub = 0;
793    let _ = trigger_finite(f, ub);
794}
795
796/// The result of inserting an element `a` into a finite set `s` is also finite.
797pub broadcast proof fn lemma_iset_insert_finite<A>(s: ISet<A>, a: A)
798    requires
799        s.finite(),
800    ensures
801        #[trigger] s.insert(a).finite(),
802{
803    let (f, ub) = choose|f: spec_fn(A) -> nat, ub: nat| #[trigger]
804        trigger_finite(f, ub) && surj_on(f, s) && (forall|a| s.contains(a) ==> f(a) < ub);
805    let f2 = |a2: A|
806        if a2 == a {
807            ub
808        } else {
809            f(a2)
810        };
811    let ub2 = ub + 1;
812    let _ = trigger_finite(f2, ub2);
813    assert forall|a1, a2|
814        #![all_triggers]
815        s.insert(a).contains(a1) && s.insert(a).contains(a2) && a1 != a2 implies f2(a1) != f2(
816        a2,
817    ) by {
818        if a != a1 {
819            assert(s.contains(a1));
820        }
821        if a != a2 {
822            assert(s.contains(a2));
823        }
824    };
825    assert forall|a2| s.insert(a).contains(a2) implies #[trigger] f2(a2) < ub2 by {
826        if a == a2 {
827        } else {
828            assert(s.contains(a2));
829        }
830    };
831}
832
833/// The result of removing an element `a` from a finite set `s` is also finite.
834pub broadcast proof fn lemma_iset_remove_finite<A>(s: ISet<A>, a: A)
835    requires
836        s.finite(),
837    ensures
838        #[trigger] s.remove(a).finite(),
839{
840    let (f, ub) = choose|f: spec_fn(A) -> nat, ub: nat| #[trigger]
841        trigger_finite(f, ub) && surj_on(f, s) && (forall|a| s.contains(a) ==> f(a) < ub);
842    assert forall|a1, a2|
843        #![all_triggers]
844        s.remove(a).contains(a1) && s.remove(a).contains(a2) && a1 != a2 implies f(a1) != f(a2) by {
845        if a != a1 {
846            assert(s.contains(a1));
847        }
848        if a != a2 {
849            assert(s.contains(a2));
850        }
851    };
852    assert(surj_on(f, s.remove(a)));
853    assert forall|a2| s.remove(a).contains(a2) implies #[trigger] f(a2) < ub by {
854        if a == a2 {
855        } else {
856            assert(s.contains(a2));
857        }
858    };
859}
860
861/// The union of two finite sets is finite.
862pub broadcast proof fn lemma_iset_union_finite<A>(s1: ISet<A>, s2: ISet<A>)
863    requires
864        s1.finite(),
865        s2.finite(),
866    ensures
867        #[trigger] s1.union(s2).finite(),
868{
869    let (f1, ub1) = choose|f: spec_fn(A) -> nat, ub: nat| #[trigger]
870        trigger_finite(f, ub) && surj_on(f, s1) && (forall|a| s1.contains(a) ==> f(a) < ub);
871    let (f2, ub2) = choose|f: spec_fn(A) -> nat, ub: nat| #[trigger]
872        trigger_finite(f, ub) && surj_on(f, s2) && (forall|a| s2.contains(a) ==> f(a) < ub);
873    let f3 = |a|
874        if s1.contains(a) {
875            f1(a)
876        } else {
877            ub1 + f2(a)
878        };
879    let ub3 = ub1 + ub2;
880    assert(trigger_finite(f3, ub3));
881    assert(forall|a|
882        #![all_triggers]
883        s1.union(s2).contains(a) ==> s1.contains(a) || s2.contains(a));
884}
885
886/// The intersection of two finite sets is finite.
887pub broadcast proof fn lemma_iset_intersect_finite<A>(s1: ISet<A>, s2: ISet<A>)
888    requires
889        s1.finite() || s2.finite(),
890    ensures
891        #[trigger] s1.intersect(s2).finite(),
892{
893    assert(forall|a|
894        #![all_triggers]
895        s1.intersect(s2).contains(a) ==> s1.contains(a) && s2.contains(a));
896}
897
898/// The set difference between two finite sets is finite.
899pub broadcast proof fn lemma_iset_difference_finite<A>(s1: ISet<A>, s2: ISet<A>)
900    requires
901        s1.finite(),
902    ensures
903        #[trigger] s1.difference(s2).finite(),
904{
905    assert(forall|a|
906        #![all_triggers]
907        s1.difference(s2).contains(a) ==> s1.contains(a) && !s2.contains(a));
908}
909
910/// An infinite set `s` contains the element `s.choose()`.
911pub broadcast proof fn lemma_iset_choose_infinite<A>(s: ISet<A>)
912    requires
913        !s.finite(),
914    ensures
915        #[trigger] s.contains(s.choose()),
916{
917    let f = |a: A| 0;
918    let ub = 0;
919    let _ = trigger_finite(f, ub);
920}
921
922// Trusted axioms about len
923// Note: we could add more axioms about len, but they would be incomplete.
924// The following, with lemma_iset_ext_equal, are enough to build libraries about len.
925/// The empty set has length 0.
926pub broadcast proof fn lemma_iset_empty_len<A>()
927    ensures
928        #[trigger] ISet::<A>::empty().len() == 0,
929{
930    fold::lemma_fold_empty(0, |b: nat, a: A| b + 1);
931}
932
933/// The result of inserting an element `a` into a finite set `s` has length
934/// `s.len() + 1` if `a` is not already in `s` and length `s.len()` otherwise.
935pub broadcast proof fn lemma_iset_insert_len<A>(s: ISet<A>, a: A)
936    requires
937        s.finite(),
938    ensures
939        #[trigger] s.insert(a).len() == s.len() + (if s.contains(a) {
940            0int
941        } else {
942            1
943        }),
944{
945    if s.contains(a) {
946        assert(s =~= s.insert(a));
947    } else {
948        fold::lemma_fold_insert(s, 0, |b: nat, a: A| b + 1, a);
949    }
950}
951
952/// The result of removing an element `a` from a finite set `s` has length
953/// `s.len() - 1` if `a` is in `s` and length `s.len()` otherwise.
954pub broadcast proof fn lemma_iset_remove_len<A>(s: ISet<A>, a: A)
955    requires
956        s.finite(),
957    ensures
958        s.len() == #[trigger] s.remove(a).len() + (if s.contains(a) {
959            1int
960        } else {
961            0
962        }),
963{
964    lemma_iset_remove_finite(s, a);
965    lemma_iset_insert_len(s.remove(a), a);
966    if s.contains(a) {
967        assert(s =~= s.remove(a).insert(a));
968    } else {
969        assert(s =~= s.remove(a));
970    }
971}
972
973/// If a finite set `s` contains any element, it has length greater than 0.
974pub broadcast proof fn lemma_iset_contains_len<A>(s: ISet<A>, a: A)
975    requires
976        s.finite(),
977        #[trigger] s.contains(a),
978    ensures
979        #[trigger] s.len() != 0,
980{
981    let a = s.choose();
982    assert(s.remove(a).insert(a) =~= s);
983    lemma_iset_remove_finite(s, a);
984    lemma_iset_insert_finite(s.remove(a), a);
985    lemma_iset_insert_len(s.remove(a), a);
986}
987
988/// A finite set `s` contains the element `s.choose()` if it has length greater than 0.
989pub broadcast proof fn lemma_iset_choose_len<A>(s: ISet<A>)
990    requires
991        s.finite(),
992        #[trigger] s.len() != 0,
993    ensures
994        #[trigger] s.contains(s.choose()),
995{
996    // Separate statements to work around https://github.com/verus-lang/verusfmt/issues/86
997    broadcast use lemma_iset_contains_len;
998    broadcast use lemma_iset_empty_len;
999    broadcast use lemma_iset_ext_equal;
1000    broadcast use lemma_iset_insert_finite;
1001
1002    let pred = |s: ISet<A>| s.finite() ==> s.len() == 0 <==> s =~= ISet::empty();
1003    fold::lemma_finite_set_induct(s, pred);
1004}
1005
1006pub proof fn lemma_iset_finite_if_subset_of_seq<A>(i: ISet<A>, s: Seq<A>)
1007    requires
1008        forall|a| i.contains(a) ==> s.contains(a),
1009    ensures
1010        i.finite(),
1011{
1012    let f = |a: A| (s.index_of(a) as nat);
1013    let ub = s.len();
1014    assert(surj_on(f, i)) by {
1015        assert forall|a1, a2|
1016            #![all_triggers]
1017            i.contains(a1) && i.contains(a2) && a1 != a2 implies f(a1) != f(a2) by {
1018            assert(s.contains(a1));
1019            assert(s.contains(a2));
1020            assert(0 <= f(a1) < s.len() && s[f(a1) as int] == a1);
1021            assert(0 <= f(a2) < s.len() && s[f(a2) as int] == a2);
1022        }
1023    }
1024    assert forall|a| i.contains(a) implies f(a) < ub by {
1025        assert(s.contains(a));
1026        assert(0 <= f(a) < s.len() && s[f(a) as int] == a);
1027    }
1028    assert(trigger_finite(f, ub));
1029}
1030
1031pub broadcast group group_iset_lemmas {
1032    lemma_iset_empty,
1033    lemma_iset_new,
1034    lemma_iset_insert_same,
1035    lemma_iset_insert_different,
1036    lemma_iset_remove_same,
1037    lemma_iset_remove_insert,
1038    lemma_iset_remove_different,
1039    lemma_iset_union,
1040    lemma_iset_intersect,
1041    lemma_iset_difference,
1042    lemma_iset_complement,
1043    lemma_iset_ext_equal,
1044    lemma_iset_ext_equal_deep,
1045    lemma_iset_mk_map_domain,
1046    lemma_iset_mk_map_index,
1047    lemma_iset_empty_finite,
1048    lemma_iset_insert_finite,
1049    lemma_iset_remove_finite,
1050    lemma_iset_union_finite,
1051    lemma_iset_intersect_finite,
1052    lemma_iset_difference_finite,
1053    lemma_iset_choose_infinite,
1054    lemma_iset_empty_len,
1055    lemma_iset_insert_len,
1056    lemma_iset_remove_len,
1057    lemma_iset_contains_len,
1058    lemma_iset_choose_len,
1059}
1060
1061// Macros
1062#[doc(hidden)]
1063#[macro_export]
1064macro_rules! iset_internal {
1065    [$($elem:expr),* $(,)?] => {
1066        $crate::vstd::iset::ISet::empty()
1067            $(.insert($elem))*
1068    };
1069}
1070
1071#[macro_export]
1072macro_rules! iset {
1073    [$($tail:tt)*] => {
1074        $crate::vstd::prelude::verus_proof_macro_exprs!($crate::vstd::iset::iset_internal!($($tail)*))
1075    };
1076}
1077
1078pub use iset_internal;
1079pub use iset;
1080
1081} // verus!