You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datasketches.apache.org by ti...@apache.org on 2026/08/09 16:22:12 UTC
(datasketches-rust) branch codex/fix-theta-v2-empty-state created (now 446d499)
This is an automated email from the ASF dual-hosted git repository.
tisonkun pushed a change to branch codex/fix-theta-v2-empty-state
in repository https://gitbox.apache.org/repos/asf/datasketches-rust.git
at 446d499 fix: preserve non-empty theta v2 exact sketches
This branch includes the following new commits:
new 446d499 fix: preserve non-empty theta v2 exact sketches
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datasketches.apache.org
For additional commands, e-mail: commits-help@datasketches.apache.org
(datasketches-rust) 01/01: fix: preserve non-empty theta v2 exact sketches
Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tisonkun pushed a commit to branch codex/fix-theta-v2-empty-state
in repository https://gitbox.apache.org/repos/asf/datasketches-rust.git
commit 446d4999c3fab015cf2aac737fb374b33193a31d
Author: tison <wa...@gmail.com>
AuthorDate: Mon Aug 10 00:21:53 2026 +0800
fix: preserve non-empty theta v2 exact sketches
---
datasketches/src/thetafamily/theta/sketch.rs | 2 +-
datasketches/tests/serde_tests/theta.rs | 55 ++++++++++++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/datasketches/src/thetafamily/theta/sketch.rs b/datasketches/src/thetafamily/theta/sketch.rs
index 833ca7c..2c3bf56 100644
--- a/datasketches/src/thetafamily/theta/sketch.rs
+++ b/datasketches/src/thetafamily/theta/sketch.rs
@@ -814,7 +814,7 @@ impl CompactThetaSketch {
theta: MAX_THETA,
seed_hash,
ordered: true,
- empty: true,
+ empty: num_entries == 0,
})
}
V2_PREAMBLE_ESTIMATE => {
diff --git a/datasketches/tests/serde_tests/theta.rs b/datasketches/tests/serde_tests/theta.rs
index 1f0f09b..b09ec8f 100644
--- a/datasketches/tests/serde_tests/theta.rs
+++ b/datasketches/tests/serde_tests/theta.rs
@@ -18,6 +18,8 @@
use std::fs;
use std::path::PathBuf;
+use datasketches::codec::SketchBytes;
+use datasketches::common::NumStdDev;
use datasketches::error::ErrorKind;
use datasketches::theta::CompactThetaSketch;
use datasketches::theta::ThetaSketchBuilder;
@@ -26,6 +28,24 @@ use googletest::prelude::near;
use crate::serialization_test_data;
+fn serialize_v2_exact(entries: &[u64]) -> Vec<u8> {
+ let current = ThetaSketchBuilder::default().build().compact(true);
+ let current_bytes = current.serialize();
+ let mut bytes = SketchBytes::with_capacity((2 + entries.len()) * size_of::<u64>());
+ bytes.write_u8(2); // preamble longs
+ bytes.write_u8(2); // serialization version
+ bytes.write_u8(current_bytes[2]); // theta family ID
+ bytes.write_u8(0); // unused
+ bytes.write_u16_le(0); // unused
+ bytes.write_u16_le(current.seed_hash());
+ bytes.write_u32_le(entries.len() as u32);
+ bytes.write_u32_le(0); // unused
+ for &entry in entries {
+ bytes.write_u64_le(entry);
+ }
+ bytes.into_bytes()
+}
+
fn test_sketch_file(path: PathBuf, expected_cardinality: usize, use_compressed_round_trip: bool) {
let expected = expected_cardinality as f64;
@@ -163,3 +183,38 @@ fn malformed_input_is_rejected() {
let err = CompactThetaSketch::deserialize(&unsupported_version).unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidData);
}
+
+#[test]
+fn test_v2_exact_non_empty_compatibility() {
+ let entries = [1, 7, 42];
+ let sketch = CompactThetaSketch::deserialize(&serialize_v2_exact(&entries)).unwrap();
+
+ assert!(!sketch.is_empty());
+ assert!(!sketch.is_estimation_mode());
+ assert!(sketch.is_ordered());
+ assert_eq!(sketch.num_retained(), entries.len());
+ assert_eq!(sketch.estimate(), entries.len() as f64);
+ assert_eq!(sketch.lower_bound(NumStdDev::One), entries.len() as f64);
+ assert_eq!(sketch.upper_bound(NumStdDev::One), entries.len() as f64);
+ assert_eq!(
+ sketch.iter().map(|entry| entry.hash()).collect::<Vec<_>>(),
+ entries
+ );
+
+ let restored = CompactThetaSketch::deserialize(&sketch.serialize()).unwrap();
+ assert!(!restored.is_empty());
+ assert_eq!(restored.num_retained(), entries.len());
+ assert_eq!(restored.estimate(), entries.len() as f64);
+}
+
+#[test]
+fn test_v2_exact_zero_entries_remains_empty() {
+ let sketch = CompactThetaSketch::deserialize(&serialize_v2_exact(&[])).unwrap();
+
+ assert!(sketch.is_empty());
+ assert!(!sketch.is_estimation_mode());
+ assert_eq!(sketch.num_retained(), 0);
+ assert_eq!(sketch.estimate(), 0.0);
+ assert_eq!(sketch.lower_bound(NumStdDev::One), 0.0);
+ assert_eq!(sketch.upper_bound(NumStdDev::One), 0.0);
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datasketches.apache.org
For additional commands, e-mail: commits-help@datasketches.apache.org