hyperloglog_rs/hyperloglog_array.rs
1use core::{
2 hash::Hash,
3 ops::{Index, IndexMut},
4};
5
6use crate::prelude::*;
7
8#[repr(transparent)]
9#[derive(Debug, Clone, Copy, Eq)]
10pub struct HyperLogLogArray<P: Precision + WordType<BITS>, const BITS: usize, const N: usize> {
11 counters: [HyperLogLog<P, BITS>; N],
12}
13
14impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize> PartialEq
15 for HyperLogLogArray<P, BITS, N>
16{
17 #[inline(always)]
18 /// Returns true if the HyperLogLogArray is equal to the other HyperLogLogArray.
19 ///
20 /// # Arguments
21 /// * `other`: The other HyperLogLogArray to compare to.
22 ///
23 /// # Returns
24 /// True if the HyperLogLogArray is equal to the other HyperLogLogArray.
25 fn eq(&self, other: &Self) -> bool {
26 self.counters.eq(&other.counters)
27 }
28}
29
30impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize> Default
31 for HyperLogLogArray<P, BITS, N>
32{
33 #[inline(always)]
34 /// Creates a new HyperLogLogArray with the given precision and number of bits.
35 ///
36 /// # Returns
37 /// A new HyperLogLogArray with the given precision and number of bits.
38 ///
39 /// # Example
40 ///
41 /// ```rust
42 /// use hyperloglog_rs::prelude::*;
43 ///
44 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::default();
45 /// ```
46 fn default() -> Self {
47 Self {
48 counters: [HyperLogLog::default(); N],
49 }
50 }
51}
52
53impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize>
54 HyperLogLogArray<P, BITS, N>
55{
56 #[inline(always)]
57 /// Creates a new HyperLogLogArray with the given precision and number of bits.
58 ///
59 /// # Example
60 ///
61 /// ```
62 /// use hyperloglog_rs::prelude::*;
63 ///
64 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::new();
65 /// ```
66 pub fn new() -> Self {
67 Self {
68 counters: [HyperLogLog::default(); N],
69 }
70 }
71
72 #[inline(always)]
73 /// Returns the estimated overlap and difference cardinality matrices and vectors with the provided HyperLogLogArray.
74 ///
75 /// # Arguments
76 /// * `other`: The HyperLogLogArray to estimate the overlap and difference cardinality matrices and vectors with.
77 ///
78 /// # Returns
79 /// The estimated overlap and difference cardinality matrices and vectors with the provided HyperLogLogArray.
80 pub fn overlap_and_differences_cardinality_matrices<F: Primitive<f32>>(
81 &self,
82 other: &Self,
83 ) -> ([[F; N]; N], [F; N], [F; N]) {
84 HyperLogLog::overlap_and_differences_cardinality_matrices(self.as_ref(), other.as_ref())
85 }
86
87 #[inline(always)]
88 /// Returns the estimated normalized overlap and difference cardinality matrices and vectors with the provided HyperLogLogArray.
89 ///
90 /// # Arguments
91 /// * `other`: The HyperLogLogArray to estimate the normalized overlap and difference cardinality matrices and vectors with.
92 ///
93 /// # Returns
94 /// The estimated normalized overlap and difference cardinality matrices and vectors with the provided HyperLogLogArray.
95 pub fn normalized_overlap_and_differences_cardinality_matrices<F: Primitive<f32>>(
96 &self,
97 other: &Self,
98 ) -> ([[F; N]; N], [F; N], [F; N]) {
99 HyperLogLog::normalized_overlap_and_differences_cardinality_matrices(
100 self.as_ref(),
101 other.as_ref(),
102 )
103 }
104}
105
106impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize>
107 AsRef<[HyperLogLog<P, BITS>; N]> for HyperLogLogArray<P, BITS, N>
108{
109 #[inline(always)]
110 /// Returns a reference to the underlying array of HyperLogLog counters.
111 ///
112 /// # Returns
113 /// A reference to the underlying array of HyperLogLog counters.
114 fn as_ref(&self) -> &[HyperLogLog<P, BITS>; N] {
115 &self.counters
116 }
117}
118
119impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize>
120 AsMut<[HyperLogLog<P, BITS>; N]> for HyperLogLogArray<P, BITS, N>
121{
122 #[inline(always)]
123 /// Returns a mutable reference to the underlying array of HyperLogLog counters.
124 ///
125 /// # Returns
126 /// A mutable reference to the underlying array of HyperLogLog counters.
127 fn as_mut(&mut self) -> &mut [HyperLogLog<P, BITS>; N] {
128 &mut self.counters
129 }
130}
131
132impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize> Index<usize>
133 for HyperLogLogArray<P, BITS, N>
134{
135 type Output = HyperLogLog<P, BITS>;
136
137 #[inline(always)]
138 /// Returns a reference to the HyperLogLog counter at the given index.
139 ///
140 /// # Arguments
141 /// * `index`: The index of the HyperLogLog counter to return.
142 ///
143 /// # Returns
144 /// A reference to the HyperLogLog counter at the given index.
145 ///
146 /// # Panics
147 /// Panics if the index is out of bounds.
148 ///
149 /// # Example
150 ///
151 /// ```rust
152 /// use hyperloglog_rs::prelude::*;
153 ///
154 /// let mut hll_array = HyperLogLogArray::<Precision12, 6, 4>::new();
155 /// hll_array[0].insert(&1);
156 /// hll_array[1].insert(&2);
157 /// hll_array[2].insert(&3);
158 ///
159 /// assert!(hll_array[0].estimate_cardinality() > 0.9
160 /// && hll_array[1].estimate_cardinality() < 1.1
161 /// );
162 /// assert!(hll_array[1].estimate_cardinality() > 0.9
163 /// && hll_array[1].estimate_cardinality() < 1.1
164 /// );
165 /// assert!(hll_array[2].estimate_cardinality() > 0.9
166 /// && hll_array[2].estimate_cardinality() < 1.1
167 /// );
168 /// assert!(hll_array[3].estimate_cardinality() > -0.1
169 /// && hll_array[3].estimate_cardinality() < 0.1
170 /// );
171 ///
172 /// ```
173 fn index(&self, index: usize) -> &Self::Output {
174 &self.counters[index]
175 }
176}
177
178impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize> IndexMut<usize>
179 for HyperLogLogArray<P, BITS, N>
180{
181 #[inline(always)]
182 /// Returns a mutable reference to the HyperLogLog counter at the given index.
183 ///
184 /// # Arguments
185 /// * `index`: The index of the HyperLogLog counter to return.
186 ///
187 /// # Returns
188 /// A mutable reference to the HyperLogLog counter at the given index.
189 ///
190 /// # Panics
191 /// Panics if the index is out of bounds.
192 ///
193 /// # Example
194 ///
195 /// ```rust
196 /// use hyperloglog_rs::prelude::*;
197 ///
198 /// let mut hll_array = HyperLogLogArray::<Precision12, 6, 4>::new();
199 /// hll_array[0].insert(&1);
200 /// hll_array[1].insert(&2);
201 /// hll_array[2].insert(&3);
202 ///
203 /// assert!(hll_array[0].estimate_cardinality() > 0.9
204 /// && hll_array[1].estimate_cardinality() < 1.1
205 /// );
206 /// assert!(hll_array[1].estimate_cardinality() > 0.9
207 /// && hll_array[1].estimate_cardinality() < 1.1
208 /// );
209 /// assert!(hll_array[2].estimate_cardinality() > 0.9
210 /// && hll_array[2].estimate_cardinality() < 1.1
211 /// );
212 /// assert!(hll_array[3].estimate_cardinality() > -0.1
213 /// && hll_array[3].estimate_cardinality() < 0.1
214 /// );
215 ///
216 /// ```
217 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
218 &mut self.counters[index]
219 }
220}
221
222impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize>
223 From<[HyperLogLog<P, BITS>; N]> for HyperLogLogArray<P, BITS, N>
224{
225 #[inline(always)]
226 /// Creates a new HyperLogLogArray from the given array of HyperLogLog counters.
227 ///
228 /// # Arguments
229 /// * `counters`: The array of HyperLogLog counters to create the HyperLogLogArray from.
230 ///
231 /// # Returns
232 /// A new HyperLogLogArray from the given array of HyperLogLog counters.
233 ///
234 /// # Example
235 ///
236 /// ```rust
237 /// use hyperloglog_rs::prelude::*;
238 ///
239 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::from([
240 /// HyperLogLog::default(),
241 /// HyperLogLog::default(),
242 /// HyperLogLog::default(),
243 /// ]);
244 /// ```
245 fn from(counters: [HyperLogLog<P, BITS>; N]) -> Self {
246 Self { counters }
247 }
248}
249
250impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize, H: Hash> From<&[&[H]; N]>
251 for HyperLogLogArray<P, BITS, N>
252{
253 #[inline(always)]
254 /// Creates a new HyperLogLogArray from the given array of vectors of hashable items.
255 ///
256 /// # Arguments
257 /// * `items`: The array of vectors of hashable items to create the HyperLogLogArray from.
258 ///
259 /// # Returns
260 /// A new HyperLogLogArray from the given array of vectors of hashable items.
261 ///
262 /// # Example
263 ///
264 /// ```rust
265 /// use core::hash::Hash;
266 /// use hyperloglog_rs::prelude::*;
267 ///
268 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::from(&[
269 /// [1, 2, 3].as_slice(),
270 /// [4, 5, 6].as_slice(),
271 /// [7, 8, 9].as_slice(),
272 /// ]);
273 /// ```
274 fn from(items: &[&[H]; N]) -> Self {
275 let mut array = [HyperLogLog::default(); N];
276 for (i, item) in items.iter().enumerate() {
277 for item in item.iter() {
278 array[i].insert(item);
279 }
280 }
281 Self { counters: array }
282 }
283}
284
285impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize> From<&[HyperLogLog<P, BITS>]>
286 for HyperLogLogArray<P, BITS, N>
287{
288 #[inline(always)]
289 /// Creates a new HyperLogLogArray from the given vector of HyperLogLog counters.
290 ///
291 /// # Arguments
292 /// * `counters`: The vector of HyperLogLog counters to create the HyperLogLogArray from.
293 ///
294 /// # Returns
295 /// A new HyperLogLogArray from the given vector of HyperLogLog counters.
296 ///
297 /// # Example
298 ///
299 /// ```rust
300 /// use hyperloglog_rs::prelude::*;
301 ///
302 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::from(vec![
303 /// HyperLogLog::default(),
304 /// HyperLogLog::default(),
305 /// HyperLogLog::default(),
306 /// ].as_slice());
307 /// ```
308 fn from(counters: &[HyperLogLog<P, BITS>]) -> Self {
309 assert_eq!(counters.len(), N, concat!(
310 "The length of the vector of HyperLogLog counters must be equal to the number of counters ",
311 "in the HyperLogLogArray."
312 ));
313 let mut array = [HyperLogLog::default(); N];
314 array.copy_from_slice(&counters[..N]);
315 Self { counters: array }
316 }
317}
318
319impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize, H: Hash> From<&[&[H]]>
320 for HyperLogLogArray<P, BITS, N>
321{
322 #[inline(always)]
323 /// Creates a new HyperLogLogArray from the given vector of vectors of hashable items.
324 ///
325 /// # Arguments
326 /// * `items`: The vector of vectors of hashable items to create the HyperLogLogArray from.
327 ///
328 /// # Returns
329 /// A new HyperLogLogArray from the given vector of vectors of hashable items.
330 ///
331 /// # Example
332 ///
333 /// ```rust
334 /// use core::hash::Hash;
335 /// use hyperloglog_rs::prelude::*;
336 ///
337 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::from(&[
338 /// [1, 2, 3].as_slice(),
339 /// [4, 5, 6].as_slice(),
340 /// [7, 8, 9].as_slice(),
341 /// ]);
342 /// ```
343 fn from(items: &[&[H]]) -> Self {
344 assert_eq!(items.len(), N, concat!(
345 "The length of the vector of vectors of hashable items must be equal to the number of counters ",
346 "in the HyperLogLogArray."
347 ));
348 let mut array = [HyperLogLog::default(); N];
349 for (i, item) in items.iter().enumerate() {
350 for item in item.iter() {
351 array[i].insert(item);
352 }
353 }
354 Self { counters: array }
355 }
356}
357
358impl<P: Precision + WordType<BITS>, const BITS: usize, const N: usize, H: Hash> From<[&[H]; N]>
359 for HyperLogLogArray<P, BITS, N>
360{
361 #[inline(always)]
362 /// Creates a new HyperLogLogArray from the given array of vectors of hashable items.
363 ///
364 /// # Arguments
365 /// * `items`: The array of vectors of hashable items to create the HyperLogLogArray from.
366 ///
367 /// # Returns
368 /// A new HyperLogLogArray from the given array of vectors of hashable items.
369 ///
370 /// # Example
371 ///
372 /// ```rust
373 /// use core::hash::Hash;
374 /// use hyperloglog_rs::prelude::*;
375 ///
376 /// let hll_array = HyperLogLogArray::<Precision12, 6, 3>::from([
377 /// vec![1_usize, 2, 3].as_slice(),
378 /// vec![4, 5, 6].as_slice(),
379 /// vec![7, 8, 9].as_slice(),
380 /// ]);
381 /// ```
382 fn from(items: [&[H]; N]) -> Self {
383 let mut array = [HyperLogLog::default(); N];
384 for (i, item) in items.iter().enumerate() {
385 for item in item.iter() {
386 array[i].insert(item);
387 }
388 }
389 Self { counters: array }
390 }
391}