Repository navigation
simd: NaN/presence bijection and SQL NULL=NaN predicates - #381
Conversation
…presence_nan_mismatches_*
On a float lane a clear presence bit and a NaN payload are one state:
presence bit i == 0 <=> values[i] is NaN. Three primitives hold it:
not_nan_{f64,f32}_to_mask (lane -> mask, ordered simd_eq against itself),
nan_where_clear_{f64,f32} (mask -> lane, NaN stamped under clear bits) and
presence_nan_mismatches_{f64,f32} (the witness: popcount(presence XOR derived)
over live rows, no allocation). F64Mask8::to_bitmask added on the AVX-512,
AVX2/AVX, NEON, wasm and scalar backends.
Parity group 0x13xx checks all three against a bit-pattern NaN reference
(quiet/signalling/negative/full-payload NaN, +-inf, +-0, subnormal, MAX) at
every lane-group boundary, plus the round trip and anti-vacuity counts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
…T under presence)
{lt,le,gt,ge,eq,ne}_{f64,f32}_to_mask pack the SQL TRUE plane: a NaN row is
NULL and never matches (<> included, unlike IEEE !=), and a NaN threshold is
the NULL literal and matches nothing. mask_not_under(pred, presence) =
presence & !pred is SQL NOT under three-valued logic: the FALSE plane, with
UNKNOWN rows in neither. presence is the PREDICATE's presence (AND of its
operands'), empty for a NULL literal; the unit test caught the column's plane
being wrong there (x > NULL reported every present row FALSE).
Parity group 0x139xx-0x13Cxx checks every operator x 9 thresholds (NaN, +-0,
+-inf, subnormal, +-1, MAX) against a bit-pattern ordering, plus the FALSE
plane. Also: clippy is_multiple_of fixes in the bijection tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
…plan status) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
… presence plane Follow-up to #380: NaN is a cleared presence bit, not the 'negative zero' codeword, so all of -255..=+255 are values and the writer stores +0 for zero and for missing rows. Masked dot splits lanes by sign_a ^ sign_b into two unsigned u8 x u8 accumulators, NULL excluded by the presence AND, n the popcount of the same mask. Decode applies nan_where_clear, so the float NaN/presence bijection holds on the decoded lane. tanh exactness vs i8 Sym (-127..=127), measured over 2,000,001 points: output quantization alone 2.01x lower max error, 1.94x lower RMS; a 256-entry table (sign-magnitude indexed by magnitude, sign passed through) 1.92-1.99x max, 1.97-2.02x RMS for input ranges 2..8; saturation onset 3.11 -> 3.46. This is the one extra bit. Scalar reference only; SIMD cost not measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
At a tolerance of 0.010 fixed in advance (between the two formats' measured 99.73% error quantiles at r = 4), sign-magnitude covers at least 0.9973 of 200,000 independent uniform inputs and i8 does not; the paired mean error difference is far above 3 standard errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
rustfmt reflows three expressions (the red format/stable check). The note said the five tests were not run; they pass on rustc 1.99.0. It also said x86 has no unsigned x unsigned dot product; AVX-VNNI-INT8 VPDPBUUD, NEON UDOT and wasm extmul do (from documentation, not measured). And it records the rule settled in #381: NaN is -0, a cleared presence bit over a stored 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
…otes facet-stride-guard --all crashed on the 34 crates/burn/src/*.rs paths, which are symlinks into an absent ../upstream checkout. The --diff and --hook modes already skipped non-files; --all now does too. The count is unchanged (166). wasm-simd-consumer-guide said wasm mul_add rounds twice; since #374/#378 it rounds once on every realization and is checked bit for bit, so a mul_add parity test may assert equality. The NaN mindmap plan records #383: on integer lanes one presence/polarity bit replaces #381's two planes, and float presence of a DR512 lane is P | ne_u8_to_mask(M, 0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY
On a float lane, a clear presence bit and a NaN payload now represent the same state:
"Is NaN" means
x != x, not a particular bit pattern. Every NaN counts (quiet, signalling-pattern, either sign, any payload), so a backend that rewrites NaN payloads, as wasm can, cannot break the invariant. Because the two encodings agree, ndarray can treat NaN as an ordinary computed value. Callers no longer need to scrub the lane before handing it over. This also makes the float lane usable for SQL with NULL = NaN.Added (
src/simd_masking_ops.rs, re-exported fromndarray::simd)not_nan_f64_to_mask,not_nan_f32_to_masksimd_eqof each value against itself.nan_where_clear_f64,nan_where_clear_f32presence_nan_mismatches_f64,presence_nan_mismatches_f32popcount(presence XOR derived)over live rows, without allocating.0means the invariant holds.{lt,le,gt,ge,eq,ne}_{f64,f32}_to_mask<>, unlike IEEE!=. A NaN threshold is the NULL literal and matches no row.mask_not_under(pred, presence)NOTunder three-valued logic:presence & !predgives the FALSE plane, and UNKNOWN rows appear in neither plane. A bare complement is wrong here, because!(NaN > 5)is true in IEEE whileNOT (NULL > 5)is UNKNOWN in SQL.F64Mask8::to_bitmaskis added on the AVX-512, AVX2/AVX, NEON, wasm and scalar backends. Nightly already had it.presenceinmask_not_undermust be the presence of the whole predicate: the AND of its operands' presence planes, and empty for a NULL literal. A unit test exposed this: when the column's own plane was used,NOT (x > NULL)reported every present row as FALSE. The requirement is now in the function's docs.Lab probe:
examples/sm9_presence_probe.rsThe same rule applied to an integer lane, as a follow-up to #380.
-0is NaN. In #380's sign-magnitude 9-bit code, NaN is the codeword "sign set, magnitude 0", written-0. This probe keeps that meaning and only changes where the state is stored:-0in the payload0+0+0A clear presence bit with
0underneath is #380's-0. It is the same NaN, not a second, different one. Moving it out of the payload into the presence plane is what frees the payload: no 9-bit code is spent on NaN any more. The writer stores+0(magnitude 0, sign clear) under a clear presence bit, so a missing row and a zero row hold the same payload bytes and only the presence bit tells them apart. A reader decodes presence-clear as NaN (nan_where_clear), whatever the payload holds.Masked dot product: lanes split by
sign_a ^ sign_binto two unsigned u8 × u8 accumulators. NULL rows are excluded by the presence AND, andnis the popcount of the same mask. It is checked against a decoded oracle on all 512 × 512 (value or NULL) pairs, on random blocks with a filter, and with a garbage payload under a clear bit.Decoding applies
nan_where_clear, so the float bijection holds on the decoded lane:presence_nan_mismatches == 0.tanh exactness against i8
Sym(−127..=127), over 2,000,001 points. tanh is odd, so the sign-magnitude table is indexed by magnitude and the sign plane passes through untouched:The largest |x| still below the top output code moves from 3.11 to 3.46. That is the gain of the one extra bit, about 2×.
3σ gate (test): 200,000 independent uniform inputs over [−4, 4], table path at r = 4. The tolerance 0.010 is fixed in advance, between the two formats' measured 99.73% error quantiles (about 0.0079 and 0.0157). Measured coverage: sign-magnitude 1.0000, i8 0.9519. The 3σ level is 0.9973, so sign-magnitude passes and i8 fails. The paired z of the error difference is 246.9. Quantizing the sign-magnitude table to even codes turns the gate red (coverage 0.9046).
Scope: scalar reference only; the SIMD cost of the u8 × u8 accumulation is not measured. In the two earlier disable runs, removing the presence AND failed 3 of the then 6 tests and replacing the sign XOR with AND failed 2.
Tests
Parity group
0x13xx: covers both directions, the mismatch count and the round trip. It runs at 12 lengths across every 8- and 16-lane group boundary, with leftover set bits beyond the last row and with a surplus output word.Parity groups
0x139xx–0x13Cxx: cover 6 operators × 9 thresholds (NaN, ±0, ±inf, subnormal, ±1, MAX), for both f64 and f32, plus the FALSE plane.The reference never does a float comparison. It detects NaN from the exponent and mantissa bits, and orders values by a sign-magnitude key in which
-0 == +0. (That is the float-0.0, an ordinary zero, not the sign-magnitude-0above.)Every backend run is green, 21/21 groups: native AVX-512, AVX2 (x86-64-v3), wasm, wasm without SIMD, wasm with relaxed SIMD, NEON under qemu, AVX under qemu, x86-64-v2 under qemu, and nightly.
Disable runs: each guard was broken in turn, the parity program was run, and the guard was restored. Every run failed, as intended:
x == xreplaced byx < inf<>NOTas a bare complementUnit tests, doctests and lint: 13 unit tests and 19 doctests pass, plus the probe's 7 tests.
cargo clippy --lib --tests -D warningsis clean, as are clippy on the parity crate and on the probe.cargo fmt --checkis clean for every line this PR changes; the parity crate still has older formatting diffs that this PR does not touch.Not in this PR
mask_andandmask_or.NaN != NaN, grouping has to use the presence bit as the key.quantize_f32_to_i8andquantize_f32_to_u8(src/hpc/quantized.rs) turn NaN into a real code through a saturating cast, so a NULL = NaN lane passed through them loses its NULLs. Not changed here.lut9, the SIMD form of the magnitude-indexed table, is in simd: simd_stride.rs (lut_u8, lut9) + FACET STRIDE rule and guard #382 (src/simd_stride.rs).🤖 Generated with Claude Code
https://claude.ai/code/session_01XAqKMPh2Seh2WLccCksAdY