diff --git a/.gitignore b/.gitignore index f03006e4..fa8608c6 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,4 @@ **/target # Generated files -*.sk \ No newline at end of file +*.sk diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b618efe..997607ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All significant changes to this project will be documented in this file. ### Breaking changes +* Move the `hash_value` module to `hash::value`. * Remove `ThetaSketch::builder`, `ThetaUnion::builder`, and `TupleSketch::builder`. Construct `ThetaSketchBuilder`, `ThetaUnionBuilder`, and `TupleSketchBuilder` with `Default::default` instead. * Standardize Theta and Tuple set-operation constructors. Zero-configuration operators use `Default::default()`, `TupleIntersection::new(policy)` uses the default seed, and `with_seed` diff --git a/datasketches/src/bloom/builder.rs b/datasketches/src/bloom/builder.rs index 7622160b..67f62b2d 100644 --- a/datasketches/src/bloom/builder.rs +++ b/datasketches/src/bloom/builder.rs @@ -62,7 +62,8 @@ impl BloomFilterBuilder { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// // Optimal for 10,000 items with 1% FPP /// let filter = BloomFilterBuilder::with_accuracy(10_000, 0.01) /// .seed(42) @@ -107,7 +108,8 @@ impl BloomFilterBuilder { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let filter = BloomFilterBuilder::with_size(10_000, 7).build(); /// ``` pub fn with_size(num_bits: u64, num_hashes: u16) -> Self { @@ -140,7 +142,8 @@ impl BloomFilterBuilder { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let filter = BloomFilterBuilder::with_accuracy(100, 0.01) /// .seed(12345) /// .build(); @@ -176,7 +179,8 @@ impl BloomFilterBuilder { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let bits = BloomFilterBuilder::suggest_num_bits(1000, 0.01); /// assert!(bits > 9000 && bits < 10000); // ~9585 bits /// ``` @@ -198,7 +202,8 @@ impl BloomFilterBuilder { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let hashes = BloomFilterBuilder::suggest_num_hashes_from_accuracy(1000, 10000); /// assert_eq!(hashes, 7); // Optimal k ≈ 6.93 /// ``` @@ -222,7 +227,8 @@ impl BloomFilterBuilder { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let hashes = BloomFilterBuilder::suggest_num_hashes_from_fpp(0.01); /// assert_eq!(hashes, 7); // -log2(0.01) ≈ 6.64 /// ``` diff --git a/datasketches/src/bloom/mod.rs b/datasketches/src/bloom/mod.rs index 3638ee26..3ee0df1e 100644 --- a/datasketches/src/bloom/mod.rs +++ b/datasketches/src/bloom/mod.rs @@ -61,7 +61,8 @@ //! Automatically calculates optimal size and hash functions: //! //! ``` -//! # use datasketches::bloom::BloomFilterBuilder; +//! use datasketches::bloom::BloomFilterBuilder; +//! //! let filter = BloomFilterBuilder::with_accuracy( //! 10_000, // Expected max items //! 0.01, // Target false positive probability (1%) @@ -75,7 +76,8 @@ //! Specify requested bit count and hash functions (rounded up to a multiple of 64 bits): //! //! ``` -//! # use datasketches::bloom::BloomFilterBuilder; +//! use datasketches::bloom::BloomFilterBuilder; +//! //! let filter = BloomFilterBuilder::with_size( //! 95_851, // Number of bits //! 7, // Number of hash functions @@ -88,7 +90,8 @@ //! Bloom filters support efficient set operations: //! //! ``` -//! # use datasketches::bloom::BloomFilterBuilder; +//! use datasketches::bloom::BloomFilterBuilder; +//! //! let mut filter1 = BloomFilterBuilder::with_accuracy(100, 0.01).build(); //! let mut filter2 = BloomFilterBuilder::with_accuracy(100, 0.01).build(); //! diff --git a/datasketches/src/bloom/sketch.rs b/datasketches/src/bloom/sketch.rs index ee17cff9..081f6d4b 100644 --- a/datasketches/src/bloom/sketch.rs +++ b/datasketches/src/bloom/sketch.rs @@ -61,7 +61,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut filter = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// filter.insert("apple"); /// @@ -85,7 +86,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut filter = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// /// let was_present = filter.contains_and_insert(&"apple"); @@ -108,7 +110,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut filter = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// /// filter.insert("apple"); @@ -129,7 +132,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut filter = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// filter.insert("apple"); /// assert!(!filter.is_empty()); @@ -156,7 +160,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut f1 = BloomFilterBuilder::with_accuracy(100, 0.01) /// .seed(123) /// .build(); @@ -198,7 +203,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut f1 = BloomFilterBuilder::with_accuracy(100, 0.01) /// .seed(123) /// .build(); @@ -238,7 +244,8 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::BloomFilterBuilder; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut filter = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// filter.insert("apple"); /// @@ -324,7 +331,9 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::{BloomFilter, BloomFilterBuilder}; + /// use datasketches::bloom::BloomFilter; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let mut filter = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// filter.insert("test"); /// @@ -387,7 +396,9 @@ impl BloomFilter { /// # Examples /// /// ``` - /// # use datasketches::bloom::{BloomFilter, BloomFilterBuilder}; + /// use datasketches::bloom::BloomFilter; + /// use datasketches::bloom::BloomFilterBuilder; + /// /// let original = BloomFilterBuilder::with_accuracy(100, 0.01).build(); /// let bytes = original.serialize(); /// diff --git a/datasketches/src/common/resize.rs b/datasketches/src/common/resize.rs index 0dbb1d51..5fa4742d 100644 --- a/datasketches/src/common/resize.rs +++ b/datasketches/src/common/resize.rs @@ -36,7 +36,8 @@ /// # Examples /// /// ``` -/// # use datasketches::common::ResizeFactor; +/// use datasketches::common::ResizeFactor; +/// /// let factor = ResizeFactor::X4; /// assert_eq!(factor.value(), 4); /// assert_eq!(factor.lg_value(), 2); diff --git a/datasketches/src/countmin/mod.rs b/datasketches/src/countmin/mod.rs index 4331c203..9572f11b 100644 --- a/datasketches/src/countmin/mod.rs +++ b/datasketches/src/countmin/mod.rs @@ -23,7 +23,8 @@ //! # Usage //! //! ``` -//! # use datasketches::countmin::CountMinSketch; +//! use datasketches::countmin::CountMinSketch; +//! //! let mut sketch = CountMinSketch::::new(5, 256); //! sketch.update("apple"); //! sketch.update_with_weight("banana", 3); @@ -33,7 +34,8 @@ //! # Configuration Helpers //! //! ``` -//! # use datasketches::countmin::CountMinSketch; +//! use datasketches::countmin::CountMinSketch; +//! //! let buckets = CountMinSketch::::suggest_num_buckets(0.01); //! let hashes = CountMinSketch::::suggest_num_hashes(0.99); //! let sketch = CountMinSketch::::new(hashes, buckets); diff --git a/datasketches/src/countmin/sketch.rs b/datasketches/src/countmin/sketch.rs index 96c8bd8b..a2dcb585 100644 --- a/datasketches/src/countmin/sketch.rs +++ b/datasketches/src/countmin/sketch.rs @@ -63,7 +63,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let sketch = CountMinSketch::::new(4, 128); /// assert_eq!(sketch.num_buckets(), 128); /// ``` @@ -84,7 +85,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let sketch = CountMinSketch::::with_seed(4, 64, 42); /// assert_eq!(sketch.seed(), 42); /// ``` @@ -155,7 +157,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let mut sketch = CountMinSketch::::new(4, 128); /// sketch.update("apple"); /// assert!(sketch.estimate("apple") >= 1); @@ -169,7 +172,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let mut sketch = CountMinSketch::::new(4, 128); /// sketch.update_with_weight("banana", 3); /// assert!(sketch.estimate("banana") >= 3); @@ -193,7 +197,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let mut sketch = CountMinSketch::::new(4, 128); /// sketch.update_with_weight("pear", 2); /// assert!(sketch.estimate("pear") >= 2); @@ -233,7 +238,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let mut left = CountMinSketch::::new(4, 128); /// let mut right = CountMinSketch::::new(4, 128); /// @@ -263,9 +269,10 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; - /// # let mut sketch = CountMinSketch::::new(4, 128); - /// # sketch.update("apple"); + /// use datasketches::countmin::CountMinSketch; + /// + /// let mut sketch = CountMinSketch::::new(4, 128); + /// sketch.update("apple"); /// let bytes = sketch.serialize(); /// let decoded = CountMinSketch::::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate("apple") >= 1); @@ -308,10 +315,11 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; - /// # let mut sketch = CountMinSketch::::new(4, 64); - /// # sketch.update("apple"); - /// # let bytes = sketch.serialize(); + /// use datasketches::countmin::CountMinSketch; + /// + /// let mut sketch = CountMinSketch::::new(4, 64); + /// sketch.update("apple"); + /// let bytes = sketch.serialize(); /// let decoded = CountMinSketch::::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate("apple") >= 1); /// ``` @@ -324,10 +332,11 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; - /// # let mut sketch = CountMinSketch::::with_seed(4, 64, 7); - /// # sketch.update("apple"); - /// # let bytes = sketch.serialize(); + /// use datasketches::countmin::CountMinSketch; + /// + /// let mut sketch = CountMinSketch::::with_seed(4, 64, 7); + /// sketch.update("apple"); + /// let bytes = sketch.serialize(); /// let decoded = CountMinSketch::::deserialize_with_seed(&bytes, 7).unwrap(); /// assert!(decoded.estimate("apple") >= 1); /// ``` @@ -425,7 +434,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let mut sketch = CountMinSketch::::new(4, 128); /// sketch.update_with_weight("apple", 3); /// sketch.halve(); @@ -446,7 +456,8 @@ impl CountMinSketch { /// # Examples /// /// ``` - /// # use datasketches::countmin::CountMinSketch; + /// use datasketches::countmin::CountMinSketch; + /// /// let mut sketch = CountMinSketch::::new(4, 128); /// sketch.update_with_weight("apple", 3); /// sketch.decay(0.5); diff --git a/datasketches/src/cpc/sketch.rs b/datasketches/src/cpc/sketch.rs index 9b61fa92..61f6c9b4 100644 --- a/datasketches/src/cpc/sketch.rs +++ b/datasketches/src/cpc/sketch.rs @@ -171,14 +171,14 @@ impl CpcSketch { /// Update the sketch with a hashable value. /// - /// You may use [`hash_value`](crate::hash_value) wrappers when matching other datasketches - /// implementations require a specific value hashing strategy. + /// You may use [`hash::value`](crate::hash::value) wrappers when another DataSketches + /// implementation requires a specific value hashing strategy. /// /// # Examples /// /// ```rust /// use datasketches::cpc::CpcSketch; - /// use datasketches::hash_value; + /// use datasketches::hash::value::canonical_float; /// /// let mut sketch = CpcSketch::with_seed(11, 123); /// sketch.update(1); @@ -186,9 +186,9 @@ impl CpcSketch { /// sketch.update(3); /// /// let mut sketch = CpcSketch::with_seed(11, 123); - /// sketch.update(hash_value::canonical_float::from_f64(1.5)); - /// sketch.update(hash_value::canonical_float::from_f64(2.5)); - /// sketch.update(hash_value::canonical_float::from_f64(3.5)); + /// sketch.update(canonical_float::from_f64(1.5)); + /// sketch.update(canonical_float::from_f64(2.5)); + /// sketch.update(canonical_float::from_f64(3.5)); /// ``` pub fn update(&mut self, value: T) { let mut hasher = MurmurHash3X64128::with_seed(self.seed); diff --git a/datasketches/src/cpc/union.rs b/datasketches/src/cpc/union.rs index a9836303..9dc2a6ce 100644 --- a/datasketches/src/cpc/union.rs +++ b/datasketches/src/cpc/union.rs @@ -121,8 +121,8 @@ impl CpcUnion { /// # Examples /// /// ``` - /// # use datasketches::cpc::CpcUnion; - /// # use datasketches::cpc::CpcSketch; + /// use datasketches::cpc::CpcSketch; + /// use datasketches::cpc::CpcUnion; /// /// let mut s1 = CpcSketch::new(12); /// s1.update(&"apple"); diff --git a/datasketches/src/error.rs b/datasketches/src/error.rs index 6e614eea..a4fe5b9f 100644 --- a/datasketches/src/error.rs +++ b/datasketches/src/error.rs @@ -50,8 +50,9 @@ impl fmt::Display for ErrorKind { /// # Examples /// /// ``` -/// # use datasketches::error::Error; -/// # use datasketches::error::ErrorKind; +/// use datasketches::error::Error; +/// use datasketches::error::ErrorKind; +/// /// let err = Error::new(ErrorKind::InvalidArgument, "bad input"); /// assert_eq!(err.kind(), ErrorKind::InvalidArgument); /// assert_eq!(err.message(), "bad input"); diff --git a/datasketches/src/frequencies/mod.rs b/datasketches/src/frequencies/mod.rs index d5e7cf0e..8ed7dcd2 100644 --- a/datasketches/src/frequencies/mod.rs +++ b/datasketches/src/frequencies/mod.rs @@ -77,8 +77,9 @@ //! # Examples //! //! ``` -//! # use datasketches::frequencies::ErrorType; -//! # use datasketches::frequencies::FrequentItemsSketch; +//! use datasketches::frequencies::ErrorType; +//! use datasketches::frequencies::FrequentItemsSketch; +//! //! let mut sketch = FrequentItemsSketch::::new(64); //! sketch.update_with_count(1, 3); //! sketch.update(2); @@ -89,7 +90,8 @@ //! # Serialization //! //! ``` -//! # use datasketches::frequencies::FrequentItemsSketch; +//! use datasketches::frequencies::FrequentItemsSketch; +//! //! let mut sketch = FrequentItemsSketch::::new(64); //! sketch.update_with_count(42, 2); //! diff --git a/datasketches/src/frequencies/sketch.rs b/datasketches/src/frequencies/sketch.rs index bb0a88f4..4f4374dc 100644 --- a/datasketches/src/frequencies/sketch.rs +++ b/datasketches/src/frequencies/sketch.rs @@ -115,7 +115,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update(1); /// sketch.update(2); @@ -154,7 +155,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update_with_count(10, 2); /// assert!(sketch.estimate(&10) >= 2); @@ -250,7 +252,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update(42); /// assert!(sketch.estimate(&42) >= 1); @@ -266,7 +269,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update_with_count(10, 3); /// assert!(sketch.estimate(&10) >= 3); @@ -290,7 +294,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update_ref("nginx"); /// sketch.update_ref("nginx"); // no allocation on the second hit @@ -313,7 +318,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update_with_count_ref("gzip", 3); /// assert!(sketch.estimate("gzip") >= 3); @@ -340,7 +346,8 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut left = FrequentItemsSketch::::new(64); /// let mut right = FrequentItemsSketch::::new(64); /// left.update(1); @@ -375,8 +382,9 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::ErrorType; - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::ErrorType; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update_with_count(1, 5); /// sketch.update(2); @@ -400,8 +408,9 @@ impl FrequentItemsSketch { /// # Examples /// /// ``` - /// # use datasketches::frequencies::ErrorType; - /// # use datasketches::frequencies::FrequentItemsSketch; + /// use datasketches::frequencies::ErrorType; + /// use datasketches::frequencies::FrequentItemsSketch; + /// /// let mut sketch = FrequentItemsSketch::::new(64); /// sketch.update_with_count(1, 5); /// sketch.update(2); @@ -607,9 +616,10 @@ impl FrequentItemsSketch { /// Built-in support for `i64`: /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; - /// # let mut sketch = FrequentItemsSketch::::new(64); - /// # sketch.update_with_count(7, 2); + /// use datasketches::frequencies::FrequentItemsSketch; + /// + /// let mut sketch = FrequentItemsSketch::::new(64); + /// sketch.update_with_count(7, 2); /// let bytes = sketch.serialize(); /// let decoded = FrequentItemsSketch::::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate(&7) >= 2); @@ -618,10 +628,11 @@ impl FrequentItemsSketch { /// Built-in support for `String`: /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; - /// # let mut sketch = FrequentItemsSketch::::new(64); - /// # let apple = "apple".to_string(); - /// # sketch.update_with_count(apple.clone(), 2); + /// use datasketches::frequencies::FrequentItemsSketch; + /// + /// let mut sketch = FrequentItemsSketch::::new(64); + /// let apple = "apple".to_string(); + /// sketch.update_with_count(apple.clone(), 2); /// let bytes = sketch.serialize(); /// let decoded = FrequentItemsSketch::::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate(&apple) >= 2); @@ -637,10 +648,11 @@ impl FrequentItemsSketch { /// Built-in support for `i64`: /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; - /// # let mut sketch = FrequentItemsSketch::::new(64); - /// # sketch.update_with_count(7, 2); - /// # let bytes = sketch.serialize(); + /// use datasketches::frequencies::FrequentItemsSketch; + /// + /// let mut sketch = FrequentItemsSketch::::new(64); + /// sketch.update_with_count(7, 2); + /// let bytes = sketch.serialize(); /// let decoded = FrequentItemsSketch::::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate(&7) >= 2); /// ``` @@ -648,11 +660,12 @@ impl FrequentItemsSketch { /// Built-in support for `String`: /// /// ``` - /// # use datasketches::frequencies::FrequentItemsSketch; - /// # let mut sketch = FrequentItemsSketch::::new(64); - /// # let apple = "apple".to_string(); - /// # sketch.update_with_count(apple.clone(), 2); - /// # let bytes = sketch.serialize(); + /// use datasketches::frequencies::FrequentItemsSketch; + /// + /// let mut sketch = FrequentItemsSketch::::new(64); + /// let apple = "apple".to_string(); + /// sketch.update_with_count(apple.clone(), 2); + /// let bytes = sketch.serialize(); /// let decoded = FrequentItemsSketch::::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate(&apple) >= 2); /// ``` diff --git a/datasketches/src/hash/mod.rs b/datasketches/src/hash/mod.rs index ef4d7459..41d879c2 100644 --- a/datasketches/src/hash/mod.rs +++ b/datasketches/src/hash/mod.rs @@ -15,6 +15,10 @@ // specific language governing permissions and limitations // under the License. +//! Hashing support for sketches. + +pub mod value; + #[cfg(any( feature = "countmin", feature = "cpc", diff --git a/datasketches/src/hash/murmurhash.rs b/datasketches/src/hash/murmurhash.rs index 03345f22..1e0a3833 100644 --- a/datasketches/src/hash/murmurhash.rs +++ b/datasketches/src/hash/murmurhash.rs @@ -18,6 +18,7 @@ use std::hash::Hasher; use crate::hash::DEFAULT_UPDATE_SEED; +use crate::hash::read_u64_le; const C1: u64 = 0x87c37b91114253d5; const C2: u64 = 0x4cf5ad432745937f; @@ -55,7 +56,7 @@ impl MurmurHash3X64128 { if rem > 0 { if rem > 8 { // read k2 little endian - let mut k2 = super::read_u64_le(&self.buf[8..rem]); + let mut k2 = read_u64_le(&self.buf[8..rem]); // mix k2 k2 = k2.wrapping_mul(C2); k2 = k2.rotate_left(33); @@ -65,7 +66,7 @@ impl MurmurHash3X64128 { // read k1 little endian let k1_len = rem.min(8); - let mut k1 = super::read_u64_le(&self.buf[..k1_len]); + let mut k1 = read_u64_le(&self.buf[..k1_len]); // mix k1 k1 = k1.wrapping_mul(C1); k1 = k1.rotate_left(31); @@ -135,8 +136,8 @@ impl Hasher for MurmurHash3X64128 { let wanted = 16 - self.buf_len; self.buf[self.buf_len..].copy_from_slice(&bytes[..wanted]); - let k1 = super::read_u64_le(&self.buf[0..8]); - let k2 = super::read_u64_le(&self.buf[8..16]); + let k1 = read_u64_le(&self.buf[0..8]); + let k2 = read_u64_le(&self.buf[8..16]); self.update(k1, k2); bytes = &bytes[wanted..]; @@ -152,8 +153,8 @@ impl Hasher for MurmurHash3X64128 { let lo = i << 4; let mi = lo + 8; let hi = mi + 8; - let k1 = super::read_u64_le(&bytes[lo..mi]); - let k2 = super::read_u64_le(&bytes[mi..hi]); + let k1 = read_u64_le(&bytes[lo..mi]); + let k2 = read_u64_le(&bytes[mi..hi]); self.update(k1, k2); } diff --git a/datasketches/src/hash_value/canonical_float.rs b/datasketches/src/hash/value/canonical_float.rs similarity index 93% rename from datasketches/src/hash_value/canonical_float.rs rename to datasketches/src/hash/value/canonical_float.rs index 354cffd5..6ed93875 100644 --- a/datasketches/src/hash_value/canonical_float.rs +++ b/datasketches/src/hash/value/canonical_float.rs @@ -26,8 +26,8 @@ use std::hash::Hash; use std::hash::Hasher; -use super::value::HashStrategy; -use super::value::Value; +use super::HashStrategy; +use super::Value; /// A floating-point value wrapper that uses canonical floating-point hashing. /// @@ -47,8 +47,9 @@ pub struct CanonicalFloatStrategy; /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::canonical_float; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::canonical_float; +/// /// assert_eq!( /// calculate_hash(canonical_float::from_f32(0.0)), /// calculate_hash(canonical_float::from_f32(-0.0)) @@ -74,8 +75,9 @@ pub fn from_f32(v: f32) -> CanonicalFloat { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::canonical_float; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::canonical_float; +/// /// assert_eq!( /// calculate_hash(canonical_float::from_f64(0.0)), /// calculate_hash(canonical_float::from_f64(-0.0)) diff --git a/datasketches/src/hash_value/mod.rs b/datasketches/src/hash/value/mod.rs similarity index 62% rename from datasketches/src/hash_value/mod.rs rename to datasketches/src/hash/value/mod.rs index 61e60247..24559656 100644 --- a/datasketches/src/hash_value/mod.rs +++ b/datasketches/src/hash/value/mod.rs @@ -76,10 +76,105 @@ pub mod canonical_float; pub mod natural_extend; pub mod raw_bytes; pub mod sign_extend; -pub mod value; +use std::cmp::Ordering; +use std::fmt; use std::hash::Hash; use std::hash::Hasher; +use std::marker::PhantomData; +use std::ops::Deref; +use std::ops::DerefMut; + +/// A value wrapper that hashes its inner value with strategy `S`. +/// +/// Most users should prefer the strategy-specific constructors. +#[doc(hidden)] +pub struct Value { + value: T, + strategy: PhantomData S>, +} + +impl Value { + /// Create a value wrapper. + #[inline(always)] + pub fn new(value: T) -> Self { + Self { + value, + strategy: PhantomData, + } + } + + /// Get the value out. + #[inline(always)] + pub fn into_inner(self) -> T { + self.value + } +} + +impl Deref for Value { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl DerefMut for Value { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.value + } +} + +impl Clone for Value { + fn clone(&self) -> Self { + Self::new(self.value.clone()) + } +} + +impl Copy for Value {} + +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +impl Eq for Value {} + +impl PartialOrd for Value { + fn partial_cmp(&self, other: &Self) -> Option { + self.value.partial_cmp(&other.value) + } +} + +impl Ord for Value { + fn cmp(&self, other: &Self) -> Ordering { + self.value.cmp(&other.value) + } +} + +impl fmt::Debug for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.value, f) + } +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.value, f) + } +} + +impl> Hash for Value { + fn hash(&self, state: &mut H) { + S::hash(&self.value, state); + } +} + +#[doc(hidden)] +pub trait HashStrategy { + fn hash(value: &T, state: &mut H); +} #[doc(hidden)] // for doctest pub fn calculate_hash(t: T) -> u64 { diff --git a/datasketches/src/hash_value/natural_extend.rs b/datasketches/src/hash/value/natural_extend.rs similarity index 84% rename from datasketches/src/hash_value/natural_extend.rs rename to datasketches/src/hash/value/natural_extend.rs index 0717b501..375fcad9 100644 --- a/datasketches/src/hash_value/natural_extend.rs +++ b/datasketches/src/hash/value/natural_extend.rs @@ -25,8 +25,8 @@ use std::hash::Hash; use std::hash::Hasher; -use super::value::HashStrategy; -use super::value::Value; +use super::HashStrategy; +use super::Value; /// An integer value wrapper that uses Rust's natural integer widening before hashing. /// @@ -42,8 +42,9 @@ pub struct NaturalExtendStrategy; /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::natural_extend::from_i8; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::natural_extend::from_i8; +/// /// assert_eq!(calculate_hash(from_i8(-1)), calculate_hash(-1i64)); /// assert_eq!(calculate_hash(from_i8(42)), calculate_hash(42i64)); /// ``` @@ -56,8 +57,9 @@ pub fn from_i8(v: i8) -> NaturalExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::natural_extend::from_u8; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::natural_extend::from_u8; +/// /// assert_eq!(calculate_hash(from_u8(255)), calculate_hash(255u64)); /// assert_eq!(calculate_hash(from_u8(42)), calculate_hash(42u64)); /// ``` @@ -70,8 +72,9 @@ pub fn from_u8(v: u8) -> NaturalExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::natural_extend::from_i16; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::natural_extend::from_i16; +/// /// assert_eq!(calculate_hash(from_i16(-1)), calculate_hash(-1i64)); /// assert_eq!(calculate_hash(from_i16(42)), calculate_hash(42i64)); /// ``` @@ -84,8 +87,9 @@ pub fn from_i16(v: i16) -> NaturalExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::natural_extend::from_u16; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::natural_extend::from_u16; +/// /// assert_eq!(calculate_hash(from_u16(65535)), calculate_hash(65535u64)); /// assert_eq!(calculate_hash(from_u16(42)), calculate_hash(42u64)); /// ``` @@ -98,8 +102,9 @@ pub fn from_u16(v: u16) -> NaturalExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::natural_extend::from_i32; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::natural_extend::from_i32; +/// /// assert_eq!(calculate_hash(from_i32(-1)), calculate_hash(-1i64)); /// assert_eq!(calculate_hash(from_i32(42)), calculate_hash(42i64)); /// ``` @@ -112,8 +117,9 @@ pub fn from_i32(v: i32) -> NaturalExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::natural_extend::from_u32; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::natural_extend::from_u32; +/// /// assert_eq!( /// calculate_hash(from_u32(4294967295)), /// calculate_hash(4294967295u64) diff --git a/datasketches/src/hash_value/raw_bytes.rs b/datasketches/src/hash/value/raw_bytes.rs similarity index 83% rename from datasketches/src/hash_value/raw_bytes.rs rename to datasketches/src/hash/value/raw_bytes.rs index 4d9cfc17..18477116 100644 --- a/datasketches/src/hash_value/raw_bytes.rs +++ b/datasketches/src/hash/value/raw_bytes.rs @@ -26,8 +26,8 @@ use std::hash::Hasher; -use super::value::HashStrategy; -use super::value::Value; +use super::HashStrategy; +use super::Value; /// A byte or string value wrapper that hashes raw bytes. /// @@ -45,8 +45,10 @@ pub struct RawBytesStrategy; /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::raw_bytes::{from_slice, from_vec}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::raw_bytes::from_slice; +/// use datasketches::hash::value::raw_bytes::from_vec; +/// /// assert_eq!( /// calculate_hash(from_vec(b"abc".to_vec())), /// calculate_hash(from_slice(b"abc")) @@ -65,8 +67,10 @@ pub fn from_vec(v: Vec) -> RawBytes> { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::raw_bytes::{from_str, from_string}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::raw_bytes::from_str; +/// use datasketches::hash::value::raw_bytes::from_string; +/// /// assert_eq!( /// calculate_hash(from_string("abc".to_owned())), /// calculate_hash(from_str("abc")) @@ -85,8 +89,10 @@ pub fn from_string(v: String) -> RawBytes { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::raw_bytes::{from_slice, from_vec}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::raw_bytes::from_slice; +/// use datasketches::hash::value::raw_bytes::from_vec; +/// /// assert_eq!( /// calculate_hash(from_slice(b"abc")), /// calculate_hash(from_vec(b"abc".to_vec())) @@ -105,8 +111,10 @@ pub fn from_slice(v: &[u8]) -> RawBytes<&[u8]> { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::raw_bytes::{from_str, from_string}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::raw_bytes::from_str; +/// use datasketches::hash::value::raw_bytes::from_string; +/// /// assert_eq!( /// calculate_hash(from_str("abc")), /// calculate_hash(from_string("abc".to_owned())) diff --git a/datasketches/src/hash_value/sign_extend.rs b/datasketches/src/hash/value/sign_extend.rs similarity index 81% rename from datasketches/src/hash_value/sign_extend.rs rename to datasketches/src/hash/value/sign_extend.rs index c1ec518c..0672f93a 100644 --- a/datasketches/src/hash_value/sign_extend.rs +++ b/datasketches/src/hash/value/sign_extend.rs @@ -25,8 +25,8 @@ use std::hash::Hash; use std::hash::Hasher; -use super::value::HashStrategy; -use super::value::Value; +use super::HashStrategy; +use super::Value; /// An integer value wrapper that sign-extends the value before hashing. /// @@ -42,8 +42,10 @@ pub struct SignExtendStrategy; /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::sign_extend::{from_i8, from_u8}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::sign_extend::from_i8; +/// use datasketches::hash::value::sign_extend::from_u8; +/// /// assert_eq!(calculate_hash(from_i8(-1)), calculate_hash(from_u8(255))); /// assert_eq!(calculate_hash(from_i8(-1)), calculate_hash(-1i64)); /// assert_eq!(calculate_hash(from_i8(42)), calculate_hash(42i64)); @@ -59,8 +61,10 @@ pub fn from_i8(v: i8) -> SignExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::sign_extend::{from_i8, from_u8}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::sign_extend::from_i8; +/// use datasketches::hash::value::sign_extend::from_u8; +/// /// assert_eq!(calculate_hash(from_u8(255)), calculate_hash(from_i8(-1))); /// assert_eq!(calculate_hash(from_u8(255)), calculate_hash(-1i64)); /// assert_eq!(calculate_hash(from_u8(1)), calculate_hash(1i64)); @@ -74,8 +78,10 @@ pub fn from_u8(v: u8) -> SignExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::sign_extend::{from_i16, from_u16}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::sign_extend::from_i16; +/// use datasketches::hash::value::sign_extend::from_u16; +/// /// assert_eq!( /// calculate_hash(from_i16(-1)), /// calculate_hash(from_u16(65535)) @@ -94,8 +100,10 @@ pub fn from_i16(v: i16) -> SignExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::sign_extend::{from_i16, from_u16}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::sign_extend::from_i16; +/// use datasketches::hash::value::sign_extend::from_u16; +/// /// assert_eq!( /// calculate_hash(from_u16(65535)), /// calculate_hash(from_i16(-1)) @@ -112,8 +120,10 @@ pub fn from_u16(v: u16) -> SignExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::sign_extend::{from_i32, from_u32}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::sign_extend::from_i32; +/// use datasketches::hash::value::sign_extend::from_u32; +/// /// assert_eq!( /// calculate_hash(from_i32(-1)), /// calculate_hash(from_u32(4294967295)) @@ -132,8 +142,10 @@ pub fn from_i32(v: i32) -> SignExtend { /// # Examples /// /// ``` -/// # use datasketches::hash_value::calculate_hash; -/// # use datasketches::hash_value::sign_extend::{from_i32, from_u32}; +/// use datasketches::hash::value::calculate_hash; +/// use datasketches::hash::value::sign_extend::from_i32; +/// use datasketches::hash::value::sign_extend::from_u32; +/// /// assert_eq!( /// calculate_hash(from_u32(4294967295)), /// calculate_hash(from_i32(-1)) diff --git a/datasketches/src/hash/xxhash.rs b/datasketches/src/hash/xxhash.rs index 25852ea5..04c3e473 100644 --- a/datasketches/src/hash/xxhash.rs +++ b/datasketches/src/hash/xxhash.rs @@ -17,6 +17,8 @@ use std::hash::Hasher; +use crate::hash::read_u64_le; + const DEFAULT_SEED: u64 = 0; // Unsigned 64-bit primes from xxhash64. @@ -76,7 +78,7 @@ impl XxHash64 { let mut idx = 0; let buf = &self.buffer[..self.buffer_len]; while idx + 8 <= buf.len() { - let mut k1 = super::read_u64_le(&buf[idx..idx + 8]); + let mut k1 = read_u64_le(&buf[idx..idx + 8]); k1 = k1.wrapping_mul(P2); k1 = k1.rotate_left(31); k1 = k1.wrapping_mul(P1); @@ -86,7 +88,7 @@ impl XxHash64 { } if idx + 4 <= buf.len() { - let k1 = super::read_u64_le(&buf[idx..idx + 4]); + let k1 = read_u64_le(&buf[idx..idx + 4]); hash ^= k1.wrapping_mul(P1); hash = hash.rotate_left(23).wrapping_mul(P2).wrapping_add(P3); idx += 4; @@ -116,10 +118,10 @@ impl XxHash64 { #[inline] fn update(&mut self, chunk: &[u8]) { - self.v1 = round(self.v1, super::read_u64_le(&chunk[0..8])); - self.v2 = round(self.v2, super::read_u64_le(&chunk[8..16])); - self.v3 = round(self.v3, super::read_u64_le(&chunk[16..24])); - self.v4 = round(self.v4, super::read_u64_le(&chunk[24..32])); + self.v1 = round(self.v1, read_u64_le(&chunk[0..8])); + self.v2 = round(self.v2, read_u64_le(&chunk[8..16])); + self.v3 = round(self.v3, read_u64_le(&chunk[16..24])); + self.v4 = round(self.v4, read_u64_le(&chunk[24..32])); } } diff --git a/datasketches/src/hash_value/value.rs b/datasketches/src/hash_value/value.rs deleted file mode 100644 index be857b06..00000000 --- a/datasketches/src/hash_value/value.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -//! Shared value wrapper and hashing strategy support. - -use std::cmp::Ordering; -use std::fmt; -use std::hash::Hash; -use std::hash::Hasher; -use std::marker::PhantomData; -use std::ops::Deref; -use std::ops::DerefMut; - -/// A value wrapper that hashes its inner value with strategy `S`. -/// -/// Most users should prefer the strategy-specific constructors. -pub struct Value { - value: T, - strategy: PhantomData S>, -} - -impl Value { - /// Create a value wrapper. - #[inline(always)] - pub fn new(value: T) -> Self { - Self { - value, - strategy: PhantomData, - } - } - - /// Get the value out. - #[inline(always)] - pub fn into_inner(self) -> T { - self.value - } -} - -impl Deref for Value { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -impl DerefMut for Value { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.value - } -} - -impl Clone for Value { - fn clone(&self) -> Self { - Self::new(self.value.clone()) - } -} - -impl Copy for Value {} - -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - self.value == other.value - } -} - -impl Eq for Value {} - -impl PartialOrd for Value { - fn partial_cmp(&self, other: &Self) -> Option { - self.value.partial_cmp(&other.value) - } -} - -impl Ord for Value { - fn cmp(&self, other: &Self) -> Ordering { - self.value.cmp(&other.value) - } -} - -impl fmt::Debug for Value { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.value, f) - } -} - -impl fmt::Display for Value { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.value, f) - } -} - -impl> Hash for Value { - fn hash(&self, state: &mut H) { - S::hash(&self.value, state); - } -} - -#[doc(hidden)] -pub trait HashStrategy { - fn hash(value: &T, state: &mut H); -} diff --git a/datasketches/src/hll/mod.rs b/datasketches/src/hll/mod.rs index ec300a8a..b6fece07 100644 --- a/datasketches/src/hll/mod.rs +++ b/datasketches/src/hll/mod.rs @@ -75,9 +75,10 @@ //! # Usage //! //! ``` -//! # use datasketches::hll::HllSketch; -//! # use datasketches::hll::HllType; -//! # use datasketches::common::NumStdDev; +//! use datasketches::common::NumStdDev; +//! use datasketches::hll::HllSketch; +//! use datasketches::hll::HllType; +//! //! let mut sketch = HllSketch::new(12, HllType::Hll8); //! sketch.update("apple"); //! let upper = sketch.upper_bound(NumStdDev::Two); @@ -87,9 +88,10 @@ //! # Union //! //! ``` -//! # use datasketches::hll::HllSketch; -//! # use datasketches::hll::HllType; -//! # use datasketches::hll::HllUnion; +//! use datasketches::hll::HllSketch; +//! use datasketches::hll::HllType; +//! use datasketches::hll::HllUnion; +//! //! let mut left = HllSketch::new(10, HllType::Hll8); //! let mut right = HllSketch::new(10, HllType::Hll8); //! left.update("apple"); @@ -174,7 +176,10 @@ const RESIZE_DENOMINATOR: u32 = 4; /// # Examples /// /// ``` -/// # use datasketches::hll::{HllSketch, HllType, Coupon}; +/// use datasketches::hll::Coupon; +/// use datasketches::hll::HllSketch; +/// use datasketches::hll::HllType; +/// /// let c = Coupon::from_value("hello"); /// /// let mut sketch1 = HllSketch::new(10, HllType::Hll8); @@ -206,8 +211,8 @@ impl Coupon { /// Compute the HLL coupon for a hashable value. /// - /// You may use [`hash_value`](crate::hash_value) wrappers when matching other datasketches - /// implementations require a specific value hashing strategy. + /// You may use [`hash::value`](crate::hash::value) wrappers when another DataSketches + /// implementation requires a specific value hashing strategy. /// /// Hashes `value` using MurmurHash3 128-bit and packs the result into a coupon: /// the low 26 bits of the low hash word become the slot index, and the diff --git a/datasketches/src/hll/sketch.rs b/datasketches/src/hll/sketch.rs index 41e838e9..9efd6ff4 100644 --- a/datasketches/src/hll/sketch.rs +++ b/datasketches/src/hll/sketch.rs @@ -82,8 +82,9 @@ impl HllSketch { /// # Examples /// /// ``` - /// # use datasketches::hll::HllSketch; - /// # use datasketches::hll::HllType; + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// /// let sketch = HllSketch::new(12, HllType::Hll8); /// assert_eq!(sketch.lg_config_k(), 12); /// ``` @@ -161,8 +162,8 @@ impl HllSketch { /// Accepts any type that implements [`Hash`]. The value is hashed and converted to /// an internal coupon, which is then inserted into the sketch. /// - /// You may use [`hash_value`](crate::hash_value) wrappers when matching other datasketches - /// implementations require a specific value hashing strategy. + /// You may use [`hash::value`](crate::hash::value) wrappers when another DataSketches + /// implementation requires a specific value hashing strategy. /// /// If you need to insert the same logical value into multiple sketches, consider /// pre-computing the coupon with [`Coupon::from_value`] and calling @@ -172,15 +173,16 @@ impl HllSketch { /// # Examples /// /// ``` - /// # use datasketches::hll::HllSketch; - /// # use datasketches::hll::HllType; - /// # use datasketches::hash_value; + /// use datasketches::hash::value::raw_bytes; + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// /// let mut sketch = HllSketch::new(10, HllType::Hll8); /// sketch.update("apple"); /// assert!(sketch.estimate() >= 1.0); /// /// let mut sketch = HllSketch::new(10, HllType::Hll8); - /// sketch.update(hash_value::raw_bytes::from_str("apple")); + /// sketch.update(raw_bytes::from_str("apple")); /// assert!(sketch.estimate() >= 1.0); /// ``` pub fn update(&mut self, value: T) { @@ -200,7 +202,10 @@ impl HllSketch { /// # Examples /// /// ``` - /// # use datasketches::hll::{HllSketch, HllType, Coupon}; + /// use datasketches::hll::Coupon; + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// /// let c = Coupon::from_value("apple"); /// let mut sketch = HllSketch::new(10, HllType::Hll8); /// sketch.update_with_coupon(c); @@ -242,8 +247,9 @@ impl HllSketch { /// # Examples /// /// ``` - /// # use datasketches::hll::HllSketch; - /// # use datasketches::hll::HllType; + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// /// let mut sketch = HllSketch::new(10, HllType::Hll8); /// sketch.update("apple"); /// assert!(sketch.estimate() >= 1.0); @@ -291,11 +297,13 @@ impl HllSketch { /// # Examples /// /// ``` - /// # use datasketches::hll::HllSketch; - /// # use datasketches::hll::HllType; - /// # let mut sketch = HllSketch::new(10, HllType::Hll8); - /// # sketch.update("apple"); - /// # let bytes = sketch.serialize(); + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// + /// let mut sketch = HllSketch::new(10, HllType::Hll8); + /// sketch.update("apple"); + /// + /// let bytes = sketch.serialize(); /// let decoded = HllSketch::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate() >= 1.0); /// ``` @@ -406,10 +414,12 @@ impl HllSketch { /// # Examples /// /// ``` - /// # use datasketches::hll::HllSketch; - /// # use datasketches::hll::HllType; - /// # let mut sketch = HllSketch::new(10, HllType::Hll8); - /// # sketch.update("apple"); + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// + /// let mut sketch = HllSketch::new(10, HllType::Hll8); + /// sketch.update("apple"); + /// /// let bytes = sketch.serialize(); /// let decoded = HllSketch::deserialize(&bytes).unwrap(); /// assert!(decoded.estimate() >= 1.0); diff --git a/datasketches/src/hll/union.rs b/datasketches/src/hll/union.rs index df995f6c..4de24d99 100644 --- a/datasketches/src/hll/union.rs +++ b/datasketches/src/hll/union.rs @@ -70,8 +70,9 @@ impl HllUnion { /// # Examples /// /// ``` - /// # use datasketches::hll::HllType; - /// # use datasketches::hll::HllUnion; + /// use datasketches::hll::HllType; + /// use datasketches::hll::HllUnion; + /// /// let mut union = HllUnion::new(10); /// union.update_value("apple"); /// let result = union.to_sketch(HllType::Hll8); @@ -98,8 +99,9 @@ impl HllUnion { /// # Examples /// /// ``` - /// # use datasketches::hll::HllType; - /// # use datasketches::hll::HllUnion; + /// use datasketches::hll::HllType; + /// use datasketches::hll::HllUnion; + /// /// let mut union = HllUnion::new(10); /// union.update_value("apple"); /// let result = union.to_sketch(HllType::Hll8); @@ -119,9 +121,10 @@ impl HllUnion { /// # Examples /// /// ``` - /// # use datasketches::hll::HllSketch; - /// # use datasketches::hll::HllType; - /// # use datasketches::hll::HllUnion; + /// use datasketches::hll::HllSketch; + /// use datasketches::hll::HllType; + /// use datasketches::hll::HllUnion; + /// /// let mut left = HllSketch::new(10, HllType::Hll8); /// let mut right = HllSketch::new(10, HllType::Hll8); /// left.update("apple"); @@ -251,8 +254,9 @@ impl HllUnion { /// # Examples /// /// ``` - /// # use datasketches::hll::HllType; - /// # use datasketches::hll::HllUnion; + /// use datasketches::hll::HllType; + /// use datasketches::hll::HllUnion; + /// /// let mut union = HllUnion::new(10); /// union.update_value("apple"); /// let result = union.to_sketch(HllType::Hll6); diff --git a/datasketches/src/lib.rs b/datasketches/src/lib.rs index 47cd37e7..e169c4c7 100644 --- a/datasketches/src/lib.rs +++ b/datasketches/src/lib.rs @@ -44,19 +44,16 @@ pub mod hll; #[cfg(feature = "tdigest")] pub mod tdigest; #[cfg(any(feature = "theta", feature = "tuple"))] -mod theta_family; +mod thetafamily; #[cfg(any(feature = "theta", feature = "tuple"))] -pub use self::theta_family::common as thetacommon; +pub use self::thetafamily::common as thetacommon; #[cfg(feature = "theta")] -pub use self::theta_family::theta; +pub use self::thetafamily::theta; #[cfg(feature = "tuple")] -pub use self::theta_family::tuple; +pub use self::thetafamily::tuple; // common modules pub mod codec; pub mod common; pub mod error; -pub mod hash_value; - -// private internal modules -mod hash; +pub mod hash; diff --git a/datasketches/src/tdigest/mod.rs b/datasketches/src/tdigest/mod.rs index b3bcf00b..5590c754 100644 --- a/datasketches/src/tdigest/mod.rs +++ b/datasketches/src/tdigest/mod.rs @@ -51,7 +51,8 @@ //! # Usage //! //! ``` -//! # use datasketches::tdigest::TDigestMut; +//! use datasketches::tdigest::TDigestMut; +//! //! let mut sketch = TDigestMut::new(100); //! sketch.update(1.0); //! sketch.update(2.0); diff --git a/datasketches/src/tdigest/sketch.rs b/datasketches/src/tdigest/sketch.rs index 45c92227..3f26b007 100644 --- a/datasketches/src/tdigest/sketch.rs +++ b/datasketches/src/tdigest/sketch.rs @@ -77,7 +77,8 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; + /// use datasketches::tdigest::TDigestMut; + /// /// let sketch = TDigestMut::new(100); /// assert_eq!(sketch.k(), 100); /// ``` @@ -104,7 +105,8 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; + /// use datasketches::tdigest::TDigestMut; + /// /// let sketch = TDigestMut::try_new(20).unwrap(); /// assert_eq!(sketch.k(), 20); /// ``` @@ -163,7 +165,8 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; + /// use datasketches::tdigest::TDigestMut; + /// /// let mut sketch = TDigestMut::new(100); /// sketch.update(1.0); /// assert!(sketch.total_weight() >= 1); @@ -220,7 +223,8 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; + /// use datasketches::tdigest::TDigestMut; + /// /// let mut left = TDigestMut::new(100); /// let mut right = TDigestMut::new(100); /// left.update(1.0); @@ -259,7 +263,8 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; + /// use datasketches::tdigest::TDigestMut; + /// /// let mut sketch = TDigestMut::new(100); /// sketch.update(1.0); /// let frozen = sketch.freeze(); @@ -292,11 +297,12 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let cdf = sketch.cdf(&[1.5]).unwrap(); /// assert_eq!(cdf.len(), 2); /// ``` @@ -315,11 +321,12 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let pmf = sketch.pmf(&[1.5]).unwrap(); /// assert_eq!(pmf.len(), 2); /// ``` @@ -338,11 +345,12 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let rank = sketch.rank(2.0).unwrap(); /// assert!((0.0..=1.0).contains(&rank)); /// ``` @@ -371,11 +379,12 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let median = sketch.quantile(0.5).unwrap(); /// assert!((1.0..=3.0).contains(&median)); /// ``` @@ -394,9 +403,10 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # sketch.update(1.0); + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// sketch.update(1.0); /// let bytes = sketch.serialize(); /// let decoded = TDigestMut::deserialize(&bytes, false).unwrap(); /// assert_eq!(decoded.max_value(), Some(1.0)); @@ -486,11 +496,12 @@ impl TDigestMut { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # sketch.update(1.0); - /// # sketch.update(2.0); - /// # let bytes = sketch.serialize(); + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// sketch.update(1.0); + /// sketch.update(2.0); + /// let bytes = sketch.serialize(); /// let decoded = TDigestMut::deserialize(&bytes, false).unwrap(); /// assert_eq!(decoded.max_value(), Some(2.0)); /// ``` @@ -894,11 +905,12 @@ impl TDigest { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let digest = sketch.freeze(); /// let cdf = digest.cdf(&[1.5]).unwrap(); /// assert_eq!(cdf.len(), 2); @@ -930,11 +942,12 @@ impl TDigest { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let digest = sketch.freeze(); /// let pmf = digest.pmf(&[1.5]).unwrap(); /// assert_eq!(pmf.len(), 2); @@ -954,11 +967,12 @@ impl TDigest { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let digest = sketch.freeze(); /// let rank = digest.rank(2.0).unwrap(); /// assert!((0.0..=1.0).contains(&rank)); @@ -979,11 +993,12 @@ impl TDigest { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # for value in [1.0, 2.0, 3.0] { - /// # sketch.update(value); - /// # } + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// for value in [1.0, 2.0, 3.0] { + /// sketch.update(value); + /// } /// let digest = sketch.freeze(); /// let q = digest.quantile(0.5).unwrap(); /// assert!((1.0..=3.0).contains(&q)); @@ -998,10 +1013,11 @@ impl TDigest { /// # Examples /// /// ``` - /// # use datasketches::tdigest::TDigestMut; - /// # let mut sketch = TDigestMut::new(100); - /// # sketch.update(1.0); - /// # let digest = sketch.freeze(); + /// use datasketches::tdigest::TDigestMut; + /// + /// let mut sketch = TDigestMut::new(100); + /// sketch.update(1.0); + /// let digest = sketch.freeze(); /// let mut mutable = digest.unfreeze(); /// mutable.update(2.0); /// assert_eq!(mutable.total_weight(), 2); diff --git a/datasketches/src/theta_family/common/bounds_binomial_proportions.rs b/datasketches/src/theta_family/common/bounds_binomial_proportions.rs deleted file mode 100644 index b075833f..00000000 --- a/datasketches/src/theta_family/common/bounds_binomial_proportions.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use crate::error::Error; - -/// Computes an approximate lower bound for an unknown binomial proportion. -pub(crate) fn approximate_lower_bound_on_p( - n: u64, - k: u64, - num_std_devs: f64, -) -> Result { - check_inputs(n, k)?; - if n == 0 || k == 0 { - Ok(0.0) - } else if k == 1 { - Ok(exact_lower_bound_on_p_k_eq_1( - n, - delta_of_num_stdevs(num_std_devs), - )) - } else if k == n { - Ok(exact_lower_bound_on_p_k_eq_n( - n, - delta_of_num_stdevs(num_std_devs), - )) - } else { - let x = abramowitz_stegun_formula_26p5p22((n - k) as f64 + 1.0, k as f64, -num_std_devs); - Ok(1.0 - x) - } -} - -/// Computes an approximate upper bound for an unknown binomial proportion. -pub(crate) fn approximate_upper_bound_on_p( - n: u64, - k: u64, - num_std_devs: f64, -) -> Result { - check_inputs(n, k)?; - if n == 0 || k == n { - Ok(1.0) - } else if k == n - 1 { - Ok(exact_upper_bound_on_p_k_eq_minusone( - n, - delta_of_num_stdevs(num_std_devs), - )) - } else if k == 0 { - Ok(exact_upper_bound_on_p_k_eq_zero( - n, - delta_of_num_stdevs(num_std_devs), - )) - } else { - let x = abramowitz_stegun_formula_26p5p22((n - k) as f64, k as f64 + 1.0, num_std_devs); - Ok(1.0 - x) - } -} - -fn check_inputs(n: u64, k: u64) -> Result<(), Error> { - if k > n { - return Err(Error::invalid_argument(format!( - "k cannot exceed n: k={k}, n={n}" - ))); - } - Ok(()) -} - -fn delta_of_num_stdevs(kappa: f64) -> f64 { - normal_cdf(-kappa) -} - -fn normal_cdf(x: f64) -> f64 { - 0.5 * (1.0 + erf(x / 2.0_f64.sqrt())) -} - -fn erf(x: f64) -> f64 { - if x < 0.0 { - -erf_of_nonneg(-x) - } else { - erf_of_nonneg(x) - } -} - -fn erf_of_nonneg(x: f64) -> f64 { - let a1 = 0.0705230784; - let a2 = 0.0422820123; - let a3 = 0.0092705272; - let a4 = 0.0001520143; - let a5 = 0.0002765672; - let a6 = 0.0000430638; - let x2 = x * x; - let x3 = x2 * x; - let x4 = x2 * x2; - let x5 = x2 * x3; - let x6 = x3 * x3; - let sum = 1.0 + (a1 * x) + (a2 * x2) + (a3 * x3) + (a4 * x4) + (a5 * x5) + (a6 * x6); - let sum2 = sum * sum; - let sum4 = sum2 * sum2; - let sum8 = sum4 * sum4; - let sum16 = sum8 * sum8; - 1.0 - (1.0 / sum16) -} - -fn abramowitz_stegun_formula_26p5p22(a: f64, b: f64, yp: f64) -> f64 { - let b2m1 = (2.0 * b) - 1.0; - let a2m1 = (2.0 * a) - 1.0; - let lambda = ((yp * yp) - 3.0) / 6.0; - let reciprocal_sum = (1.0 / a2m1) + (1.0 / b2m1); - let h = 2.0 / reciprocal_sum; - let term1 = (yp * (h + lambda).sqrt()) / h; - let term2 = (1.0 / b2m1) - (1.0 / a2m1); - let term3 = (lambda + (5.0 / 6.0)) - (2.0 / (3.0 * h)); - let w = term1 - (term2 * term3); - a / (a + (b * (2.0 * w).exp())) -} - -fn exact_upper_bound_on_p_k_eq_zero(n: u64, delta: f64) -> f64 { - 1.0 - delta.powf(1.0 / n as f64) -} - -fn exact_lower_bound_on_p_k_eq_n(n: u64, delta: f64) -> f64 { - delta.powf(1.0 / n as f64) -} - -fn exact_lower_bound_on_p_k_eq_1(n: u64, delta: f64) -> f64 { - 1.0 - (1.0 - delta).powf(1.0 / n as f64) -} - -fn exact_upper_bound_on_p_k_eq_minusone(n: u64, delta: f64) -> f64 { - (1.0 - delta).powf(1.0 / n as f64) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn rejects_invalid_counts() { - assert!(approximate_lower_bound_on_p(1, 2, 2.0).is_err()); - assert!(approximate_upper_bound_on_p(1, 2, 2.0).is_err()); - } - - #[test] - fn computes_exact_edge_cases() { - assert_eq!(approximate_lower_bound_on_p(0, 0, 2.0).unwrap(), 0.0); - assert_eq!(approximate_upper_bound_on_p(0, 0, 2.0).unwrap(), 1.0); - assert_eq!(approximate_lower_bound_on_p(10, 0, 2.0).unwrap(), 0.0); - assert_eq!(approximate_upper_bound_on_p(10, 10, 2.0).unwrap(), 1.0); - } - - #[test] - fn matches_cross_language_reference_vectors() { - const LOWER: [f64; 6] = [ - 0.0, - 0.004592032688529923, - 0.04725537386564205, - 0.1396230607626959, - 0.2735831034867167, - 0.4692424353373485, - ]; - const UPPER: [f64; 6] = [ - 0.5307575646626514, - 0.7264168965132833, - 0.860376939237304, - 0.952744626134358, - 0.9954079673114701, - 1.0, - ]; - - for k in 0..=5 { - let lower = approximate_lower_bound_on_p(5, k, 2.0).unwrap(); - let upper = approximate_upper_bound_on_p(5, k, 2.0).unwrap(); - assert!((lower - LOWER[k as usize]).abs() < 1e-14); - assert!((upper - UPPER[k as usize]).abs() < 1e-14); - } - } -} diff --git a/datasketches/src/theta_family/common/a_not_b.rs b/datasketches/src/thetafamily/common/a_not_b.rs similarity index 100% rename from datasketches/src/theta_family/common/a_not_b.rs rename to datasketches/src/thetafamily/common/a_not_b.rs diff --git a/datasketches/src/theta_family/common/binomial_bounds.rs b/datasketches/src/thetafamily/common/binomial_bounds.rs similarity index 88% rename from datasketches/src/theta_family/common/binomial_bounds.rs rename to datasketches/src/thetafamily/common/binomial_bounds.rs index 2950d1de..d3a3dde8 100644 --- a/datasketches/src/theta_family/common/binomial_bounds.rs +++ b/datasketches/src/thetafamily/common/binomial_bounds.rs @@ -341,6 +341,130 @@ pub(crate) fn upper_bound( Ok(estimate.max(ub)) } +/// Computes an approximate lower bound for an unknown binomial proportion. +pub(crate) fn approximate_lower_bound_on_p( + n: u64, + k: u64, + num_std_devs: f64, +) -> Result { + check_proportion_inputs(n, k)?; + if n == 0 || k == 0 { + Ok(0.0) + } else if k == 1 { + Ok(exact_lower_bound_on_p_k_eq_1( + n, + delta_of_num_stdevs(num_std_devs), + )) + } else if k == n { + Ok(exact_lower_bound_on_p_k_eq_n( + n, + delta_of_num_stdevs(num_std_devs), + )) + } else { + let x = abramowitz_stegun_formula_26p5p22((n - k) as f64 + 1.0, k as f64, -num_std_devs); + Ok(1.0 - x) + } +} + +/// Computes an approximate upper bound for an unknown binomial proportion. +pub(crate) fn approximate_upper_bound_on_p( + n: u64, + k: u64, + num_std_devs: f64, +) -> Result { + check_proportion_inputs(n, k)?; + if n == 0 || k == n { + Ok(1.0) + } else if k == n - 1 { + Ok(exact_upper_bound_on_p_k_eq_minusone( + n, + delta_of_num_stdevs(num_std_devs), + )) + } else if k == 0 { + Ok(exact_upper_bound_on_p_k_eq_zero( + n, + delta_of_num_stdevs(num_std_devs), + )) + } else { + let x = abramowitz_stegun_formula_26p5p22((n - k) as f64, k as f64 + 1.0, num_std_devs); + Ok(1.0 - x) + } +} + +fn check_proportion_inputs(n: u64, k: u64) -> Result<(), Error> { + if k > n { + return Err(Error::invalid_argument(format!( + "k cannot exceed n: k={k}, n={n}" + ))); + } + Ok(()) +} + +fn delta_of_num_stdevs(kappa: f64) -> f64 { + normal_cdf(-kappa) +} + +fn normal_cdf(x: f64) -> f64 { + 0.5 * (1.0 + erf(x / 2.0_f64.sqrt())) +} + +fn erf(x: f64) -> f64 { + if x < 0.0 { + -erf_of_nonneg(-x) + } else { + erf_of_nonneg(x) + } +} + +fn erf_of_nonneg(x: f64) -> f64 { + let a1 = 0.0705230784; + let a2 = 0.0422820123; + let a3 = 0.0092705272; + let a4 = 0.0001520143; + let a5 = 0.0002765672; + let a6 = 0.0000430638; + let x2 = x * x; + let x3 = x2 * x; + let x4 = x2 * x2; + let x5 = x2 * x3; + let x6 = x3 * x3; + let sum = 1.0 + (a1 * x) + (a2 * x2) + (a3 * x3) + (a4 * x4) + (a5 * x5) + (a6 * x6); + let sum2 = sum * sum; + let sum4 = sum2 * sum2; + let sum8 = sum4 * sum4; + let sum16 = sum8 * sum8; + 1.0 - (1.0 / sum16) +} + +fn abramowitz_stegun_formula_26p5p22(a: f64, b: f64, yp: f64) -> f64 { + let b2m1 = (2.0 * b) - 1.0; + let a2m1 = (2.0 * a) - 1.0; + let lambda = ((yp * yp) - 3.0) / 6.0; + let reciprocal_sum = (1.0 / a2m1) + (1.0 / b2m1); + let h = 2.0 / reciprocal_sum; + let term1 = (yp * (h + lambda).sqrt()) / h; + let term2 = (1.0 / b2m1) - (1.0 / a2m1); + let term3 = (lambda + (5.0 / 6.0)) - (2.0 / (3.0 * h)); + let w = term1 - (term2 * term3); + a / (a + (b * (2.0 * w).exp())) +} + +fn exact_upper_bound_on_p_k_eq_zero(n: u64, delta: f64) -> f64 { + 1.0 - delta.powf(1.0 / n as f64) +} + +fn exact_lower_bound_on_p_k_eq_n(n: u64, delta: f64) -> f64 { + delta.powf(1.0 / n as f64) +} + +fn exact_lower_bound_on_p_k_eq_1(n: u64, delta: f64) -> f64 { + 1.0 - (1.0 - delta).powf(1.0 / n as f64) +} + +fn exact_upper_bound_on_p_k_eq_minusone(n: u64, delta: f64) -> f64 { + (1.0 - delta).powf(1.0 / n as f64) +} + /// Computes the lower bound using a Gaussian approximation with continuity correction. fn cont_classic_lb(num_samples: u64, theta: f64, num_std_devs: f64) -> f64 { let n_hat = (num_samples as f64 - 0.5) / theta; @@ -746,4 +870,45 @@ mod tests { let result = upper_bound(0, 0.5, NumStdDev::One, false).unwrap(); assert!(result > 0.0); // Upper bound should exist } + + #[test] + fn rejects_invalid_proportion_counts() { + assert!(approximate_lower_bound_on_p(1, 2, 2.0).is_err()); + assert!(approximate_upper_bound_on_p(1, 2, 2.0).is_err()); + } + + #[test] + fn computes_exact_proportion_edge_cases() { + assert_eq!(approximate_lower_bound_on_p(0, 0, 2.0).unwrap(), 0.0); + assert_eq!(approximate_upper_bound_on_p(0, 0, 2.0).unwrap(), 1.0); + assert_eq!(approximate_lower_bound_on_p(10, 0, 2.0).unwrap(), 0.0); + assert_eq!(approximate_upper_bound_on_p(10, 10, 2.0).unwrap(), 1.0); + } + + #[test] + fn matches_cross_language_proportion_reference_vectors() { + const LOWER: [f64; 6] = [ + 0.0, + 0.004592032688529923, + 0.04725537386564205, + 0.1396230607626959, + 0.2735831034867167, + 0.4692424353373485, + ]; + const UPPER: [f64; 6] = [ + 0.5307575646626514, + 0.7264168965132833, + 0.860376939237304, + 0.952744626134358, + 0.9954079673114701, + 1.0, + ]; + + for k in 0..=5 { + let lower = approximate_lower_bound_on_p(5, k, 2.0).unwrap(); + let upper = approximate_upper_bound_on_p(5, k, 2.0).unwrap(); + assert!((lower - LOWER[k as usize]).abs() < 1e-14); + assert!((upper - UPPER[k as usize]).abs() < 1e-14); + } + } } diff --git a/datasketches/src/theta_family/common/constants.rs b/datasketches/src/thetafamily/common/constants.rs similarity index 100% rename from datasketches/src/theta_family/common/constants.rs rename to datasketches/src/thetafamily/common/constants.rs diff --git a/datasketches/src/theta_family/common/hash_table.rs b/datasketches/src/thetafamily/common/hash_table.rs similarity index 100% rename from datasketches/src/theta_family/common/hash_table.rs rename to datasketches/src/thetafamily/common/hash_table.rs diff --git a/datasketches/src/theta_family/common/intersection.rs b/datasketches/src/thetafamily/common/intersection.rs similarity index 100% rename from datasketches/src/theta_family/common/intersection.rs rename to datasketches/src/thetafamily/common/intersection.rs diff --git a/datasketches/src/theta_family/common/jaccard_similarity.rs b/datasketches/src/thetafamily/common/jaccard_similarity.rs similarity index 97% rename from datasketches/src/theta_family/common/jaccard_similarity.rs rename to datasketches/src/thetafamily/common/jaccard_similarity.rs index d2a1704a..4e97b30d 100644 --- a/datasketches/src/theta_family/common/jaccard_similarity.rs +++ b/datasketches/src/thetafamily/common/jaccard_similarity.rs @@ -21,7 +21,7 @@ use crate::hash::compute_seed_hash; use crate::thetacommon::RetainedEntry; use crate::thetacommon::ThetaFamilySketchView; use crate::thetacommon::ThetaKeySketchView; -use crate::thetacommon::bounds_binomial_proportions; +use crate::thetacommon::binomial_bounds; use crate::thetacommon::constants::MAX_LG_K; use crate::thetacommon::constants::MAX_THETA; use crate::thetacommon::constants::MIN_LG_K; @@ -92,13 +92,13 @@ impl JaccardSimilarity { let adjustment = NUM_STD_DEVS * sampling_adjuster(sampling_probability); Ok(Self { - lower_bound: bounds_binomial_proportions::approximate_lower_bound_on_p( + lower_bound: binomial_bounds::approximate_lower_bound_on_p( union_count, intersection_count, adjustment, )?, estimate: intersection_count as f64 / union_count as f64, - upper_bound: bounds_binomial_proportions::approximate_upper_bound_on_p( + upper_bound: binomial_bounds::approximate_upper_bound_on_p( union_count, intersection_count, adjustment, diff --git a/datasketches/src/theta_family/common/mod.rs b/datasketches/src/thetafamily/common/mod.rs similarity index 98% rename from datasketches/src/theta_family/common/mod.rs rename to datasketches/src/thetafamily/common/mod.rs index 43141582..199e5cc9 100644 --- a/datasketches/src/theta_family/common/mod.rs +++ b/datasketches/src/thetafamily/common/mod.rs @@ -19,7 +19,6 @@ pub(crate) mod a_not_b; pub(crate) mod binomial_bounds; -pub(crate) mod bounds_binomial_proportions; pub(crate) mod constants; pub(crate) mod hash_table; pub(crate) mod intersection; diff --git a/datasketches/src/theta_family/common/union.rs b/datasketches/src/thetafamily/common/union.rs similarity index 100% rename from datasketches/src/theta_family/common/union.rs rename to datasketches/src/thetafamily/common/union.rs diff --git a/datasketches/src/theta_family/mod.rs b/datasketches/src/thetafamily/mod.rs similarity index 100% rename from datasketches/src/theta_family/mod.rs rename to datasketches/src/thetafamily/mod.rs diff --git a/datasketches/src/theta_family/theta/a_not_b.rs b/datasketches/src/thetafamily/theta/a_not_b.rs similarity index 97% rename from datasketches/src/theta_family/theta/a_not_b.rs rename to datasketches/src/thetafamily/theta/a_not_b.rs index bef222c4..7def6e90 100644 --- a/datasketches/src/theta_family/theta/a_not_b.rs +++ b/datasketches/src/thetafamily/theta/a_not_b.rs @@ -35,7 +35,9 @@ use crate::thetacommon::a_not_b::ANotBOperator; /// # Examples /// /// ``` -/// # use datasketches::theta::{ThetaANotB, ThetaSketchBuilder}; +/// use datasketches::theta::ThetaANotB; +/// use datasketches::theta::ThetaSketchBuilder; +/// /// let mut a = ThetaSketchBuilder::default().build(); /// a.update("apple"); /// a.update("banana"); diff --git a/datasketches/src/theta_family/theta/bit_pack.rs b/datasketches/src/thetafamily/theta/bit_pack.rs similarity index 100% rename from datasketches/src/theta_family/theta/bit_pack.rs rename to datasketches/src/thetafamily/theta/bit_pack.rs diff --git a/datasketches/src/theta_family/theta/hash_table.rs b/datasketches/src/thetafamily/theta/hash_table.rs similarity index 100% rename from datasketches/src/theta_family/theta/hash_table.rs rename to datasketches/src/thetafamily/theta/hash_table.rs diff --git a/datasketches/src/theta_family/theta/intersection.rs b/datasketches/src/thetafamily/theta/intersection.rs similarity index 100% rename from datasketches/src/theta_family/theta/intersection.rs rename to datasketches/src/thetafamily/theta/intersection.rs diff --git a/datasketches/src/theta_family/theta/jaccard_similarity.rs b/datasketches/src/thetafamily/theta/jaccard_similarity.rs similarity index 95% rename from datasketches/src/theta_family/theta/jaccard_similarity.rs rename to datasketches/src/thetafamily/theta/jaccard_similarity.rs index 0c1937f8..83beff0e 100644 --- a/datasketches/src/theta_family/theta/jaccard_similarity.rs +++ b/datasketches/src/thetafamily/theta/jaccard_similarity.rs @@ -31,7 +31,9 @@ use crate::thetacommon::jaccard_similarity::JaccardSimilarityOperator; /// # Examples /// /// ``` -/// # use datasketches::theta::{ThetaJaccardSimilarity, ThetaSketchBuilder}; +/// use datasketches::theta::ThetaJaccardSimilarity; +/// use datasketches::theta::ThetaSketchBuilder; +/// /// let mut a = ThetaSketchBuilder::default().build(); /// let mut b = ThetaSketchBuilder::default().build(); /// a.update("apple"); diff --git a/datasketches/src/theta_family/theta/mod.rs b/datasketches/src/thetafamily/theta/mod.rs similarity index 97% rename from datasketches/src/theta_family/theta/mod.rs rename to datasketches/src/thetafamily/theta/mod.rs index 87f21fe6..e63fffec 100644 --- a/datasketches/src/theta_family/theta/mod.rs +++ b/datasketches/src/thetafamily/theta/mod.rs @@ -33,7 +33,8 @@ //! # Usage //! //! ``` -//! # use datasketches::theta::ThetaSketchBuilder; +//! use datasketches::theta::ThetaSketchBuilder; +//! //! let mut sketch = ThetaSketchBuilder::default().build(); //! sketch.update("apple"); //! assert!(sketch.estimate() >= 1.0); diff --git a/datasketches/src/theta_family/theta/serialization.rs b/datasketches/src/thetafamily/theta/serialization.rs similarity index 100% rename from datasketches/src/theta_family/theta/serialization.rs rename to datasketches/src/thetafamily/theta/serialization.rs diff --git a/datasketches/src/theta_family/theta/sketch.rs b/datasketches/src/thetafamily/theta/sketch.rs similarity index 97% rename from datasketches/src/theta_family/theta/sketch.rs rename to datasketches/src/thetafamily/theta/sketch.rs index 3be2441e..5c1f7615 100644 --- a/datasketches/src/theta_family/theta/sketch.rs +++ b/datasketches/src/thetafamily/theta/sketch.rs @@ -106,13 +106,13 @@ pub struct ThetaSketch { impl ThetaSketch { /// Update the sketch with a hashable value. /// - /// You may use [`hash_value`](crate::hash_value) wrappers when matching other datasketches - /// implementations require a specific value hashing strategy. + /// You may use [`hash::value`](crate::hash::value) wrappers when another DataSketches + /// implementation requires a specific value hashing strategy. /// /// # Examples /// /// ``` - /// use datasketches::hash_value; + /// use datasketches::hash::value::raw_bytes; /// use datasketches::theta::ThetaSketchBuilder; /// /// let mut sketch = ThetaSketchBuilder::default().build(); @@ -120,7 +120,7 @@ impl ThetaSketch { /// assert!(sketch.estimate() >= 1.0); /// /// let mut sketch = ThetaSketchBuilder::default().build(); - /// sketch.update(hash_value::raw_bytes::from_str("apple")); + /// sketch.update(raw_bytes::from_str("apple")); /// assert!(sketch.estimate() >= 1.0); /// ``` pub fn update(&mut self, value: T) { @@ -132,9 +132,10 @@ impl ThetaSketch { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; - /// # let mut sketch = ThetaSketchBuilder::default().build(); - /// # sketch.update("apple"); + /// use datasketches::theta::ThetaSketchBuilder; + /// + /// let mut sketch = ThetaSketchBuilder::default().build(); + /// sketch.update("apple"); /// assert!(sketch.estimate() >= 1.0); /// ``` pub fn estimate(&self) -> f64 { @@ -196,9 +197,10 @@ impl ThetaSketch { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; - /// # let mut sketch = ThetaSketchBuilder::default().build(); - /// # sketch.update("apple"); + /// use datasketches::theta::ThetaSketchBuilder; + /// + /// let mut sketch = ThetaSketchBuilder::default().build(); + /// sketch.update("apple"); /// let mut iter = sketch.iter(); /// assert!(iter.next().is_some()); /// ``` @@ -213,7 +215,8 @@ impl ThetaSketch { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; + /// use datasketches::theta::ThetaSketchBuilder; + /// /// let mut sketch = ThetaSketchBuilder::default().build(); /// sketch.update("apple"); /// let compact = sketch.compact(true); @@ -935,7 +938,8 @@ impl ThetaSketchBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; + /// use datasketches::theta::ThetaSketchBuilder; + /// /// let sketch = ThetaSketchBuilder::default().lg_k(12).build(); /// assert_eq!(sketch.lg_k(), 12); /// ``` @@ -969,7 +973,8 @@ impl ThetaSketchBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; + /// use datasketches::theta::ThetaSketchBuilder; + /// /// ThetaSketchBuilder::default() /// .sampling_probability(0.5) /// .build(); @@ -988,7 +993,8 @@ impl ThetaSketchBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; + /// use datasketches::theta::ThetaSketchBuilder; + /// /// ThetaSketchBuilder::default().seed(7).build(); /// ``` pub fn seed(mut self, seed: u64) -> Self { @@ -1001,7 +1007,8 @@ impl ThetaSketchBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaSketchBuilder; + /// use datasketches::theta::ThetaSketchBuilder; + /// /// ThetaSketchBuilder::default().lg_k(10).build(); /// ``` pub fn build(self) -> ThetaSketch { diff --git a/datasketches/src/theta_family/theta/union.rs b/datasketches/src/thetafamily/theta/union.rs similarity index 95% rename from datasketches/src/theta_family/theta/union.rs rename to datasketches/src/thetafamily/theta/union.rs index 94a974f2..d5216128 100644 --- a/datasketches/src/theta_family/theta/union.rs +++ b/datasketches/src/thetafamily/theta/union.rs @@ -98,7 +98,8 @@ impl ThetaUnionBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaUnionBuilder; + /// use datasketches::theta::ThetaUnionBuilder; + /// /// ThetaUnionBuilder::default().lg_k(12).build(); /// ``` pub fn lg_k(mut self, lg_k: u8) -> Self { @@ -125,7 +126,8 @@ impl ThetaUnionBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaUnionBuilder; + /// use datasketches::theta::ThetaUnionBuilder; + /// /// ThetaUnionBuilder::default() /// .sampling_probability(0.5) /// .build(); @@ -144,7 +146,8 @@ impl ThetaUnionBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaUnionBuilder; + /// use datasketches::theta::ThetaUnionBuilder; + /// /// ThetaUnionBuilder::default().seed(7).build(); /// ``` pub fn seed(mut self, seed: u64) -> Self { @@ -157,7 +160,8 @@ impl ThetaUnionBuilder { /// # Examples /// /// ``` - /// # use datasketches::theta::ThetaUnionBuilder; + /// use datasketches::theta::ThetaUnionBuilder; + /// /// ThetaUnionBuilder::default().lg_k(10).build(); /// ``` pub fn build(self) -> ThetaUnion { diff --git a/datasketches/src/theta_family/tuple/a_not_b.rs b/datasketches/src/thetafamily/tuple/a_not_b.rs similarity index 96% rename from datasketches/src/theta_family/tuple/a_not_b.rs rename to datasketches/src/thetafamily/tuple/a_not_b.rs index 5584b9d0..b79430f7 100644 --- a/datasketches/src/theta_family/tuple/a_not_b.rs +++ b/datasketches/src/thetafamily/tuple/a_not_b.rs @@ -38,7 +38,10 @@ use crate::tuple::sketch::TupleSketchView; /// # Examples /// /// ``` -/// # use datasketches::tuple::{DefaultUpdatePolicy, TupleANotB, TupleSketchBuilder}; +/// use datasketches::tuple::DefaultUpdatePolicy; +/// use datasketches::tuple::TupleANotB; +/// use datasketches::tuple::TupleSketchBuilder; +/// /// let update_policy = DefaultUpdatePolicy::::default(); /// let mut a = TupleSketchBuilder::new(update_policy).build(); /// a.update("apple", 1); diff --git a/datasketches/src/theta_family/tuple/hash_table.rs b/datasketches/src/thetafamily/tuple/hash_table.rs similarity index 100% rename from datasketches/src/theta_family/tuple/hash_table.rs rename to datasketches/src/thetafamily/tuple/hash_table.rs diff --git a/datasketches/src/theta_family/tuple/intersection.rs b/datasketches/src/thetafamily/tuple/intersection.rs similarity index 100% rename from datasketches/src/theta_family/tuple/intersection.rs rename to datasketches/src/thetafamily/tuple/intersection.rs diff --git a/datasketches/src/theta_family/tuple/jaccard_similarity.rs b/datasketches/src/thetafamily/tuple/jaccard_similarity.rs similarity index 94% rename from datasketches/src/theta_family/tuple/jaccard_similarity.rs rename to datasketches/src/thetafamily/tuple/jaccard_similarity.rs index d2627143..6ad38357 100644 --- a/datasketches/src/theta_family/tuple/jaccard_similarity.rs +++ b/datasketches/src/thetafamily/tuple/jaccard_similarity.rs @@ -32,7 +32,10 @@ use crate::tuple::TupleKeySketchView; /// # Examples /// /// ``` -/// # use datasketches::tuple::{DefaultUpdatePolicy, TupleJaccardSimilarity, TupleSketchBuilder}; +/// use datasketches::tuple::DefaultUpdatePolicy; +/// use datasketches::tuple::TupleJaccardSimilarity; +/// use datasketches::tuple::TupleSketchBuilder; +/// /// let policy = DefaultUpdatePolicy::::default(); /// let mut a = TupleSketchBuilder::new(policy).build(); /// let mut b = TupleSketchBuilder::new(policy).build(); diff --git a/datasketches/src/theta_family/tuple/mod.rs b/datasketches/src/thetafamily/tuple/mod.rs similarity index 96% rename from datasketches/src/theta_family/tuple/mod.rs rename to datasketches/src/thetafamily/tuple/mod.rs index e77f5d4e..a8dfcba7 100644 --- a/datasketches/src/theta_family/tuple/mod.rs +++ b/datasketches/src/thetafamily/tuple/mod.rs @@ -31,7 +31,9 @@ //! # Usage //! //! ``` -//! # use datasketches::tuple::{DefaultUpdatePolicy, TupleSketchBuilder}; +//! use datasketches::tuple::DefaultUpdatePolicy; +//! use datasketches::tuple::TupleSketchBuilder; +//! //! let policy = DefaultUpdatePolicy::::default(); //! let mut sketch = TupleSketchBuilder::new(policy).build(); //! sketch.update("apple", 1_u64); diff --git a/datasketches/src/theta_family/tuple/policy.rs b/datasketches/src/thetafamily/tuple/policy.rs similarity index 100% rename from datasketches/src/theta_family/tuple/policy.rs rename to datasketches/src/thetafamily/tuple/policy.rs diff --git a/datasketches/src/theta_family/tuple/serialization.rs b/datasketches/src/thetafamily/tuple/serialization.rs similarity index 100% rename from datasketches/src/theta_family/tuple/serialization.rs rename to datasketches/src/thetafamily/tuple/serialization.rs diff --git a/datasketches/src/theta_family/tuple/sketch.rs b/datasketches/src/thetafamily/tuple/sketch.rs similarity index 98% rename from datasketches/src/theta_family/tuple/sketch.rs rename to datasketches/src/thetafamily/tuple/sketch.rs index 67080d8e..bd483224 100644 --- a/datasketches/src/theta_family/tuple/sketch.rs +++ b/datasketches/src/thetafamily/tuple/sketch.rs @@ -88,7 +88,9 @@ impl TupleSketchView for T where /// # Examples /// /// ``` -/// # use datasketches::tuple::{DefaultUpdatePolicy, TupleSketchBuilder}; +/// use datasketches::tuple::DefaultUpdatePolicy; +/// use datasketches::tuple::TupleSketchBuilder; +/// /// let policy = DefaultUpdatePolicy::::default(); /// let mut sketch = TupleSketchBuilder::new(policy).build(); /// sketch.update("apple", 1); @@ -118,7 +120,9 @@ where /// # Examples /// /// ``` - /// # use datasketches::tuple::{DefaultUpdatePolicy, TupleSketchBuilder}; + /// use datasketches::tuple::DefaultUpdatePolicy; + /// use datasketches::tuple::TupleSketchBuilder; + /// /// let policy = DefaultUpdatePolicy::::default(); /// let mut sketch = TupleSketchBuilder::new(policy).build(); /// sketch.update(42, 5); @@ -242,7 +246,9 @@ where /// # Examples /// /// ``` - /// # use datasketches::tuple::{DefaultUpdatePolicy, TupleSketchBuilder}; + /// use datasketches::tuple::DefaultUpdatePolicy; + /// use datasketches::tuple::TupleSketchBuilder; + /// /// let policy = DefaultUpdatePolicy::::default(); /// let mut sketch = TupleSketchBuilder::new(policy).build(); /// sketch.update("apple", 1); @@ -439,7 +445,9 @@ impl CompactTupleSketch { /// # Examples /// /// ``` - /// # use datasketches::tuple::{DefaultUpdatePolicy, TupleSketchBuilder}; + /// use datasketches::tuple::DefaultUpdatePolicy; + /// use datasketches::tuple::TupleSketchBuilder; + /// /// let policy = DefaultUpdatePolicy::::default(); /// let mut sketch = TupleSketchBuilder::new(policy).build(); /// sketch.update("apple", 1); diff --git a/datasketches/src/theta_family/tuple/union.rs b/datasketches/src/thetafamily/tuple/union.rs similarity index 96% rename from datasketches/src/theta_family/tuple/union.rs rename to datasketches/src/thetafamily/tuple/union.rs index 4fdf5e4b..c64bbcdb 100644 --- a/datasketches/src/theta_family/tuple/union.rs +++ b/datasketches/src/thetafamily/tuple/union.rs @@ -43,7 +43,11 @@ use crate::tuple::sketch::TupleSketchView; /// # Examples /// /// ``` -/// # use datasketches::tuple::{DefaultUnionPolicy, DefaultUpdatePolicy, TupleSketchBuilder, TupleUnionBuilder}; +/// use datasketches::tuple::DefaultUnionPolicy; +/// use datasketches::tuple::DefaultUpdatePolicy; +/// use datasketches::tuple::TupleSketchBuilder; +/// use datasketches::tuple::TupleUnionBuilder; +/// /// let update_policy = DefaultUpdatePolicy::::default(); /// let mut a = TupleSketchBuilder::new(update_policy).build(); /// a.update("apple", 1); diff --git a/datasketches/tests/serde_tests/hll.rs b/datasketches/tests/serde_tests/hll.rs index 3447c786..4501b1f8 100644 --- a/datasketches/tests/serde_tests/hll.rs +++ b/datasketches/tests/serde_tests/hll.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; -use datasketches::hash_value::natural_extend; +use datasketches::hash::value::natural_extend; use datasketches::hll::HllSketch; use datasketches::hll::HllType; diff --git a/datasketches/tests/theta_test/sketch.rs b/datasketches/tests/theta_test/sketch.rs index 3ce86f0c..2ed07db7 100644 --- a/datasketches/tests/theta_test/sketch.rs +++ b/datasketches/tests/theta_test/sketch.rs @@ -16,7 +16,7 @@ // under the License. use datasketches::common::NumStdDev; -use datasketches::hash_value; +use datasketches::hash::value::canonical_float; use datasketches::theta::ThetaSketchBuilder; #[test] @@ -41,10 +41,10 @@ fn test_update_various_types() { sketch.update(42i64); sketch.update(42u64); // where floating-point numbers have different representations - sketch.update(hash_value::canonical_float::from_f64(3.15)); - sketch.update(hash_value::canonical_float::from_f64(3.15)); - sketch.update(hash_value::canonical_float::from_f32(3.15)); - sketch.update(hash_value::canonical_float::from_f32(3.15)); + sketch.update(canonical_float::from_f64(3.15)); + sketch.update(canonical_float::from_f64(3.15)); + sketch.update(canonical_float::from_f32(3.15)); + sketch.update(canonical_float::from_f32(3.15)); sketch.update([1u8, 2, 3]); assert!(!sketch.is_empty()); @@ -56,10 +56,10 @@ fn test_update_various_types() { sketch.update(42i64); sketch.update(42u64); // where floating-point numbers have the same representation - sketch.update(hash_value::canonical_float::from_f64(5.0)); - sketch.update(hash_value::canonical_float::from_f64(5.0)); - sketch.update(hash_value::canonical_float::from_f32(5.0)); - sketch.update(hash_value::canonical_float::from_f32(5.0)); + sketch.update(canonical_float::from_f64(5.0)); + sketch.update(canonical_float::from_f64(5.0)); + sketch.update(canonical_float::from_f32(5.0)); + sketch.update(canonical_float::from_f32(5.0)); sketch.update([1u8, 2, 3]); assert!(!sketch.is_empty()); diff --git a/datasketches/tests/tuple_test/sketch.rs b/datasketches/tests/tuple_test/sketch.rs index a13d36a7..34110e73 100644 --- a/datasketches/tests/tuple_test/sketch.rs +++ b/datasketches/tests/tuple_test/sketch.rs @@ -16,7 +16,7 @@ // under the License. use datasketches::common::NumStdDev; -use datasketches::hash_value; +use datasketches::hash::value; use datasketches::tuple::CompactTupleSketch; use datasketches::tuple::DefaultUpdatePolicy; use datasketches::tuple::SummaryPolicy; @@ -47,8 +47,8 @@ fn accepts_supported_hash_representations() { sketch.update("string", 1u64); sketch.update(42i64, 1u64); sketch.update(42u64, 1u64); - sketch.update(hash_value::canonical_float::from_f64(5.0), 1u64); - sketch.update(hash_value::canonical_float::from_f32(5.0), 1u64); + sketch.update(value::canonical_float::from_f64(5.0), 1u64); + sketch.update(value::canonical_float::from_f32(5.0), 1u64); sketch.update([1u8, 2, 3], 1u64); assert_eq!(sketch.estimate(), 4.0);