Skip to main content

vstd/
iset_lib.rs

1#[allow(unused_imports)]
2use super::iset::*;
3#[allow(unused_imports)]
4use super::multiset::Multiset;
5#[allow(unused_imports)]
6use super::pervasive::*;
7use super::prelude::Seq;
8#[allow(unused_imports)]
9use super::prelude::*;
10#[allow(unused_imports)]
11use super::relations::*;
12#[allow(unused_imports)]
13use super::set::*;
14
15verus! {
16
17broadcast use super::iset::group_iset_lemmas;
18
19impl<A> ISet<A> {
20    /// Is `true` if called by a "full" set, i.e., a set containing every element of type `A`.
21    pub open spec fn is_full(self) -> bool {
22        self == ISet::<A>::full()
23    }
24
25    /// Is `true` if called by an "empty" set, i.e., a set containing no elements and has length 0
26    pub open spec fn is_empty(self) -> (b: bool) {
27        self =~= ISet::<A>::empty()
28    }
29
30    /// Returns the set contains an element `f(x)` for every element `x` in `self`.
31    pub open spec fn map<B>(self, f: spec_fn(A) -> B) -> ISet<B> {
32        ISet::new(|a: B| exists|x: A| self.contains(x) && a == f(x))
33    }
34
35    /// `ISet::map_by` is like `ISet::map`, but `map` only takes a forward function `fwd: spec_fn(A) -> B`,
36    /// while `map_by` also takes a reverse function `rev: spec_fn(B) -> A`
37    /// such that `rev(fwd(a)) == a`.
38    /// When `fwd` has such a reverse function, `ISet::map_by` can make proofs easier
39    /// by avoiding the "exists" that appears in lemmas about `ISet::map`.
40    /// Example: for a set `s: ISet<int>`, to map each `i` in `s` to `(i, 10 * i)`,
41    /// we can write either `s.map(|i: int| (i, 10 * i))`
42    /// or `s.map_by(|i: int| (i, 10 * i), |p: (int, int)| p.0)`;
43    /// the version with `map_by` is usually easier to use in proofs.
44    /// If the recommendation `forall|a: A| self.contains(a) ==> rev(fwd(a)) == a` is satisfied,
45    /// it is trivially guaranteed that `self.map_by(fwd, rev) == self.map(fwd)`.
46    /// Also see the `set_build!` macro for a convenient interface to `map_by`.
47    pub open spec fn map_by<B>(self, fwd: spec_fn(A) -> B, rev: spec_fn(B) -> A) -> ISet<B>
48        recommends
49            forall|a: A| self.contains(a) ==> rev(fwd(a)) == a,
50    {
51        ISet::new(|b: B| self.contains(rev(b)) && b == fwd(rev(b)))
52    }
53
54    /// Similar to `ISet::map_by`, but the forward function returns `ISet<B>` rather than `B`,
55    /// and `map_flatten_by` flattens the final result from `ISet<ISet<B>>` to just `ISet<B>`.
56    /// This can be easier to work with in proofs than calling `map` and `flatten` separately,
57    /// since `map` and `flatten` introduce "exists", while `map_flatten_by` does not.
58    /// Also see the `set_build!` macro for a convenient interface to `map_flatten_by`.
59    pub open spec fn map_flatten_by<B>(
60        self,
61        fwd: spec_fn(A) -> ISet<B>,
62        rev: spec_fn(B) -> A,
63    ) -> ISet<B>
64        recommends
65            forall|a: A, b: B| #[trigger]
66                self.contains(a) && fwd(a).contains(b) ==> #[trigger] rev(b) == a,
67    {
68        ISet::new(|b: B| self.contains(rev(b)) && fwd(rev(b)).contains(b))
69    }
70
71    /// This proof demonstrates that calling `map_flatten_by` is equivalent to
72    /// first calling `map`, then calling `flatten`.
73    pub proof fn map_flatten_by_is_map_flatten<B>(
74        self,
75        fwd: spec_fn(A) -> ISet<B>,
76        rev: spec_fn(B) -> A,
77    )
78        requires
79            forall|a: A, b: B| #[trigger]
80                self.contains(a) && fwd(a).contains(b) ==> #[trigger] rev(b) == a,
81        ensures
82            self.map_flatten_by(fwd, rev) == self.map(fwd).flatten(),
83    {
84        assert forall|b: B| self.map_flatten_by(fwd, rev).contains(b) implies #[trigger] self.map(
85            fwd,
86        ).flatten().contains(b) by {
87            let bs = choose|bs: ISet<B>|
88                (exists|a: A| self.contains(a) && bs == fwd(a)) && bs.contains(b);
89            assert(self.map(fwd).contains(bs) <==> (exists|a: A| self.contains(a) && bs == fwd(a)));
90        }
91    }
92
93    /// Converts a set into a sequence with an arbitrary ordering.
94    pub open spec fn to_seq(self) -> Seq<A>
95        recommends
96            self.finite(),
97        decreases self.len(),
98        when self.finite()
99    {
100        if self.len() == 0 {
101            Seq::<A>::empty()
102        } else {
103            let x = self.choose();
104            Seq::<A>::empty().push(x) + self.remove(x).to_seq()
105        }
106    }
107
108    /// Converts a set into a sequence sorted by the given ordering function `leq`
109    pub open spec fn to_sorted_seq(self, leq: spec_fn(A, A) -> bool) -> Seq<A> {
110        self.to_seq().sort_by(leq)
111    }
112
113    /// A singleton set has at least one element and any two elements are equal.
114    pub open spec fn is_singleton(self) -> bool {
115        &&& self.len() > 0
116        &&& (forall|x: A, y: A| self.contains(x) && self.contains(y) ==> x == y)
117    }
118
119    /// Indicates if the function given by `r` is injective on this set,
120    /// i.e., whether each element of this set is mapped to a different
121    /// value by `r`.
122    pub open spec fn injective_on<B>(self, r: spec_fn(A) -> B) -> bool {
123        forall|x1: A, x2: A|
124            self.contains(x1) && self.contains(x2) && #[trigger] r(x1) == #[trigger] r(x2) ==> x1
125                == x2
126    }
127
128    /// An element in an ordered set is called a least element (or a minimum), if it is less than
129    /// every other element of the set.
130    pub open spec fn has_least(self, leq: spec_fn(A, A) -> bool, min: A) -> bool {
131        self.contains(min) && forall|x: A| self.contains(x) ==> #[trigger] leq(min, x)
132    }
133
134    /// An element in an ordered set is called a minimal element, if no other element is less than it.
135    pub open spec fn has_minimum(self, leq: spec_fn(A, A) -> bool, min: A) -> bool {
136        self.contains(min) && forall|x: A|
137            self.contains(x) && #[trigger] leq(x, min) ==> #[trigger] leq(min, x)
138    }
139
140    /// An element in an ordered set is called a greatest element (or a maximum), if it is greater than
141    ///every other element of the set.
142    pub open spec fn has_greatest(self, leq: spec_fn(A, A) -> bool, max: A) -> bool {
143        self.contains(max) && forall|x: A| self.contains(x) ==> #[trigger] leq(x, max)
144    }
145
146    /// An element in an ordered set is called a maximal element, if no other element is greater than it.
147    pub open spec fn has_maximum(self, leq: spec_fn(A, A) -> bool, max: A) -> bool {
148        self.contains(max) && forall|x: A|
149            self.contains(x) && #[trigger] leq(max, x) ==> #[trigger] leq(x, max)
150    }
151
152    /// If a function is injective on the set `self`, then it is also injective on any subset `other` of `self`.
153    pub proof fn lemma_injective_on_subset<B>(self, r: spec_fn(A) -> B, other: Self)
154        requires
155            other <= self,
156            self.injective_on(r),
157        ensures
158            other.injective_on(r),
159    {
160        assert forall|a1: A, a2: A|
161            other.contains(a1) && other.contains(a2) && #[trigger] r(a1) == #[trigger] r(
162                a2,
163            ) implies a1 == a2 by {
164            assert(self.contains(a1));
165            assert(self.contains(a2));
166            assert(r(a1) == r(a2));
167        }
168    }
169
170    /// Any totally-ordered set contains a unique minimal (equivalently, least) element.
171    /// Returns an arbitrary value if r is not a total ordering
172    pub closed spec fn find_unique_minimal(self, r: spec_fn(A, A) -> bool) -> A
173        recommends
174            total_ordering(r),
175            self.len() > 0,
176            self.finite(),
177        decreases self.len(),
178        when self.finite()
179    {
180        proof {
181            broadcast use group_iset_properties;
182
183        }
184        if self.len() <= 1 {
185            self.choose()
186        } else {
187            let x = choose|x: A| self.contains(x);
188            let min = self.remove(x).find_unique_minimal(r);
189            if r(min, x) {
190                min
191            } else {
192                x
193            }
194        }
195    }
196
197    /// Proof of correctness and expected behavior for `ISet::find_unique_minimal`.
198    pub proof fn find_unique_minimal_ensures(self, r: spec_fn(A, A) -> bool)
199        requires
200            self.finite(),
201            self.len() > 0,
202            total_ordering(r),
203        ensures
204            self.has_minimum(r, self.find_unique_minimal(r)) && (forall|min: A|
205                self.has_minimum(r, min) ==> self.find_unique_minimal(r) == min),
206        decreases self.len(),
207    {
208        broadcast use group_iset_properties;
209
210        if self.len() == 1 {
211            let x = choose|x: A| self.contains(x);
212            assert(self.remove(x).insert(x) =~= self);
213            assert(self.has_minimum(r, self.find_unique_minimal(r)));
214        } else {
215            let x = choose|x: A| self.contains(x);
216            self.remove(x).find_unique_minimal_ensures(r);
217            assert(self.remove(x).has_minimum(r, self.remove(x).find_unique_minimal(r)));
218            let y = self.remove(x).find_unique_minimal(r);
219            let min_updated = self.find_unique_minimal(r);
220            assert(!r(y, x) ==> min_updated == x);
221            assert(forall|elt: A|
222                self.remove(x).contains(elt) && #[trigger] r(elt, y) ==> #[trigger] r(y, elt));
223            assert forall|elt: A|
224                self.contains(elt) && #[trigger] r(elt, min_updated) implies #[trigger] r(
225                min_updated,
226                elt,
227            ) by {
228                assert(r(min_updated, x) || r(min_updated, y));
229                if min_updated == y {  // Case where the new min is the old min
230                    assert(self.has_minimum(r, self.find_unique_minimal(r)));
231                } else {  //Case where the new min is the newest element
232                    assert(self.remove(x).contains(elt) || elt == x);
233                    assert(min_updated == x);
234                    assert(r(x, y) || r(y, x));
235                    assert(!r(x, y) || !r(y, x));
236                    assert(!(min_updated == y) ==> !r(y, x));
237                    assert(r(x, y));
238                    if (self.remove(x).contains(elt)) {
239                        assert(r(elt, y) && r(y, elt) ==> elt == y);
240                    } else {
241                    }
242                }
243            }
244            assert forall|min_poss: A|
245                self.has_minimum(r, min_poss) implies self.find_unique_minimal(r) == min_poss by {
246                assert(self.remove(x).has_minimum(r, min_poss) || x == min_poss);
247                if self.remove(x).has_minimum(r, min_poss) {
248                    assert(r(x, min_poss) ==> r(min_poss, x));
249                    assert(r(min_poss, self.find_unique_minimal(r)));
250                } else {
251                    assert(x == min_poss);
252                    assert(r(x, y));
253                }
254            }
255        }
256    }
257
258    /// Any totally-ordered set contains a unique maximal (equivalently, greatest) element.
259    /// Returns an arbitrary value if r is not a total ordering
260    pub closed spec fn find_unique_maximal(self, r: spec_fn(A, A) -> bool) -> A
261        recommends
262            total_ordering(r),
263            self.len() > 0,
264        decreases self.len(),
265        when self.finite()
266    {
267        proof {
268            broadcast use group_iset_properties;
269
270        }
271        if self.len() <= 1 {
272            self.choose()
273        } else {
274            let x = choose|x: A| self.contains(x);
275            let max = self.remove(x).find_unique_maximal(r);
276            if r(x, max) {
277                max
278            } else {
279                x
280            }
281        }
282    }
283
284    /// Proof of correctness and expected behavior for `ISet::find_unique_maximal`.
285    pub proof fn find_unique_maximal_ensures(self, r: spec_fn(A, A) -> bool)
286        requires
287            self.finite(),
288            self.len() > 0,
289            total_ordering(r),
290        ensures
291            self.has_maximum(r, self.find_unique_maximal(r)) && (forall|max: A|
292                self.has_maximum(r, max) ==> self.find_unique_maximal(r) == max),
293        decreases self.len(),
294    {
295        broadcast use group_iset_properties;
296
297        if self.len() == 1 {
298            let x = choose|x: A| self.contains(x);
299            assert(self.remove(x) =~= ISet::<A>::empty());
300            assert(self.contains(self.find_unique_maximal(r)));
301        } else {
302            let x = choose|x: A| self.contains(x);
303            self.remove(x).find_unique_maximal_ensures(r);
304            assert(self.remove(x).has_maximum(r, self.remove(x).find_unique_maximal(r)));
305            assert(self.remove(x).insert(x) =~= self);
306            let y = self.remove(x).find_unique_maximal(r);
307            let max_updated = self.find_unique_maximal(r);
308            assert(max_updated == x || max_updated == y);
309            assert(!r(x, y) ==> max_updated == x);
310            assert forall|elt: A|
311                self.contains(elt) && #[trigger] r(max_updated, elt) implies #[trigger] r(
312                elt,
313                max_updated,
314            ) by {
315                assert(r(x, max_updated) || r(y, max_updated));
316                if max_updated == y {  // Case where the new max is the old max
317                    assert(r(elt, max_updated));
318                    assert(r(x, max_updated));
319                    assert(self.has_maximum(r, self.find_unique_maximal(r)));
320                } else {  //Case where the new max is the newest element
321                    assert(self.remove(x).contains(elt) || elt == x);
322                    assert(max_updated == x);
323                    assert(r(x, y) || r(y, x));
324                    assert(!r(x, y) || !r(y, x));
325                    assert(!(max_updated == y) ==> !r(x, y));
326                    assert(r(y, x));
327                    if (self.remove(x).contains(elt)) {
328                        assert(r(y, elt) ==> r(elt, y));
329                        assert(r(y, elt) && r(elt, y) ==> elt == y);
330                        assert(r(elt, x));
331                        assert(r(elt, max_updated))
332                    } else {
333                    }
334                }
335            }
336            assert forall|max_poss: A|
337                self.has_maximum(r, max_poss) implies self.find_unique_maximal(r) == max_poss by {
338                assert(self.remove(x).has_maximum(r, max_poss) || x == max_poss);
339                assert(r(max_poss, self.find_unique_maximal(r)));
340                assert(r(self.find_unique_maximal(r), max_poss));
341            }
342        }
343    }
344
345    /// Converts a set into a multiset where each element from the set has
346    /// multiplicity 1 and any other element has multiplicity 0.
347    pub open spec fn to_multiset(self) -> Multiset<A>
348        decreases self.len(),
349        when self.finite()
350    {
351        if self.len() == 0 {
352            Multiset::<A>::empty()
353        } else {
354            Multiset::<A>::empty().insert(self.choose()).add(
355                self.remove(self.choose()).to_multiset(),
356            )
357        }
358    }
359
360    /// A finite set with length 0 is equivalent to the empty set.
361    pub proof fn lemma_len0_is_empty(self)
362        requires
363            self.finite(),
364            self.len() == 0,
365        ensures
366            self == ISet::<A>::empty(),
367    {
368        if exists|a: A| self.contains(a) {
369            // derive contradiction:
370            assert(self.remove(self.choose()).len() + 1 == 0);
371        }
372        assert(self =~= ISet::empty());
373    }
374
375    /// A singleton set has length 1.
376    pub proof fn lemma_singleton_size(self)
377        requires
378            self.is_singleton(),
379        ensures
380            self.len() == 1,
381    {
382        broadcast use group_iset_properties;
383
384        assert(self.remove(self.choose()) =~= ISet::empty());
385    }
386
387    /// A set has exactly one element, if and only if, it has at least one element and any two elements are equal.
388    pub proof fn lemma_is_singleton(s: ISet<A>)
389        requires
390            s.finite(),
391        ensures
392            s.is_singleton() == (s.len() == 1),
393    {
394        if s.is_singleton() {
395            s.lemma_singleton_size();
396        }
397        if s.len() == 1 {
398            assert forall|x: A, y: A| s.contains(x) && s.contains(y) implies x == y by {
399                let x = choose|x: A| s.contains(x);
400                broadcast use group_iset_properties;
401
402                assert(s.remove(x).len() == 0);
403                assert(s.insert(x) =~= s);
404            }
405        }
406    }
407
408    /// The result of filtering a finite set is finite and has size less than or equal to the original set.
409    pub proof fn lemma_len_filter(self, f: spec_fn(A) -> bool)
410        requires
411            self.finite(),
412        ensures
413            self.filter(f).finite(),
414            self.filter(f).len() <= self.len(),
415        decreases self.len(),
416    {
417        lemma_len_intersect::<A>(self, ISet::new(f));
418    }
419
420    /// In a pre-ordered set, a greatest element is necessarily maximal.
421    pub proof fn lemma_greatest_implies_maximal(self, r: spec_fn(A, A) -> bool, max: A)
422        requires
423            pre_ordering(r),
424        ensures
425            self.has_greatest(r, max) ==> self.has_maximum(r, max),
426    {
427    }
428
429    /// In a pre-ordered set, a least element is necessarily minimal.
430    pub proof fn lemma_least_implies_minimal(self, r: spec_fn(A, A) -> bool, min: A)
431        requires
432            pre_ordering(r),
433        ensures
434            self.has_least(r, min) ==> self.has_minimum(r, min),
435    {
436    }
437
438    /// In a totally-ordered set, an element is maximal if and only if it is a greatest element.
439    pub proof fn lemma_maximal_equivalent_greatest(self, r: spec_fn(A, A) -> bool, max: A)
440        requires
441            total_ordering(r),
442        ensures
443            self.has_greatest(r, max) <==> self.has_maximum(r, max),
444    {
445        assert(self.has_maximum(r, max) ==> forall|x: A|
446            !self.contains(x) || !r(max, x) || r(x, max));
447    }
448
449    /// In a totally-ordered set, an element is maximal if and only if it is a greatest element.
450    pub proof fn lemma_minimal_equivalent_least(self, r: spec_fn(A, A) -> bool, min: A)
451        requires
452            total_ordering(r),
453        ensures
454            self.has_least(r, min) <==> self.has_minimum(r, min),
455    {
456        assert(self.has_minimum(r, min) ==> forall|x: A|
457            !self.contains(x) || !r(x, min) || r(min, x));
458    }
459
460    /// In a partially-ordered set, there exists at most one least element.
461    pub proof fn lemma_least_is_unique(self, r: spec_fn(A, A) -> bool)
462        requires
463            partial_ordering(r),
464        ensures
465            forall|min: A, min_prime: A|
466                self.has_least(r, min) && self.has_least(r, min_prime) ==> min == min_prime,
467    {
468        assert forall|min: A, min_prime: A|
469            self.has_least(r, min) && self.has_least(r, min_prime) implies min == min_prime by {
470            assert(r(min, min_prime));
471            assert(r(min_prime, min));
472        }
473    }
474
475    /// In a partially-ordered set, there exists at most one greatest element.
476    pub proof fn lemma_greatest_is_unique(self, r: spec_fn(A, A) -> bool)
477        requires
478            partial_ordering(r),
479        ensures
480            forall|max: A, max_prime: A|
481                self.has_greatest(r, max) && self.has_greatest(r, max_prime) ==> max == max_prime,
482    {
483        assert forall|max: A, max_prime: A|
484            self.has_greatest(r, max) && self.has_greatest(r, max_prime) implies max
485            == max_prime by {
486            assert(r(max_prime, max));
487            assert(r(max, max_prime));
488        }
489    }
490
491    /// In a totally-ordered set, there exists at most one minimal element.
492    pub proof fn lemma_minimal_is_unique(self, r: spec_fn(A, A) -> bool)
493        requires
494            total_ordering(r),
495        ensures
496            forall|min: A, min_prime: A|
497                self.has_minimum(r, min) && self.has_minimum(r, min_prime) ==> min == min_prime,
498    {
499        assert forall|min: A, min_prime: A|
500            self.has_minimum(r, min) && self.has_minimum(r, min_prime) implies min == min_prime by {
501            self.lemma_minimal_equivalent_least(r, min);
502            self.lemma_minimal_equivalent_least(r, min_prime);
503            self.lemma_least_is_unique(r);
504        }
505    }
506
507    /// In a totally-ordered set, there exists at most one maximal element.
508    pub proof fn lemma_maximal_is_unique(self, r: spec_fn(A, A) -> bool)
509        requires
510            self.finite(),
511            total_ordering(r),
512        ensures
513            forall|max: A, max_prime: A|
514                self.has_maximum(r, max) && self.has_maximum(r, max_prime) ==> max == max_prime,
515    {
516        assert forall|max: A, max_prime: A|
517            self.has_maximum(r, max) && self.has_maximum(r, max_prime) implies max == max_prime by {
518            self.lemma_maximal_equivalent_greatest(r, max);
519            self.lemma_maximal_equivalent_greatest(r, max_prime);
520            self.lemma_greatest_is_unique(r);
521        }
522    }
523
524    /// ISet difference with an additional element inserted decreases the size of
525    /// the result. This can be useful for proving termination when traversing
526    /// a set while tracking the elements that have already been handled.
527    pub broadcast proof fn lemma_iset_insert_diff_decreases(self, s: ISet<A>, elt: A)
528        requires
529            self.contains(elt),
530            !s.contains(elt),
531            self.finite(),
532        ensures
533            #[trigger] self.difference(s.insert(elt)).len() < self.difference(s).len(),
534    {
535        self.difference(s.insert(elt)).lemma_subset_not_in_lt(self.difference(s), elt);
536    }
537
538    /// If there is an element not present in a subset, its length is stricly smaller.
539    pub proof fn lemma_subset_not_in_lt(self: ISet<A>, s2: ISet<A>, elt: A)
540        requires
541            self.subset_of(s2),
542            s2.finite(),
543            !self.contains(elt),
544            s2.contains(elt),
545        ensures
546            self.len() < s2.len(),
547    {
548        let s2_no_elt = s2.remove(elt);
549        assert(self.len() <= s2_no_elt.len()) by {
550            lemma_len_subset(self, s2_no_elt);
551        }
552    }
553
554    /// Inserting an element and mapping a function over a set commute
555    pub broadcast proof fn lemma_iset_map_insert_commute<B>(self, elt: A, f: spec_fn(A) -> B)
556        ensures
557            #[trigger] self.insert(elt).map(f) =~= self.map(f).insert(f(elt)),
558    {
559        assert forall|x: B| self.map(f).insert(f(elt)).contains(x) implies self.insert(elt).map(
560            f,
561        ).contains(x) by {
562            if x == f(elt) {
563                assert(self.insert(elt).contains(elt));
564            } else {
565                let y = choose|y: A| self.contains(y) && f(y) == x;
566                assert(self.insert(elt).contains(y));
567            }
568        }
569    }
570
571    /// `map` and `union` commute
572    pub proof fn lemma_map_union_commute<B>(self, t: ISet<A>, f: spec_fn(A) -> B)
573        ensures
574            (self.union(t)).map(f) =~= self.map(f).union(t.map(f)),
575    {
576        broadcast use group_iset_lemmas;
577
578        let lhs = self.union(t).map(f);
579        let rhs = self.map(f).union(t.map(f));
580
581        assert forall|elem: B| rhs.contains(elem) implies lhs.contains(elem) by {
582            if self.map(f).contains(elem) {
583                let preimage = choose|preimage: A| self.contains(preimage) && f(preimage) == elem;
584                assert(self.union(t).contains(preimage));
585            } else {
586                assert(t.map(f).contains(elem));
587                let preimage = choose|preimage: A| t.contains(preimage) && f(preimage) == elem;
588                assert(self.union(t).contains(preimage));
589            }
590        }
591    }
592
593    /// Utility function for more concise universal quantification over sets
594    pub open spec fn all(&self, pred: spec_fn(A) -> bool) -> bool {
595        forall|x: A| self.contains(x) ==> pred(x)
596    }
597
598    /// Utility function for more concise existential quantification over sets
599    pub open spec fn any(&self, pred: spec_fn(A) -> bool) -> bool {
600        exists|x: A| self.contains(x) && pred(x)
601    }
602
603    /// `any` is preserved between predicates `p` and `q` if `p` implies `q`.
604    pub broadcast proof fn lemma_any_map_preserved_pred<B>(
605        self,
606        p: spec_fn(A) -> bool,
607        q: spec_fn(B) -> bool,
608        f: spec_fn(A) -> B,
609    )
610        requires
611            #[trigger] self.any(p),
612            forall|x: A| #[trigger] p(x) ==> q(f(x)),
613        ensures
614            #[trigger] self.map(f).any(q),
615    {
616        let x = choose|x: A| self.contains(x) && p(x);
617        assert(self.map(f).contains(f(x)));
618    }
619
620    /// Collecting all elements `b` where `f` returns `Some(b)`
621    pub open spec fn filter_map<B>(self, f: spec_fn(A) -> Option<B>) -> ISet<B> {
622        self.map(
623            |elem: A|
624                match f(elem) {
625                    Option::Some(r) => iset!{r},
626                    Option::None => iset!{},
627                },
628        ).flatten()
629    }
630
631    /// Inserting commutes with `filter_map`
632    pub broadcast proof fn lemma_filter_map_insert<B>(
633        s: ISet<A>,
634        f: spec_fn(A) -> Option<B>,
635        elem: A,
636    )
637        ensures
638            #[trigger] s.insert(elem).filter_map(f) == (match f(elem) {
639                Some(res) => s.filter_map(f).insert(res),
640                None => s.filter_map(f),
641            }),
642    {
643        broadcast use group_iset_lemmas;
644        broadcast use ISet::lemma_iset_map_insert_commute;
645
646        let lhs = s.insert(elem).filter_map(f);
647        let rhs = match f(elem) {
648            Some(res) => s.filter_map(f).insert(res),
649            None => s.filter_map(f),
650        };
651        let to_set = |elem: A|
652            match f(elem) {
653                Option::Some(r) => iset!{r},
654                Option::None => iset!{},
655            };
656        assert forall|r: B| #[trigger] lhs.contains(r) implies rhs.contains(r) by {
657            if f(elem) != Some(r) {
658                let orig = choose|orig: A| #[trigger]
659                    s.contains(orig) && f(orig) == Option::Some(r);
660                assert(to_set(orig) == iset!{r});
661                assert(s.map(to_set).contains(to_set(orig)));
662            }
663        }
664        assert forall|r: B| #[trigger] rhs.contains(r) implies lhs.contains(r) by {
665            if Some(r) == f(elem) {
666                assert(s.insert(elem).map(to_set).contains(to_set(elem)));
667            } else {
668                let orig = choose|orig: A| #[trigger]
669                    s.contains(orig) && f(orig) == Option::Some(r);
670                assert(s.insert(elem).map(to_set).contains(to_set(orig)));
671            }
672        }
673        assert(lhs =~= rhs);
674    }
675
676    /// `filter_map` and `union` commute.
677    pub broadcast proof fn lemma_filter_map_union<B>(self, f: spec_fn(A) -> Option<B>, t: ISet<A>)
678        ensures
679            #[trigger] self.union(t).filter_map(f) == self.filter_map(f).union(t.filter_map(f)),
680    {
681        broadcast use group_iset_lemmas;
682
683        let lhs = self.union(t).filter_map(f);
684        let rhs = self.filter_map(f).union(t.filter_map(f));
685        let to_set = |elem: A|
686            match f(elem) {
687                Option::Some(r) => iset!{r},
688                Option::None => iset!{},
689            };
690
691        assert forall|elem: B| rhs.contains(elem) implies lhs.contains(elem) by {
692            if self.filter_map(f).contains(elem) {
693                let x = choose|x: A| self.contains(x) && f(x) == Option::Some(elem);
694                assert(self.union(t).contains(x));
695                assert(self.union(t).map(to_set).contains(to_set(x)));
696            }
697            if t.filter_map(f).contains(elem) {
698                let x = choose|x: A| t.contains(x) && f(x) == Option::Some(elem);
699                assert(self.union(t).contains(x));
700                assert(self.union(t).map(to_set).contains(to_set(x)));
701            }
702        }
703        assert forall|elem: B| lhs.contains(elem) implies rhs.contains(elem) by {
704            let x = choose|x: A| self.union(t).contains(x) && f(x) == Option::Some(elem);
705            if self.contains(x) {
706                assert(self.map(to_set).contains(to_set(x)));
707                assert(self.filter_map(f).contains(elem));
708            } else {
709                assert(t.contains(x));
710                assert(t.map(to_set).contains(to_set(x)));
711                assert(t.filter_map(f).contains(elem));
712            }
713        }
714        assert(lhs =~= rhs);
715    }
716
717    /// `map` preserves finiteness
718    pub proof fn lemma_map_finite<B>(self, f: spec_fn(A) -> B)
719        requires
720            self.finite(),
721        ensures
722            self.map(f).finite(),
723        decreases self.len(),
724    {
725        broadcast use group_iset_lemmas;
726        broadcast use lemma_iset_empty_equivalency_len;
727
728        if self.len() == 0 {
729            assert(forall|elem: A| !(#[trigger] self.contains(elem)));
730            assert forall|res: B| #[trigger] self.map(f).contains(res) implies false by {
731                let x = choose|x: A| self.contains(x) && f(x) == res;
732            }
733            assert(self.map(f) =~= ISet::<B>::empty());
734        } else {
735            let x = choose|x: A| self.contains(x);
736            assert(self.map(f).contains(f(x)));
737            self.remove(x).lemma_map_finite(f);
738            assert(self.remove(x).insert(x) == self);
739            assert(self.map(f) == self.remove(x).map(f).insert(f(x)));
740        }
741    }
742
743    /// `map_by` preserves finiteness.
744    pub broadcast proof fn lemma_map_by_finite<B>(self, fwd: spec_fn(A) -> B, rev: spec_fn(B) -> A)
745        requires
746            self.finite(),
747        ensures
748            #[trigger] self.map_by(fwd, rev).finite(),
749    {
750        broadcast use lemma_iset_subset_finite;
751
752        assert(self.map_by(fwd, rev).subset_of(self.map(fwd)));
753        self.lemma_map_finite(fwd);
754    }
755
756    /// `map_flatten_by` preserves finiteness.
757    pub broadcast proof fn lemma_map_flatten_by_finite<B>(
758        self,
759        fwd: spec_fn(A) -> ISet<B>,
760        rev: spec_fn(B) -> A,
761    )
762        requires
763            self.finite(),
764            forall|a: A| self.contains(a) ==> fwd(a).finite(),
765        ensures
766            #[trigger] self.map_flatten_by(fwd, rev).finite(),
767    {
768        broadcast use lemma_iset_subset_finite;
769
770        let s1 = self.map_flatten_by(fwd, rev);
771        let s2 = self.map(fwd).flatten();
772        assert forall|b: B| s1.contains(b) implies s2.contains(b) by {
773            assert(self.map(fwd).contains(fwd(rev(b))));
774        }
775        assert(s1.subset_of(s2));
776        self.lemma_map_finite(fwd);
777        self.map(fwd).lemma_flatten_finite();
778    }
779
780    /// If `self` is a subset of `s2`, and all elements of `s2`
781    /// satisfy predicate `p`, then all elements of `self` satisfy
782    /// predicate `p`.
783    pub broadcast proof fn lemma_iset_all_subset(self, s2: ISet<A>, p: spec_fn(A) -> bool)
784        requires
785            #[trigger] self.subset_of(s2),
786            s2.all(p),
787        ensures
788            #[trigger] self.all(p),
789    {
790        broadcast use group_iset_lemmas;
791
792    }
793
794    /// `filter_map` preserves finiteness.
795    pub broadcast proof fn lemma_filter_map_finite<B>(self, f: spec_fn(A) -> Option<B>)
796        requires
797            self.finite(),
798        ensures
799            #[trigger] self.filter_map(f).finite(),
800        decreases self.len(),
801    {
802        broadcast use group_iset_lemmas;
803        broadcast use ISet::lemma_filter_map_insert;
804
805        let mapped = self.filter_map(f);
806        if self.len() == 0 {
807            assert(self.filter_map(f) =~= ISet::<B>::empty());
808        } else {
809            let elem = self.choose();
810            self.remove(elem).lemma_filter_map_finite(f);
811            assert(self =~= self.remove(elem).insert(elem));
812        }
813    }
814
815    /// Conversion to a sequence and back to a set is the identity function.
816    pub broadcast proof fn lemma_to_seq_to_set_id(self)
817        requires
818            self.finite(),
819        ensures
820            #[trigger] self.to_seq().to_set().to_iset() =~= self,
821        decreases self.len(),
822    {
823        broadcast use group_set_lemmas;
824        broadcast use group_iset_lemmas;
825        broadcast use lemma_iset_empty_equivalency_len;
826        broadcast use super::seq_lib::group_seq_lib_default;
827        broadcast use super::seq_lib::group_seq_properties;
828
829        if self.len() == 0 {
830            assert(self.to_seq().to_set().to_iset() =~= ISet::<A>::empty());
831        } else {
832            let elem = self.choose();
833            self.remove(elem).lemma_to_seq_to_set_id();
834            assert(self =~= self.remove(elem).insert(elem));
835            assert(self.to_seq().to_set() =~= self.remove(elem).to_seq().to_set().insert(elem));
836        }
837    }
838}
839
840impl<A> ISet<ISet<A>> {
841    /// This function creates a set from all the elements of all the elements
842    /// of `self`.
843    pub open spec fn flatten(self) -> ISet<A> {
844        ISet::new(
845            |elem|
846                exists|elem_s: ISet<A>| #[trigger] self.contains(elem_s) && elem_s.contains(elem),
847        )
848    }
849
850    /// Flattening then unioning with another set is equivalent to
851    /// inserting that other set and then flattening.
852    pub broadcast proof fn flatten_insert_union_commute(self, other: ISet<A>)
853        ensures
854            self.flatten().union(other) =~= #[trigger] self.insert(other).flatten(),
855    {
856        broadcast use group_iset_lemmas;
857
858        let lhs = self.flatten().union(other);
859        let rhs = self.insert(other).flatten();
860
861        assert forall|elem: A| lhs.contains(elem) implies rhs.contains(elem) by {
862            if exists|s: ISet<A>| self.contains(s) && s.contains(elem) {
863                let s = choose|s: ISet<A>| self.contains(s) && s.contains(elem);
864                assert(self.insert(other).contains(s));
865                assert(s.contains(elem));
866            } else {
867                assert(self.insert(other).contains(other));
868            }
869        }
870    }
871
872    /// If `self` is finite and all its elements are finite, then `self.flatten()`
873    /// is also finite.
874    pub proof fn lemma_flatten_finite(self)
875        requires
876            self.finite(),
877            forall|s: ISet<A>| self.contains(s) ==> #[trigger] s.finite(),
878        ensures
879            self.flatten().finite(),
880        decreases self.len(),
881    {
882        broadcast use group_iset_lemmas;
883
884        if self.len() == 0 {
885            assert(self.flatten() =~= ISet::<A>::empty());
886        } else {
887            let s = self.choose();
888            let self2 = self.remove(s);
889            self2.lemma_flatten_finite();
890            self2.flatten_insert_union_commute(s);
891        }
892    }
893}
894
895/// Two sets are equal iff mapping `f` results in equal sets, if `f` is injective.
896pub proof fn lemma_isets_eq_iff_injective_map_eq<T, S>(s1: ISet<T>, s2: ISet<T>, f: spec_fn(T) -> S)
897    requires
898        super::relations::injective(f),
899    ensures
900        (s1 == s2) <==> (s1.map(f) == s2.map(f)),
901{
902    broadcast use group_iset_lemmas;
903
904    if (s1.map(f) == s2.map(f)) {
905        assert(s1.map(f).len() == s2.map(f).len());
906        if !s1.subset_of(s2) {
907            let x = choose|x: T| s1.contains(x) && !s2.contains(x);
908            assert(s1.map(f).contains(f(x)));
909        } else if !s2.subset_of(s1) {
910            let x = choose|x: T| s2.contains(x) && !s1.contains(x);
911            assert(s2.map(f).contains(f(x)));
912        }
913        assert(s1 =~= s2);
914    }
915}
916
917/// Two sets are equal iff applying an injective (in the union of the sets) function `f` to each set produces equal sets.
918pub proof fn lemma_isets_eq_iff_injective_map_on_eq<T, S>(
919    s1: ISet<T>,
920    s2: ISet<T>,
921    f: spec_fn(T) -> S,
922)
923    requires
924        (s1 + s2).injective_on(f),
925    ensures
926        (s1 == s2) <==> (s1.map(f) == s2.map(f)),
927{
928    broadcast use group_iset_lemmas;
929
930    if (s1.map(f) == s2.map(f)) {
931        assert(s1.map(f).len() == s2.map(f).len());
932        if !s1.subset_of(s2) {
933            let x = choose|x: T| s1.contains(x) && !s2.contains(x);
934            assert(s1.map(f).contains(f(x)));
935        } else if !s2.subset_of(s1) {
936            let x = choose|x: T| s2.contains(x) && !s1.contains(x);
937            assert(s2.map(f).contains(f(x)));
938        }
939        assert(s1 =~= s2);
940    }
941}
942
943/// The result of inserting an element `a` into a set `s` is finite iff `s` is finite.
944pub broadcast proof fn lemma_iset_insert_finite_iff<A>(s: ISet<A>, a: A)
945    ensures
946        #[trigger] s.insert(a).finite() <==> s.finite(),
947{
948    if s.insert(a).finite() {
949        if s.contains(a) {
950            assert(s == s.insert(a));
951        } else {
952            assert(s == s.insert(a).remove(a));
953        }
954    }
955    assert(s.insert(a).finite() ==> s.finite());
956}
957
958/// The result of removing an element `a` into a set `s` is finite iff `s` is finite.
959pub broadcast proof fn lemma_iset_remove_finite_iff<A>(s: ISet<A>, a: A)
960    ensures
961        #[trigger] s.remove(a).finite() <==> s.finite(),
962{
963    if s.remove(a).finite() {
964        if s.contains(a) {
965            assert(s == s.remove(a).insert(a));
966        } else {
967            assert(s == s.remove(a));
968        }
969    }
970}
971
972/// The union of two sets is finite iff both sets are finite.
973pub broadcast proof fn lemma_iset_union_finite_iff<A>(s1: ISet<A>, s2: ISet<A>)
974    ensures
975        #[trigger] s1.union(s2).finite() <==> s1.finite() && s2.finite(),
976{
977    if s1.union(s2).finite() {
978        lemma_iset_union_finite_implies_sets_finite(s1, s2);
979    }
980}
981
982/// If the union of two `ISet`s is finite, then each of those `ISet`s
983/// is also finite.
984pub proof fn lemma_iset_union_finite_implies_sets_finite<A>(s1: ISet<A>, s2: ISet<A>)
985    requires
986        s1.union(s2).finite(),
987    ensures
988        s1.finite(),
989        s2.finite(),
990    decreases s1.union(s2).len(),
991{
992    if s1.union(s2) =~= ISet::<A>::empty() {
993        assert(s1 =~= ISet::<A>::empty());
994        assert(s2 =~= ISet::<A>::empty());
995    } else {
996        let a = s1.union(s2).choose();
997        assert(s1.remove(a).union(s2.remove(a)) == s1.union(s2).remove(a));
998        lemma_iset_remove_len(s1.union(s2), a);
999        lemma_iset_union_finite_implies_sets_finite(s1.remove(a), s2.remove(a));
1000        assert(forall|s: ISet<A>|
1001            #![auto]
1002            s.remove(a).insert(a) == if s.contains(a) {
1003                s
1004            } else {
1005                s.insert(a)
1006            });
1007        lemma_iset_insert_finite_iff(s1, a);
1008        lemma_iset_insert_finite_iff(s2, a);
1009    }
1010}
1011
1012/// The size of a union of two sets is less than or equal to the size of
1013/// both individual sets combined.
1014pub proof fn lemma_len_union<A>(s1: ISet<A>, s2: ISet<A>)
1015    requires
1016        s1.finite(),
1017        s2.finite(),
1018    ensures
1019        s1.union(s2).len() <= s1.len() + s2.len(),
1020    decreases s1.len(),
1021{
1022    if s1.is_empty() {
1023        assert(s1.union(s2) =~= s2);
1024    } else {
1025        let a = s1.choose();
1026        if s2.contains(a) {
1027            assert(s1.union(s2) =~= s1.remove(a).union(s2));
1028        } else {
1029            assert(s1.union(s2).remove(a) =~= s1.remove(a).union(s2));
1030        }
1031        lemma_len_union::<A>(s1.remove(a), s2);
1032    }
1033}
1034
1035/// The size of a union of two sets is greater than or equal to the size of
1036/// both individual sets.
1037pub proof fn lemma_len_union_ind<A>(s1: ISet<A>, s2: ISet<A>)
1038    requires
1039        s1.finite(),
1040        s2.finite(),
1041    ensures
1042        s1.union(s2).len() >= s1.len(),
1043        s1.union(s2).len() >= s2.len(),
1044    decreases s2.len(),
1045{
1046    broadcast use group_iset_properties;
1047
1048    if s2.len() == 0 {
1049    } else {
1050        let y = choose|y: A| s2.contains(y);
1051        if s1.contains(y) {
1052            assert(s1.remove(y).union(s2.remove(y)) =~= s1.union(s2).remove(y));
1053            lemma_len_union_ind(s1.remove(y), s2.remove(y))
1054        } else {
1055            assert(s1.union(s2.remove(y)) =~= s1.union(s2).remove(y));
1056            lemma_len_union_ind(s1, s2.remove(y))
1057        }
1058    }
1059}
1060
1061/// The size of the intersection of finite set `s1` and set `s2` is less than or equal to the size of `s1`.
1062pub proof fn lemma_len_intersect<A>(s1: ISet<A>, s2: ISet<A>)
1063    requires
1064        s1.finite(),
1065    ensures
1066        s1.intersect(s2).len() <= s1.len(),
1067    decreases s1.len(),
1068{
1069    if s1.is_empty() {
1070        assert(s1.intersect(s2) =~= s1);
1071    } else {
1072        let a = s1.choose();
1073        assert(s1.intersect(s2).remove(a) =~= s1.remove(a).intersect(s2));
1074        lemma_len_intersect::<A>(s1.remove(a), s2);
1075    }
1076}
1077
1078/// If `s1` is a subset of finite set `s2`, then the size of `s1` is less than or equal to
1079/// the size of `s2` and `s1` must be finite.
1080pub proof fn lemma_len_subset<A>(s1: ISet<A>, s2: ISet<A>)
1081    requires
1082        s2.finite(),
1083        s1.subset_of(s2),
1084    ensures
1085        s1.len() <= s2.len(),
1086        s1.finite(),
1087{
1088    lemma_len_intersect::<A>(s2, s1);
1089    assert(s2.intersect(s1) =~= s1);
1090}
1091
1092/// A subset of a finite set `s` is finite.
1093pub broadcast proof fn lemma_iset_subset_finite<A>(s: ISet<A>, sub: ISet<A>)
1094    requires
1095        s.finite(),
1096        sub.subset_of(s),
1097    ensures
1098        #![trigger sub.subset_of(s)]
1099        sub.finite(),
1100{
1101    let complement = s.difference(sub);
1102    assert(sub =~= s.difference(complement));
1103}
1104
1105/// The size of the difference of finite set `s1` and set `s2` is less than or equal to the size of `s1`.
1106pub proof fn lemma_len_difference<A>(s1: ISet<A>, s2: ISet<A>)
1107    requires
1108        s1.finite(),
1109    ensures
1110        s1.difference(s2).len() <= s1.len(),
1111    decreases s1.len(),
1112{
1113    if s1.is_empty() {
1114        assert(s1.difference(s2) =~= s1);
1115    } else {
1116        let a = s1.choose();
1117        assert(s1.difference(s2).remove(a) =~= s1.remove(a).difference(s2));
1118        lemma_len_difference::<A>(s1.remove(a), s2);
1119    }
1120}
1121
1122/// Creates a finite set of integers in the range [lo, hi).
1123pub open spec fn set_int_range(lo: int, hi: int) -> ISet<int> {
1124    ISet::new(|i: int| lo <= i && i < hi)
1125}
1126
1127/// If a set solely contains integers in the range [a, b), then its size is
1128/// bounded by b - a.
1129pub proof fn lemma_int_range(lo: int, hi: int)
1130    requires
1131        lo <= hi,
1132    ensures
1133        set_int_range(lo, hi).finite(),
1134        set_int_range(lo, hi).len() == hi - lo,
1135    decreases hi - lo,
1136{
1137    if lo == hi {
1138        assert(set_int_range(lo, hi) =~= ISet::empty());
1139    } else {
1140        lemma_int_range(lo, hi - 1);
1141        assert(set_int_range(lo, hi - 1).insert(hi - 1) =~= set_int_range(lo, hi));
1142    }
1143}
1144
1145/// If x is a subset of y and the size of x is equal to the size of y, x is equal to y.
1146pub proof fn lemma_subset_equality<A>(x: ISet<A>, y: ISet<A>)
1147    requires
1148        x.subset_of(y),
1149        x.finite(),
1150        y.finite(),
1151        x.len() == y.len(),
1152    ensures
1153        x =~= y,
1154    decreases x.len(),
1155{
1156    broadcast use group_iset_properties;
1157
1158    if x =~= ISet::<A>::empty() {
1159    } else {
1160        let e = x.choose();
1161        lemma_subset_equality(x.remove(e), y.remove(e));
1162    }
1163}
1164
1165/// If an injective function is applied to each element of a set to construct
1166/// another set, the two sets have the same size.
1167pub proof fn lemma_map_size<A, B>(x: ISet<A>, y: ISet<B>, f: spec_fn(A) -> B)
1168    requires
1169        x.finite(),
1170        x.injective_on(f),
1171        x.map(f) == y,
1172    ensures
1173        y.finite(),
1174        x.len() == y.len(),
1175    decreases x.len(),
1176{
1177    broadcast use group_iset_properties;
1178
1179    if x.len() == 0 {
1180        if !y.is_empty() {
1181            let e = y.choose();
1182        }
1183    } else {
1184        let a = x.choose();
1185        assert(x.remove(a).map(f) == y.remove(f(a)));
1186        lemma_map_size(x.remove(a), y.remove(f(a)), f);
1187        assert(y == y.remove(f(a)).insert(f(a)));
1188    }
1189}
1190
1191/// If any function is applied to each element of a set to construct
1192/// another set, the constructed set's length is at most the original's
1193pub proof fn lemma_map_size_bound<A, B>(x: ISet<A>, y: ISet<B>, f: spec_fn(A) -> B)
1194    requires
1195        x.finite(),
1196        x.map(f) == y,
1197    ensures
1198        y.finite(),
1199        y.len() <= x.len(),
1200    decreases x.len(),
1201{
1202    broadcast use group_iset_properties;
1203
1204    if x.is_empty() {
1205        if !y.is_empty() {
1206            let e = y.choose();
1207        }
1208    } else {
1209        let xx = x.choose();
1210        let img = f(xx);
1211        let pre = x.filter(|a: A| f(a) == f(xx));
1212        x.lemma_len_filter(|a: A| f(a) == f(xx));
1213        let wit = choose|a: A| x.contains(a) && f(a) == f(xx);
1214        assert forall|b: B| (#[trigger] y.remove(f(xx)).contains(b)) implies exists|a: A|
1215            x.difference(pre).contains(a) && f(a) == b by {
1216            let pre_wit = choose|a: A| x.contains(a) && f(a) == b;
1217            assert(x.difference(pre).contains(pre_wit));
1218        }
1219
1220        assert(x == x.difference(pre).union(pre));
1221        assert(y == y.remove(f(xx)).insert(f(xx)));
1222        assert(x.difference(pre).map(f) == y.remove(f(xx)));
1223        lemma_map_size_bound(x.difference(pre), y.remove(f(xx)), f);
1224    }
1225}
1226
1227// This verified lemma used to be an axiom in the Dafny prelude
1228/// Taking the union of sets `a` and `b` and then taking the union of the result with `b`
1229/// is the same as taking the union of `a` and `b` once.
1230pub broadcast proof fn lemma_iset_union_again1<A>(a: ISet<A>, b: ISet<A>)
1231    ensures
1232        #[trigger] a.union(b).union(b) =~= a.union(b),
1233{
1234}
1235
1236// This verified lemma used to be an axiom in the Dafny prelude
1237/// Taking the union of sets `a` and `b` and then taking the union of the result with `a`
1238/// is the same as taking the union of `a` and `b` once.
1239pub broadcast proof fn lemma_iset_union_again2<A>(a: ISet<A>, b: ISet<A>)
1240    ensures
1241        #[trigger] a.union(b).union(a) =~= a.union(b),
1242{
1243}
1244
1245// This verified lemma used to be an axiom in the Dafny prelude
1246/// Taking the intersection of sets `a` and `b` and then taking the intersection of the result with `b`
1247/// is the same as taking the intersection of `a` and `b` once.
1248pub broadcast proof fn lemma_iset_intersect_again1<A>(a: ISet<A>, b: ISet<A>)
1249    ensures
1250        #![trigger (a.intersect(b)).intersect(b)]
1251        (a.intersect(b)).intersect(b) =~= a.intersect(b),
1252{
1253}
1254
1255// This verified lemma used to be an axiom in the Dafny prelude
1256/// Taking the intersection of sets `a` and `b` and then taking the intersection of the result with `a`
1257/// is the same as taking the intersection of `a` and `b` once.
1258pub broadcast proof fn lemma_iset_intersect_again2<A>(a: ISet<A>, b: ISet<A>)
1259    ensures
1260        #![trigger (a.intersect(b)).intersect(a)]
1261        (a.intersect(b)).intersect(a) =~= a.intersect(b),
1262{
1263}
1264
1265// This verified lemma used to be an axiom in the Dafny prelude
1266/// If set `s2` contains element `a`, then the set difference of `s1` and `s2` does not contain `a`.
1267pub broadcast proof fn lemma_iset_difference2<A>(s1: ISet<A>, s2: ISet<A>, a: A)
1268    ensures
1269        #![trigger s1.difference(s2).contains(a)]
1270        s2.contains(a) ==> !s1.difference(s2).contains(a),
1271{
1272}
1273
1274// This verified lemma used to be an axiom in the Dafny prelude
1275/// If sets `a` and `b` are disjoint, meaning they have no elements in common, then the set difference
1276/// of `a + b` and `b` is equal to `a` and the set difference of `a + b` and `a` is equal to `b`.
1277pub broadcast proof fn lemma_iset_disjoint<A>(a: ISet<A>, b: ISet<A>)
1278    ensures
1279        #![trigger (a + b).difference(a)]  //TODO: this might be too free
1280        a.disjoint(b) ==> ((a + b).difference(a) =~= b && (a + b).difference(b) =~= a),
1281{
1282}
1283
1284// This verified lemma used to be an axiom in the Dafny prelude
1285// Dafny encodes the second clause with a single directional, although
1286// it should be fine with both directions?
1287// REVIEW: excluded from broadcast group if trigger is too free
1288//         also not that some proofs in seq_lib requires this lemma
1289/// ISet `s` has length 0 if and only if it is equal to the empty set. If `s` has length greater than 0,
1290/// Then there must exist an element `x` such that `s` contains `x`.
1291pub broadcast proof fn lemma_iset_empty_equivalency_len<A>(s: ISet<A>)
1292    requires
1293        s.finite(),
1294    ensures
1295        #![trigger s.len()]
1296        (s.len() == 0 <==> s == ISet::<A>::empty()) && (s.len() != 0 ==> exists|x: A|
1297            s.contains(x)),
1298{
1299    assert(s.len() == 0 ==> s =~= ISet::empty()) by {
1300        if s.len() == 0 {
1301            assert(forall|a: A| !(ISet::empty().contains(a)));
1302            assert(ISet::<A>::empty().len() == 0);
1303            assert(ISet::<A>::empty().len() == s.len());
1304            assert((exists|a: A| s.contains(a)) || (forall|a: A| !s.contains(a)));
1305            if exists|a: A| s.contains(a) {
1306                let a = s.choose();
1307                assert(s.remove(a).len() == s.len() - 1) by {
1308                    lemma_iset_remove_len(s, a);
1309                }
1310            }
1311        }
1312    }
1313    assert(s.len() == 0 <== s =~= ISet::empty());
1314}
1315
1316// This verified lemma used to be an axiom in the Dafny prelude
1317/// If sets `a` and `b` are disjoint, meaning they share no elements in common, then the length
1318/// of the union `a + b` is equal to the sum of the lengths of `a` and `b`.
1319pub broadcast proof fn lemma_iset_disjoint_lens<A>(a: ISet<A>, b: ISet<A>)
1320    requires
1321        a.finite(),
1322        b.finite(),
1323    ensures
1324        a.disjoint(b) ==> #[trigger] (a + b).len() == a.len() + b.len(),
1325    decreases a.len(),
1326{
1327    if a.len() == 0 {
1328        lemma_iset_empty_equivalency_len(a);
1329        assert(a + b =~= b);
1330    } else {
1331        if a.disjoint(b) {
1332            let x = a.choose();
1333            assert(a.remove(x) + b =~= (a + b).remove(x));
1334            lemma_iset_disjoint_lens(a.remove(x), b);
1335        }
1336    }
1337}
1338
1339/// Two sets are disjoint iff their intersection is empty
1340pub proof fn lemma_iset_disjoint_iff_empty_intersection<T>(a: ISet<T>, b: ISet<T>)
1341    ensures
1342        a.disjoint(b) <==> a.intersect(b).is_empty(),
1343{
1344    broadcast use group_iset_properties;
1345
1346    if a.disjoint(b) {
1347        assert(b.disjoint(a));
1348        assert(forall|x: T| a.contains(x) ==> !(a.contains(x) && b.contains(x)));
1349        assert(forall|x: T| b.contains(x) ==> !(a.contains(x) && b.contains(x)));
1350        assert(forall|x: T| !a.intersect(b).contains(x));
1351    }
1352    if a.intersect(b).is_empty() {
1353        assert(forall|x: T| !a.intersect(b).contains(x));
1354        if !a.disjoint(b) {
1355            assert(exists|x: T| a.contains(x) && b.contains(x));
1356            let x = choose|x: T| a.contains(x) && b.contains(x);
1357            assert(a.intersect(b).contains(x));
1358            assert(!a.intersect(b).is_empty());
1359        }
1360    }
1361}
1362
1363// This verified lemma used to be an axiom in the Dafny prelude
1364/// The length of the union between two sets added to the length of the intersection between the
1365/// two sets is equal to the sum of the lengths of the two sets.
1366pub broadcast proof fn lemma_iset_intersect_union_lens<A>(a: ISet<A>, b: ISet<A>)
1367    requires
1368        a.finite(),
1369        b.finite(),
1370    ensures
1371        #[trigger] (a + b).len() + #[trigger] a.intersect(b).len() == a.len() + b.len(),
1372    decreases a.len(),
1373{
1374    if a.len() == 0 {
1375        lemma_iset_empty_equivalency_len(a);
1376        assert(a + b =~= b);
1377        assert(a.intersect(b) =~= ISet::empty());
1378        assert(a.intersect(b).len() == 0);
1379    } else {
1380        let x = a.choose();
1381        lemma_iset_intersect_union_lens(a.remove(x), b);
1382        if (b.contains(x)) {
1383            assert(a.remove(x) + b =~= (a + b));
1384            assert(a.intersect(b).remove(x) =~= a.remove(x).intersect(b));
1385        } else {
1386            assert(a.remove(x) + b =~= (a + b).remove(x));
1387            assert(a.remove(x).intersect(b) =~= a.intersect(b));
1388        }
1389    }
1390}
1391
1392// This verified lemma used to be an axiom in the Dafny prelude
1393/// The length of the set difference `A \ B` added to the length of the set difference `B \ A` added to
1394/// the length of the intersection `A ∩ B` is equal to the length of the union `A + B`.
1395///
1396/// The length of the set difference `A \ B` is equal to the length of `A` minus the length of the
1397/// intersection `A ∩ B`.
1398pub broadcast proof fn lemma_iset_difference_len<A>(a: ISet<A>, b: ISet<A>)
1399    requires
1400        a.finite(),
1401        b.finite(),
1402    ensures
1403        (#[trigger] a.difference(b).len() + b.difference(a).len() + a.intersect(b).len() == (a
1404            + b).len()) && (a.difference(b).len() == a.len() - a.intersect(b).len()),
1405    decreases a.len(),
1406{
1407    if a.len() == 0 {
1408        lemma_iset_empty_equivalency_len(a);
1409        assert(a.difference(b) =~= ISet::empty());
1410        assert(b.difference(a) =~= b);
1411        assert(a.intersect(b) =~= ISet::empty());
1412        assert(a + b =~= b);
1413    } else {
1414        let x = a.choose();
1415        lemma_iset_difference_len(a.remove(x), b);
1416        if b.contains(x) {
1417            assert(a.intersect(b).remove(x) =~= a.remove(x).intersect(b));
1418            assert(a.remove(x).difference(b) =~= a.difference(b));
1419            assert(b.difference(a.remove(x)).remove(x) =~= b.difference(a));
1420            assert(a.remove(x) + b =~= a + b);
1421        } else {
1422            assert(a.remove(x) + b =~= (a + b).remove(x));
1423            assert(a.remove(x).difference(b) =~= a.difference(b).remove(x));
1424            assert(b.difference(a.remove(x)) =~= b.difference(a));
1425            assert(a.remove(x).intersect(b) =~= a.intersect(b));
1426        }
1427    }
1428}
1429
1430pub broadcast group group_iset_properties {
1431    lemma_iset_union_again1,
1432    lemma_iset_union_again2,
1433    lemma_iset_intersect_again1,
1434    lemma_iset_intersect_again2,
1435    lemma_iset_difference2,
1436    lemma_iset_disjoint,
1437    lemma_iset_disjoint_lens,
1438    lemma_iset_intersect_union_lens,
1439    lemma_iset_difference_len,
1440    // REVIEW: exclude from broadcast group if trigger is too free
1441    //         also note that some proofs in seq_lib requires this lemma
1442    lemma_iset_empty_equivalency_len,
1443}
1444
1445pub broadcast axiom fn axiom_iset_is_empty<A>(s: ISet<A>)
1446    requires
1447        !(#[trigger] s.is_empty()),
1448    ensures
1449        exists|a: A|
1450            s.contains(
1451                a,
1452            ),
1453// REVIEW, should this be in `set`, or have a proof?
1454
1455;
1456
1457pub broadcast proof fn lemma_iset_is_empty_len0<A>(s: ISet<A>)
1458    ensures
1459        #[trigger] s.is_empty() <==> (s.finite() && s.len() == 0),
1460{
1461}
1462
1463#[doc(hidden)]
1464#[verifier::inline]
1465pub open spec fn check_argument_is_set<A>(s: ISet<A>) -> ISet<A> {
1466    s
1467}
1468
1469/// Prove two sets equal by extensionality. Usage is:
1470///
1471/// ```rust
1472/// assert_isets_equal!(set1 == set2);
1473/// ```
1474///
1475/// or,
1476///
1477/// ```rust
1478/// assert_isets_equal!(set1 == set2, elem => {
1479///     // prove that set1.contains(elem) iff set2.contains(elem)
1480/// });
1481/// ```
1482#[macro_export]
1483macro_rules! assert_isets_equal {
1484    [$($tail:tt)*] => {
1485        $crate::vstd::prelude::verus_proof_macro_exprs!($crate::vstd::iset_lib::assert_isets_equal_internal!($($tail)*))
1486    };
1487}
1488
1489#[macro_export]
1490#[doc(hidden)]
1491macro_rules! assert_isets_equal_internal {
1492    (::vstd::prelude::spec_eq($s1:expr, $s2:expr)) => {
1493        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2)
1494    };
1495    (::vstd::prelude::spec_eq($s1:expr, $s2:expr), $elem:ident $( : $t:ty )? => $bblock:block) => {
1496        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2, $elem $( : $t )? => $bblock)
1497    };
1498    (crate::prelude::spec_eq($s1:expr, $s2:expr)) => {
1499        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2)
1500    };
1501    (crate::prelude::spec_eq($s1:expr, $s2:expr), $elem:ident $( : $t:ty )? => $bblock:block) => {
1502        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2, $elem $( : $t )? => $bblock)
1503    };
1504    (crate::verus_builtin::spec_eq($s1:expr, $s2:expr)) => {
1505        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2)
1506    };
1507    (crate::verus_builtin::spec_eq($s1:expr, $s2:expr), $elem:ident $( : $t:ty )? => $bblock:block) => {
1508        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2, $elem $( : $t )? => $bblock)
1509    };
1510    ($s1:expr, $s2:expr $(,)?) => {
1511        $crate::vstd::iset_lib::assert_isets_equal_internal!($s1, $s2, elem => { })
1512    };
1513    ($s1:expr, $s2:expr, $elem:ident $( : $t:ty )? => $bblock:block) => {
1514        #[verifier::spec] let s1 = $crate::vstd::iset_lib::check_argument_is_set($s1);
1515        #[verifier::spec] let s2 = $crate::vstd::iset_lib::check_argument_is_set($s2);
1516        $crate::vstd::prelude::assert_by($crate::vstd::prelude::equal(s1, s2), {
1517            $crate::vstd::prelude::assert_forall_by(|$elem $( : $t )?| {
1518                $crate::vstd::prelude::ensures(
1519                    $crate::vstd::prelude::imply(s1.contains($elem), s2.contains($elem))
1520                    &&
1521                    $crate::vstd::prelude::imply(s2.contains($elem), s1.contains($elem))
1522                );
1523                { $bblock }
1524            });
1525            $crate::vstd::prelude::assert_($crate::vstd::prelude::ext_equal(s1, s2));
1526        });
1527    }
1528}
1529
1530pub broadcast group group_iset_lib_default {
1531    axiom_iset_is_empty,
1532    lemma_iset_is_empty_len0,
1533    lemma_iset_subset_finite,
1534    ISet::lemma_map_by_finite,
1535    ISet::lemma_map_flatten_by_finite,
1536}
1537
1538pub use assert_isets_equal_internal;
1539pub use assert_isets_equal;
1540
1541} // verus!