tisonkun commented on PR #772: URL: https://github.com/apache/datasketches-java/pull/772#issuecomment-5861603990
@leerho While evaluating the corresponding Rust change (apache/datasketches-rust#283), I would like to understand the rationale for the empty Theta/Tuple seed-hash rule. Is this an intentional semantic distinction, or is the Tuple change primarily following the existing C++ encoding? I have two questions: 1. **What concrete problem does zeroing the seed hash solve?** An empty sketch can still have a configured seed. As this PR notes, the existing nonzero seed hash is already accepted by the empty Tuple readers, so retaining it does not appear to break deserialization compatibility. Writing zero also does not reduce the image size. Ignoring an empty input during a set operation and discarding its seed fingerprint during serialization seem like separate decisions: the former does not require the latter. Is there a documented requirement for a unique, seed-independent empty encoding, or another benefit that justifies this special case? 2. **Why does this apply specifically to Theta/Tuple?** I checked both the Java code at this PR's head and C++ at `70e462f`. Other seeded families preserve and validate their configuration even when empty: | Family | Java | C++ | | --- | --- | --- | | CPC | [Empty serialization retains the seed hash](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/cpc/CompressedState.java#L223-L232); [heapify/uncompress validates it](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/cpc/CpcSketch.java#L664-L676). | [Writes the seed hash before the non-empty payload branch](https://github.com/apache/datasketches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/cpc/include/cpc_sketch_impl.hpp#L431-L435); [deserialization validates it](https://github.com/apache/datasketches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/cpc/include/cpc_sketch_impl.hpp#L580-L585). | | Count-Min | [Writes the seed hash before returning the empty image](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/count/CountMinSketch.java#L416-L425); [deserialization checks it before the empty return](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/count/CountMinSketch.java#L469-L482). | [Writes the seed hash for empty images](https://github.com/apache/datasketches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/count/include/count_min_impl.hpp#L294-L303); [deserialization checks it before the empty return](https://github.com/apache/datasketches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/count/include/count_min_impl.hpp#L331-L343). | | Bloom | Stores the full seed rather than a seed hash: [empty serialization preserves it](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/filters/bloomfilter/BloomFilter.java#L819-L837), and [union/intersection require compatibility](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/filters/bloomfilter/BloomFilter.java#L681-L701), including [matching seeds](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/filters/bloomfilter/BloomFilter.java#L753-L760). | [Empty serialization preserves the full seed](https://github.com/apache/datasketches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/filters/include/bloom_filter_impl.hpp#L424-L441); [union/intersection check seed compatibility without an empty-input exception](https://github.com/apache/dataske tches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/filters/include/bloom_filter_impl.hpp#L855-L878). | CPC is an especially direct contrast: [Java's union checks the seed hash before returning for an empty serialized input](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/cpc/CpcUnion.java#L303-L306), its [object-input path does the same with the seed](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/cpc/CpcUnion.java#L350-L355), and [C++ also checks before its empty-input return](https://github.com/apache/datasketches-cpp/blob/70e462fcd03977e378c34ca121ba9f40d17ecef3/cpc/include/cpc_union_impl.hpp#L104-L112). Thus even an empty input can produce a seed-mismatch error in both implementations. That is a configuration invariant, despite the empty input contributing no data. I see that [Java Theta uses an empty compact singleton and a fixed byte representation](https://github.com/apache/datasketches-java/blob/1481c3fc76bf78bf79a0d4a3edffba877911694b/src/main/java/org/apache/datasketches/theta/EmptyCompactSketch.java#L27-L45). Is the intended boundary that immutable compact Theta/Tuple results discard seed identity when empty, while updateable sketches retain configuration? Or is this a historical format convention that Tuple is following for byte-level consistency? The differing policies may be intentional, but it would help to state the distinction explicitly rather than infer a general rule that emptiness makes the seed irrelevant. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
