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