Skip to content

Commit ee6e1cc

Browse files
ZENOTMEtisonkun
andauthored
feat(theta): add theta union (#145)
Co-authored-by: tison <wander4096@gmail.com>
1 parent eefe065 commit ee6e1cc

21 files changed

Lines changed: 1384 additions & 205 deletions

datasketches/src/bloom/sketch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ impl BloomFilter {
564564

565565
/// Returns the estimated size of the filter in bytes
566566
pub fn estimated_size(&self) -> usize {
567-
std::mem::size_of::<Self>() + self.bit_array.len() * std::mem::size_of::<u64>()
567+
size_of::<Self>() + self.bit_array.len() * size_of::<u64>()
568568
}
569569
}
570570

datasketches/src/common/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,5 @@ mod resize;
2222
pub use self::num_std_dev::NumStdDev;
2323
pub use self::resize::ResizeFactor;
2424

25-
#[cfg(feature = "theta")]
26-
pub(crate) mod binomial_bounds;
2725
#[cfg(any(feature = "cpc", feature = "hll"))]
2826
pub(crate) mod inv_pow2_table;

datasketches/src/cpc/pair_table.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,6 @@ impl PairTable {
249249

250250
/// Returns the estimated size of the heap allocations in bytes
251251
pub fn estimated_size(&self) -> usize {
252-
self.slots.capacity() * std::mem::size_of::<u32>()
252+
self.slots.capacity() * size_of::<u32>()
253253
}
254254
}

datasketches/src/cpc/sketch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ impl CpcSketch {
460460
.map(|t| t.estimated_size())
461461
.unwrap_or(0);
462462

463-
std::mem::size_of::<Self>() + heap_size
463+
size_of::<Self>() + heap_size
464464
}
465465
}
466466

datasketches/src/hll/aux_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ impl AuxMap {
229229

230230
/// Returns the estimated size of the heap allocations in bytes
231231
pub fn estimated_size(&self) -> usize {
232-
self.entries.len() * std::mem::size_of::<Coupon>()
232+
self.entries.len() * size_of::<Coupon>()
233233
}
234234
}
235235

datasketches/src/hll/container.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,6 @@ impl Container {
138138

139139
/// Returns the estimated size of the heap allocations in bytes
140140
pub fn estimated_size(&self) -> usize {
141-
self.coupons.len() * std::mem::size_of::<Coupon>()
141+
self.coupons.len() * size_of::<Coupon>()
142142
}
143143
}

datasketches/src/hll/sketch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ impl HllSketch {
434434
Mode::Array8(arr) => arr.estimated_size(),
435435
};
436436

437-
std::mem::size_of::<Self>() + heap_size
437+
size_of::<Self>() + heap_size
438438
}
439439
}
440440

datasketches/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ pub mod hll;
4545
pub mod tdigest;
4646
#[cfg(feature = "theta")]
4747
pub mod theta;
48+
#[cfg(feature = "theta")]
49+
pub mod thetacommon;
4850

4951
// common modules
5052
pub mod codec;

datasketches/src/tdigest/sketch.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -796,9 +796,9 @@ impl TDigestMut {
796796

797797
/// Returns the estimated size of the sketch in bytes
798798
pub fn estimated_size(&self) -> usize {
799-
std::mem::size_of::<Self>()
800-
+ self.centroids.capacity() * std::mem::size_of::<Centroid>()
801-
+ self.buffer.capacity() * std::mem::size_of::<f64>()
799+
size_of::<Self>()
800+
+ self.centroids.capacity() * size_of::<Centroid>()
801+
+ self.buffer.capacity() * size_of::<f64>()
802802
}
803803
}
804804

@@ -1011,7 +1011,7 @@ impl TDigest {
10111011

10121012
/// Returns the estimated size of the sketch in bytes
10131013
pub fn estimated_size(&self) -> usize {
1014-
std::mem::size_of::<Self>() + self.centroids.capacity() * std::mem::size_of::<Centroid>()
1014+
size_of::<Self>() + self.centroids.capacity() * size_of::<Centroid>()
10151015
}
10161016
}
10171017

