From 27a3c992ce765a53dd095127966fefacede8a60a Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Wed, 21 Aug 2024 14:42:20 +0200 Subject: [PATCH] Finalized massive lineup of models for cardinality benchmark --- Cargo.toml | 4 + benches/array.rs | 52 ++++++++++++ hyperloglog-derive/src/lib.rs | 4 +- src/mle.rs | 14 +-- src/registers/packed_array.rs | 9 +- src/utils.rs | 2 +- statistical_comparisons/Cargo.toml | 2 +- .../macro_test_utils/Cargo.toml | 2 +- .../macro_test_utils/src/lib.rs | 85 ++++++++++++++++++- statistical_comparisons/src/enumerations.rs | 64 ++++---------- .../src/estimation_tests.rs | 26 +++--- statistical_comparisons/src/main.rs | 26 +----- .../src/proxy_implementations.rs | 57 ++++++++----- 13 files changed, 228 insertions(+), 119 deletions(-) create mode 100644 benches/array.rs diff --git a/Cargo.toml b/Cargo.toml index 1460f6a..e40d9e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,3 +133,7 @@ harness = false [[bench]] name = "hybrid" harness = false + +[[bench]] +name = "array" +harness = false diff --git a/benches/array.rs b/benches/array.rs new file mode 100644 index 0000000..bd83237 --- /dev/null +++ b/benches/array.rs @@ -0,0 +1,52 @@ +//! Benchmark for the methods of the array data structure. +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use hyperloglog_rs::prelude::*; + +const PRECISION: usize = 15; +const REGISTER_SIZE: usize = 6; +const NUMBER_OF_REGISTERS: usize = 1 << PRECISION; +const NUMBER_OF_REGISTERS_IN_U64: usize = 64 / REGISTER_SIZE; +const PADDED_SIZE: usize = ceil(NUMBER_OF_REGISTERS, NUMBER_OF_REGISTERS_IN_U64); +const PACKED_SIZE: usize = ceil(NUMBER_OF_REGISTERS * REGISTER_SIZE, 64); + +fn bench_array(c: &mut Criterion) { + let mut group = c.benchmark_group("array"); + + group.bench_function("array_insert", |b| { + b.iter(|| { + let mut left = 0; + let mut right = 0; + let mut array: Array = Array::default(); + for i in 0..NUMBER_OF_REGISTERS { + for value in 0..64 { + let (l, r) = array.set_apply(black_box(i), black_box(|x: u8| x.max(value))); + left ^= l; + right ^= r; + } + } + (left, right) + }); + }); + + group.bench_function("packed_insert", |b| { + b.iter(|| { + let mut left = 0; + let mut right = 0; + let mut packed: Array = Array::default(); + for i in 0..NUMBER_OF_REGISTERS { + for value in 0..64 { + let (l, r) = packed.set_apply(black_box(i), black_box(|x: u8| x.max(value))); + left ^= l; + right ^= r; + } + } + (left, right) + }); + }); + + group.finish(); +} + +criterion_group!(benches, bench_array); + +criterion_main!(benches); \ No newline at end of file diff --git a/hyperloglog-derive/src/lib.rs b/hyperloglog-derive/src/lib.rs index 53bdb61..32b8529 100644 --- a/hyperloglog-derive/src/lib.rs +++ b/hyperloglog-derive/src/lib.rs @@ -546,7 +546,7 @@ pub fn derive_variable_word(input: TokenStream) -> TokenStream { #[inline] #[must_use] fn name(&self) -> String { - "#name".to_owned() + stringify!(#name).to_string() } } }; @@ -812,3 +812,5 @@ pub fn test_estimator(_attr: TokenStream, item: TokenStream) -> TokenStream { // Convert the expanded code into a token stream TokenStream::from(expanded) } + + diff --git a/src/mle.rs b/src/mle.rs index 96ed1ac..16aa0ca 100644 --- a/src/mle.rs +++ b/src/mle.rs @@ -294,16 +294,15 @@ fn mle_union_cardinality< let yjoint_right_zleft = y_register[2] * z_register[0] * y_register[1]; let yjoint_left_zright = y_register[2] * z_register[1] * y_register[0]; - let yjointleft = y_register[2] * y_register[0]; - let yjointright = y_register[2] * y_register[1]; let zj_plus_yjoint_zright = z_register[2] + y_register[2] * z_register[1]; let zj_plus_yjoint_zlr = z_register[2] + y_register[2] * z_register[0] * z_register[1]; let reciprocal_zj_plus_yjoint_zlr = f64::ONE / zj_plus_yjoint_zlr; let left_reciprocal = left_smaller_k - * (y_register[2] * y_register[0] / (z_register[2] + y_register[2] * z_register[0]) - f64::ONE); - let right_reciprocal = - right_smaller_k * (yjointright / zj_plus_yjoint_zright - f64::ONE); + * (y_register[2] * y_register[0] / (z_register[2] + y_register[2] * z_register[0]) + - f64::ONE); + let right_reciprocal = right_smaller_k + * (y_register[2] * y_register[1] / zj_plus_yjoint_zright - f64::ONE); let delta = [ left_reciprocal @@ -315,7 +314,8 @@ fn mle_union_cardinality< left_reciprocal + right_reciprocal + joint_k - * ((yjointleft + yjoint_right_zleft) * reciprocal_zj_plus_yjoint_zlr + * ((y_register[2] * y_register[0] + yjoint_right_zleft) + * reciprocal_zj_plus_yjoint_zlr - f64::ONE), ]; @@ -472,7 +472,7 @@ impl Default for Adam { first_moments: [0.0; N], second_moments: [0.0; N], time: 0, - learning_rate: 0.01, + learning_rate: 0.1, first_order_decay_factor: 0.9, second_order_decay_factor: 0.999, } diff --git a/src/registers/packed_array.rs b/src/registers/packed_array.rs index f3f599a..d313e71 100644 --- a/src/registers/packed_array.rs +++ b/src/registers/packed_array.rs @@ -712,6 +712,7 @@ impl Array { } #[inline] + #[allow(unsafe_code)] /// Applies a function to the value at the given index. /// /// # Arguments @@ -720,14 +721,18 @@ impl Array { /// /// # Returns /// The previous value at the given index and the new value. - fn set_apply(&mut self, index: usize, ops: F) -> (V::Word, V::Word) + /// + /// # Safety + /// This method accesses values in the underlying array without checking whether the index is valid, + /// as it is guaranteed to be valid by the split_index method. + pub fn set_apply(&mut self, index: usize, ops: F) -> (V::Word, V::Word) where F: Fn(V::Word) -> V::Word, { let (word_index, relative_value_offset) = split_index::(index); if Self::is_bridge_offset(relative_value_offset) { - let (low, high) = self.words.split_at_mut(word_index + 1); + let (low, high) = unsafe {self.words.split_at_mut_unchecked(word_index + 1)}; let low = &mut low[word_index]; let high = &mut high[0]; let value = extract_bridge_value_from_word::(*low, *high, relative_value_offset); diff --git a/src/utils.rs b/src/utils.rs index 9646715..dc99da1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -71,7 +71,7 @@ impl Named for u64 { /// # Arguments /// * `numerator` - The numerator of the division. /// * `denominator` - The denominator of the division. -pub(crate) const fn ceil(numerator: usize, denominator: usize) -> usize { +pub const fn ceil(numerator: usize, denominator: usize) -> usize { (numerator + denominator - 1) / denominator } diff --git a/statistical_comparisons/Cargo.toml b/statistical_comparisons/Cargo.toml index 106cc3f..016c4dc 100644 --- a/statistical_comparisons/Cargo.toml +++ b/statistical_comparisons/Cargo.toml @@ -14,7 +14,7 @@ cardinality-estimator = {git = "https://github.com/LucaCappelletti94/cardinality rust-hyperloglog = {git = "https://github.com/LucaCappelletti94/rust-hyperloglog.git", branch = "updated_siphasher", package = "hyperloglog", features = ["mem_dbg"]} sourmash = {git="https://github.com/LucaCappelletti94/sourmash.git", features = ["mem_dbg"], branch = "latest_merged"} hypertwobits = {git="https://github.com/LucaCappelletti94/hypertwobits.git", features = ["mem_dbg"], branch="main"} -simple_hll = {git="https://github.com/LucaCappelletti94/simple_hll.git", features = ["mem_dbg"], branch="main"} +simple_hll = {git="https://github.com/LucaCappelletti94/simple_hll.git", features = ["mem_dbg"], branch="hasher"} stattest = {git = "https://github.com/LucaCappelletti94/stattest", branch = "faster_wilcoxon"} csv = "1.3.0" wyhash = {git="https://github.com/LucaCappelletti94/wyhash-rs", branch="merged", features=["mem_dbg"]} diff --git a/statistical_comparisons/macro_test_utils/Cargo.toml b/statistical_comparisons/macro_test_utils/Cargo.toml index f287125..78dc992 100644 --- a/statistical_comparisons/macro_test_utils/Cargo.toml +++ b/statistical_comparisons/macro_test_utils/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -syn = "2.0" +syn = {version="2.0", features=["full"]} quote = "1.0" proc-macro2 = "1.0" diff --git a/statistical_comparisons/macro_test_utils/src/lib.rs b/statistical_comparisons/macro_test_utils/src/lib.rs index d995c1c..80c6f1a 100644 --- a/statistical_comparisons/macro_test_utils/src/lib.rs +++ b/statistical_comparisons/macro_test_utils/src/lib.rs @@ -3,7 +3,7 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields}; +use syn::{parse_macro_input, Data, DeriveInput, Fields, Ident, ItemFn}; #[proc_macro_derive(Named)] pub fn my_trait_derive(input: TokenStream) -> TokenStream { @@ -222,3 +222,86 @@ pub fn transparent_mem_size_derive(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +#[proc_macro_attribute] +pub fn cardinality_benchmark(_attr: TokenStream, item: TokenStream) -> TokenStream { + // Parse the input token stream (the function we're deriving for) + let input = parse_macro_input!(item as ItemFn); + + // Extract the function name + let fn_name = &input.sig.ident; + + // Define a list of generics we want to cover + let precisions = (4..=18) + .map(|precision| { + ( + precision, + Ident::new(&format!("Precision{}", precision), fn_name.span()), + ) + }) + .collect::>(); + let bits = (4..=6) + .map(|bits| (bits, Ident::new(&format!("Bits{}", bits), fn_name.span()))) + .collect::>(); + let hashers = vec![ + Ident::new("XxHash64", fn_name.span()), + Ident::new("WyHash", fn_name.span()), + Ident::new("AHasher", fn_name.span()), + Ident::new("XxH3", fn_name.span()), + ]; + let words = vec![ + (8, Ident::new("u8", fn_name.span())), + (16, Ident::new("u16", fn_name.span())), + (24, Ident::new("u24", fn_name.span())), + (32, Ident::new("u32", fn_name.span())), + (48, Ident::new("u48", fn_name.span())), + (56, Ident::new("u56", fn_name.span())), + (64, Ident::new("u64", fn_name.span())), + ]; + + // Generate the test functions + let benchmarks = hashers.into_iter().flat_map(move |hasher| { + let precisions = precisions.clone(); + let bits = bits.clone(); + let words = words.clone(); + precisions.into_iter().map(move |(exponent, precision)| { + let bits = bits.clone(); + let words = words.clone(); + let hasher = hasher.clone(); + let h2b_calls = quote! { + HyperTwoVariants::<#hasher>::prepare_cardinality_reports(); + }; + let hll_calls = bits + .into_iter() + .flat_map(move |(bit_num, bit)| { + let words = words.clone(); + let precision = precision.clone(); + let hasher = hasher.clone(); + words.into_iter().map(move |(word_size, word)| { + if exponent + bit_num > word_size { + return quote! {}; + } + quote! { + HLLVariants::<#exponent, #precision, #hasher, #bit_num, #bit, #word>::prepare_cardinality_reports(); + } + }) + }); + quote! { + #h2b_calls + #(#hll_calls)* + } + }) + }); + + // Generate the final token stream + let expanded = quote! { + #input + + fn cardinality_benchmarks() { + #(#benchmarks)* + } + }; + + // Convert the expanded code into a token stream + TokenStream::from(expanded) +} diff --git a/statistical_comparisons/src/enumerations.rs b/statistical_comparisons/src/enumerations.rs index d9402bc..96773c4 100644 --- a/statistical_comparisons/src/enumerations.rs +++ b/statistical_comparisons/src/enumerations.rs @@ -51,56 +51,28 @@ pub enum HyperTwoVariants { #[derive(Clone, Named, ExtendableApproximatedSet, Estimator, TransparentMemSize, EnumIter)] /// Enumerations will all `HyperLogLog` variants we /// take into consideration for the benchmarks. -pub enum HLLVariants +pub enum HLLVariants where - P: AllArrays + Named, -

