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