diff --git a/datasketches/src/theta/a_not_b.rs b/datasketches/src/theta/a_not_b.rs index 58ea236..bef222c 100644 --- a/datasketches/src/theta/a_not_b.rs +++ b/datasketches/src/theta/a_not_b.rs @@ -17,15 +17,15 @@ //! Theta sketch set difference (`A and not B`). //! -//! [`ThetaAnotB`] computes the set difference of two Theta sketches: the keys retained in `A` -//! that are not present in `B`. The logic lives in the shared raw operator (`RawThetaAnotB`) that -//! also drives the Tuple a-not-B; Theta entries carry no summary, so nothing needs to be combined. +//! [`ThetaANotB`] computes the set difference of two Theta sketches: the keys retained in `A` +//! that are not present in `B`. It shares its set-difference implementation with Tuple a-not-B; +//! Theta entries carry no summary, so nothing needs to be combined. use crate::error::Error; use crate::hash::DEFAULT_UPDATE_SEED; use crate::theta::CompactThetaSketch; use crate::theta::ThetaSketchView; -use crate::thetacommon::a_not_b::RawThetaAnotB; +use crate::thetacommon::a_not_b::ANotBOperator; /// Set difference operator (`A and not B`) for Theta sketches. /// @@ -35,7 +35,7 @@ use crate::thetacommon::a_not_b::RawThetaAnotB; /// # Examples /// /// ``` -/// # use datasketches::theta::{ThetaAnotB, ThetaSketchBuilder}; +/// # use datasketches::theta::{ThetaANotB, ThetaSketchBuilder}; /// let mut a = ThetaSketchBuilder::default().build(); /// a.update("apple"); /// a.update("banana"); @@ -43,26 +43,26 @@ use crate::thetacommon::a_not_b::RawThetaAnotB; /// let mut b = ThetaSketchBuilder::default().build(); /// b.update("banana"); /// -/// let a_not_b = ThetaAnotB::default(); +/// let a_not_b = ThetaANotB::default(); /// let result = a_not_b.compute(&a, &b, true).unwrap(); /// assert_eq!(result.num_retained(), 1); // only "apple" survives /// ``` #[derive(Debug, Clone, Copy)] -pub struct ThetaAnotB { - raw: RawThetaAnotB, +pub struct ThetaANotB { + op: ANotBOperator, } -impl Default for ThetaAnotB { +impl Default for ThetaANotB { fn default() -> Self { Self::with_seed(DEFAULT_UPDATE_SEED) } } -impl ThetaAnotB { +impl ThetaANotB { /// Creates a new set difference operator for the given `seed`. pub fn with_seed(seed: u64) -> Self { Self { - raw: RawThetaAnotB::new(seed), + op: ANotBOperator::new(seed), } } @@ -80,7 +80,7 @@ impl ThetaAnotB { A: ThetaSketchView, B: ThetaSketchView, { - let parts = self.raw.compute(a, b, ordered)?; + let parts = self.op.compute(a, b, ordered)?; Ok(CompactThetaSketch::from_parts( parts .entries diff --git a/datasketches/src/theta/hash_table.rs b/datasketches/src/theta/hash_table.rs index 0837147..f9e82d6 100644 --- a/datasketches/src/theta/hash_table.rs +++ b/datasketches/src/theta/hash_table.rs @@ -18,8 +18,8 @@ use std::hash::Hash; use std::num::NonZeroU64; -use crate::thetacommon::RawHashTableEntry; -use crate::thetacommon::hash_table::RawHashTable; +use crate::thetacommon::RetainedEntry; +use crate::thetacommon::hash_table::SketchHashTable; /// Specific hash table for theta sketch /// @@ -28,7 +28,7 @@ use crate::thetacommon::hash_table::RawHashTable; /// * After it reaches the capacity bigger than 2^lg_nom_size, every time the number of entries /// exceeds the threshold, it will rebuild the table: only keep the min 2^lg_nom_size entries and /// update the theta to the k-th smallest entry. -pub(super) type ThetaHashTable = RawHashTable; +pub(super) type ThetaHashTable = SketchHashTable; /// A retained entry in a Theta sketch. #[derive(Debug, Clone, Copy)] @@ -48,7 +48,7 @@ impl ThetaEntry { } } -impl RawHashTableEntry for ThetaEntry { +impl RetainedEntry for ThetaEntry { fn hash(&self) -> u64 { self.hash.get() } @@ -90,7 +90,7 @@ mod tests { impl ThetaHashTable { /// Get iterator over entries. pub fn iter(&self) -> impl Iterator + '_ { - self.iter_entries().map(RawHashTableEntry::hash) + self.iter_entries().map(RetainedEntry::hash) } } diff --git a/datasketches/src/theta/intersection.rs b/datasketches/src/theta/intersection.rs index b5c699a..e518bc7 100644 --- a/datasketches/src/theta/intersection.rs +++ b/datasketches/src/theta/intersection.rs @@ -20,8 +20,8 @@ use crate::hash::DEFAULT_UPDATE_SEED; use crate::theta::CompactThetaSketch; use crate::theta::ThetaSketchView; use crate::theta::hash_table::ThetaEntry; -use crate::thetacommon::intersection::RawThetaIntersection; -use crate::thetacommon::intersection::RawThetaIntersectionPolicy; +use crate::thetacommon::intersection::IntersectionMergePolicy; +use crate::thetacommon::intersection::IntersectionState; /// Stateful intersection operator for Theta sketches. /// @@ -29,7 +29,7 @@ use crate::thetacommon::intersection::RawThetaIntersectionPolicy; /// [`has_result`](Self::has_result) to check. #[derive(Debug)] pub struct ThetaIntersection { - raw: RawThetaIntersection, + state: IntersectionState, } impl Default for ThetaIntersection { @@ -41,7 +41,7 @@ impl Default for ThetaIntersection { #[derive(Debug)] struct NoopIntersectionPolicy; -impl RawThetaIntersectionPolicy for NoopIntersectionPolicy { +impl IntersectionMergePolicy for NoopIntersectionPolicy { fn merge(&self, _existing: &mut ThetaEntry, _incoming: ThetaEntry) {} } @@ -49,7 +49,7 @@ impl ThetaIntersection { /// Creates a new intersection operator for the given `seed`. pub fn with_seed(seed: u64) -> Self { Self { - raw: RawThetaIntersection::new(seed, NoopIntersectionPolicy), + state: IntersectionState::new(seed, NoopIntersectionPolicy), } } @@ -59,12 +59,12 @@ impl ThetaIntersection { /// and every update can reduce the current set to leave the overlapping /// subset only. pub fn update(&mut self, sketch: &S) -> Result<(), Error> { - self.raw.update(sketch) + self.state.update(sketch) } /// Returns whether this operator has received at least one update. pub fn has_result(&self) -> bool { - self.raw.has_result() + self.state.has_result() } /// Returns the intersection result as a compact theta sketch. @@ -74,10 +74,10 @@ impl ThetaIntersection { /// Panics if called before the first [`update`](Self::update). pub fn to_sketch(&self, ordered: bool) -> CompactThetaSketch { assert!( - self.raw.has_result(), + self.state.has_result(), "ThetaIntersection::to_sketch() called before first update()" ); - let parts = self.raw.result(ordered); + let parts = self.state.result(ordered); CompactThetaSketch::from_parts( parts .entries diff --git a/datasketches/src/theta/mod.rs b/datasketches/src/theta/mod.rs index 596f85e..4b5d28b 100644 --- a/datasketches/src/theta/mod.rs +++ b/datasketches/src/theta/mod.rs @@ -47,7 +47,7 @@ mod serialization; mod sketch; mod union; -pub use self::a_not_b::ThetaAnotB; +pub use self::a_not_b::ThetaANotB; pub use self::hash_table::ThetaEntry; pub use self::intersection::ThetaIntersection; pub use self::sketch::CompactThetaSketch; diff --git a/datasketches/src/theta/sketch.rs b/datasketches/src/theta/sketch.rs index ed354b2..cbf7885 100644 --- a/datasketches/src/theta/sketch.rs +++ b/datasketches/src/theta/sketch.rs @@ -43,7 +43,7 @@ use crate::theta::serialization; use crate::theta::serialization::V2_PREAMBLE_EMPTY; use crate::theta::serialization::V2_PREAMBLE_ESTIMATE; use crate::theta::serialization::V2_PREAMBLE_PRECISE; -use crate::thetacommon::RawThetaSketchView; +use crate::thetacommon::ThetaFamilySketchView; use crate::thetacommon::binomial_bounds; use crate::thetacommon::constants::DEFAULT_LG_K; use crate::thetacommon::constants::FLAGS_IS_COMPACT; @@ -58,11 +58,13 @@ use crate::thetacommon::constants::MIN_LG_K; /// /// This trait provides a unified input abstraction for APIs that can accept either /// mutable [`ThetaSketch`] or immutable [`CompactThetaSketch`]. -pub trait ThetaSketchView: RawThetaSketchView {} +pub trait ThetaSketchView: ThetaFamilySketchView {} -impl> ThetaSketchView for T {} +impl> ThetaSketchView for T {} + +impl ThetaFamilySketchView for ThetaSketch { + type Entry = ThetaEntry; -impl RawThetaSketchView for ThetaSketch { fn seed_hash(&self) -> u16 { ThetaSketch::seed_hash(self) } @@ -862,7 +864,9 @@ impl CompactThetaSketch { } } -impl RawThetaSketchView for CompactThetaSketch { +impl ThetaFamilySketchView for CompactThetaSketch { + type Entry = ThetaEntry; + fn seed_hash(&self) -> u16 { CompactThetaSketch::seed_hash(self) } diff --git a/datasketches/src/theta/union.rs b/datasketches/src/theta/union.rs index 71bd5dc..94a974f 100644 --- a/datasketches/src/theta/union.rs +++ b/datasketches/src/theta/union.rs @@ -24,31 +24,31 @@ use crate::theta::hash_table::ThetaEntry; use crate::thetacommon::constants::DEFAULT_LG_K; use crate::thetacommon::constants::MAX_LG_K; use crate::thetacommon::constants::MIN_LG_K; -use crate::thetacommon::union::RawThetaUnion; -use crate::thetacommon::union::RawThetaUnionPolicy; +use crate::thetacommon::union::UnionMergePolicy; +use crate::thetacommon::union::UnionState; /// Stateful union operator for Theta sketches. #[derive(Debug)] pub struct ThetaUnion { - raw: RawThetaUnion, + state: UnionState, } #[derive(Debug)] struct NoopUnionPolicy; -impl RawThetaUnionPolicy for NoopUnionPolicy { +impl UnionMergePolicy for NoopUnionPolicy { fn merge(&self, _existing: &mut ThetaEntry, _incoming: ThetaEntry) {} } impl ThetaUnion { /// Update this union with a given sketch. pub fn update(&mut self, sketch: &S) -> Result<(), Error> { - self.raw.update(sketch) + self.state.update(sketch) } /// Return this union as a compact sketch. pub fn to_sketch(&self, ordered: bool) -> CompactThetaSketch { - let parts = self.raw.to_compact_parts(ordered); + let parts = self.state.to_compact_parts(ordered); CompactThetaSketch::from_parts( parts .entries @@ -64,7 +64,7 @@ impl ThetaUnion { /// Reset the union to empty state. pub fn reset(&mut self) { - self.raw.reset(); + self.state.reset(); } } @@ -162,7 +162,7 @@ impl ThetaUnionBuilder { /// ``` pub fn build(self) -> ThetaUnion { ThetaUnion { - raw: RawThetaUnion::new( + state: UnionState::new( self.lg_k, self.resize_factor, self.sampling_probability, diff --git a/datasketches/src/thetacommon/a_not_b.rs b/datasketches/src/thetacommon/a_not_b.rs index dbe22a0..a6ab089 100644 --- a/datasketches/src/thetacommon/a_not_b.rs +++ b/datasketches/src/thetacommon/a_not_b.rs @@ -19,22 +19,23 @@ use std::collections::HashSet; use crate::error::Error; use crate::hash::compute_seed_hash; -use crate::thetacommon::RawHashTableEntry; -use crate::thetacommon::RawThetaSketchView; +use crate::thetacommon::RetainedEntry; +use crate::thetacommon::ThetaFamilySketchView; use crate::thetacommon::constants::MAX_THETA; -use crate::thetacommon::hash_table::RawCompactParts; +use crate::thetacommon::hash_table::CompactSketchParts; /// Stateless set difference (`A and not B`) operator shared by Theta and Tuple sketches. /// -/// `E` is the retained entry type. Ordinary Theta entries only contain a hash, while tuple -/// entries also carry a summary. Surviving entries are moved from `A` unchanged, so unlike the -/// union and intersection this operation needs no entry-merge policy. +/// Ordinary Theta entries only contain a hash, while tuple entries also carry a summary. +/// Surviving entries are moved from `A` unchanged, and `B` contributes only hashes, so unlike +/// the union and intersection this operation needs neither matching entry types nor an +/// entry-merge policy. #[derive(Debug, Clone, Copy)] -pub struct RawThetaAnotB { +pub struct ANotBOperator { seed_hash: u16, } -impl RawThetaAnotB { +impl ANotBOperator { /// Creates a new set difference operator for the given `seed`. pub fn new(seed: u64) -> Self { Self { @@ -51,11 +52,15 @@ impl RawThetaAnotB { /// /// Returns an error if either non-trivial input has a seed hash that differs from this /// operator's seed. - pub fn compute(&self, a: &A, b: &B, ordered: bool) -> Result, Error> + pub fn compute( + &self, + a: &A, + b: &B, + ordered: bool, + ) -> Result, Error> where - E: RawHashTableEntry, - A: RawThetaSketchView, - B: RawThetaSketchView, + A: ThetaFamilySketchView, + B: ThetaFamilySketchView, { // If A is empty the result is an (empty) copy of A. As with the union and intersection, an // empty input carries no keys, so its seed is not validated. @@ -93,7 +98,7 @@ impl RawThetaAnotB { // mode (handled below). let mut is_empty = false; - let entries: Vec = if b.num_retained() == 0 { + let entries: Vec = if b.num_retained() == 0 { a.iter().filter(|entry| entry.hash() < theta).collect() } else if a.is_ordered() && b.is_ordered() { // Both inputs are sorted ascending by hash: merge-scan without a hash set. Only @@ -150,10 +155,10 @@ impl RawThetaAnotB { let out_ordered = ordered || a.is_ordered(); let mut entries = entries; if ordered && !a.is_ordered() && entries.len() > 1 { - entries.sort_unstable_by_key(RawHashTableEntry::hash); + entries.sort_unstable_by_key(RetainedEntry::hash); } - Ok(RawCompactParts { + Ok(CompactSketchParts { entries, theta, seed_hash: self.seed_hash, @@ -163,17 +168,16 @@ impl RawThetaAnotB { } /// Builds compact parts that are a copy of the view `a`. - fn parts_from_view(a: &V, ordered: bool) -> RawCompactParts + fn parts_from_view(a: &V, ordered: bool) -> CompactSketchParts where - E: RawHashTableEntry, - V: RawThetaSketchView, + V: ThetaFamilySketchView, { - let mut entries: Vec = a.iter().collect(); + let mut entries: Vec = a.iter().collect(); let out_ordered = ordered || a.is_ordered(); if ordered && !a.is_ordered() && entries.len() > 1 { - entries.sort_unstable_by_key(RawHashTableEntry::hash); + entries.sort_unstable_by_key(RetainedEntry::hash); } - RawCompactParts { + CompactSketchParts { entries, theta: a.theta(), seed_hash: a.seed_hash(), diff --git a/datasketches/src/thetacommon/hash_table.rs b/datasketches/src/thetacommon/hash_table.rs index 19aae1f..21b54f7 100644 --- a/datasketches/src/thetacommon/hash_table.rs +++ b/datasketches/src/thetacommon/hash_table.rs @@ -20,16 +20,16 @@ use std::hash::Hash; use crate::common::ResizeFactor; use crate::hash::MurmurHash3X64128; use crate::hash::compute_seed_hash; -use crate::thetacommon::RawHashTableEntry; +use crate::thetacommon::RetainedEntry; use crate::thetacommon::constants::HASH_TABLE_REBUILD_THRESHOLD; use crate::thetacommon::constants::HASH_TABLE_RESIZE_THRESHOLD; use crate::thetacommon::constants::MAX_THETA; use crate::thetacommon::constants::MIN_LG_K; use crate::thetacommon::constants::STRIDE_MASK; -/// Raw compact-sketch state from which a sketch family creates its compact result type. +/// Compact-sketch state from which a sketch family creates its compact result type. #[derive(Debug)] -pub struct RawCompactParts { +pub struct CompactSketchParts { pub entries: Vec, pub theta: u64, pub seed_hash: u16, @@ -48,7 +48,7 @@ pub struct RawCompactParts { /// exceeds the threshold, it will rebuild the table: only keep the min 2^lg_nom_size entries and /// update the theta to the k-th smallest entry. #[derive(Debug)] -pub struct RawHashTable { +pub struct SketchHashTable { lg_cur_size: u8, lg_nom_size: u8, lg_max_size: u8, @@ -72,9 +72,9 @@ pub struct RawHashTable { num_retained: usize, } -impl RawHashTable +impl SketchHashTable where - E: RawHashTableEntry, + E: RetainedEntry, { /// Create a new hash table. pub fn new( @@ -260,13 +260,13 @@ where self.entries.iter().filter_map(Option::as_ref) } - /// Returns the retained entries and theta as raw compact-sketch parts. + /// Returns the retained entries and theta as compact-sketch parts. /// /// An empty table reports `MAX_THETA` rather than its current theta, matching Java's /// `correctThetaOnCompact()` behavior for never-updated sketches initialized with p < 1.0. /// Empty and single-entry exact-mode results are always marked ordered (Java/C++ /// compatibility). - pub fn to_compact_parts(&self, ordered: bool) -> RawCompactParts + pub fn to_compact_parts(&self, ordered: bool) -> CompactSketchParts where E: Clone, { @@ -276,9 +276,9 @@ where let is_single = entries.len() == 1 && theta == MAX_THETA; let ordered = ordered || empty || is_single; if ordered && entries.len() > 1 { - entries.sort_unstable_by_key(RawHashTableEntry::hash); + entries.sort_unstable_by_key(RetainedEntry::hash); } - RawCompactParts { + CompactSketchParts { entries, theta, seed_hash: self.seed_hash(), diff --git a/datasketches/src/thetacommon/intersection.rs b/datasketches/src/thetacommon/intersection.rs index 5a60eef..d131369 100644 --- a/datasketches/src/thetacommon/intersection.rs +++ b/datasketches/src/thetacommon/intersection.rs @@ -17,18 +17,18 @@ use crate::common::ResizeFactor; use crate::error::Error; -use crate::thetacommon::RawHashTableEntry; -use crate::thetacommon::RawThetaSketchView; +use crate::thetacommon::RetainedEntry; +use crate::thetacommon::ThetaFamilySketchView; use crate::thetacommon::constants::HASH_TABLE_REBUILD_THRESHOLD; use crate::thetacommon::constants::MAX_THETA; -use crate::thetacommon::hash_table::RawCompactParts; -use crate::thetacommon::hash_table::RawHashTable; +use crate::thetacommon::hash_table::CompactSketchParts; +use crate::thetacommon::hash_table::SketchHashTable; /// Merges an incoming entry into an existing entry with the same hash. /// /// For plain Theta entries there is nothing to merge (the entry is only a hash); tuple entries /// combine their summaries. -pub trait RawThetaIntersectionPolicy { +pub trait IntersectionMergePolicy { fn merge(&self, existing: &mut E, incoming: E); } @@ -37,21 +37,21 @@ pub trait RawThetaIntersectionPolicy { /// `E` is the retained entry type. `P` defines how equal-hash entries are combined; it is only /// exercised for keys present in both the running intersection and the incoming sketch. #[derive(Debug)] -pub struct RawThetaIntersection { - table: RawHashTable, +pub struct IntersectionState { + table: SketchHashTable, policy: P, has_result: bool, } -impl RawThetaIntersection +impl IntersectionState where - E: RawHashTableEntry, + E: RetainedEntry, { /// Creates a new intersection operator for the given `seed` and entry-merge `policy`. pub fn new(seed: u64, policy: P) -> Self { Self { has_result: false, - table: RawHashTable::from_raw_parts( + table: SketchHashTable::from_raw_parts( 0, 0, ResizeFactor::X1, @@ -70,12 +70,12 @@ where /// reduces the current set to the keys it shares with `sketch`. pub fn update(&mut self, sketch: &S) -> Result<(), Error> where - S: RawThetaSketchView, + S: ThetaFamilySketchView, E: Clone, - P: RawThetaIntersectionPolicy, + P: IntersectionMergePolicy, { - let new_default_table = |table: &RawHashTable| { - RawHashTable::from_raw_parts( + let new_default_table = |table: &SketchHashTable| { + SketchHashTable::from_raw_parts( 0, 0, ResizeFactor::X1, @@ -121,14 +121,14 @@ where // first update, copy incoming entries if !self.has_result { self.has_result = true; - let lg_size = RawHashTable::::lg_size_from_count_for_rebuild( + let lg_size = SketchHashTable::::lg_size_from_count_for_rebuild( sketch.num_retained(), HASH_TABLE_REBUILD_THRESHOLD, ); // num_retained >= 1 here (the zero case returned early above), so lg_size >= 1 and // lg_size - 1 below cannot underflow. debug_assert!(lg_size >= 1); - self.table = RawHashTable::from_raw_parts( + self.table = SketchHashTable::from_raw_parts( lg_size, lg_size - 1, ResizeFactor::X1, @@ -192,14 +192,14 @@ where self.table.set_empty(true); } } else { - let lg_size = RawHashTable::::lg_size_from_count_for_rebuild( + let lg_size = SketchHashTable::::lg_size_from_count_for_rebuild( matched_entries.len(), HASH_TABLE_REBUILD_THRESHOLD, ); // matched_entries is non-empty here (the empty case is handled above), so // lg_size >= 1 and lg_size - 1 below cannot underflow. debug_assert!(lg_size >= 1); - self.table = RawHashTable::from_raw_parts( + self.table = SketchHashTable::from_raw_parts( lg_size, lg_size - 1, ResizeFactor::X1, @@ -229,16 +229,16 @@ where self.has_result } - /// Return the current intersection state as raw compact-sketch parts. - pub fn result(&self, ordered: bool) -> RawCompactParts + /// Return the current intersection state as compact-sketch parts. + pub fn result(&self, ordered: bool) -> CompactSketchParts where E: Clone, { let mut entries: Vec = self.table.iter_entries().cloned().collect(); if ordered { - entries.sort_unstable_by_key(RawHashTableEntry::hash); + entries.sort_unstable_by_key(RetainedEntry::hash); } - RawCompactParts { + CompactSketchParts { entries, theta: self.table.theta(), seed_hash: self.table.seed_hash(), @@ -259,7 +259,7 @@ mod tests { summary: u64, } - impl RawHashTableEntry for TestEntry { + impl RetainedEntry for TestEntry { fn hash(&self) -> u64 { self.hash } @@ -280,7 +280,9 @@ mod tests { } } - impl RawThetaSketchView for TestSketch { + impl ThetaFamilySketchView for TestSketch { + type Entry = TestEntry; + fn seed_hash(&self) -> u16 { crate::hash::compute_seed_hash(DEFAULT_UPDATE_SEED) } @@ -308,7 +310,7 @@ mod tests { struct SumPolicy; - impl RawThetaIntersectionPolicy for SumPolicy { + impl IntersectionMergePolicy for SumPolicy { fn merge(&self, existing: &mut TestEntry, incoming: TestEntry) { existing.summary += incoming.summary; } @@ -316,7 +318,7 @@ mod tests { #[test] fn first_update_copies_entries() { - let mut intersection = RawThetaIntersection::new(DEFAULT_UPDATE_SEED, SumPolicy); + let mut intersection = IntersectionState::new(DEFAULT_UPDATE_SEED, SumPolicy); assert!(!intersection.has_result()); intersection @@ -346,7 +348,7 @@ mod tests { #[test] fn second_update_keeps_matches_and_merges_with_policy() { - let mut intersection = RawThetaIntersection::new(DEFAULT_UPDATE_SEED, SumPolicy); + let mut intersection = IntersectionState::new(DEFAULT_UPDATE_SEED, SumPolicy); intersection .update(&TestSketch::of_hashes(&[1, 2, 3])) .unwrap(); @@ -372,7 +374,7 @@ mod tests { #[test] fn disjoint_second_update_empties_intersection() { - let mut intersection = RawThetaIntersection::new(DEFAULT_UPDATE_SEED, SumPolicy); + let mut intersection = IntersectionState::new(DEFAULT_UPDATE_SEED, SumPolicy); intersection .update(&TestSketch::of_hashes(&[1, 2, 3])) .unwrap(); diff --git a/datasketches/src/thetacommon/mod.rs b/datasketches/src/thetacommon/mod.rs index 458f092..62e791b 100644 --- a/datasketches/src/thetacommon/mod.rs +++ b/datasketches/src/thetacommon/mod.rs @@ -25,16 +25,19 @@ pub(crate) mod intersection; pub(crate) mod union; /// An entry retained by a Theta sketch family hash table. -pub trait RawHashTableEntry { +pub trait RetainedEntry { /// Return the hash used as this entry's key. fn hash(&self) -> u64; } -/// Read-only input accepted by raw Theta-family set operations. +/// Read-only input accepted by Theta-family set operations. /// /// This trait carries complete retained entries, so Tuple union, intersection, and A-not-B /// operations can share the Theta-family state machines while preserving per-key summaries. -pub trait RawThetaSketchView { +pub trait ThetaFamilySketchView { + /// The retained entry representation yielded by this view. + type Entry: RetainedEntry; + /// Return the 16-bit seed hash. fn seed_hash(&self) -> u16; @@ -48,7 +51,7 @@ pub trait RawThetaSketchView { fn is_ordered(&self) -> bool; /// Return an iterator over retained entries. - fn iter(&self) -> impl Iterator + '_; + fn iter(&self) -> impl Iterator + '_; /// Return the number of retained entries. fn num_retained(&self) -> usize; diff --git a/datasketches/src/thetacommon/union.rs b/datasketches/src/thetacommon/union.rs index c9ea9fe..500d80e 100644 --- a/datasketches/src/thetacommon/union.rs +++ b/datasketches/src/thetacommon/union.rs @@ -17,14 +17,14 @@ use crate::common::ResizeFactor; use crate::error::Error; -use crate::thetacommon::RawHashTableEntry; -use crate::thetacommon::RawThetaSketchView; +use crate::thetacommon::RetainedEntry; +use crate::thetacommon::ThetaFamilySketchView; use crate::thetacommon::constants::MAX_THETA; -use crate::thetacommon::hash_table::RawCompactParts; -use crate::thetacommon::hash_table::RawHashTable; +use crate::thetacommon::hash_table::CompactSketchParts; +use crate::thetacommon::hash_table::SketchHashTable; /// Merges an incoming entry into an existing entry with the same hash. -pub trait RawThetaUnionPolicy { +pub trait UnionMergePolicy { fn merge(&self, existing: &mut E, incoming: E); } @@ -33,15 +33,15 @@ pub trait RawThetaUnionPolicy { /// `E` is the retained entry type. Ordinary Theta entries only contain a hash, while tuple /// entries also carry a summary. `P` defines how equal-hash entries are combined. #[derive(Debug)] -pub struct RawThetaUnion { - table: RawHashTable, +pub struct UnionState { + table: SketchHashTable, policy: P, union_theta: u64, } -impl RawThetaUnion +impl UnionState where - E: RawHashTableEntry, + E: RetainedEntry, { pub fn new( lg_k: u8, @@ -50,7 +50,7 @@ where seed: u64, policy: P, ) -> Self { - let table = RawHashTable::new(lg_k, resize_factor, sampling_probability, seed); + let table = SketchHashTable::new(lg_k, resize_factor, sampling_probability, seed); Self { union_theta: table.theta(), table, @@ -61,8 +61,8 @@ where /// Incorporate a sketch into the union. pub fn update(&mut self, sketch: &S) -> Result<(), Error> where - S: RawThetaSketchView, - P: RawThetaUnionPolicy, + S: ThetaFamilySketchView, + P: UnionMergePolicy, { if sketch.is_empty() { return Ok(()); @@ -98,15 +98,15 @@ where Ok(()) } - /// Return the current compact-union state as raw compact-sketch parts. - pub fn to_compact_parts(&self, ordered: bool) -> RawCompactParts + /// Return the current compact-union state as compact-sketch parts. + pub fn to_compact_parts(&self, ordered: bool) -> CompactSketchParts where E: Clone, { let seed_hash = self.table.seed_hash(); if self.table.is_empty() { - return RawCompactParts { + return CompactSketchParts { entries: vec![], theta: self.union_theta, seed_hash, @@ -135,10 +135,10 @@ where let ordered = ordered || (entries.len() == 1 && theta == MAX_THETA); if ordered { - entries.sort_unstable_by_key(RawHashTableEntry::hash); + entries.sort_unstable_by_key(RetainedEntry::hash); } - RawCompactParts { + CompactSketchParts { entries, theta, seed_hash, @@ -165,7 +165,7 @@ mod tests { summary: u64, } - impl RawHashTableEntry for TestEntry { + impl RetainedEntry for TestEntry { fn hash(&self) -> u64 { self.hash } @@ -175,7 +175,9 @@ mod tests { entries: Vec, } - impl RawThetaSketchView for TestSketch { + impl ThetaFamilySketchView for TestSketch { + type Entry = TestEntry; + fn seed_hash(&self) -> u16 { crate::hash::compute_seed_hash(DEFAULT_UPDATE_SEED) } @@ -203,7 +205,7 @@ mod tests { struct SumPolicy; - impl RawThetaUnionPolicy for SumPolicy { + impl UnionMergePolicy for SumPolicy { fn merge(&self, existing: &mut TestEntry, incoming: TestEntry) { existing.summary += incoming.summary; } @@ -211,8 +213,7 @@ mod tests { #[test] fn merges_equal_hash_entries_with_policy() { - let mut union = - RawThetaUnion::new(5, ResizeFactor::X1, 1.0, DEFAULT_UPDATE_SEED, SumPolicy); + let mut union = UnionState::new(5, ResizeFactor::X1, 1.0, DEFAULT_UPDATE_SEED, SumPolicy); union .update(&TestSketch { entries: vec![TestEntry { diff --git a/datasketches/src/tuple/a_not_b.rs b/datasketches/src/tuple/a_not_b.rs index 0ae407a..16c9355 100644 --- a/datasketches/src/tuple/a_not_b.rs +++ b/datasketches/src/tuple/a_not_b.rs @@ -17,14 +17,14 @@ //! Tuple sketch set difference (`A and not B`). //! -//! [`TupleAnotB`] computes the set difference of two Tuple sketches: the keys retained in `A` that +//! [`TupleANotB`] computes the set difference of two Tuple sketches: the keys retained in `A` that //! are not present in `B`. Surviving keys keep their summaries from `A` unchanged, so unlike the -//! union and intersection this operation needs no combine policy. The logic lives in the shared -//! raw operator (`RawThetaAnotB`) that also drives the Theta a-not-B. +//! union and intersection this operation needs no combine policy. It shares its set-difference +//! implementation with Theta a-not-B. use crate::error::Error; use crate::hash::DEFAULT_UPDATE_SEED; -use crate::thetacommon::a_not_b::RawThetaAnotB; +use crate::thetacommon::a_not_b::ANotBOperator; use crate::tuple::sketch::CompactTupleSketch; use crate::tuple::sketch::TupleSketchView; @@ -37,7 +37,7 @@ use crate::tuple::sketch::TupleSketchView; /// # Examples /// /// ``` -/// # use datasketches::tuple::{DefaultUpdatePolicy, TupleAnotB, TupleSketchBuilder}; +/// # use datasketches::tuple::{DefaultUpdatePolicy, TupleANotB, TupleSketchBuilder}; /// let update_policy = DefaultUpdatePolicy::::default(); /// let mut a = TupleSketchBuilder::new(update_policy).build(); /// a.update("apple", 1); @@ -46,26 +46,26 @@ use crate::tuple::sketch::TupleSketchView; /// let mut b = TupleSketchBuilder::new(update_policy).build(); /// b.update("banana", 1); /// -/// let a_not_b = TupleAnotB::default(); +/// let a_not_b = TupleANotB::default(); /// let result = a_not_b.compute(&a, &b, true).unwrap(); /// assert_eq!(result.num_retained(), 1); // only "apple" survives /// ``` #[derive(Debug, Clone, Copy)] -pub struct TupleAnotB { - raw: RawThetaAnotB, +pub struct TupleANotB { + op: ANotBOperator, } -impl Default for TupleAnotB { +impl Default for TupleANotB { fn default() -> Self { Self::with_seed(DEFAULT_UPDATE_SEED) } } -impl TupleAnotB { +impl TupleANotB { /// Creates a new set difference operator for the given `seed`. pub fn with_seed(seed: u64) -> Self { Self { - raw: RawThetaAnotB::new(seed), + op: ANotBOperator::new(seed), } } @@ -89,7 +89,7 @@ impl TupleAnotB { A: TupleSketchView, B: TupleSketchView, { - let parts = self.raw.compute(a, b, ordered)?; + let parts = self.op.compute(a, b, ordered)?; Ok(CompactTupleSketch::from_parts( parts.entries, parts.theta, @@ -129,7 +129,7 @@ mod tests { b.update(i, 1u64); } - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); // Keys 0..500 are only in A (exact mode). assert_eq!(result.num_retained(), 500); assert_eq!(result.estimate(), 500.0); @@ -143,7 +143,7 @@ mod tests { let mut b = default_sketch_builder().build(); b.update("shared", 99u64); - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert_eq!(result.num_retained(), 1); // The surviving key keeps A's summary; B's summary is never combined in. assert_eq!(result.iter().next().unwrap().1, &7); @@ -157,7 +157,7 @@ mod tests { } let b = default_sketch_builder().build(); - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert_eq!(result.num_retained(), 100); assert!(result.iter().all(|(_, &s)| s == 3)); } @@ -170,7 +170,7 @@ mod tests { b.update(i, 1u64); } - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert!(result.is_empty()); assert_eq!(result.num_retained(), 0); assert_eq!(result.estimate(), 0.0); @@ -187,7 +187,7 @@ mod tests { b.update(i, 1u64); } - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert_eq!(result.num_retained(), 0); assert_eq!(result.estimate(), 0.0); } @@ -203,7 +203,7 @@ mod tests { b.update(i, 1u64); } - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert_eq!(result.num_retained(), 500); } @@ -220,12 +220,12 @@ mod tests { let b_compact = b.compact(true); // a (updatable) not b (compact) - let result = TupleAnotB::default().compute(&a, &b_compact, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b_compact, true).unwrap(); assert_eq!(result.num_retained(), 500); // a (compact) not b (compact) let a_compact = a.compact(true); - let result2 = TupleAnotB::default() + let result2 = TupleANotB::default() .compute(&a_compact, &b_compact, true) .unwrap(); assert_eq!(result2.num_retained(), 500); @@ -245,7 +245,7 @@ mod tests { } assert!(a.is_estimation_mode() && b.is_estimation_mode()); - let op = TupleAnotB::default(); + let op = TupleANotB::default(); let unordered = op.compute(&a, &b, true).unwrap(); let ordered = op .compute(&a.compact(true), &b.compact(true), true) @@ -267,7 +267,7 @@ mod tests { b.update(i, 1u64); } - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert!(result.is_ordered()); let entries = sorted_entries(&result); let iter_order: Vec = result.iter().map(|(h, _)| h).collect(); @@ -282,7 +282,7 @@ mod tests { let mut b = default_sketch_builder().seed(1).build(); b.update(2, 1u64); - let err = TupleAnotB::with_seed(2).compute(&a, &b, true).unwrap_err(); + let err = TupleANotB::with_seed(2).compute(&a, &b, true).unwrap_err(); assert_eq!(err.kind(), ErrorKind::InvalidArgument); } @@ -294,7 +294,7 @@ mod tests { a.update(1, 1u64); let b = default_sketch_builder().seed(1).build(); // empty - let err = TupleAnotB::with_seed(2).compute(&a, &b, true).unwrap_err(); + let err = TupleANotB::with_seed(2).compute(&a, &b, true).unwrap_err(); assert_eq!(err.kind(), ErrorKind::InvalidArgument); } @@ -312,7 +312,7 @@ mod tests { // lowered by B). let b = default_sketch_builder().seed(999).build(); - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert!(!result.is_empty()); assert_eq!(result.num_retained(), 0); assert_eq!(result.theta64(), a.theta64()); @@ -329,7 +329,7 @@ mod tests { b.update(i, 1u64); } - let result = TupleAnotB::default().compute(&a, &b, true).unwrap(); + let result = TupleANotB::default().compute(&a, &b, true).unwrap(); assert!(result.is_estimation_mode()); // True difference size is 25000 (keys 0..25000). let lower = result.lower_bound(NumStdDev::Three); diff --git a/datasketches/src/tuple/hash_table.rs b/datasketches/src/tuple/hash_table.rs index de0ff1f..c88d4f0 100644 --- a/datasketches/src/tuple/hash_table.rs +++ b/datasketches/src/tuple/hash_table.rs @@ -18,10 +18,10 @@ use std::hash::Hash; use std::num::NonZeroU64; -use crate::thetacommon::RawHashTableEntry; -use crate::thetacommon::hash_table::RawHashTable; -use crate::thetacommon::intersection::RawThetaIntersectionPolicy; -use crate::thetacommon::union::RawThetaUnionPolicy; +use crate::thetacommon::RetainedEntry; +use crate::thetacommon::hash_table::SketchHashTable; +use crate::thetacommon::intersection::IntersectionMergePolicy; +use crate::thetacommon::union::UnionMergePolicy; use crate::tuple::SummaryCombinePolicy; /// A retained entry in a Tuple sketch: a hash key together with its associated summary. @@ -61,9 +61,9 @@ impl TupleEntry { /// This is the Theta sketch hash table extended so that each retained key carries a user-defined /// summary. Unlike the Theta hash table, when a key is inserted that already exists, the incoming /// update is merged into the existing summary rather than discarded. -pub(super) type TupleHashTable = RawHashTable>; +pub(super) type TupleHashTable = SketchHashTable>; -impl RawHashTableEntry for TupleEntry { +impl RetainedEntry for TupleEntry { fn hash(&self) -> u64 { self.hash.get() } @@ -108,13 +108,13 @@ impl TupleHashTable { } } -impl RawThetaUnionPolicy> for P { +impl UnionMergePolicy> for P { fn merge(&self, existing: &mut TupleEntry, incoming: TupleEntry) { self.combine(&mut existing.summary, &incoming.summary); } } -impl RawThetaIntersectionPolicy> for P { +impl IntersectionMergePolicy> for P { fn merge(&self, existing: &mut TupleEntry, incoming: TupleEntry) { self.combine(&mut existing.summary, &incoming.summary); } diff --git a/datasketches/src/tuple/intersection.rs b/datasketches/src/tuple/intersection.rs index 678a9e8..531a7ea 100644 --- a/datasketches/src/tuple/intersection.rs +++ b/datasketches/src/tuple/intersection.rs @@ -17,17 +17,17 @@ //! Tuple sketch intersection. //! -//! [`TupleIntersection`] computes the intersection (set AND) of Tuple sketches. It reuses the raw -//! intersection state machine (`RawThetaIntersection`) that also drives the Theta intersection; -//! the only Tuple-specific addition is that for each key retained in both the running result and -//! the incoming sketch, the two summaries are combined with a [`SummaryCombinePolicy`]. +//! [`TupleIntersection`] computes the intersection (set AND) of Tuple sketches. It shares its state +//! machine with the Theta intersection; the only Tuple-specific addition is that for each key +//! retained in both the running result and the incoming sketch, the two summaries are combined +//! with a [`SummaryCombinePolicy`]. //! //! Unlike the union there is no default policy: how to combine the summaries of keys present in //! both inputs is application-specific, so a policy must always be supplied. use crate::error::Error; use crate::hash::DEFAULT_UPDATE_SEED; -use crate::thetacommon::intersection::RawThetaIntersection; +use crate::thetacommon::intersection::IntersectionState; use crate::tuple::hash_table::TupleEntry; use crate::tuple::policy::SummaryCombinePolicy; use crate::tuple::sketch::CompactTupleSketch; @@ -88,7 +88,7 @@ pub struct TupleIntersection

