Skip to content

PiPNN 2/6: add numerical kernels - #1287

Open
weiyaoluo (SeliMeli) wants to merge 107 commits into
mainfrom
pipnn-stack/01-kernels
Open

PiPNN 2/6: add numerical kernels#1287
weiyaoluo (SeliMeli) wants to merge 107 commits into
mainfrom
pipnn-stack/01-kernels

Conversation

@SeliMeli

@SeliMeli weiyaoluo (SeliMeli) commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Purpose

This PR adds the numerical kernels that PiPNN uses for partition ranking and leaf-neighbor selection.

It does not add graph construction, providers, serialization, or search.

Module structure

  • leaf_metric.rs writes one flattened lower-triangle ranking buffer for a leaf.
  • partition_metric.rs writes one flattened point-to-leader ranking buffer for a point stripe.
  • leaf_kernel.rs scans each unordered point pair once and retains local top-k neighbors.
  • partition_kernel.rs retains the nearest sampled leaders for each point.
  • simd.rs selects one dispatched f32 vector type for both ranking kernels.
  • diskann-linalg provides lower-triangle replace and add forms of scaled A · Aᵀ.

The metric modules own GEMM configuration, portable norm-prefill loops, and metric formulas. They do not receive an architecture value. The kernels own architecture dispatch, buffer reuse, SIMD/scalar traversal, and top-k insertion.

The leaf entry point validates output width before it changes scratch or evaluates distances. The internal ranking loop returns (). Insertion returns the farthest retained ranking distance.

Metric data flow

Leaf

  • L2 initializes the lower triangle with endpoint squared-norm sums. GEMM adds -2 · A · Aᵀ.
  • Cosine uses GEMM for dot products. It derives norms from the diagonal and converts the lower triangle in place.
  • Normalized cosine and inner product share the GEMM calculation with alpha = -1. They use -dot as the ranking distance because the omitted constant cannot change order. Their metric types remain separate.

Partition

PartitionMetric::create_leaders returns an opaque metric-owned leader set. The caller does not manage its norms.

  • L2 computes sequentially reduced leader squared norms during construction.
  • Cosine computes leader norms during construction.
  • Normalized cosine and inner product share the negative-dot calculation and need no leader norms.
  • L2 omits the point norm because it is constant across one leader-ranking row.

Point stripes share immutable leader norms. Construction computes them before parallel stripe work starts; there is no lazy initialization state.

Numerical behavior

  • Equal distances can select either candidate. No fixed tie order is required.
  • NaN and positive infinity do not enter retained top-k sets.
  • A finite negative Gram-expanded L2 value remains a valid internal ranking distance.
  • Cosine preserves DiskANN zero-norm handling and clamps finite similarity to [-1, 1].
  • GEMM can return either zero sign. Tests check numeric zero, not the bit pattern of a scalar reduction. This PR adds no zero-sign normalization.

Tests

Ranking tests pass distance buffers directly to the ranking kernels. Metric tests call the production metric implementations. The shared cosine helper tests cover clamp, zero-norm, subnormal, and NaN behavior.

The private tests cover:

  • all four metrics;
  • lower-triangle replace and add behavior;
  • fixed top-k widths and the runtime-width path;
  • SIMD lane boundaries and scalar tails;
  • valid tied candidates, NaN, infinity, numeric zero, and negative ranking distances;
  • singleton leaves and invalid neighbor widths;
  • workspace reuse and unchanged buffers after width rejection;
  • sequential L2 leader-norm reduction.

Local validation for the audit cleanup and leaf-kernel follow-up:

  • PR2 cargo test --locked -p diskann --all-features --lib: 463 passed, including 109 PiPNN tests.
  • AArch64 Linux musl under QEMU: all 109 PiPNN tests passed. The original scalar-bit-pattern assertions failed in this environment before the fix.
  • cargo test --locked -p diskann-linalg --lib sgemm_aat_lower: 6 passed.
  • Complete stacked PR6 cargo test --locked -p diskann --all-features --lib: 613 passed in an isolated worktree with the PR2 patch.
  • PR2 and PR6 cargo clippy --locked -p diskann --all-features --all-targets -- -D warnings: passed.
  • cargo fmt --all --check and git diff --check: passed.

Prefill microbenchmarks

Measured on an AMD EPYC 7763 with portable x86-64 compilation. LLVM vectorized the scalar loops with baseline SSE2.

For Leaf L2, portable scalar prefill was 45–77% faster than the prior explicit SIMD loop across 16–512 points. For Partition L2, results depended on leader count: most tested shapes improved, while 128/256/512/1000 leaders regressed by 1.5–7.9% in the isolated prefill loop.

Earlier E2E A/B

These E2E measurements precede the portable-prefill replacement and the subsequent audit cleanup. The prefill change used the microbenchmarks above. The audit cleanup used unit tests and Clippy; it has no new performance measurements.

Measured locally on 16 logical CPUs of an AMD EPYC 7763. Both binaries used -C target-cpu=native and identical HashPrune configurations.

Dataset Runs Build median Wall median Peak RSS median Recall
BigANN 10M baseline 5 124.383 s 141.06 s 11.583 GiB 0.956730
BigANN 10M candidate 5 126.690 s (+1.85%) 140.21 s (-0.60%) 11.581 GiB (-0.01%) 0.956730
Enron 1M baseline 3 22.324 s 28.66 s 2.268 GiB 0.972889
Enron 1M candidate 3 20.993 s (-5.96%) 26.56 s (-7.33%) 2.274 GiB (+0.27%) 0.972911

BigANN paired build-time deltas had a +2.35% median. Every BigANN run had identical recall and mean hops. Enron paired build-time deltas had a -6.11% median.

Review order

  1. Review diskann-linalg/src/faer.rs and the lower-triangle API in diskann-linalg/src/lib.rs.
  2. Review diskann/src/graph/pipnn/leaf_metric.rs.
  3. Review diskann/src/graph/pipnn/leaf_kernel.rs.
  4. Review diskann/src/graph/pipnn/partition_metric.rs.
  5. Review diskann/src/graph/pipnn/partition_kernel.rs.
  6. Review diskann/src/graph/pipnn/simd.rs and the nightly Miri scope.

Stack

Stack 2/6. #1315 is merged into main. #1290 adds provider-independent graph construction.

@SeliMeli
weiyaoluo (SeliMeli) requested review from a team and a lite review from Copilot July 29, 2026 11:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-pipnn crate with partition_kernel and leaf_kernel implementations plus extensive correctness tests and Criterion benchmarks.
  • Extend diskann-wide to support Div on 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_simd for lower clamping can erase NaNs on the Scalar/Emulated backend, making NaN distances rankable. Clamp with lt_simd + select to 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 (via f32::max). That contradicts the comment about preserving non-rankable NaNs and can change output ordering. Prefer an lt_simd + select clamp 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.

Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel/tests.rs Outdated
@SeliMeli weiyaoluo (SeliMeli) changed the title Pipnn stack/01 kernels PiPNN 1/6: add numerical kernels Jul 29, 2026
Copilot AI review requested due to automatic review settings July 30, 2026 08:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated no new comments.

@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.69281% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.50%. Comparing base (600c2b9) to head (00b8a5c).

Files with missing lines Patch % Lines
diskann/src/graph/pipnn/partition_metric.rs 95.45% 9 Missing ⚠️
diskann/src/graph/pipnn/topk.rs 98.40% 3 Missing ⚠️
diskann/src/graph/pipnn/leaf_kernel.rs 99.57% 1 Missing ⚠️
diskann/src/graph/pipnn/partition_kernel.rs 99.12% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1287      +/-   ##
==========================================
- Coverage   91.55%   91.50%   -0.05%     
==========================================
  Files         521      528       +7     
  Lines      100302   101756    +1454     
==========================================
+ Hits        91828    93113    +1285     
- Misses       8474     8643     +169     
Flag Coverage Δ
miri 91.50% <98.69%> (-0.05%) ⬇️
unittests 91.30% <98.69%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
diskann-linalg/src/faer.rs 100.00% <100.00%> (ø)
diskann-linalg/src/lib.rs 99.77% <100.00%> (+0.08%) ⬆️
diskann-utils/src/views.rs 100.00% <100.00%> (ø)
diskann/src/graph/pipnn/leaf_metric.rs 100.00% <100.00%> (ø)
diskann/src/graph/pipnn/mod.rs 100.00% <100.00%> (ø)
diskann/src/graph/pipnn/simd.rs 100.00% <100.00%> (ø)
diskann/src/graph/pipnn/leaf_kernel.rs 99.57% <99.57%> (ø)
diskann/src/graph/pipnn/partition_kernel.rs 99.12% <99.12%> (ø)
diskann/src/graph/pipnn/topk.rs 98.40% <98.40%> (ø)
diskann/src/graph/pipnn/partition_metric.rs 95.45% <95.45%> (ø)

... and 41 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI review requested due to automatic review settings July 30, 2026 08:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 PartitionTopK contract for Metric::L2 expects leader_scales to contain squared leader norms (see docs and distance(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 rejects fanout > leaders. When leaders < maximum this 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}")]

Copilot AI review requested due to automatic review settings July 31, 2026 04:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) because denominator.gt_simd(0) is false for NaN, so the lane falls back to cosine = 0. That makes NaN-derived pairs/leaders “rankable”, which contradicts the module’s stated NaN-rejection behavior and differs from diskann-vector cosine semantics (NaN norms propagate to a NaN similarity/distance). Consider explicitly preserving NaN denominators so the resulting distance stays NaN and is ignored by insert_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

Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann/src/graph/pipnn/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated

@partychen juchen-ms (partychen) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work overall. I found one correctness issue in the cosine handling that should be resolved before merge. The remaining comments are mostly about reducing duplicated or unsafe code and tightening the API contracts.

Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann/src/graph/pipnn/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-linalg/src/lib.rs Outdated
Comment thread diskann-wide/src/emulated.rs Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Weiyao, this is progress from the previous mega-PR. I still have some big-picture comments (we covered most of these offline) -

  • Documentation: As I mentioned, we need thorough documentation in the diskann-pipnn crate. The main modules, partition_kernel and leaf_kernel need documentation up top, highlighting the main structures and how they are used - e.g. process_rows_binary/unary and nearest_leaders. Similarly with process_pairs_simd_* and nearest_leaf_neighbors
  • Testing: I am concerned about the lack of testing for partition_kernel.rs and leaf_kernel.rs.
    • I notice some e2e integration tests but these kernels should be thoroughly tested, sweeping different input parameters, architectures and edge cases. This is especially needed given the amount of unsafe code.
    • That brings me to miri - there should be miri tests too.
    • I'm curious why are the tests in a separate submodule to the main files (for partition_kernel.rs and leaf_kernel.rs)? Let's try to keep tests along with the code being tested.
  • Criterion: Since criterion is not a standard part of our library for benchmarking, let us not introduce it for this crate.
  • Kernel dispatch: I left comments about you're disptaching the kernels, please take a look.

Comment thread .cargo/mutants.toml Outdated
Comment thread diskann-pipnn/src/lib.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/src/partition_kernel.rs Outdated
Comment thread diskann-pipnn/tests/leaf_kernel_api.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Comment thread diskann-pipnn/src/leaf_kernel.rs Outdated
Copilot AI review requested due to automatic review settings August 3, 2026 02:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated no new comments.

Suppressed comments (2)

diskann-pipnn/src/partition_kernel/tests.rs:19

  • PartitionTopK::leader_scales is documented as "squared leader norms for L2" (and cosine uses unsquared norms), but this test helper feeds unsquared values for the L2 case. That makes the test data inconsistent with the public contract and can mask mistakes in distance computation. Consider squaring the L2 norms here so the tests exercise the intended inputs.
    let leader_scales = match metric {
        Metric::L2 => (0..leaders).map(|leader| (leader + 1) as f32).collect(),
        Metric::Cosine => (0..leaders)

diskann-pipnn/src/partition_kernel.rs:252

  • For the L2 path, the SIMD chunk uses mul_add_simd (fused multiply-add) but the scalar tail uses norm - 2.0 * dot (non-fused). This can introduce small rounding differences between SIMD and tail elements, which can change ordering/tie behavior right at SIMD-width boundaries. Use f32::mul_add for the scalar tail so both paths compute the same value shape.
                |dot, norm| F::splat(arch, -2.0).mul_add_simd(dot, norm),
                |dot, norm| norm - 2.0 * dot,

@SeliMeli

Copy link
Copy Markdown
Contributor Author

weiyaoluo (@SeliMeli) please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

@microsoft-github-policy-service agree company="Microsoft"

Copilot AI review requested due to automatic review settings August 3, 2026 10:49
Use named cases and derived expected values so each failure identifies a ranking behavior that can change graph output.
Derive Gram, dot, and norm inputs from source vectors and name each test by the ranking behavior it protects.
Add direct SIMD metric coverage and make the caller-owned insertion eligibility precondition explicit in names, docs, and tests.
Keep runtime-dispatch adapters only for SIMD checks and pass direct production calls through setup closures for ordinary behavior tests.
Keep NaN scores non-rankable and make SIMD InnerProduct match scalar unary negation for signed zero.
Cover exceptional metric values, exact norm boundaries, all-ineligible SIMD groups, and zero-width partition output.
Metric modules own GEMM setup and leader caches. Kernels consume flat ranking distances without metric-specific norm plumbing.
Portable scalar prefill loops auto-vectorize without exposing SIMD types through metric interfaces.
Test ranking directly from distances and keep metric checks at their
production seam. Prepare leader norms before stripe workers and retain
fixed-width neighbor insertion without a generic comparator.

Equal distances need no fixed candidate order. Accept either GEMM zero
sign instead of requiring scalar bit patterns across architectures.
Reject invalid neighbor widths before distance evaluation or scratch
mutation. Keep ranking infallible and return the farthest distance
directly from insertion.

@wuw92 Wei Wu (wuw92) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, the implementation looks reasonable, I have a few maintainability concerns:

  1. Please document non-obvious optimizations and their benchmark evidence near the code. Otherwise, the reasoning is only available in review discussions and commit history.
  2. There are many tests with overlapping functional coverage. Could we consolidate cases that verify the same invariant, while keeping separate tests for distinct code paths and boundary conditions?
  3. PiPNN does not appear in the repository's Codecov results. Could we confirm that these tests run in the coverage job?

Comment thread diskann/src/graph/pipnn/leaf_metric.rs Outdated
impl LeafMetric for InnerProduct {
fn compute_distances(points: MatrixView<'_, f32>, storage: &mut [f32]) -> ANNResult<()> {
// Both metrics rank with `-dot`. Their graph-pruning policies stay separate.
CosineNormalized::compute_distances(points, storage)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Would it be clearer for CosineNormalized to delegate to InnerProduct instead? For normalized vectors, cosine similarity is just the inner product.

/// triangle stays unspecified. The input matrix has one point in each row.
/// A zero distance can have either sign. Equal distances can select either candidate.
pub(super) trait LeafMetric: Send + Sync + 'static {
/// Compute ranking distances for all unordered point pairs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this method document that it returns ranking values, not standard metric distances? L2 omits the square root, and normalized cosine returns -dot instead of 1 - dot. Callers should not interpret the buffer as metric distances.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2c26d8b. The method now documents the ranking formulas: squared L2, -dot for normalized cosine and inner product, and 1 - similarity for cosine. The partition method also documents the omitted point norm.

Comment thread diskann/src/graph/pipnn/leaf_metric.rs Outdated
let point_count = points.nrows();
// The constant in `1 - dot` does not change nearest-first order.
diskann_linalg::sgemm_aat_lower(
point_count,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use points.nrows() and remove point_count

Comment thread diskann/src/graph/pipnn/leaf_metric.rs
Comment thread diskann/src/graph/pipnn/leaf_metric.rs Outdated
}

#[cfg(test)]
#[allow(clippy::unwrap_used, reason = "test matrices have fixed valid shapes")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allow appears redundant.

Comment thread diskann/src/graph/pipnn/leaf_kernel.rs Outdated
fn insert_eligible(&mut self, candidate: LeafNeighbor) -> f32;
}

impl NeighborInsert for [LeafNeighbor; 1] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we document why widths 1–3 have separate insertion implementations and link the benchmark that supports this optimization? Without that context, the extra paths look unnecessary and may be simplified later.

}

#[cfg(test)]
#[allow(clippy::unwrap_used, reason = "test matrices have fixed valid shapes")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allow appears redundant.

}

