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}