where P: SummaryCombinePolicy, { - raw: RawThetaIntersection, P>, + state: IntersectionState, P>, } impl

TupleIntersection

@@ -103,7 +103,7 @@ where /// Creates a new intersection operator for the given combine `policy` and `seed`. pub fn with_seed(policy: P, seed: u64) -> Self { Self { - raw: RawThetaIntersection::new(seed, policy), + state: IntersectionState::new(seed, policy), } } @@ -122,12 +122,12 @@ where V: TupleSketchView, P::Summary: Clone, { - self.raw.update(sketch) + self.state.update(sketch) } /// Returns whether this operator has received at least one update. pub fn has_result(&self) -> bool { - self.raw.has_result() + self.state.has_result() } /// Returns the intersection result as a compact Tuple sketch. @@ -142,10 +142,10 @@ where P::Summary: Clone, { assert!( - self.raw.has_result(), + self.state.has_result(), "TupleIntersection::to_sketch() called before first update()" ); - let parts = self.raw.result(ordered); + let parts = self.state.result(ordered); CompactTupleSketch::from_parts( parts.entries, parts.theta, diff --git a/datasketches/src/tuple/mod.rs b/datasketches/src/tuple/mod.rs index ffa4603..4c88058 100644 --- a/datasketches/src/tuple/mod.rs +++ b/datasketches/src/tuple/mod.rs @@ -46,7 +46,7 @@ mod serialization; mod sketch; mod union; -pub use self::a_not_b::TupleAnotB; +pub use self::a_not_b::TupleANotB; pub use self::hash_table::TupleEntry; pub use self::intersection::TupleIntersection; pub use self::policy::DefaultUnionPolicy; diff --git a/datasketches/src/tuple/sketch.rs b/datasketches/src/tuple/sketch.rs index 501ebcc..ac45ee0 100644 --- a/datasketches/src/tuple/sketch.rs +++ b/datasketches/src/tuple/sketch.rs @@ -34,7 +34,7 @@ use crate::common::ResizeFactor; use crate::error::Error; use crate::hash::DEFAULT_UPDATE_SEED; use crate::hash::compute_seed_hash; -use crate::thetacommon::RawThetaSketchView; +use crate::thetacommon::ThetaFamilySketchView; use crate::thetacommon::binomial_bounds; use crate::thetacommon::constants::DEFAULT_LG_K; use crate::thetacommon::constants::FLAGS_IS_COMPACT; @@ -60,11 +60,11 @@ use crate::tuple::serialization::TupleSummaryValue; /// either a mutable [`TupleSketch`] or an immutable [`CompactTupleSketch`]. `S` is the /// summary type retained by the sketch. /// -/// It is blanket-implemented for every [`RawThetaSketchView`] over [`TupleEntry`], so custom -/// sketch-like inputs can be supplied by implementing that trait. -pub trait TupleSketchView: RawThetaSketchView> {} +/// It is blanket-implemented for every [`ThetaFamilySketchView`] whose associated entry type is +/// [`TupleEntry`], so custom sketch-like inputs can be supplied by implementing that trait. +pub trait TupleSketchView: ThetaFamilySketchView> {} -impl TupleSketchView for T where T: RawThetaSketchView> {} +impl TupleSketchView for T where T: ThetaFamilySketchView> {} /// Mutable Tuple sketch for building from input data. /// @@ -248,11 +248,13 @@ where } } -impl

