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}