Skip to content

feat(writer): run-length encode float columns like Rust's FloatRLEScheme - #438

Merged
dfa1 merged 1 commit into
mainfrom
feat/float-rle
Oct 3, 2026
Merged

dfa1 merged 1 commit into
mainfrom
feat/float-rle

Conversation

@dfa1

@dfa1 dfa1 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Closes the parity gap found in #437: Rust's vortex-btrblocks has a FloatRLEScheme next to IntRLEScheme, while our RleEncodingEncoder refused floats (accepts returned false for them).

  • accepts takes every primitive. Rust's float scheme matches is_float(), and its int scheme is_int().
  • Lossless: a run is equal raw bits (toLongs already read floats that way), so -0.0/+0.0 are separate runs and a NaN payload survives. == would merge the zeros and split every NaN.
  • Cascade: the values child is the column's own double[]/float[] (F16: short[]), so ALP and friends can compete on the run values. Indices and offsets work exactly as for integers. Rust's float scheme reuses rle_descendant_exclusions and rle_compress, so the exclusions are identical.
  • The terminal float path was already correct (PTypeIO.set reinterprets the long as raw bits for F32/F64/F16). It just had never been reachable.

Tests

  • Unit (RleEncodingEncoderTest.Floats): accepts F32/F64, an F64 round-trip keeping -0.0 and a NaN payload bit-exact, and an F32 cascade values child as float[].
  • Interop: javaWriter_rustReader_rle_f64 (forced RLE; vortex-jni reads raw bits back exactly, including -0.0 and the NaN payload) and javaWriter_jniReader_rle_f64_cascading.
  • Size comparisons are byte-identical. Green: writer and reader suites, plus 369 integration tests.

Docs: docs/compatibility.md RLE row, plus the CHANGELOG.

🤖 Generated with Claude Code

Parity gap found while porting IntRLEScheme (#437): Rust also RLE-encodes
floats, while RleEncodingEncoder refused them. It now accepts every
primitive. Runs compare raw bits (as toLongs already did for floats), so
the encoding is lossless: -0.0, +0.0 and NaN payloads stay distinct. The
cascade's values child is the column's own float[]/double[], so ALP can
compete on the run values; Rust's float scheme shares the int one's
children and exclusions, so nothing else changes.

vortex-jni reads Java-written float RLE back bit for bit, forced and
through the cascade. Size comparisons are byte-identical.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dfa1
dfa1 merged commit 36a8b84 into main Oct 3, 2026
6 checks passed
@dfa1
dfa1 deleted the feat/float-rle branch October 3, 2026 07:27
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