Skip to content

Train ALP-RD dictionary on a stratified sample#308

Merged
dfa1 merged 1 commit into
mainfrom
alprd-stratified-sample
Jul 25, 2026
Merged

Train ALP-RD dictionary on a stratified sample#308
dfa1 merged 1 commit into
mainfrom
alprd-stratified-sample

Conversation

@dfa1

@dfa1 dfa1 commented Jul 25, 2026

Copy link
Copy Markdown
Owner

What

Follow-up to #304 (PR #307), from that PR's review. Two fixes:

1. ALP-RD sampled its dictionary from the head, not a stratified sample. findBestDictionaryF64/F32 trained the left-parts dictionary from values[0 .. SAMPLE_SIZE) — the first physical rows. But the cascade measures ALP-RD's cost on its own stratified sample, so a head-only dictionary can look cheap in the competition and then flood the tail with exceptions on the full re-encode when the leading rows are unrepresentative (sorted or clustered floats). That's a size-regression vector newly reachable now that ALP-RD is a top-level cascade candidate. AlpEncodingEncoder.findExponentsF64 already strides across the whole array to avoid exactly this; ALP-RD now does the same.

2. Hardened the selection test. AlpRdCascadeSelectionIntegrationTest asserted only the categorical usedEncodings().contains("vortex.alprd") — a winner decided on a 4096-row sample, with no size margin. It now also asserts the file compresses below raw F64, so it can't pass on a degenerate "selected but didn't actually beat raw" outcome.

Impact

Correctness-neutral (ALP-RD is lossless regardless of dictionary contents — exceptions cover misses); this is a size-robustness fix for adversarially-ordered float columns.

  • nyc-311 unchanged at 1644.25 MB (its Latitude/Longitude leading rows were already representative, so head vs stratified produced the same dictionary).
  • 408 round-trip property tests, 16 ALP-RD unit tests, 217 Java-writes-Rust-reads interop tests pass; full ./mvnw verify green.

🤖 Generated with Claude Code

ALP-RD built its left-parts dictionary from the first SAMPLE_SIZE physical rows
(findBestDictionaryF64/F32 iterated values[0..sampleLen)). The cascade measures
ALP-RD's cost on its own stratified sample, so a head-only dictionary could look
cheap in the competition yet flood the tail with exceptions on the full re-encode
when the leading rows are unrepresentative (sorted or clustered floats) — a size
regression newly reachable now that ALP-RD is a top-level cascade candidate (#304
review). Train on a stratified sample spanning the whole array instead, matching
AlpEncodingEncoder.findExponentsF64.

Also harden AlpRdCascadeSelectionIntegrationTest: besides asserting the categorical
ALP-RD win (decided on a 4096-row sample), assert the file compresses below raw F64,
so the test can't pass on a degenerate "selected but didn't beat raw" outcome.

nyc-311 unchanged at 1644.25 MB (its leading rows were already representative);
408 round-trip property tests, 16 ALP-RD unit tests, and 217 interop tests pass;
full verify green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dfa1
dfa1 merged commit 0e3d35c into main Jul 25, 2026
6 checks passed
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