This is an automated email from the ASF dual-hosted git repository.

tisonkun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datasketches-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new c7e745a  feat: add diagnostic summaries for HLL and CPC (#232)
c7e745a is described below

commit c7e745affc08b95dfd601ae426043e7818bf8a60
Author: Xinyao Zhang <[email protected]>
AuthorDate: Sat Sep 26 09:15:24 2026 -0400

    feat: add diagnostic summaries for HLL and CPC (#232)
    
    Co-authored-by: tison <[email protected]>
---
 CHANGELOG.md                   |  1 +
 datasketches/src/cpc/sketch.rs | 19 ++++++++++++++++++-
 datasketches/src/cpc/union.rs  | 21 ++++++++++++++++++++-
 datasketches/src/hll/sketch.rs | 36 +++++++++++++++++++++++++++++++++++-
 4 files changed, 74 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ba590ae..e6614a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ All significant changes to this project will be documented in 
this file.
 
 ### Improvements
 
+* Improve the readability of `Debug` output for HLL and CPC sketches and 
unions.
 * `BloomFilter::insert` is faster for integer and raw-byte inputs. 
`BloomFilter::contains_and_insert` is also faster when checking already-present 
integer values.
 * `CountMinSketch` updates are faster for integer and raw-byte inputs.
 * `CpcSketch` updates are faster for integer and raw-byte inputs.
diff --git a/datasketches/src/cpc/sketch.rs b/datasketches/src/cpc/sketch.rs
index 2cc4a7a..d946b1b 100644
--- a/datasketches/src/cpc/sketch.rs
+++ b/datasketches/src/cpc/sketch.rs
@@ -15,6 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::fmt;
 use std::hash::Hash;
 
 use crate::codec::SketchBytes;
@@ -59,7 +60,7 @@ use crate::hash::compute_seed_hash;
 /// A Compressed Probabilistic Counting sketch.
 ///
 /// See the [module level documentation](super) for more.
-#[derive(Debug, Clone)]
+#[derive(Clone)]
 pub struct CpcSketch {
     // immutable config variables
     lg_k: u8,
@@ -471,6 +472,22 @@ impl CpcSketch {
     }
 }
 
+impl fmt::Debug for CpcSketch {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let estimator = if self.merge_flag { "ICON" } else { "HIP" };
+        f.debug_struct("CpcSketch")
+            .field("lg_k", &self.lg_k())
+            .field("seed", &self.seed)
+            .field("flavor", &self.flavor())
+            .field("is_empty", &self.is_empty())
+            .field("merged", &self.merge_flag)
+            .field("estimator", &estimator)
+            .field("num_coupons", &self.num_coupons)
+            .field("estimate", &self.estimate())
+            .finish()
+    }
+}
+
 impl CpcSketch {
     /// Serializes this `CpcSketch` to bytes.
     pub fn serialize(&self) -> Vec<u8> {
diff --git a/datasketches/src/cpc/union.rs b/datasketches/src/cpc/union.rs
index 51742a3..67870f5 100644
--- a/datasketches/src/cpc/union.rs
+++ b/datasketches/src/cpc/union.rs
@@ -61,6 +61,8 @@
 //! which requires doing some extra work to figure out the values of 
num_coupons, offset,
 //! first_interesting_column, and kxp.
 
+use std::fmt;
+
 use crate::cpc::CpcSketch;
 use crate::cpc::DEFAULT_LG_K;
 use crate::cpc::Flavor;
@@ -71,7 +73,7 @@ use crate::error::Error;
 use crate::hash::DEFAULT_UPDATE_SEED;
 
 /// Union operator for CPC sketches.
-#[derive(Debug, Clone)]
+#[derive(Clone)]
 pub struct CpcUnion {
     // immutable config variables
     lg_k: u8,
@@ -356,6 +358,23 @@ impl CpcUnion {
     }
 }
 
+impl fmt::Debug for CpcUnion {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let (state, num_coupons) = match &self.state {
+            UnionState::Accumulator(sketch) => ("Accumulator", 
sketch.num_coupons),
+            UnionState::BitMatrix(matrix) => ("BitMatrix", 
count_bits_set_in_matrix(matrix)),
+        };
+
+        f.debug_struct("CpcUnion")
+            .field("lg_k", &self.lg_k())
+            .field("seed", &self.seed)
+            .field("state", &state)
+            .field("is_empty", &(num_coupons == 0))
+            .field("num_coupons", &num_coupons)
+            .finish()
+    }
+}
+
 fn or_window_into_matrix(
     dst_matrix: &mut [u64],
     dst_lg_k: u8,
diff --git a/datasketches/src/hll/sketch.rs b/datasketches/src/hll/sketch.rs
index a229b3b..bef4fbb 100644
--- a/datasketches/src/hll/sketch.rs
+++ b/datasketches/src/hll/sketch.rs
@@ -20,6 +20,7 @@
 //! This module provides the main [`HllSketch`] struct, which is the primary 
interface
 //! for creating and using HLL sketches for cardinality estimation.
 
+use std::fmt;
 use std::hash::Hash;
 
 use crate::codec::SketchSlice;
@@ -60,7 +61,7 @@ use crate::hll::serialization::extract_tgt_hll_type;
 /// A HyperLogLog sketch.
 ///
 /// See the [module level documentation](super) for more.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Clone, PartialEq)]
 pub struct HllSketch {
     lg_config_k: u8,
     mode: Mode,
@@ -464,6 +465,39 @@ impl HllSketch {
     }
 }
 
+impl fmt::Debug for HllSketch {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let (mode, estimate_state) = match &self.mode {
+            Mode::List { .. } => ("List", None),
+            Mode::Set { .. } => ("Set", None),
+            Mode::Array4(array) => ("Hll", Some(array.estimate_state())),
+            Mode::Array6(array) => ("Hll", Some(array.estimate_state())),
+            Mode::Array8(array) => ("Hll", Some(array.estimate_state())),
+        };
+
+        let mut debug = f.debug_struct("HllSketch");
+        debug
+            .field("lg_config_k", &self.lg_config_k())
+            .field("target_type", &self.target_type())
+            .field("mode", &mode)
+            .field("is_empty", &self.is_empty());
+        if let Some(state) = estimate_state {
+            let estimator = match state {
+                EstimateState::Hip(_) => "HIP",
+                EstimateState::Composite => "Composite",
+            };
+            debug.field("estimator", &estimator);
+        }
+        debug
+            .field("estimate", &self.estimate())
+            .field(
+                "bounds",
+                
&(self.lower_bound(NumStdDev::One)..=self.upper_bound(NumStdDev::One)),
+            )
+            .finish()
+    }
+}
+
 fn promote_container_to_set(container: &Container, hll_type: HllType) -> Mode {
     let mut set = HashSet::default();
     for coupon in container.iter() {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to