>::Array: VariableWords, -

>::Array: VariableWords, -

>::Array: VariableWords, -

>::Packed: VariableWords, -

>::Packed: VariableWords, -

>::Packed: VariableWords, + P: Named + ArrayRegister, + B: Named + Bits, + CH: Named + CompositeHash, +

>::Array: VariableWords, +

>::Packed: VariableWords, { TabacHyperLogLogPlus(TabacHLLPlusPlus), TabacHyperLogLogPF(TabacHLL), SAHyperLogLog(AlecHLL

), RustHyperLogLog(RustHLL

), - CE4(CloudFlareHLL), - CE5(CloudFlareHLL), - CE6(CloudFlareHLL), - SimpleHLL(SimpleHLL), - PP4ArrayXxhasher(PlusPlus>::Array, H>), - PP5ArrayXxhasher(PlusPlus>::Array, H>), - PP6ArrayXxhasher(PlusPlus>::Array, H>), - PP4PackedXxhasher(PlusPlus>::Packed, H>), - PP5PackedXxhasher(PlusPlus>::Packed, H>), - PP6PackedXxhasher(PlusPlus>::Packed, H>), - LLB4ArrayXxhasher(LogLogBeta>::Array, H>), - LLB5ArrayXxhasher(LogLogBeta>::Array, H>), - LLB6ArrayXxhasher(LogLogBeta>::Array, H>), - LLB5PackedXxhasher(LogLogBeta>::Packed, H>), - LLB6PackedXxhasher(LogLogBeta>::Packed, H>), - MLEPP4Xxhasher(MLE>::Array, H>>), - MLEPP5Xxhasher(MLE>::Array, H>>), - MLEPP6Xxhasher(MLE>::Array, H>>), - MLELLB4Xxhasher(MLE>::Array, H>>), - MLELLB5Xxhasher(MLE>::Array, H>>), - MLELLB6Xxhasher(MLE>::Array, H>>), - HybridPP4ArrayXxhasher(Hybrid>::Array, H>>), - HybridPP5ArrayXxhasher(Hybrid>::Array, H>>), - HybridPP6ArrayXxhasher(Hybrid>::Array, H>>), - HybridPP4PackedXxhasher(Hybrid>::Packed, H>>), - HybridPP5PackedXxhasher(Hybrid>::Packed, H>>), - HybridPP6PackedXxhasher(Hybrid>::Packed, H>>), - HybridLLB4ArrayXxhasher(Hybrid>::Array, H>>), - HybridLLB5ArrayXxhasher(Hybrid>::Array, H>>), - HybridLLB6ArrayXxhasher(Hybrid>::Array, H>>), - HybridLLB5PackedXxhasher(Hybrid>::Packed, H>>), - HybridLLB6PackedXxhasher(Hybrid>::Packed, H>>), - HybridMLEPP4Xxhasher(Hybrid>::Array, H>>>), - HybridMLEPP5Xxhasher(Hybrid>::Array, H>>>), - HybridMLEPP6Xxhasher(Hybrid>::Array, H>>>), - HybridMLELLB4Xxhasher(Hybrid>::Array, H>>>), - HybridMLELLB5Xxhasher(Hybrid>::Array, H>>>), - HybridMLELLB6Xxhasher(Hybrid>::Array, H>>>), + CE4(CloudFlareHLL), + SimpleHLL(SimpleHLL), + PP4ArrayXxhasher(PlusPlus>::Array, H>), + PP4PackedXxhasher(PlusPlus>::Packed, H>), + LLB4ArrayXxhasher(LogLogBeta>::Array, H>), + MLEPP4Xxhasher(MLE>::Array, H>>), + MLELLB4Xxhasher(MLE>::Array, H>>), + HybridPP4ArrayXxhasher(Hybrid>::Array, H>, CH>), + HybridPP4PackedXxhasher(Hybrid>::Packed, H>, CH>), + HybridLLB4ArrayXxhasher(Hybrid>::Array, H>, CH>), + HybridMLEPP4Xxhasher(Hybrid>::Array, H>>, CH>), + HybridMLELLB4Xxhasher(Hybrid>::Array, H>>, CH>), } diff --git a/statistical_comparisons/src/estimation_tests.rs b/statistical_comparisons/src/estimation_tests.rs index 35d72a9..cb63ae9 100644 --- a/statistical_comparisons/src/estimation_tests.rs +++ b/statistical_comparisons/src/estimation_tests.rs @@ -49,9 +49,10 @@ pub(crate) fn cardinality_test< multi_progress: Option<&indicatif::MultiProgress>, ) -> Vec { let number_of_vectors = 1_000_u64; - let minimum_sample_interval = 5_u64; - let maximum_sample_interval = 20_000_u64; - let random_state = splitmix64(9_516_748_163_234_878_233_u64); + let number_of_elements = 1_000_000; + let sample_interval = number_of_elements / 1_000; + let sequence_random_state = splitmix64(9_516_748_163_234_878_233_u64); + let sample_index_random_state = splitmix64(234_878_239_9_516_748_163_u64); let estimator_name = estimator.name(); @@ -73,23 +74,22 @@ pub(crate) fn cardinality_test< progress_bar }) .flat_map(|thread_number| { - let mut random_state = - splitmix64(splitmix64(random_state.wrapping_mul(thread_number + 1))); + let sequence_random_state = + splitmix64(splitmix64(sequence_random_state.wrapping_mul(thread_number + 1))); + let mut sample_index_random_state = + splitmix64(splitmix64(sample_index_random_state.wrapping_mul(thread_number + 1))); let mut performance_reports = Vec::new(); let mut estimator = estimator.clone(); - - let mut current_sample_rate = minimum_sample_interval; + let mut next_sample_index = sample_interval; for (i, element) in - iter_random_values::(2_000_000, None, Some(random_state)).enumerate() + iter_random_values::(number_of_elements, None, Some(sequence_random_state)).enumerate() { estimator.insert(&element); - if u64::try_from(i).unwrap() % current_sample_rate == 0 { - if current_sample_rate < maximum_sample_interval { - random_state = splitmix64(random_state); - current_sample_rate += random_state % current_sample_rate; - } + if next_sample_index == i as u64{ + sample_index_random_state = splitmix64(sample_index_random_state); + next_sample_index += sample_index_random_state % sample_interval; performance_reports.push(PerformanceReport { prediction: estimator.estimate_cardinality(), diff --git a/statistical_comparisons/src/main.rs b/statistical_comparisons/src/main.rs index c56a849..6346eef 100644 --- a/statistical_comparisons/src/main.rs +++ b/statistical_comparisons/src/main.rs @@ -5,35 +5,15 @@ use statistical_comparisons::reports_generator::SetTester; use twox_hash::{XxHash64, xxh3::Hash64 as XxH3}; use wyhash::WyHash; use ahash::AHasher; +use macro_test_utils::cardinality_benchmark; -/// Macro to generate the calls to the HLLVariant reports for precisions from 4 to 18. -macro_rules! generate_hll_variant_reports { - ($hasher:ty, $($exponent:expr),*) => { - $( - paste::item! { - HLLVariants::<$exponent, [], $hasher>::prepare_cardinality_reports(); - // HLLVariants::<$exponent, []>::prepare_union_reports(); - } - )* - }; -} -macro_rules! generate_hll_variant_reports_per_hasher { - ($($hasher:ty),*) => { - $( - HyperTwoVariants::<$hasher>::prepare_cardinality_reports(); - // HyperTwoVariants::<$hasher>::prepare_union_reports(); - generate_hll_variant_reports!($hasher, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); - )* - }; -} +#[cardinality_benchmark] fn main() { // We init the logger env_logger::init(); - - generate_hll_variant_reports_per_hasher!(XxHash64, XxH3, WyHash, AHasher); - + cardinality_benchmarks(); cartesian_wilcoxon_test("cardinality"); // cartesian_wilcoxon_test("union"); } diff --git a/statistical_comparisons/src/proxy_implementations.rs b/statistical_comparisons/src/proxy_implementations.rs index 999f8f6..4eeea69 100644 --- a/statistical_comparisons/src/proxy_implementations.rs +++ b/statistical_comparisons/src/proxy_implementations.rs @@ -17,7 +17,7 @@ use sourmash::sketch::hyperloglog::HyperLogLog as SourMashHyperLogLog; use std::marker::PhantomData; use streaming_algorithms::HyperLogLog as SAHyperLogLog; -pub trait HasherBuilderAssociated: HasherType + MemSize{ +pub trait HasherBuilderAssociated: HasherType + MemSize { type Builder: BuildHasher + Default + Clone + Send + Sync + MemSize; } @@ -38,8 +38,8 @@ impl HasherBuilderAssociated for ahash::AHasher { } #[derive(Debug, Clone, Default, MemDbg, MemSize)] -pub struct SimpleHLL { - estimator: SimpleHyperLogLog

, +pub struct SimpleHLL { + estimator: SimpleHyperLogLog, } #[derive(Debug, Clone, Default, MemDbg, MemSize)] @@ -49,12 +49,12 @@ pub struct CloudFlareHLL { #[derive(Debug, Clone, Default, MemDbg, MemSize)] pub struct HyperTwoBits { - estimator: H2B + estimator: H2B, } #[derive(Debug, Clone, Default, MemDbg, MemSize)] pub struct HyperThreeBits { - estimator: H3B + estimator: H3B, } #[derive(Debug, Clone, MemDbg, MemSize)] @@ -114,7 +114,6 @@ pub struct TabacHLL { _precision: PhantomData

, } - impl Default for TabacHLL { fn default() -> Self { Self { @@ -140,30 +139,34 @@ impl Default for AlecHLL

{ } #[cfg(feature = "std")] -impl hyperloglog_rs::prelude::Named for SimpleHLL

{ +impl hyperloglog_rs::prelude::Named for SimpleHLL { fn name(&self) -> String { - format!("SHLL") + format!("SHLL + {}", core::any::type_name::()) } } #[cfg(feature = "std")] -impl hyperloglog_rs::prelude::Named for HyperTwoBits { +impl hyperloglog_rs::prelude::Named + for HyperTwoBits +{ fn name(&self) -> String { format!( "H2B<{}> + {}", - std::any::type_name::().split("::").last().unwrap(), - std::any::type_name::().split("::").last().unwrap() + core::any::type_name::().split("::").last().unwrap(), + core::any::type_name::().split("::").last().unwrap() ) } } #[cfg(feature = "std")] -impl hyperloglog_rs::prelude::Named for HyperThreeBits { +impl hyperloglog_rs::prelude::Named + for HyperThreeBits +{ fn name(&self) -> String { format!( "H3B<{}> + {}", - std::any::type_name::().split("::").last().unwrap(), - std::any::type_name::().split("::").last().unwrap() + core::any::type_name::().split("::").last().unwrap(), + core::any::type_name::().split("::").last().unwrap() ) } } @@ -184,7 +187,7 @@ impl hyperloglog_rs::prelude::Nam "CF + {}", P, B, - std::any::type_name::().split("::").last().unwrap() + core::any::type_name::().split("::").last().unwrap() ) } } @@ -204,7 +207,7 @@ impl hyperloglog_rs::prelude::Named format!( "TabacPP + {}", P::EXPONENT, - std::any::type_name::().split("::").last().unwrap() + core::any::type_name::().split("::").last().unwrap() ) } } @@ -215,7 +218,7 @@ impl hyperloglog_rs::prelude::Named fo format!( "Tabac + {}", P::EXPONENT, - std::any::type_name::().split("::").last().unwrap() + core::any::type_name::().split("::").last().unwrap() ) } } @@ -229,21 +232,25 @@ impl hyperloglog_rs::prelude::Named for AlecHLL

{ } } -impl ExtendableApproximatedSet for SimpleHLL

{ +impl ExtendableApproximatedSet for SimpleHLL { fn insert(&mut self, item: &u64) -> bool { self.estimator.add_object(item); true } } -impl ExtendableApproximatedSet for HyperTwoBits { +impl ExtendableApproximatedSet + for HyperTwoBits +{ fn insert(&mut self, item: &u64) -> bool { self.estimator.insert(item); true } } -impl ExtendableApproximatedSet for HyperThreeBits { +impl ExtendableApproximatedSet + for HyperThreeBits +{ fn insert(&mut self, item: &u64) -> bool { self.estimator.insert(item); true @@ -298,7 +305,7 @@ impl ExtendableApproximatedSet for AlecHLL

{ } } -impl Estimator for SimpleHLL

{ +impl Estimator for SimpleHLL { #[expect( clippy::cast_precision_loss, reason = "We do not expect to exceeed 2**54 in set cardinality in our tests." @@ -350,7 +357,9 @@ impl Estimator for CloudFlar } } -impl Estimator for HyperTwoBits { +impl Estimator + for HyperTwoBits +{ #[expect( clippy::cast_precision_loss, reason = "We do not expect to exceeed 2**54 in set cardinality in our tests." @@ -376,7 +385,9 @@ impl Estimator for HyperThreeBits { +impl Estimator + for HyperThreeBits +{ #[expect( clippy::cast_precision_loss, reason = "We do not expect to exceeed 2**54 in set cardinality in our tests."