Skip to main content

vstd/
multiset.rs

1use core::marker;
2
3#[allow(unused_imports)]
4use super::map::*;
5#[cfg(verus_keep_ghost)]
6use super::math::clip;
7#[cfg(verus_keep_ghost)]
8use super::math::min;
9#[allow(unused_imports)]
10use super::pervasive::*;
11#[allow(unused_imports)]
12use super::prelude::*;
13#[allow(unused_imports)]
14use super::set::*;
15
16verus! {
17
18broadcast use group_set_lemmas;
19
20/// `Multiset<V>` is an abstract multiset type for specifications.
21///
22/// `Multiset<V>` can be encoded as a (total) map from elements to natural numbers,
23/// where the number of nonzero entries is finite.
24///
25/// Multisets can be constructed in a few different ways:
26///  * [`Multiset::empty`] constructs an empty multiset.
27///  * [`Multiset::singleton`] constructs a multiset that contains a single element with multiplicity 1.
28///  * [`Multiset::from_map`] constructs a multiset from a map of elements to multiplicities.
29///  * By manipulating existings multisets with [`Multiset::add`], [`Multiset::insert`],
30///    [`Multiset::sub`], [`Multiset::remove`], [`Multiset::update`], or [`Multiset::filter`].
31///  * TODO: `multiset!` constructor macro, multiset from set, from map, etc.
32///
33/// To prove that two multisets are equal, it is usually easiest to use the
34/// extensionality operator `=~=`.
35///
36// We could in principle implement the Multiset via an inductive datatype
37// and so we can mark its type argument as accept_recursive_types.
38// Note: Multiset is finite because it isn't entirely obvious how to represent an
39// infinite multiset in the case where a single value (v: V) has an infinite
40// multiplicity. It seems to require either:
41//   (1) representing multiplicity by an ordinal or cardinal or something
42//   (2) limiting each multiplicity to be finite
43// (1) would be complicated and it's not clear what the use would be; (2) has some
44// weird properties (e.g., you can't in general define a multiset `map` function
45// since it might map an infinite number of elements to the same one).
46// Also, note that if multiset were infinite, it couldn't accept_recursive_types.
47//
48// Now that Verus has a finite Map that is labeled as accept_recursive_types, this file should
49// be rewritten as just a wrapper around Map rather than the present pile of trusted axioms.
50// See https://github.com/verus-lang/verus/discussions/1663
51//
52#[verifier::external_body]
53#[verifier::ext_equal]
54#[verifier::accept_recursive_types(V)]
55pub struct Multiset<V> {
56    dummy: marker::PhantomData<V>,
57}
58
59impl<V> Multiset<V> {
60    /// Returns the _count_, or _multiplicity_ of a single value within the multiset.
61    pub uninterp spec fn count(self, value: V) -> nat;
62
63    /// The total size of the multiset, i.e., the sum of all multiplicities over all values.
64    pub uninterp spec fn len(self) -> nat;
65
66    /// An empty multiset.
67    pub uninterp spec fn empty() -> Self;
68
69    /// Creates a multiset whose elements are given by the domain of the map `m` and whose
70    /// multiplicities are given by the corresponding values of `m[element]`.
71    pub uninterp spec fn from_map(m: Map<V, nat>) -> Self;
72
73    pub open spec fn from_set(m: Set<V>) -> Self {
74        Self::from_map(Map::new(m, |v| 1))
75    }
76
77    /// A singleton multiset, i.e., a multiset with a single element of multiplicity 1.
78    pub uninterp spec fn singleton(v: V) -> Self;
79
80    /// Takes the union of two multisets. For a given element, its multiplicity in
81    /// the resulting multiset is the sum of its multiplicities in the operands.
82    pub uninterp spec fn add(self, m2: Self) -> Self;
83
84    /// Takes the difference of two multisets.
85    /// The multiplicities of `m2` are subtracted from those of `self`; if any element
86    /// occurs more in `m2` then the resulting multiplicity bottoms out at 0.
87    /// (See [`axiom_multiset_sub`] for the precise definition.)
88    ///
89    /// Note in particular that `self == self.sub(m).add(m)` only holds if
90    /// `m` is included in `self`.
91    pub uninterp spec fn sub(self, m2: Self) -> Self;
92
93    /// Inserts one instance the value `v` into the multiset.
94    ///
95    /// This always increases the total size of the multiset by 1.
96    pub open spec fn insert(self, v: V) -> Self {
97        self.add(Self::singleton(v))
98    }
99
100    /// Removes one instance of the value `v` from the multiset.
101    ///
102    /// If `v` was absent from the multiset, then the multiset is unchanged.
103    pub open spec fn remove(self, v: V) -> Self {
104        self.sub(Self::singleton(v))
105    }
106
107    /// Updates the multiplicity of the value `v` in the multiset to `mult`.
108    pub open spec fn update(self, v: V, mult: nat) -> Self {
109        let map = Map::new(
110            self.dom().insert(v),
111            |key: V|
112                if key == v {
113                    mult
114                } else {
115                    self.count(key)
116                },
117        );
118        Self::from_map(map)
119    }
120
121    /// Returns `true` is the left argument is contained in the right argument,
122    /// that is, if for each value `v`, the number of occurences in the left
123    /// is at most the number of occurences in the right.
124    pub open spec fn subset_of(self, m2: Self) -> bool {
125        forall|v: V| self.count(v) <= m2.count(v)
126    }
127
128    #[verifier::inline]
129    pub open spec fn spec_le(self, m2: Self) -> bool {
130        self.subset_of(m2)
131    }
132
133    // TODO define this in terms of a more general constructor?
134    pub uninterp spec fn filter(self, f: impl Fn(V) -> bool) -> Self;
135
136    /// Chooses an arbitrary value of the multiset.
137    ///
138    /// This is often useful for proofs by induction.
139    ///
140    /// (Note that, although the result is arbitrary, it is still a _deterministic_ function
141    /// like any other `spec` function.)
142    pub open spec fn choose(self) -> V {
143        choose|v: V| self.count(v) > 0
144    }
145
146    /// Predicate indicating if the multiset contains the given value.
147    pub open spec fn contains(self, v: V) -> bool {
148        self.count(v) > 0
149    }
150
151    /// Predicate indicating if the set contains the given element: supports `self has a` syntax.
152    #[verifier::inline]
153    pub open spec fn spec_has(self, v: V) -> bool {
154        self.contains(v)
155    }
156
157    /// Returns a multiset containing the lower count of a given element
158    /// between the two sets. In other words, returns a multiset with only
159    /// the elements that "overlap".
160    pub open spec fn intersection_with(self, other: Self) -> Self {
161        let m = Map::<V, nat>::new(
162            self.dom(),
163            |v: V| min(self.count(v) as int, other.count(v) as int) as nat,
164        );
165        Self::from_map(m)
166    }
167
168    /// Returns a multiset containing the difference between the count of a
169    /// given element of the two sets.
170    pub open spec fn difference_with(self, other: Self) -> Self {
171        let m = Map::<V, nat>::new(self.dom(), |v: V| clip(self.count(v) - other.count(v)));
172        Self::from_map(m)
173    }
174
175    /// Returns true if there exist no elements that have a count greater
176    /// than 0 in both multisets. In other words, returns true if the two
177    /// multisets have no elements in common.
178    pub open spec fn is_disjoint_from(self, other: Self) -> bool {
179        forall|x: V| self.count(x) == 0 || other.count(x) == 0
180    }
181
182    // This module assumes that all well-formed multisets have finite footprint,
183    // so this axiom is reasonable.
184    axiom fn axiom_dom_finite(self)
185        ensures
186            #[trigger] ISet::new(|v: V| self.count(v) > 0).finite(),
187    ;
188
189    /// Returns the set of all elements that have a count greater than 0
190    pub closed spec fn dom(self) -> Set<V> {
191        Set::new(|v: V| self.count(v) > 0).unwrap()
192    }
193
194    // dom() won't mean anything unless we know our domain is finite, which is a soundness
195    // invariant that the present axiom-heavy representation promises to maintain.
196    pub broadcast proof fn dom_ensures(self)
197        ensures
198            #![trigger(self.dom())]
199            forall|v: V| #[trigger]
200                self.dom().contains(v) <==> self.count(v) > 0,
201    {
202        self.axiom_dom_finite();
203        assert forall|v: V| #[trigger] self.dom().contains(v) <==> self.count(v) > 0 by {
204            super::iset::lemma_iset_new(|vv: V| self.count(vv) > 0, v);
205        }
206    }
207}
208
209// Specification of `empty`
210/// The empty multiset maps every element to multiplicity 0
211pub broadcast axiom fn axiom_multiset_empty<V>(v: V)
212    ensures
213        #[trigger] Multiset::empty().count(v) == 0,
214;
215
216// This verified lemma used to be an axiom in the Dafny prelude
217/// A multiset is equivalent to the empty multiset if and only if it has length 0.
218/// If the multiset has length greater than 0, then there exists some element in the
219/// multiset that has a count greater than 0.
220pub broadcast proof fn lemma_multiset_empty_len<V>(m: Multiset<V>)
221    ensures
222        #[trigger] m.len() == 0 <==> m =~= Multiset::empty(),
223        #[trigger] m.len() > 0 ==> exists|v: V| 0 < m.count(v),
224{
225    broadcast use group_multiset_axioms;
226
227    assert(m.len() == 0 <==> m =~= Multiset::empty());
228}
229
230// Specifications of `from_map`
231/// A call to Multiset::new with input map `m` will return a multiset that maps
232/// value `v` to multiplicity `m[v]` if `v` is in the domain of `m`.
233pub broadcast axiom fn axiom_multiset_contained<V>(m: Map<V, nat>, v: V)
234    requires
235        m.dom().contains(v),
236    ensures
237//         #[trigger] Multiset::from_map(m).dom().contains(v),
238
239        #[trigger] Multiset::from_map(m).count(v) == m[v],
240;
241
242/// A call to Multiset::new with input map `m` will return a multiset that maps
243/// value `v` to multiplicity 0 if `v` is not in the domain of `m`.
244pub broadcast axiom fn axiom_multiset_new_not_contained<V>(m: Map<V, nat>, v: V)
245    requires
246        !m.dom().contains(v),
247    ensures
248        #[trigger] Multiset::from_map(m).count(v) == 0,
249;
250
251pub broadcast proof fn lemma_from_map_dom<V>(mymap: Map<V, nat>)
252    requires
253        forall|k| #[trigger] mymap.contains_key(k) ==> mymap[k] > 0,
254    ensures
255        #[trigger] Multiset::from_map(mymap).dom() == mymap.dom(),
256{
257    broadcast use {
258        super::set::group_set_lemmas,
259        Multiset::dom_ensures,
260        axiom_multiset_contained,
261        axiom_multiset_new_not_contained,
262    };
263
264    let lhs = Multiset::from_map(mymap).dom();
265    let rhs = mymap.dom();
266    assert forall|v: V| lhs.contains(v) <==> rhs.contains(v) by {
267        if lhs.contains(v) {
268            assert(Multiset::from_map(mymap).count(v) > 0);
269            if !mymap.dom().contains(v) {
270                axiom_multiset_new_not_contained(mymap, v);
271                assert(false);
272            }
273        }
274        if rhs.contains(v) {
275            assert(mymap.dom().contains(v));
276            assert(mymap.contains_key(v));
277            axiom_multiset_contained(mymap, v);
278            assert(mymap[v] > 0);
279            assert(Multiset::from_map(mymap).count(v) > 0);
280            assert(lhs.contains(v));
281        }
282    };
283    axiom_set_ext_equal(lhs, rhs);
284}
285
286// Specification of `singleton`
287/// A call to Multiset::singleton with input value `v` will return a multiset that maps
288/// value `v` to multiplicity 1.
289pub broadcast axiom fn axiom_multiset_singleton<V>(v: V)
290    ensures
291        (#[trigger] Multiset::singleton(v)).count(v) == 1,
292;
293
294/// A call to Multiset::singleton with input value `v` will return a multiset that maps
295/// any value other than `v` to 0
296pub broadcast axiom fn axiom_multiset_singleton_different<V>(v: V, w: V)
297    ensures
298        v != w ==> #[trigger] Multiset::singleton(v).count(w) == 0,
299;
300
301// Specification of `add`
302/// The count of value `v` in the multiset `m1.add(m2)` is equal to the sum of the
303/// counts of `v` in `m1` and `m2` individually.
304pub broadcast axiom fn axiom_multiset_add<V>(m1: Multiset<V>, m2: Multiset<V>, v: V)
305    ensures
306        #[trigger] m1.add(m2).count(v) == m1.count(v) + m2.count(v),
307;
308
309// Specification of `sub`
310/// The count of value `v` in the multiset `m1.sub(m2)` is equal to the difference between the
311/// count of `v` in `m1` and `m2` individually. However, the difference is cut off at 0 and
312/// cannot be negative.
313pub broadcast axiom fn axiom_multiset_sub<V>(m1: Multiset<V>, m2: Multiset<V>, v: V)
314    ensures
315        #[trigger] m1.sub(m2).count(v) == if m1.count(v) >= m2.count(v) {
316            m1.count(v) - m2.count(v)
317        } else {
318            0
319        },
320;
321
322// Extensional equality
323/// Two multisets are equivalent if and only if they have the same count for every value.
324pub broadcast axiom fn axiom_multiset_ext_equal<V>(m1: Multiset<V>, m2: Multiset<V>)
325    ensures
326        #[trigger] (m1 =~= m2) <==> (forall|v: V| m1.count(v) == m2.count(v)),
327;
328
329pub broadcast axiom fn axiom_multiset_ext_equal_deep<V>(m1: Multiset<V>, m2: Multiset<V>)
330    ensures
331        #[trigger] (m1 =~~= m2) <==> m1 =~= m2,
332;
333
334// Specification of `len`
335/// The length of the empty multiset is 0.
336pub broadcast axiom fn axiom_len_empty<V>()
337    ensures
338        (#[trigger] Multiset::<V>::empty().len()) == 0,
339;
340
341/// The length of a singleton multiset is 1.
342pub broadcast axiom fn axiom_len_singleton<V>(v: V)
343    ensures
344        (#[trigger] Multiset::<V>::singleton(v).len()) == 1,
345;
346
347/// The length of the addition of two multisets is equal to the sum of the lengths of each individual multiset.
348pub broadcast axiom fn axiom_len_add<V>(m1: Multiset<V>, m2: Multiset<V>)
349    ensures
350        (#[trigger] m1.add(m2).len()) == m1.len() + m2.len(),
351;
352
353// TODO could probably prove this theorem.
354/// The length of the subtraction of two multisets is equal to the difference between the lengths of each individual multiset.
355pub broadcast axiom fn axiom_len_sub<V>(m1: Multiset<V>, m2: Multiset<V>)
356    requires
357        m2.subset_of(m1),
358    ensures
359        (#[trigger] m1.sub(m2).len()) == m1.len() - m2.len(),
360;
361
362/// The count for any given value `v` in a multiset `m` must be less than or equal to the length of `m`.
363pub broadcast axiom fn axiom_count_le_len<V>(m: Multiset<V>, v: V)
364    ensures
365        #[trigger] m.count(v) <= #[trigger] m.len(),
366;
367
368// Specification of `filter`
369/// For a given value `v` and boolean predicate `f`, if `f(v)` is true, then the count of `v` in
370/// `m.filter(f)` is the same as the count of `v` in `m`. Otherwise, the count of `v` in `m.filter(f)` is 0.
371pub broadcast axiom fn axiom_filter_count<V>(m: Multiset<V>, f: spec_fn(V) -> bool, v: V)
372    ensures
373        (#[trigger] m.filter(f).count(v)) == if f(v) {
374            m.count(v)
375        } else {
376            0
377        },
378;
379
380// Specification of `choose`
381/// In a nonempty multiset `m`, the `choose` function will return a value that maps to a multiplicity
382/// greater than 0 in `m`.
383pub broadcast axiom fn axiom_choose_count<V>(m: Multiset<V>)
384    requires
385        #[trigger] m.len() != 0,
386    ensures
387        #[trigger] m.count(m.choose()) > 0,
388;
389
390pub broadcast group group_multiset_axioms {
391    axiom_multiset_empty,
392    axiom_multiset_contained,
393    axiom_multiset_new_not_contained,
394    lemma_from_map_dom,
395    axiom_multiset_singleton,
396    axiom_multiset_singleton_different,
397    axiom_multiset_add,
398    axiom_multiset_sub,
399    axiom_multiset_ext_equal,
400    axiom_multiset_ext_equal_deep,
401    axiom_len_empty,
402    axiom_len_singleton,
403    axiom_len_add,
404    axiom_len_sub,
405    axiom_count_le_len,
406    axiom_filter_count,
407    axiom_choose_count,
408}
409
410// Lemmas about `update`
411/// The multiset resulting from updating a value `v` in a multiset `m` to multiplicity `mult` will
412/// have a count of `mult` for `v`.
413pub broadcast proof fn lemma_update_same<V>(m: Multiset<V>, v: V, mult: nat)
414    ensures
415        #[trigger] m.update(v, mult).count(v) == mult,
416{
417    broadcast use {
418        group_set_lemmas,
419        super::map::group_map_lemmas,
420        group_multiset_axioms,
421        Multiset::dom_ensures,
422    };
423
424    reveal(Multiset::update);
425    let key_set = m.dom().insert(v);
426    let fv = |key: V|
427        if key == v {
428            mult
429        } else {
430            m.count(key)
431        };
432    let map = Map::new(key_set, fv);
433    crate::vstd::map_lib::lemma_map_new_domain(key_set, fv);
434    assert(key_set.contains(v));
435    assert(map.dom().contains(v));
436    assert(map[v] == mult);
437    axiom_multiset_contained(map, v);
438}
439
440/// The multiset resulting from updating a value `v1` in a multiset `m` to multiplicity `mult` will
441/// not change the multiplicities of any other values in `m`.
442pub broadcast proof fn lemma_update_different<V>(m: Multiset<V>, v1: V, mult: nat, v2: V)
443    requires
444        v1 != v2,
445    ensures
446        #[trigger] m.update(v1, mult).count(v2) == m.count(v2),
447{
448    broadcast use {group_set_lemmas, super::map::group_map_lemmas, group_multiset_axioms};
449    broadcast use {axiom_multiset_contained, Multiset::dom_ensures};
450
451    reveal(Multiset::update);
452    let key_set = m.dom().insert(v1);
453    let fv = |key: V|
454        if key == v1 {
455            mult
456        } else {
457            m.count(key)
458        };
459    let map = Map::new(key_set, fv);
460    crate::vstd::map_lib::lemma_map_new_domain(key_set, fv);
461    if map.dom().contains(v2) {
462        assert(map[v2] == m.count(v2));
463        axiom_multiset_contained(map, v2);
464    } else {
465        axiom_multiset_new_not_contained(map, v2);
466        assert(!m.dom().contains(v2)) by {
467            if m.dom().contains(v2) {
468                assert(key_set.contains(v2));
469                assert(map.dom().contains(v2));
470                assert(false);
471            }
472        }
473        m.dom_ensures();
474        assert(m.count(v2) == 0);
475    }
476}
477
478// Lemmas about `insert`
479// This verified lemma used to be an axiom in the Dafny prelude
480/// If you insert element x into multiset m, then element y maps
481/// to a count greater than 0 if and only if x==y or y already
482/// mapped to a count greater than 0 before the insertion of x.
483pub broadcast proof fn lemma_insert_containment<V>(m: Multiset<V>, x: V, y: V)
484    ensures
485        0 < #[trigger] m.insert(x).count(y) <==> x == y || 0 < m.count(y),
486{
487    broadcast use group_multiset_axioms;
488
489}
490
491// This verified lemma used to be an axiom in the Dafny prelude
492/// Inserting an element `x` into multiset `m` will increase the count of `x` in `m` by 1.
493pub broadcast proof fn lemma_insert_increases_count_by_1<V>(m: Multiset<V>, x: V)
494    ensures
495        #[trigger] m.insert(x).count(x) == m.count(x) + 1,
496{
497    broadcast use group_multiset_axioms;
498
499}
500
501// This verified lemma used to be an axiom in the Dafny prelude
502/// If multiset `m` maps element `y` to a multiplicity greater than 0, then inserting any element `x`
503/// into `m` will not cause `y` to map to a multiplicity of 0. This is a way of saying that inserting `x`
504/// will not cause any counts to decrease, because it accounts both for when x == y and when x != y.
505pub broadcast proof fn lemma_insert_non_decreasing<V>(m: Multiset<V>, x: V, y: V)
506    ensures
507        0 < m.count(y) ==> 0 < #[trigger] m.insert(x).count(y),
508{
509    broadcast use group_multiset_axioms;
510
511}
512
513// This verified lemma used to be an axiom in the Dafny prelude
514/// Inserting an element `x` into a multiset `m` will not change the count of any other element `y` in `m`.
515pub broadcast proof fn lemma_insert_other_elements_unchanged<V>(m: Multiset<V>, x: V, y: V)
516    ensures
517        x != y ==> m.count(y) == #[trigger] m.insert(x).count(y),
518{
519    broadcast use group_multiset_axioms;
520
521}
522
523// This verified lemma used to be an axiom in the Dafny prelude
524/// Inserting an element `x` into a multiset `m` will increase the length of `m` by 1.
525pub broadcast proof fn lemma_insert_len<V>(m: Multiset<V>, x: V)
526    ensures
527        #[trigger] m.insert(x).len() == m.len() + 1,
528{
529    broadcast use group_multiset_axioms;
530
531}
532
533// Lemmas about `intersection_with`
534// This verified lemma used to be an axiom in the Dafny prelude
535/// The multiplicity of an element `x` in the intersection of multisets `a` and `b` will be the minimum
536/// count of `x` in either `a` or `b`.
537pub broadcast proof fn lemma_intersection_count<V>(a: Multiset<V>, b: Multiset<V>, x: V)
538    ensures
539        #[trigger] a.intersection_with(b).count(x) == min(a.count(x) as int, b.count(x) as int),
540{
541    broadcast use {group_set_lemmas, super::map::group_map_lemmas, group_multiset_axioms};
542    broadcast use {group_multiset_axioms, Multiset::dom_ensures};
543
544    let m = Map::new(a.dom(), |v: V| min(a.count(v) as int, b.count(v) as int) as nat);
545    crate::vstd::map_lib::lemma_map_new_domain(
546        a.dom(),
547        |v: V| min(a.count(v) as int, b.count(v) as int) as nat,
548    );
549    if m.dom().contains(x) {
550        assert(m[x] == min(a.count(x) as int, b.count(x) as int) as nat);
551        axiom_multiset_contained(m, x);
552    } else {
553        axiom_multiset_new_not_contained(m, x);
554        assert(!a.dom().contains(x));
555        a.dom_ensures();
556        assert(a.count(x) == 0) by {
557            if a.count(x) != 0 {
558                assert(a.count(x) > 0);
559                assert(a.dom().contains(x));
560                assert(false);
561            }
562        }
563        assert(min(a.count(x) as int, b.count(x) as int) == 0);
564    }
565}
566
567// This verified lemma used to be an axiom in the Dafny prelude
568/// Taking the intersection of multisets `a` and `b` and then taking the resulting multiset's intersection
569/// with `b` again is the same as just taking the intersection of `a` and `b` once.
570pub broadcast proof fn lemma_left_pseudo_idempotence<V>(a: Multiset<V>, b: Multiset<V>)
571    ensures
572        #[trigger] a.intersection_with(b).intersection_with(b) =~= a.intersection_with(b),
573{
574    broadcast use group_multiset_axioms;
575
576    assert forall|x: V| #[trigger]
577        a.intersection_with(b).count(x) == min(a.count(x) as int, b.count(x) as int) by {
578        lemma_intersection_count(a, b, x);
579    }
580    assert forall|x: V| #[trigger]
581        a.intersection_with(b).intersection_with(b).count(x) == min(
582            a.count(x) as int,
583            b.count(x) as int,
584        ) by {
585        lemma_intersection_count(a.intersection_with(b), b, x);
586        assert(min(min(a.count(x) as int, b.count(x) as int) as int, b.count(x) as int) == min(
587            a.count(x) as int,
588            b.count(x) as int,
589        ));
590    }
591}
592
593// This verified lemma used to be an axiom in the Dafny prelude
594/// Taking the intersection of multiset `a` with the result of taking the intersection of `a` and `b`
595/// is the same as just taking the intersection of `a` and `b` once.
596pub broadcast proof fn lemma_right_pseudo_idempotence<V>(a: Multiset<V>, b: Multiset<V>)
597    ensures
598        #[trigger] a.intersection_with(a.intersection_with(b)) =~= a.intersection_with(b),
599{
600    broadcast use group_multiset_axioms;
601
602    assert forall|x: V| #[trigger]
603        a.intersection_with(b).count(x) == min(a.count(x) as int, b.count(x) as int) by {
604        lemma_intersection_count(a, b, x);
605    }
606    assert forall|x: V| #[trigger]
607        a.intersection_with(a.intersection_with(b)).count(x) == min(
608            a.count(x) as int,
609            b.count(x) as int,
610        ) by {
611        lemma_intersection_count(a, a.intersection_with(b), x);
612        assert(min(a.count(x) as int, min(a.count(x) as int, b.count(x) as int) as int) == min(
613            a.count(x) as int,
614            b.count(x) as int,
615        ));
616    }
617}
618
619// Lemmas about `difference_with`
620// This verified lemma used to be an axiom in the Dafny prelude
621/// The multiplicity of an element `x` in the difference of multisets `a` and `b` will be
622/// equal to the difference of the counts of `x` in `a` and `b`, or 0 if this difference is negative.
623pub broadcast proof fn lemma_difference_count<V>(a: Multiset<V>, b: Multiset<V>, x: V)
624    ensures
625        #[trigger] a.difference_with(b).count(x) == clip(a.count(x) - b.count(x)),
626{
627    broadcast use {
628        group_set_lemmas,
629        super::map::group_map_lemmas,
630        group_multiset_axioms,
631        Multiset::dom_ensures,
632    };
633
634    let map = Map::<V, nat>::new(a.dom(), |v: V| clip(a.count(v) - b.count(v)));
635    crate::vstd::map_lib::lemma_map_new_domain(a.dom(), |v: V| clip(a.count(v) - b.count(v)));
636    if map.dom().contains(x) {
637        assert(map[x] == clip(a.count(x) - b.count(x)));
638        axiom_multiset_contained(map, x);
639    } else {
640        axiom_multiset_new_not_contained(map, x);
641        assert(!a.dom().contains(x));
642        a.dom_ensures();
643        assert(a.count(x) == 0) by {
644            if a.count(x) != 0 {
645                assert(a.count(x) > 0);
646                assert(a.dom().contains(x));
647                assert(false);
648            }
649        }
650        assert(clip(a.count(x) - b.count(x)) == 0);
651    }
652}
653
654// This verified lemma used to be an axiom in the Dafny prelude
655/// If the multiplicity of element `x` is less in multiset `a` than in multiset `b`, then the multiplicity
656/// of `x` in the difference of `a` and `b` will be 0.
657pub broadcast proof fn lemma_difference_bottoms_out<V>(a: Multiset<V>, b: Multiset<V>, x: V)
658    ensures
659        #![trigger a.count(x), b.count(x), a.difference_with(b)]
660        a.count(x) <= b.count(x) ==> a.difference_with(b).count(x) == 0,
661{
662    broadcast use group_multiset_axioms;
663
664    lemma_difference_count(a, b, x);
665}
666
667#[macro_export]
668macro_rules! assert_multisets_equal {
669    [$($tail:tt)*] => {
670        $crate::vstd::prelude::verus_proof_macro_exprs!($crate::vstd::multiset::assert_multisets_equal_internal!($($tail)*))
671    };
672}
673
674#[macro_export]
675macro_rules! assert_multisets_equal_internal {
676    (::verus_builtin::spec_eq($m1:expr, $m2:expr)) => {
677        $crate::vstd::multiset::assert_multisets_equal_internal!($m1, $m2)
678    };
679    (::verus_builtin::spec_eq($m1:expr, $m2:expr), $k:ident $( : $t:ty )? => $bblock:block) => {
680        $crate::vstd::multiset::assert_multisets_equal_internal!($m1, $m2, $k $( : $t )? => $bblock)
681    };
682    (crate::verus_builtin::spec_eq($m1:expr, $m2:expr)) => {
683        $crate::vstd::multiset::assert_multisets_equal_internal!($m1, $m2)
684    };
685    (crate::verus_builtin::spec_eq($m1:expr, $m2:expr), $k:ident $( : $t:ty )? => $bblock:block) => {
686        $crate::vstd::multiset::assert_multisets_equal_internal!($m1, $m2, $k $( : $t )? => $bblock)
687    };
688    ($m1:expr, $m2:expr $(,)?) => {
689        $crate::vstd::multiset::assert_multisets_equal_internal!($m1, $m2, key => { })
690    };
691    ($m1:expr, $m2:expr, $k:ident $( : $t:ty )? => $bblock:block) => {
692        #[verifier::spec] let m1 = $m1;
693        #[verifier::spec] let m2 = $m2;
694        $crate::vstd::prelude::assert_by($crate::vstd::prelude::equal(m1, m2), {
695            $crate::vstd::prelude::assert_forall_by(|$k $( : $t )?| {
696                $crate::vstd::prelude::ensures([
697                    $crate::vstd::prelude::equal(m1.count($k), m2.count($k))
698                ]);
699                { $bblock }
700            });
701            $crate::vstd::prelude::assert_($crate::vstd::prelude::ext_equal(m1, m2));
702        });
703    }
704}
705
706pub broadcast group group_multiset_properties {
707    lemma_update_same,
708    lemma_update_different,
709    lemma_multiset_empty_len,
710    lemma_insert_containment,
711    lemma_insert_increases_count_by_1,
712    lemma_insert_non_decreasing,
713    lemma_insert_other_elements_unchanged,
714    lemma_insert_len,
715    lemma_intersection_count,
716    lemma_left_pseudo_idempotence,
717    lemma_right_pseudo_idempotence,
718    lemma_difference_count,
719    lemma_difference_bottoms_out,
720    Multiset::dom_ensures,
721}
722
723#[doc(hidden)]
724pub use assert_multisets_equal_internal;
725pub use assert_multisets_equal;
726
727} // verus!