threshold/
multiset.rs

1//! This module contains an implementation of a multi-set supporting a threshold
2//! operation.
3//!
4//! The concept of threshold is explained in detail in [this blog post](https://vitorenes.org/post/2018/11/threshold-union/).
5//!
6//! # Examples
7//! ```
8//! use std::iter::FromIterator;
9//! use threshold::*;
10//!
11//! let mut mset = MultiSet::new();
12//!
13//! mset.add(vec![(17, 1), (23, 1)]);
14//! assert_eq!(mset.threshold(1), vec![&17, &23]);
15//!
16//! mset.add(vec![(17, 1), (42, 3)]);
17//! assert_eq!(mset.threshold(1), vec![&17, &23, &42]);
18//! assert_eq!(mset.threshold(2), vec![&17, &42]);
19//! assert_eq!(mset.threshold(3), vec![&42]);
20//! ```
21
22use crate::Count;
23use std::collections::btree_map::{self, BTreeMap};
24use std::iter::FromIterator;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct MultiSet<E: Ord, C: Count> {
28    /// Associate a count to each element
29    occurrences: BTreeMap<E, C>,
30}
31
32impl<E: Ord, C: Count> MultiSet<E, C> {
33    /// Returns a new `MultiSet` instance.
34    #[allow(clippy::new_without_default)]
35    pub fn new() -> Self {
36        MultiSet {
37            occurrences: BTreeMap::new(),
38        }
39    }
40
41    /// Creates a new `MultiSet` from an iterator of tuples (elem, elem count).
42    ///
43    /// # Examples
44    /// ```
45    /// use threshold::*;
46    ///
47    /// let mset = MultiSet::from(vec![(17, 1), (23, 2)]);
48    /// assert_eq!(mset.count(&17), 1);
49    /// assert_eq!(mset.count(&23), 2);
50    /// ```
51    pub fn from<I: IntoIterator<Item = (E, C)>>(iter: I) -> Self {
52        MultiSet {
53            occurrences: BTreeMap::from_iter(iter),
54        }
55    }
56
57    /// Adds several elements (each with an associated count) to the `MultiSet`.
58    ///
59    /// # Examples
60    /// ```
61    /// use threshold::*;
62    ///
63    /// let mut mset = MultiSet::new();
64    /// assert_eq!(mset.count(&17), 0);
65    ///
66    /// mset.add(vec![(17, 1), (23, 2)]);
67    /// assert_eq!(mset.count(&17), 1);
68    /// assert_eq!(mset.count(&23), 2);
69    /// ```
70    pub fn add<I: IntoIterator<Item = (E, C)>>(&mut self, iter: I) {
71        for (elem, by) in iter {
72            self.add_elem(elem, by);
73        }
74    }
75
76    /// Adds a single element (with an associated count) to the `MultiSet`.
77    ///
78    /// # Examples
79    /// ```
80    /// use threshold::*;
81    ///
82    /// let mut mset = MultiSet::new();
83    /// assert_eq!(mset.count(&17), 0);
84    ///
85    /// mset.add_elem(17, 2);
86    /// assert_eq!(mset.count(&17), 2);
87    /// ```
88    pub fn add_elem(&mut self, elem: E, by: C) {
89        // increase element count
90        let count = self.occurrences.entry(elem).or_insert_with(Count::zero);
91        count.add(by);
92    }
93
94    /// Returns the `Count` of an element.
95    ///
96    /// # Examples
97    /// ```
98    /// use threshold::*;
99    ///
100    /// let mut mset = MultiSet::new();
101    /// assert_eq!(mset.count(&17), 0);
102    ///
103    /// mset.add(vec![(17, 1), (23, 1)]);
104    /// assert_eq!(mset.count(&17), 1);
105    /// assert_eq!(mset.count(&23), 1);
106    /// assert_eq!(mset.count(&42), 0);
107    ///
108    /// mset.add(vec![(17, 1), (42, 1)]);
109    /// assert_eq!(mset.count(&17), 2);
110    /// assert_eq!(mset.count(&23), 1);
111    /// assert_eq!(mset.count(&42), 1);
112    /// assert_eq!(mset.count(&108), 0);
113    /// ```
114    pub fn count(&self, elem: &E) -> C {
115        self.occurrences
116            .get(elem)
117            .map_or(Count::zero(), |&count| count)
118    }
119
120    /// Returns a sorted (ASC) double ended iterator.
121    pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&E, &C)> {
122        self.occurrences.iter()
123    }
124}
125
126impl<E: Ord> MultiSet<E, u64> {
127    /// Returns the elements in the `MultiSet` such that its multiplicity is
128    /// bigger or equal than a given [threshold](https://vitorenes.org/post/2018/11/threshold-union/).
129    ///
130    /// # Examples
131    /// ```
132    /// use threshold::*;
133    ///
134    /// let mut mset = MultiSet::new();
135    /// let empty: Vec<&u64> = Vec::new();
136    /// assert_eq!(mset.threshold(1), empty);
137    ///
138    /// mset.add(vec![(17, 1), (23, 1)]);
139    /// assert_eq!(mset.threshold(1), vec![&17, &23]);
140    /// assert_eq!(mset.threshold(2), empty);
141    ///
142    /// mset.add(vec![(17, 1), (42, 3)]);
143    /// assert_eq!(mset.threshold(1), vec![&17, &23, &42]);
144    /// assert_eq!(mset.threshold(2), vec![&17, &42]);
145    /// assert_eq!(mset.threshold(3), vec![&42]);
146    /// assert_eq!(mset.threshold(4), empty);
147    /// ```
148    pub fn threshold(&self, threshold: u64) -> Vec<&E> {
149        self.threshold_iter(threshold).collect()
150    }
151
152    pub fn threshold_iter(&self, threshold: u64) -> impl Iterator<Item = &E> {
153        self.occurrences
154            .iter()
155            .filter(move |(_, &count)| count >= threshold)
156            .map(|(elem, _)| elem)
157    }
158
159    pub fn elem_count(&self) -> usize {
160        self.occurrences.len()
161    }
162}
163
164pub struct IntoIter<E: Ord, C: Count>(btree_map::IntoIter<E, C>);
165
166impl<E: Ord, C: Count> Iterator for IntoIter<E, C> {
167    type Item = (E, C);
168
169    fn next(&mut self) -> Option<Self::Item> {
170        self.0.next()
171    }
172}
173
174impl<E: Ord, C: Count> IntoIterator for MultiSet<E, C> {
175    type Item = (E, C);
176    type IntoIter = IntoIter<E, C>;
177
178    /// Returns a `MultiSet` into iterator.
179    ///
180    /// # Examples
181    /// ```
182    /// use threshold::*;
183    ///
184    /// let elems_count = vec![("A", 2), ("B", 1)];
185    /// let mset = MultiSet::from(elems_count);
186    ///
187    /// let mut iter = mset.into_iter();
188    /// assert_eq!(Some(("A", 2)), iter.next());
189    /// assert_eq!(Some(("B", 1)), iter.next());
190    /// assert_eq!(None, iter.next());
191    /// ```
192    fn into_iter(self) -> Self::IntoIter {
193        IntoIter(self.occurrences.into_iter())
194    }
195}