Skip to content

feat(writer): cascade zigzag like Rust's ZigZagScheme (issue #410) - #436

Merged
dfa1 merged 1 commit into
mainfrom
feat/410-zigzag-cascade
Oct 3, 2026
Merged

dfa1 merged 1 commit into
mainfrom
feat/410-zigzag-cascade

Conversation

@dfa1

@dfa1 dfa1 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Part of #410, Rust-parity port number 2 after RunEnd (#435).

  • ZigZagEncodingEncoder.encodeCascade: the zigzag output (the unsigned counterpart: I32 → U32, which is what our decoder already reads) becomes an open child. It is not applicable without a negative value, matching Rust's min_is_negative skip. The negative check is a read-only scan before anything is allocated, since our ArrayStats carries no minimum.
  • Child exclusions match Rust's ZigZagScheme: Dict, RunEnd, Sparse (a bijection preserves cardinality, runs and dominance, so they would lose again), plus ZigZag itself.
  • Registered as a cascade candidate, as in Rust. It was never in buildCascadeCodecs before, so the cascade never tried it.
  • Rust's ancestor rule (no ZigZag on Dict codes) holds by construction: codes are unsigned, and ZigZag accepts signed types only.

Size: byte-identical on every comparison (FileSizeComparison 1,161,559, GlobalDict 2,466,808, …) and on a mixed-sign probe. FoR competes for the same columns and never needs more bits: bits(max − min) ≤ bits(2·max|v|), with a tie when the data is symmetric around zero. This PR is for parity, not size.

Tests: ZigZagEncodingEncoderTest.Cascade (I8 zigzag values including the extremes, the child dtype, exclusions, bounds from the signed values, the no-negatives skip). Green: 1,925 writer, 1,592 reader and 367 integration tests, including every vortex-jni interop suite.

No CHANGELOG entry: output is unchanged, so nothing is user-visible.

🤖 Generated with Claude Code

Parity with the reference compressor: ZigZag overrides encodeCascade and
hands its unsigned output to the compressor as an open child, with Rust's
descendant exclusions (Dict, RunEnd, Sparse; plus itself), and is not
applicable without a negative value. It is now also a cascade candidate,
as in Rust; before, it was never offered to the cascade at all.

Output is byte-identical on every size comparison: FoR competes for the
same columns and never needs more bits (bits(max - min) <=
bits(2 * max|v|)), so it wins or ties. Rust's dict-codes ancestor rule
holds by construction: codes are unsigned and ZigZag accepts signed only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dfa1
dfa1 merged commit f4504a4 into main Oct 3, 2026
6 checks passed
@dfa1
dfa1 deleted the feat/410-zigzag-cascade branch October 3, 2026 07:01
dfa1 added a commit that referenced this pull request Oct 3, 2026
Date the section, add decimal and compressor-parity highlights, cover the
zigzag/RLE cascade PRs (#436, #437), and bump the README snippets to 0.15.2
with a pointer to the Raincloud conformance result.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant