Repository navigation
[muilt-vetor] Add standalone MinMax8 x MinMax4 MaxSim kernel - #1494
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The new unsafe SIMD paths require cross-platform validation and final human review.
0 open findings
What changed in this PR
Adds a standalone quantized MaxSim kernel to DiskANN’s matrix kernels, leaving distance API integration for a follow-up.
Changes:
- Implements packed-A, B-tiled computation for Scalar, V3, V4, and Neon.
- Adds compensated inner products and NaN-aware maximum reduction.
- Adds supporting SIMD conversions and regression coverage.
| File | Description |
|---|---|
| diskann-wide/src/reference.rs | Adds reference u32-to-f32 conversion. |
| diskann-wide/src/emulated.rs | Adds and tests 16-lane i32-to-f32 conversion. |
| diskann-wide/src/arch/x86_64/v4/conversion.rs | Adds and tests AVX-512 conversion. |
| diskann-wide/src/arch/x86_64/v3/conversion.rs | Adds and tests split-vector conversion. |
| diskann-wide/src/arch/aarch64/u32x4_.rs | Adds and tests Neon conversion and reinterpretation. |
| diskann-quantization/src/matrix_kernels/maxsim/packed_minmax8_x_unpacked_minmax4.rs | Implements the kernel, backends, and regression tests. |
| diskann-quantization/src/matrix_kernels/maxsim/mod.rs | Registers the kernel pending integration. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1494 +/- ##
==========================================
+ Coverage 91.06% 91.11% +0.05%
==========================================
Files 591 592 +1
Lines 122196 123745 +1549
==========================================
+ Hits 111275 112754 +1479
- Misses 10921 10991 +70
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Support all 1-8 bit A/B combinations through shared packing, tiled execution, compensation and maximum-inner-product reduction. Retain the tuned byte backends alongside full-range i16 paths, keep quantization widths out of the numeric microkernels, and add the required SIMD conversions and correctness coverage. Leave factory, fallback and public distance integration to follow-up PRs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 74814a43-c576-493a-8783-585ef48c3f1c
f074880 to
e465898
Compare
Mark Hildebrand (hildebrandmw)
left a comment
There was a problem hiding this comment.
Thanks Junkui. This is a simplification over the earlier PR! There still is some coupling between the lower-level kernels and some of the higher data preparation stuff.
A few other things that stand out to me:
- It makes heavy use of post-monomorphization errors via
const { assert!(...) }. These aren't necessarily wrong, but they are kind of hard to debug when they trigger, don't compose with higher level code well, and to me often indicate that there is another way of structuring the code so they aren't needed. I'm not saying get rid of them, but that over reliance could indicate a missing abstraction. - Why are 16-wide accumulators used for all architectures? This seems like it could be problematic for Neon or Scalar. Have you checked that the generated code isn't spilling too much and is reasonable?
I know a few other folks are planning on reviewing this as well - let's see what they have to say.
e360602 to
2538cc7
Compare
Thanks for the feedback. I’ve moved SIMD-specific operations behind I’ve also added MR=8 alternatives for Neon, V3, and Scalar’s i16 path rather than requiring 16-wide accumulators everywhere. Earlier V3 assembly inspection showed register-resident accumulators in the full contraction loop, but stack traffic around compensation and tails; I’m not claiming all configurations are spill-free.
|
Move bulk decoding into BitSlice and zero-pad prepared B rows for a unified pack loop. Decouple backend representations behind fixed-size operations, retain smaller row-panel choices, and replace redundant test sweeps with directed coverage. Make B preparation independent of backend and row-panel types by accepting a code converter. Keep backend capability validation at the Driver construction boundary. Give each backend the full microkernel compensation and reduction stage through max_into with borrowed coefficients. Keep MR16 contraction intact while V3 reduces native eight-row halves. Define backend operations explicitly and share the compensation formula; preserve floating-point order and NaN semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2538cc7 to
41710a5
Compare
Use From<u8> for architecture-independent A packing. Project canonical B metadata into the existing Coefficients type at preparation, preserving dimension checks and updating cache footprints and focused regression tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mark Hildebrand (hildebrandmw)
left a comment
There was a problem hiding this comment.
I still have structural maintenance concerns. The lowering infrastructure either reverifies constraints that the caller should have already established (via asserts), or through slicing, or through tests rather than making the structure easy to follow.
There's also a pretty hefty monomorphization tax for all the different parameters run under test that I'm not thrilled about.
If your team is willing to accept all maintenance associated with this code, I'll sign off.
|
Thanks, Mark. I pushed another cleanup. K now comes from packed A instead of being passed separately, A’s coefficients are prepared per panel, and B reuses the existing unpacked traversal. I also reduced the full-driver test combinations and removed duplicate test setup. |
Clarify BitSlice decode_into test names without changing test behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 74814a43-c576-493a-8783-585ef48c3f1c
d3347e2 to
0977338
Compare
Reuse the u32x4-to-f32x4 conversion and tests from main, retain the unsigned-byte reinterpretation and composed casts, and remove duplicate conversion definitions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 74814a43-c576-493a-8783-585ef48c3f1c
Mark Hildebrand (hildebrandmw)
left a comment
There was a problem hiding this comment.
Thanks for your patience - I think there's still a lot of work that can be done within all of matrix_kernels to make these less spooky. But let's unblock the work gated behind this.
# DiskANN v0.61.0 ## Highlights - **Quantization:** Added 3-bit spherical quantization with AVX2 acceleration, faster spherical encoding, and NEON float32 MinMax kernels. - **In-memory indexing (experimental):** Added product quantization and 1-8-bit scalar quantization, unified quantized representations, and AArch64 prefetching. - **Multi-vector search:** Added `i8 x i8` and MinMax8 x MinMax4 MaxSim kernels. - **Fixes:** Preserve virtual start-point out-edges when writing disk indexes, correctly round-trip scalar quantization configurations without standard deviation, and support zero-column mutable matrix iterators. ## Breaking changes and upgrading Changes are concentrated in quantization APIs and experimental/tooling crates. * PQ training (#1467) - Training now returns `BasicTable`. `SimplePivots` was removed. Replace `flatten()` with `view_pivots().as_slice()` and use `pivots_for(chunk)` for per-chunk access. * PQ distance tables (#1458) - Change `ProcessInto` bounds to `ProcessInto<f32>` and calls from `process_into::<Metric>(...)` to `process_into::<Metric, f32>(...)`. * MaxSim kernels (#1429) - Generic kernel/erasure code now requires `T: MaxSimElement` and score buffers of `T::Score` (`f32` for floats, `i32` for `i8`). Update `build_max_sim` error handling from `NotSupported` to `BuildMaxSimError`. * `diskann-inmem` (#1485) - Replace `repr::Spherical` with `repr::Quantized`. Wrap the quantizer in `repr::quantized::spherical::Spherical::new(...)` when configuring it. Configuration and `Rerank` types now live under `repr::quantized`. * `diskann-benchmark-runner` (#1475) - `input::Registered` and public `Registry::input` were removed. Use the concrete `Input` implementation's `tag()` and `example()` methods instead. ## All Changes * Fix serialization round trip for QuantizationType::SQ without standard deviation by @arrayka in #1461 * i8 x i8 MaxSim Kernels by @suri-kumkaran in #1429 * Adding `subview_mut` to `MatrixMut` by @arkrishn94 in #1463 * Add InsertResult::SuccessUpdate by @metajack in #1449 * [diskann-quantization] PQ Infrastructure for `diskann-inmem` by @hildebrandmw in #1458 * [diskann-quantization] Teach PQ training to return a `BasicTable`. by @hildebrandmw in #1467 * [deps] Run `cargo-update` by @hildebrandmw in #1452 * Support zero-column mutable matrix iterators by @arrayka in #1462 * [diskann-quantization] Use `f32::NAN` instead of `core::f32::NAN`. by @hildebrandmw in #1471 * [diskann-wide] Add `V4::new_checked_miri_uncached`. by @hildebrandmw in #1480 * [diskann-wide] Add maddubs intrinsic wrappers to V3 and V4 by @partychen in #1479 * Bump the github-actions group across 1 directory with 5 updates by @dependabot[bot] in #1482 * [benchmark-runner] Simplify Input representation by @hildebrandmw in #1475 * [diskann-quantization] Optimize spherical encoding scale search by @xinyuwen2 in #1478 * [diskann-garnet] Implement XVCREATE, XVIMPORT by @metajack in #1455 * [diskann-garnet] Support configurable start points and allow importing start points by @metajack in #1464 * [diskann-garnet] Add spherical 2-bit and 4-bit quantization by @metajack in #1465 * [deps] Address depandabot issue 32 by @hildebrandmw in #1496 * [diskann-disk] Preserve virtual start point out-edges when writing the disk index by @doliawu in #1483 * [diskann-quantization] Add Neon F32 Minmax Kernels by @pfoxARM in #1431 * [diskann-garnet] Add macOS arm64 support to NuGet publishing by @metajack in #1495 * [diskann-disk] Require start points at index initialization. by @hildebrandmw in #1497 * Expose metric-aware quantizer centroid distance by @cherryrhea in #1395 * [diskann-inmem] Add support for Product Quantization by @hildebrandmw in #1469 * Adds aarch64 prefetching into diskann-vector and diskann-inmem by @pfoxARM in #1408 * [diskann-inmem] Add scalar quantization by @hildebrandmw in #1484 * Bump the github-actions group with 3 updates by @dependabot[bot] in #1505 * [diskann-inmem] Spherical Quantization Round 2 by @hildebrandmw in #1485 * [diskann-quantization] Add SphericalQ 3-bit support and AVX2 kernel by @xinyuwen2 in #1474 * [muilt-vetor] Add standalone MinMax8 x MinMax4 MaxSim kernel by @partychen in #1494 ## New Contributors * @cherryrhea made their first contribution in #1395 **Full Changelog**: v0.60.0...v0.61.0 Co-authored-by: Mark Hildebrand <mhildebrand@microsoft.com>
No new dependencies. Public additions are backward-compatible SIMD trait implementations. The matrix kernel and
BitSlice::decode_intoremainpub(crate); existing distance APIs and canonical MinMax storage are unchanged. Contracts and safety requirements are documented inline.Reference Issues/PRs
Reworks the matrix-kernel portion of #1394 into a standalone implementation. Uses SIMD reinterpretation and
maddubssupport from #1445 and #1479.What does this implement/fix? Briefly explain your changes.
Adds an internal matrix MaxSim kernel for MinMax A/B inputs with 1-8 bits per code, supporting all 64 input-width combinations through the available numeric layouts. A is packed once and reused across B comparisons; each call writes one compensated maximum inner product per A row without materializing the full pairwise score matrix.
Preparation and execution
From<u8>and stores coefficients per physical panel. Internal A/B views bind codes, coefficients, and dimensions together instead of passing unrelated slices through the kernel.Drive -> PanelKernel -> MicroKernelstructure prepares each B tile once and reuses it across A panels.BitSlice<'_, NBITS, Unsigned, Dense>::decode_into, not MinMax-local bit-width special cases. It applies conversion while writing, ignores unused trailing bits, and rejects a length mismatch before writing or invoking the callback.ExtraWide<MR, PACK>exposes numeric backend operations without input-width parameters. Concrete load/store operations establish register extents. The Driver derives K and A's width from the packed input and retains the integer-range and B-width checks.PanelKernelimplementations. Each handles only its applicable remainders; unsupported NR configurations do not implement the required trait.Available layouts
All layouts accept A_BITS=1-8. MR counts A rows per microkernel; PACK counts contraction elements processed together. These are available layouts, not an automatic selection policy.
u8/i8i16/i16u8/i8i16/i16u8/i8i16/i16u8/u8The byte limits prevent signed-byte misinterpretation and, on V3, saturation of intermediate i16 sums. They guarantee correctness for the full A code range, not just a particular A_BITS. Full-range eight-bit B uses the i16 path on Scalar/x86 and unsigned byte dots on Neon; widening does not requantize the inputs.
The original V3 byte layout remains alongside the general path. MR=16 V3 compensation finishes one native eight-row half before processing the other, and MR=8 alternatives are available. These changes are not a claim that generated code is spill-free or that one layout is optimal for every workload.
Behavior and tests
i32::MAX / ((2^A_BITS - 1) * (2^B_BITS - 1)): 561,433 for 8x4/4x8 and 33,025 for 8x8. Conversion to f32 may still round.Any other comments?
Scope: Factory/ISA selection, public prepared-query distance integration, distance negation/no-match adaptation, externally owned/FFI layouts, relocation of the pairwise implementation into fallback, and benchmark integration remain follow-up work. No temporary performance or code-generation tooling is included.
Validation at
0977338a-- Windows x86-64:cargo fmt --all --checkcargo test -p diskann-quantization --lib --quiet -- bits::slice::tests::test_decode_into matrix_kernels::maxsim::packed_minmax_x_unpacked_minmaxcargo clippy --workspace --all-targets --quiet -- -D warningscargo clippy -p diskann-quantization -p diskann-wide --all-targets --target aarch64-pc-windows-msvc --quiet -- -D warningsScalar and V3 execute locally; V4 test bodies are conditionally skipped on this host but still compiled. Neon execution, SDE/Miri, and coverage were not rerun for this head. Earlier CI/coverage results and exploratory performance timings are not claimed as validation of this revision.