RawThetaSketchView> for TupleSketch

+impl

ThetaFamilySketchView for TupleSketch

where P: SummaryPolicy, P::Summary: Clone, { + type Entry = TupleEntry; + fn seed_hash(&self) -> u16 { self.table.seed_hash() } @@ -566,7 +568,9 @@ impl CompactTupleSketch { } } -impl RawThetaSketchView> for CompactTupleSketch { +impl ThetaFamilySketchView for CompactTupleSketch { + type Entry = TupleEntry; + fn seed_hash(&self) -> u16 { self.seed_hash } diff --git a/datasketches/src/tuple/union.rs b/datasketches/src/tuple/union.rs index 3267c54..ea3a8b2 100644 --- a/datasketches/src/tuple/union.rs +++ b/datasketches/src/tuple/union.rs @@ -17,10 +17,10 @@ //! Tuple sketch union. //! -//! [`TupleUnion`] computes the union (set OR) of any number of Tuple sketches. It reuses the raw -//! union state machine (`RawThetaUnion`) that also drives the Theta union; the only Tuple-specific -//! behavior is that when an incoming key already exists in the union, the two summaries are -//! combined with a [`SummaryCombinePolicy`] instead of one being dropped. +//! [`TupleUnion`] computes the union (set OR) of any number of Tuple sketches. It shares its state +//! machine with the Theta union; the only Tuple-specific behavior is that when an incoming key +//! already exists in the union, the two summaries are combined with a [`SummaryCombinePolicy`] +//! instead of one being dropped. use crate::common::ResizeFactor; use crate::error::Error; @@ -28,7 +28,7 @@ use crate::hash::DEFAULT_UPDATE_SEED; use crate::thetacommon::constants::DEFAULT_LG_K; use crate::thetacommon::constants::MAX_LG_K; use crate::thetacommon::constants::MIN_LG_K; -use crate::thetacommon::union::RawThetaUnion; +use crate::thetacommon::union::UnionState; use crate::tuple::hash_table::TupleEntry; use crate::tuple::policy::SummaryCombinePolicy; use crate::tuple::sketch::CompactTupleSketch; @@ -65,7 +65,7 @@ pub struct TupleUnion

where P: SummaryCombinePolicy, { - raw: RawThetaUnion, P>, + state: UnionState, P>, } impl

TupleUnion

@@ -86,7 +86,7 @@ where where V: TupleSketchView, { - self.raw.update(sketch) + self.state.update(sketch) } /// Returns the union as a [`CompactTupleSketch`]. @@ -96,7 +96,7 @@ where where P::Summary: Clone, { - let result = self.raw.to_compact_parts(ordered); + let result = self.state.to_compact_parts(ordered); CompactTupleSketch::from_parts( result.entries, result.theta, @@ -108,7 +108,7 @@ where /// Resets the union to its initial empty state. pub fn reset(&mut self) { - self.raw.reset(); + self.state.reset(); } } @@ -198,7 +198,7 @@ where /// Builds the [`TupleUnion`]. pub fn build(self) -> TupleUnion

{ TupleUnion { - raw: RawThetaUnion::new( + state: UnionState::new( self.lg_k, self.resize_factor, self.sampling_probability, diff --git a/datasketches/tests/theta_a_not_b_test.rs b/datasketches/tests/theta_a_not_b_test.rs index 8d3dfdf..1e0c0a3 100644 --- a/datasketches/tests/theta_a_not_b_test.rs +++ b/datasketches/tests/theta_a_not_b_test.rs @@ -23,7 +23,7 @@ #![cfg(feature = "theta")] use datasketches::theta::CompactThetaSketch; -use datasketches::theta::ThetaAnotB; +use datasketches::theta::ThetaANotB; use datasketches::theta::ThetaSketch; use datasketches::theta::ThetaSketchBuilder; @@ -44,7 +44,7 @@ fn test_basic_difference() { b.update("shared"); b.update("only_b"); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); // "shared" is subtracted; only "only_a" survives. @@ -58,7 +58,7 @@ fn test_accepts_updatable_and_compact_inputs() { let a = sketch_with_range(0, 1000); let b = sketch_with_range(500, 1000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a.compact(true), &b, true).unwrap(); assert_eq!(r.num_retained(), 500); @@ -72,7 +72,7 @@ fn test_seed_mismatch_returns_error() { one_other_seed.update("value"); let good = sketch_with_range(0, 10); - let a_not_b = ThetaAnotB::with_seed(1); + let a_not_b = ThetaANotB::with_seed(1); assert!(a_not_b.compute(&one_other_seed, &good, true).is_err()); assert!(a_not_b.compute(&good, &one_other_seed, true).is_err()); } @@ -83,7 +83,7 @@ fn test_seed_mismatch_ignored_for_empty_inputs() { let empty_other_seed = ThetaSketchBuilder::default().seed(2).build(); let good = sketch_with_range(0, 10); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&empty_other_seed, &good, true).unwrap(); assert!(r.is_empty()); @@ -97,7 +97,7 @@ fn test_empty_a_returns_empty() { let empty = ThetaSketchBuilder::default().build(); let b = sketch_with_range(0, 1000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&empty, &b, true).unwrap(); assert!(r.is_empty()); @@ -110,7 +110,7 @@ fn test_empty_b_returns_a() { let a = sketch_with_range(0, 1000); let empty = ThetaSketchBuilder::default().build(); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &empty, true).unwrap(); assert_eq!(r.num_retained(), 1000); @@ -122,7 +122,7 @@ fn test_exact_partial_overlap_unordered() { let a = sketch_with_range(0, 1000); let b = sketch_with_range(500, 1000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); // Keys 0..500 survive (exact mode). @@ -137,7 +137,7 @@ fn test_exact_partial_overlap_ordered() { let a = sketch_with_range(0, 1000); let b = sketch_with_range(500, 1000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b .compute(&a.compact(true), &b.compact(true), true) .unwrap(); @@ -153,7 +153,7 @@ fn test_exact_disjoint_returns_a() { let a = sketch_with_range(0, 1000); let b = sketch_with_range(1000, 1000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); assert!(!r.is_estimation_mode()); @@ -166,7 +166,7 @@ fn test_exact_superset_b_returns_empty() { let a = sketch_with_range(0, 1000); let b = sketch_with_range(0, 2000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); assert!(r.is_empty()); @@ -179,7 +179,7 @@ fn test_result_ordering() { let a = sketch_with_range(0, 64); let empty = ThetaSketchBuilder::default().build(); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &empty, true).unwrap(); assert!(r.is_ordered()); @@ -193,7 +193,7 @@ fn test_estimation_partial_overlap_unordered() { let a = sketch_with_range(0, 10000); let b = sketch_with_range(5000, 10000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); // True difference size is 5000 (keys 0..5000). @@ -207,7 +207,7 @@ fn test_estimation_partial_overlap_ordered() { let a = sketch_with_range(0, 10000); let b = sketch_with_range(5000, 10000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b .compute(&a.compact(true), &b.compact(true), true) .unwrap(); @@ -224,7 +224,7 @@ fn test_estimation_partial_overlap_deserialized_compact() { let c1 = CompactThetaSketch::deserialize(&a.compact(true).serialize()).unwrap(); let c2 = CompactThetaSketch::deserialize(&b.compact(true).serialize()).unwrap(); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&c1, &c2, true).unwrap(); assert!(!r.is_empty()); @@ -237,7 +237,7 @@ fn test_estimation_disjoint_returns_a() { let a = sketch_with_range(0, 10000); let b = sketch_with_range(10000, 10000); - let a_not_b = ThetaAnotB::default(); + let a_not_b = ThetaANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); assert!(!r.is_empty()); diff --git a/datasketches/tests/tuple_test/a_not_b.rs b/datasketches/tests/tuple_test/a_not_b.rs index 51db68b..ac1d3a8 100644 --- a/datasketches/tests/tuple_test/a_not_b.rs +++ b/datasketches/tests/tuple_test/a_not_b.rs @@ -22,7 +22,7 @@ //! so the distinct-count behavior matches a plain Theta a-not-B. use datasketches::tuple::CompactTupleSketch; -use datasketches::tuple::TupleAnotB; +use datasketches::tuple::TupleANotB; use super::default_tuple_sketch_builder; use super::tuple_sketch_with_range; @@ -36,7 +36,7 @@ fn test_basic_difference_keeps_summaries_from_a() { b.update("shared", 9u64); b.update("only_b", 7u64); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); // "shared" is subtracted; "only_a" survives with A's summary. @@ -51,7 +51,7 @@ fn test_accepts_updatable_and_compact_inputs() { let a = tuple_sketch_with_range(0, 1000); let b = tuple_sketch_with_range(500, 1000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a.compact(true), &b, true).unwrap(); assert_eq!(r.num_retained(), 500); @@ -65,7 +65,7 @@ fn test_seed_mismatch_returns_error() { one_other_seed.update("value", 1u64); let good = tuple_sketch_with_range(0, 10); - let a_not_b = TupleAnotB::with_seed(1); + let a_not_b = TupleANotB::with_seed(1); assert!(a_not_b.compute(&one_other_seed, &good, true).is_err()); assert!(a_not_b.compute(&good, &one_other_seed, true).is_err()); } @@ -76,7 +76,7 @@ fn test_seed_mismatch_ignored_for_empty_inputs() { let empty_other_seed = default_tuple_sketch_builder().seed(2).build(); let good = tuple_sketch_with_range(0, 10); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&empty_other_seed, &good, true).unwrap(); assert!(r.is_empty()); @@ -90,7 +90,7 @@ fn test_empty_a_returns_empty() { let empty = default_tuple_sketch_builder().build(); let b = tuple_sketch_with_range(0, 1000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&empty, &b, true).unwrap(); assert!(r.is_empty()); @@ -103,7 +103,7 @@ fn test_empty_b_returns_a() { let a = tuple_sketch_with_range(0, 1000); let empty = default_tuple_sketch_builder().build(); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &empty, true).unwrap(); assert_eq!(r.num_retained(), 1000); @@ -115,7 +115,7 @@ fn test_exact_partial_overlap_unordered() { let a = tuple_sketch_with_range(0, 1000); let b = tuple_sketch_with_range(500, 1000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); // Keys 0..500 survive (exact mode). @@ -130,7 +130,7 @@ fn test_exact_partial_overlap_ordered() { let a = tuple_sketch_with_range(0, 1000); let b = tuple_sketch_with_range(500, 1000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b .compute(&a.compact(true), &b.compact(true), true) .unwrap(); @@ -146,7 +146,7 @@ fn test_exact_disjoint_returns_a() { let a = tuple_sketch_with_range(0, 1000); let b = tuple_sketch_with_range(1000, 1000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); assert!(!r.is_estimation_mode()); @@ -159,7 +159,7 @@ fn test_exact_superset_b_returns_empty() { let a = tuple_sketch_with_range(0, 1000); let b = tuple_sketch_with_range(0, 2000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); assert!(r.is_empty()); @@ -175,7 +175,7 @@ fn test_result_ordering() { } let empty = default_tuple_sketch_builder().build(); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &empty, true).unwrap(); assert!(r.is_ordered()); @@ -189,7 +189,7 @@ fn test_estimation_partial_overlap_unordered() { let a = tuple_sketch_with_range(0, 10000); let b = tuple_sketch_with_range(5000, 10000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); // True difference size is 5000 (keys 0..5000). @@ -203,7 +203,7 @@ fn test_estimation_partial_overlap_ordered() { let a = tuple_sketch_with_range(0, 10000); let b = tuple_sketch_with_range(5000, 10000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b .compute(&a.compact(true), &b.compact(true), true) .unwrap(); @@ -220,7 +220,7 @@ fn test_estimation_partial_overlap_deserialized_compact() { let c1 = CompactTupleSketch::::deserialize(&a.compact(true).serialize()).unwrap(); let c2 = CompactTupleSketch::::deserialize(&b.compact(true).serialize()).unwrap(); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&c1, &c2, true).unwrap(); assert!(!r.is_empty()); @@ -233,7 +233,7 @@ fn test_estimation_disjoint_returns_a() { let a = tuple_sketch_with_range(0, 10000); let b = tuple_sketch_with_range(10000, 10000); - let a_not_b = TupleAnotB::default(); + let a_not_b = TupleANotB::default(); let r = a_not_b.compute(&a, &b, true).unwrap(); assert!(!r.is_empty());