PiPNN 1/6: add numerical kernels - #1287
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds the first set of PiPNN “kernel” building blocks to the DiskANN Rust workspace: SIMD-accelerated top‑k selection for partition assignment and leaf neighbor selection, along with supporting SIMD division and a new lower-triangular A·Aᵀ helper in diskann-linalg.
Changes:
- Add a new
diskann-pipnncrate withpartition_kernelandleaf_kernelimplementations plus extensive correctness tests and Criterion benchmarks. - Extend
diskann-wideto supportDivon relevant f32 SIMD types (native, doubled, and scalar/emulated) and add a corresponding division test macro. - Add
diskann_linalg::sgemm_aat_lower(lower-triangle-only AAT) and wire new crate/tests/CI/mutants exclusions into the workspace.
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| diskann-wide/src/test_utils/ops.rs | Adds test_div! macro to validate lane-wise SIMD division correctness. |
| diskann-wide/src/emulated.rs | Adds Div for scalar/emulated Emulated<f32, N, A> to support division in scalar dispatch. |
| diskann-wide/src/doubled.rs | Adds Div for Doubled<T> to support composite SIMD widths. |
| diskann-wide/src/arch/x86_64/v4/f32x8_.rs | Adds AVX Div op mapping + division tests. |
| diskann-wide/src/arch/x86_64/v4/f32x4_.rs | Adds SSE Div op mapping + division tests. |
| diskann-wide/src/arch/x86_64/v4/f32x16_.rs | Adds AVX-512 Div op mapping + division tests. |
| diskann-wide/src/arch/x86_64/v3/f32x8_.rs | Adds AVX Div op mapping + division tests for V3. |
| diskann-wide/src/arch/x86_64/v3/f32x4_.rs | Adds SSE Div op mapping + division tests for V3. |
| diskann-wide/src/arch/x86_64/v3/f32x16_.rs | Adds division tests for the f32x16 V3 path (likely via doubled composition). |
| diskann-wide/src/arch/aarch64/f32x4_.rs | Adds Neon Div op mapping + division tests. |
| diskann-wide/src/arch/aarch64/f32x2_.rs | Adds Neon Div op mapping + division tests. |
| diskann-pipnn/tests/partition_kernel.rs | New integration tests for partition top‑k dispatch correctness and edge cases. |
| diskann-pipnn/tests/leaf_kernel.rs | New integration tests for leaf neighbor top‑k dispatch correctness and edge cases. |
| diskann-pipnn/src/partition_kernel/tests.rs | New unit tests comparing scalar reference vs runtime dispatch and metric contracts. |
| diskann-pipnn/src/partition_kernel.rs | New partition-assignment distance + top‑k kernel with validation and SIMD dispatch. |
| diskann-pipnn/src/lib.rs | New crate root exporting PiPNN kernel modules. |
| diskann-pipnn/src/leaf_kernel/tests.rs | New unit tests for scalar reference parity and workspace behavior. |
| diskann-pipnn/src/leaf_kernel.rs | New fused lower-triangle leaf neighbor kernel with SIMD dispatch and workspace support. |
| diskann-pipnn/Cargo.toml | Defines new diskann-pipnn crate, dev-deps, and benches. |
| diskann-pipnn/benches/kernels.rs | Adds benchmarks for partition top‑k, lower AAT, leaf top‑k, and full leaf workflow. |
| diskann-linalg/tests/sgemm_aat_lower.rs | New tests for lower-triangle AAT behavior and validation errors. |
| diskann-linalg/src/lib.rs | Adds public sgemm_aat_lower API with dimension checks. |
| diskann-linalg/src/faer.rs | Implements sgemm_aat_lower_impl using Faer triangular matmul. |
| Cargo.toml | Adds diskann-pipnn to workspace members and workspace dependencies. |
| Cargo.lock | Records the new diskann-pipnn package entry. |
| .github/workflows/ci.yml | Adds diskann-pipnn to CI test package lists. |
| .cargo/mutants.toml | Adds mutation-test exclusions for kernel code paths and equivalent transformations. |
Comments suppressed due to low confidence (2)
diskann-pipnn/src/leaf_kernel.rs:651
- Same issue as the L2 arm: using
max_simdfor lower clamping can erase NaNs on the Scalar/Emulated backend, making NaN distances rankable. Clamp withlt_simd+selectto preserve NaNs consistently.
Metric::CosineNormalized => {
let distance = F::splat(arch, 1.0) - dot;
zero.max_simd(distance)
}
diskann-pipnn/src/leaf_kernel.rs:664
- The cosine path also uses
zero.max_simd(distance)for clamping, which can collapse NaNs to zero on the Scalar/Emulated backend (viaf32::max). That contradicts the comment about preserving non-rankable NaNs and can change output ordering. Prefer anlt_simd+selectclamp here as well.
let distance = one - cosine;
// Comparisons with NaN are false, so this explicit lower clamp
// preserves non-rankable NaNs while matching the existing PiPNN
// distance formulas for finite values.
zero.max_simd(distance)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e204cb9 to
b046174
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1287 +/- ##
==========================================
+ Coverage 90.59% 92.51% +1.91%
==========================================
Files 513 519 +6
Lines 99091 99281 +190
==========================================
+ Hits 89775 91849 +2074
+ Misses 9316 7432 -1884
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 26 out of 27 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
diskann-pipnn/src/partition_kernel/tests.rs:20
- The
PartitionTopKcontract forMetric::L2expectsleader_scalesto contain squared leader norms (see docs anddistance(Metric::L2, ..)test). This helper currently populates unsquared norms, which makes the test data inconsistent with the public API contract and could hide contract-related bugs.
let leader_scales = match metric {
Metric::L2 => (0..leaders).map(|leader| (leader + 1) as f32).collect(),
Metric::Cosine => (0..leaders)
.map(|leader| {
diskann-pipnn/src/partition_kernel.rs:61
InvalidFanout’s error message says the maximum is{maximum}, but validation also rejectsfanout > leaders. Whenleaders < maximumthis message is misleading (it implies the only limit is{maximum}). Consider spelling out both constraints in the message so callers immediately see why it failed.
#[error("invalid fanout {fanout} for {leaders} leaders; maximum is {maximum}")]
8fb4e92 to
20ab8a0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 26 changed files in this pull request and generated no new comments.
Suppressed comments (1)
diskann-pipnn/src/partition_kernel.rs:294
- For
Metric::Cosine, NaN norms currently produce a finite distance (1.0) becausedenominator.gt_simd(0)is false for NaN, so the lane falls back tocosine = 0. That makes NaN-derived pairs/leaders “rankable”, which contradicts the module’s stated NaN-rejection behavior and differs fromdiskann-vectorcosine semantics (NaN norms propagate to a NaN similarity/distance). Consider explicitly preserving NaN denominators so the resulting distance stays NaN and is ignored byinsert_topk.
let denominator = row_norm * leader_norm;
let valid = denominator.gt_simd(zero);
let safe_denominator = valid.select(denominator, one);
let cosine = valid.select(dot / safe_denominator, zero);
one - cosine
| check_length("leader scales", input.leader_scales.len(), leader_scales) | ||
| } | ||
|
|
||
| fn checked_area( |
There was a problem hiding this comment.
checked_area, check_length, ShapeOverflow and InvalidBufferLength are duplicated character-for-character with leaf_kernel. Small enough to shrug at now, but with four more PRs coming it's probably worth a src/shape.rs with a shared ShapeError that each kernel error wraps via #[from].
There was a problem hiding this comment.
I kept the two tiny checked-area/length adapters local because they construct different public kernel error types and sit immediately before each module's unsafe accesses. MatrixView adoption removed the other duplicated shape state; introducing a shared wrapped error would enlarge the public error interface for two call sites.
|
Review follow-up at PR1 head Dispatch and API
Documentation
Tests and repository fit
Validation: Pinned fixed-iteration leaf measurements still show no material kernel regression after converting fixed outputs to array rows once per leaf: k=3 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 26 changed files in this pull request and generated no new comments.
Suppressed comments (1)
diskann-pipnn/src/kernel_metric.rs:152
L2::partition_distanceusesmul_add_simd, which can be a fused multiply-add (e.g._mm256_fmadd_ps). That means SIMD-chunk distances can differ from the scalar tail formulaleader_scale - 2.0 * dot(this file’s ownl2_partition_scalar_tail_preserves_non_fused_roundingtest demonstrates such a mismatch). BecausePartitionKernelmixes SIMD chunks and a scalar tail within the same row, this can change ordering/tie behavior depending on whether a leader lands in the SIMD chunk or tail.
F::splat(arch, -2.0).mul_add_simd(dot, leader_scale)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 26 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/workflows/nightly.yml:23
DISKANN_FEATURESis defined as a folded multi-line string with trailing commas. YAML folding inserts spaces at line breaks, producing feature tokens like"tracing, experimental_diversity_search"(note the space) which can be mis-parsed as invalid feature names. Prefer a whitespace-separated feature list (or a single-line comma-separated list without spaces) to avoid CI flakiness.
DISKANN_FEATURES: >-
virtual_storage,spherical-quantization,product-quantization,tracing,
experimental_diversity_search,disk-index,flatbuffers,linalg,codegen,
multi-vector,bftree,inmem2,integration-test
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 26 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/workflows/nightly.yml:23
DISKANN_FEATURESis defined as a folded scalar with commas at line ends. YAML folding inserts spaces at line breaks, producing a value liketracing, experimental_diversity_search,...which can be parsed as having empty/whitespace-prefixed feature names depending on Cargo’s splitting rules. This is brittle and can break thecargo ... --features "${{ env.DISKANN_FEATURES }}"steps.
DISKANN_FEATURES: >-
virtual_storage,spherical-quantization,product-quantization,tracing,
experimental_diversity_search,disk-index,flatbuffers,linalg,codegen,
multi-vector,bftree,inmem2,integration-test
Use output columns as the sole leaf-specific neighbor count and reserve row/column terminology for matrix shapes. BREAKING CHANGE: LeafKernel::new no longer takes k, nearest_neighbors returns (), and kernel input/neighbor/error fields use source-target and point-leader names.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 26 changed files in this pull request and generated no new comments.
Suppressed comments (1)
diskann-pipnn/src/leaf_kernel.rs:467
- The comment claims no output or scratch mutation occurs on error, but after
validate(...)the call toprepare_workspace(...)can returnLeafKernelError::Allocationafter partially resizing/fillingworkspace.norms(beforeworkspace.worstis reserved). This makes the comment/documentation inaccurate and could mislead callers relying on workspace immutability on error.
// Validation establishes every shape and active-prefix invariant used by
// unchecked loads below. No output or scratch mutation occurs on error.
validate(call.input, &call.output)?;
Adds the numerical kernels used by later PiPNN layers.
Code map
diskann-linalg::sgemm_aat_lowercomputesA · Aᵀbut writes only the lower triangle. Callers may leave the upper triangle uninitialized; tests assert that it is not touched.partition_kernel.rsconverts a row of point/leader dot products into the nearestfanoutleader IDs. Metric-specific norm handling happens before the fixed-size top-k insertion.leaf_kernel.rsscans each strict-lower-triangle pair once and updates both endpoint top-k trackers.k <= 3uses const-sized insertion arms; largerkuses the dynamic fallback.diskann-wide; PiPNN targetsArchitectureassociated vector types only.Review path
f32::MAXcandidates.cosine_zero_norm_masks_nan_norm_at_simd_boundaries; SIMD max has backend-specific NaN behavior, so the clamp explicitly selects the original NaN.Validation includes differential boundary tests, x86-64 baseline/AArch64 builds, SDE jobs, Criterion workloads, and full-leaf numerical tests.
Stack 1/6 → #1288