#[test]
fn reused_l2_leaders_match_fresh_leaders_for_a_new_point_stripe() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these reuse tests still protect distinct behavior? Leader norms are now computed eagerly and stored in immutable Vecs, so reusing leaders has no state transition to verify. A smaller multi-point correctness test may cover the remaining behavior.

fn compute_distances(
points: MatrixView<'_, f32>,
leaders: &Self::Leaders<'_>,
storage: &mut [f32],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could compute_distances take a MutMatrixView instead? The caller already knows the shape, and the row operations become simpler:

// L2
for row in storage.row_iter_mut() {
    row.copy_from_slice(&leaders.norms);
}

// Cosine
for (row, point_norm) in storage.row_iter_mut().zip(cosine_norms(points)) {
    for (distance, &leader_norm) in row.iter_mut().zip(&leaders.norms) {
        *distance = cosine_distance(*distance, point_norm, leader_norm);
    }
}

A: PiPNNSIMDSchema,
M: PartitionMetric,
{
let point_count = points.nrows();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this validate that output.nrows() == point_count? The later zip stops at the shorter matrix, so a short output silently skips points and still returns Ok(()), while extra output rows keep stale values.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, will throw new error when not match

Keep constant widths in row dispatch so the compiler can optimize
one insertion loop. Test shifts directly and share width-dispatch
coverage across scalar and SIMD updates.
Comment thread diskann/src/graph/pipnn/simd.rs Outdated

/// One group of distances and their column indexes in the supplied slice.
#[derive(Clone, Copy)]
pub(super) enum DistanceBlock<'a, F: PiPNNSIMDVector> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we reconsider this module boundary? DistanceBlock appears to be an implementation protocol that only TopKRows can interpret: this module performs the SIMD load, while Top-k performs the comparison, mask traversal, lane handling, and scalar insertion. That splits one ranking operation across modules and exposes SIMD details to the leaf and partition kernels.

return;
}
worst.resize(distances.nrows(), f32::INFINITY);
with_topk_rows!(output, worst, |topks| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could each kernel call one function that performs the full ranking? The kernels currently manage with_topk_rows!, the architecture scope, distance blocks, and the one/many updates. These details seem to belong inside Top-k.

For example, leaf ranking could call topk::rank_symmetric(...), and partition ranking could call topk::rank_rows(...).

Comment thread diskann/src/graph/pipnn/simd.rs Outdated
Comment thread diskann/src/graph/pipnn/simd.rs
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.

Support PiPNN builds

6 participants