datasketches/src/theta/hash_table.rs

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,8 @@
1818
use std::hash::Hash;
1919
use std::num::NonZeroU64;
2020

21-
use crate::theta::raw_hash_table::RawHashTable;
22-
use crate::theta::raw_hash_table::RawHashTableEntry;
23-
#[cfg(test)]
24-
pub(crate) use crate::theta::raw_hash_table::starting_sub_multiple;
25-
#[cfg(test)]
26-
pub(crate) use crate::theta::raw_hash_table::starting_theta_from_sampling_probability;
21+
use crate::thetacommon::RawHashTableEntry;
22+
use crate::thetacommon::hash_table::RawHashTable;
2723

2824
/// Specific hash table for theta sketch
2925
///
@@ -34,16 +30,22 @@ pub(crate) use crate::theta::raw_hash_table::starting_theta_from_sampling_probab
3430
/// update the theta to the k-th smallest entry.
3531
pub(super) type ThetaHashTable = RawHashTable<ThetaEntry>;
3632

33+
/// A retained entry in a Theta sketch.
3734
#[derive(Debug, Clone, Copy)]
38-
pub(crate) struct ThetaEntry {
35+
pub struct ThetaEntry {
3936
hash: NonZeroU64,
4037
}
4138

4239
impl ThetaEntry {
43-
fn new(hash: u64) -> Self {
40+
pub(crate) fn new(hash: u64) -> Self {
4441
let hash = NonZeroU64::new(hash).expect("hash must be non-zero");
4542
Self { hash }
4643
}
44+
45+
/// Return the hash used as this entry's key.
46+
pub fn hash(&self) -> u64 {
47+
self.hash.get()
48+
}
4749
}
4850

4951
impl RawHashTableEntry for ThetaEntry {
@@ -90,18 +92,20 @@ mod tests {
9092
use super::*;
9193
use crate::common::ResizeFactor;
9294
use crate::hash::DEFAULT_UPDATE_SEED;
93-
use crate::theta::MAX_THETA;
94-
use crate::theta::MIN_LG_K;
95+
use crate::thetacommon::constants::MAX_THETA;
96+
use crate::thetacommon::constants::MIN_LG_K;
97+
use crate::thetacommon::hash_table::starting_sub_multiple;
98+
use crate::thetacommon::hash_table::starting_theta_from_sampling_probability;
9599

96100
#[test]
97101
fn test_new_hash_table() {
98102
let table = ThetaHashTable::new(8, ResizeFactor::X8, 1.0, DEFAULT_UPDATE_SEED);
99103

100104
assert_eq!(
101-
table.lg_cur_size,
105+
table.lg_cur_size(),
102106
starting_sub_multiple(8 + 1, MIN_LG_K, ResizeFactor::X8.lg_value())
103107
);
104-
assert_eq!(table.theta, starting_theta_from_sampling_probability(1.0));
108+
assert_eq!(table.theta(), starting_theta_from_sampling_probability(1.0));
105109
assert_eq!(table.num_retained(), 0);
106110
assert!(table.is_empty());
107111
assert_eq!(table.iter().count(), 0);
@@ -119,7 +123,7 @@ mod tests {
119123
assert_ne!(hash1, hash2);
120124

121125
// With low theta, update should be screened out.
122-
table.theta = 1;
126+
table.set_theta(1);
123127
assert!(!table.try_insert("test3"));
124128
}
125129

@@ -136,7 +140,7 @@ mod tests {
136140
assert_eq!(table.num_retained(), 1);
137141

138142
// Force screening and verify insertion fails
139-
table.theta = 0;
143+
table.set_theta(1); // Set theta to a low value to screen out new entries
140144
assert!(!table.try_insert("screened"));
141145
assert_eq!(table.num_retained(), 1);
142146
assert!(!table.is_empty());
@@ -174,7 +178,7 @@ mod tests {
174178
{
175179
let mut table = ThetaHashTable::new(8, ResizeFactor::X2, 1.0, DEFAULT_UPDATE_SEED);
176180

177-
assert_eq!(table.entries.len(), 32);
181+
assert_eq!(table.num_entries(), 32);
178182

179183
// Insert enough values to trigger resize (50% threshold)
180184
// Capacity = 32 * 0.5 = 16
@@ -183,14 +187,14 @@ mod tests {
183187
// Table should have resized and all values should be inserted
184188
assert!(table.num_retained() > 0);
185189
assert_eq!(table.num_retained(), inserted);
186-
assert_eq!(table.entries.len(), 64);
190+
assert_eq!(table.num_entries(), 64);
187191
}
188192

189193
// Test different resize factors
190194
{
191195
let mut table = ThetaHashTable::new(8, ResizeFactor::X4, 1.0, DEFAULT_UPDATE_SEED);
192196

193-
assert_eq!(table.entries.len(), 32);
197+
assert_eq!(table.num_entries(), 32);
194198

195199
// Insert enough values to trigger resize (50% threshold)
196200
// Capacity = 32 * 0.5 = 16
@@ -199,17 +203,17 @@ mod tests {
199203
// Table should have resized and all values should be inserted
200204
assert!(table.num_retained() > 0);
201205
assert_eq!(table.num_retained(), inserted);
202-
assert_eq!(table.entries.len(), 128);
206+
assert_eq!(table.num_entries(), 128);
203207
}
204208
}
205209

206210
#[test]
207211
fn test_rebuild() {
208212
let mut table = ThetaHashTable::new(5, ResizeFactor::X8, 1.0, DEFAULT_UPDATE_SEED);
209213

210-
assert_eq!(table.lg_cur_size, 6);
211-
assert_eq!(table.entries.len(), 64);
212-
assert_eq!(table.theta, MAX_THETA);
214+
assert_eq!(table.lg_cur_size(), 6);
215+
assert_eq!(table.num_entries(), 64);
216+
assert_eq!(table.theta(), MAX_THETA);
213217

214218
// Insert many values to trigger rebuild
215219
for i in 0..100 {
@@ -228,9 +232,9 @@ mod tests {
228232
let _ = table.try_insert(format!("value_{}", i));
229233
}
230234

231-
assert_eq!(table.lg_cur_size, 6);
232-
assert!(table.entries.len() >= 64);
233-
assert!(table.theta < new_theta);
235+
assert_eq!(table.lg_cur_size(), 6);
236+
assert!(table.num_entries() >= 64);
237+
assert!(table.theta() < new_theta);
234238
}
235239

236240
#[test]
@@ -274,8 +278,8 @@ mod tests {
274278
fn test_reset() {
275279
let mut table = ThetaHashTable::new(8, ResizeFactor::X8, 1.0, DEFAULT_UPDATE_SEED);
276280
let init_theta = table.theta();
277-
let init_lg_cur = table.lg_cur_size;
278-
let init_entries = table.entries.len();
281+
let init_lg_cur = table.lg_cur_size();
282+
let init_entries = table.num_entries();
279283

280284
// Insert some values
281285
for i in 0..10 {
@@ -291,8 +295,8 @@ mod tests {
291295
assert!(table.is_empty());
292296
assert_eq!(table.num_retained(), 0);
293297
assert_eq!(table.theta(), init_theta);
294-
assert_eq!(table.lg_cur_size, init_lg_cur);
295-
assert_eq!(table.entries.len(), init_entries);
298+
assert_eq!(table.lg_cur_size(), init_lg_cur);
299+
assert_eq!(table.num_entries(), init_entries);
296300
assert_eq!(table.iter().count(), 0);
297301
}
298302

0 commit comments

Comments
 (0)