Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
234 commits
Select commit Hold shift + click to select a range
ae6886b
linalg: add fallible lower-triangular AAT kernel
SeliMeli Jul 28, 2026
8da96e4
pipnn: add dispatched numerical kernels
SeliMeli Jul 28, 2026
15d8365
pipnn: benchmark and exercise numerical kernels
SeliMeli Jul 28, 2026
5b56fda
pipnn: harden kernel coverage and benchmarks
SeliMeli Jul 28, 2026
846bf59
fix(pipnn): accept finite maximum distances
SeliMeli Jul 29, 2026
35f65ca
refactor(pipnn): make kernels architecture-neutral
SeliMeli Jul 29, 2026
b25d701
fix(pipnn): preserve NaN distances across SIMD backends
SeliMeli Jul 30, 2026
7ba81b6
docs(pipnn): explain numerical kernel invariants
SeliMeli Jul 31, 2026
0090fea
test(pipnn): name SIMD metric boundary matrices
SeliMeli Jul 31, 2026
03277f6
fix(pipnn): preserve dispatched kernel semantics
SeliMeli Aug 3, 2026
218cc38
style(wide): format array trait bounds
SeliMeli Aug 3, 2026
b7cd61d
fix(pipnn): address kernel review feedback
SeliMeli Aug 3, 2026
7153969
refactor(pipnn)!: prepare kernel dispatch
SeliMeli Aug 3, 2026
ad2d7dc
docs(pipnn): describe full crate scope
SeliMeli Aug 3, 2026
7025c22
docs(pipnn): map dispatch hot paths
SeliMeli Aug 3, 2026
d16d946
test(pipnn): confine traversal references
SeliMeli Aug 3, 2026
da45d8e
refactor(pipnn): name metric visitor by action
SeliMeli Aug 3, 2026
699d11b
refactor(pipnn): carry dynamic leaf width
SeliMeli Aug 3, 2026
400e91a
refactor(pipnn)!: clarify point and neighbor roles
SeliMeli Aug 3, 2026
afe1d38
docs(pipnn): explain kernel pipeline
SeliMeli Aug 3, 2026
d4a1230
docs(pipnn): state cosine threshold
SeliMeli Aug 3, 2026
85ec4cc
refactor(pipnn): move kernels into diskann graph
SeliMeli Aug 5, 2026
e3d20a6
test(pipnn): document fixture panic policy
SeliMeli Aug 5, 2026
1bf66b2
ci(pipnn): cover the in-crate feature
SeliMeli Aug 5, 2026
44fb69a
bench(pipnn): add IAI kernel microbenchmarks
SeliMeli Aug 5, 2026
318f8ea
fix(ci): use workspace feature name for pipnn
SeliMeli Aug 6, 2026
c13226d
fix(ci): validate every stacked layer
SeliMeli Aug 6, 2026
22ca492
ci(pipnn): run IAI and ARM feature gates
SeliMeli Aug 6, 2026
db4b711
test(pipnn): keep regression tooling local
SeliMeli Aug 6, 2026
6dfc07b
ci(pipnn): validate numerical feature
SeliMeli Aug 6, 2026
8ce46fc
fix(pipnn): enforce SIMD safety invariants
SeliMeli Aug 7, 2026
1d49dab
refactor(pipnn): pass leaf matrices directly
SeliMeli Aug 7, 2026
ad19c82
refactor(pipnn): cap leaf kernel at k three
SeliMeli Aug 7, 2026
9628de5
fix(pipnn): return errors for invalid leaf widths
SeliMeli Aug 7, 2026
88d06c1
fix(utils): reject overflowing matrix shapes
SeliMeli Aug 7, 2026
6f23dee
refactor(pipnn): trust validated matrix views
SeliMeli Aug 7, 2026
88f6f72
perf(pipnn): retain measured fixed-k insertion
SeliMeli Aug 7, 2026
815c2a4
docs(pipnn): remove stale dynamic-k reference
SeliMeli Aug 7, 2026
bf989e2
refactor(pipnn): constrain SIMD lanes locally
SeliMeli Aug 7, 2026
51684ad
refactor(pipnn): remove stored kernel pointers
SeliMeli Aug 7, 2026
98be0dc
test(pipnn): cover runtime partition fanout
SeliMeli Aug 7, 2026
96ceb24
refactor(pipnn): make kernels generic-only
SeliMeli Aug 7, 2026
465a96b
refactor(pipnn): keep numerical kernels private
SeliMeli Aug 7, 2026
32d6524
refactor(pipnn): use default kernel workspaces
SeliMeli Aug 7, 2026
038c069
docs(pipnn): align kernel comments with implementation
SeliMeli Aug 7, 2026
df9061a
docs(pipnn): remove kernel performance notes
SeliMeli Aug 7, 2026
aa948a6
refactor(pipnn): report partition underfill locally
SeliMeli Aug 7, 2026
163cff7
refactor(pipnn): remove unused leaf output helper
SeliMeli Aug 7, 2026
f945817
refactor(pipnn): remove kernel assertions
SeliMeli Aug 7, 2026
6d0dc2b
docs(pipnn): state partition row contract
SeliMeli Aug 7, 2026
b7e4db7
refactor(pipnn): name kernel responsibilities
SeliMeli Aug 7, 2026
bf7cead
docs(pipnn): define partition leader semantics
SeliMeli Aug 7, 2026
fd0f4e2
docs(pipnn): state norm conversion behavior
SeliMeli Aug 7, 2026
6671cc8
refactor(pipnn): name fixed-width leaf scan
SeliMeli Aug 7, 2026
b40d54c
docs(pipnn): remove type-restatement comments
SeliMeli Aug 7, 2026
1813388
docs(pipnn): describe leaf insertion by domain role
SeliMeli Aug 7, 2026
fe5a29c
refactor(pipnn): name kernel test helpers
SeliMeli Aug 7, 2026
e707437
refactor(pipnn): inline fixed-width leaf dispatch
SeliMeli Aug 10, 2026
a1bdc73
refactor(pipnn): inline leader ID publication
SeliMeli Aug 10, 2026
1f8ae26
refactor(matrix): preserve constructor behavior
SeliMeli Aug 10, 2026
617e746
refactor(pipnn): split stage metric contracts
SeliMeli Aug 10, 2026
05ad4da
perf(pipnn): specialize stage norm handling
SeliMeli Aug 10, 2026
dc5cdba
docs(pipnn): use active metric comments
SeliMeli Aug 10, 2026
e32b0a3
test(pipnn): use norm-specific terminology
SeliMeli Aug 10, 2026
00b69ce
perf(pipnn): bound leaf SIMD prefix once
SeliMeli Aug 10, 2026
21885e6
refactor(pipnn): remove metric tag indirection
SeliMeli Aug 10, 2026
803f981
docs(pipnn): keep metric comments factual
SeliMeli Aug 10, 2026
b28d67a
refactor(pipnn): pass prepared norms to kernels
SeliMeli Aug 11, 2026
afbb576
perf(pipnn): specialize prepared norm layouts
SeliMeli Aug 11, 2026
17aea03
perf(pipnn): reuse each leaf source norm
SeliMeli Aug 11, 2026
0dccf08
refactor(pipnn): name prepared norm layouts
SeliMeli Aug 11, 2026
a3396a5
refactor(pipnn): make metric types prepare norms
SeliMeli Aug 11, 2026
9d4342a
refactor(pipnn): move norm policy into metric types
SeliMeli Aug 11, 2026
52bc12a
test(utils): cover zero-wrapping matrix area
SeliMeli Aug 11, 2026
cc82f9c
refactor(pipnn): give metrics exact ranking inputs
SeliMeli Aug 11, 2026
09704bd
refactor(pipnn): deepen numerical kernels
SeliMeli Aug 12, 2026
38cd3b5
fix(pipnn): mark unrankable kernel slots
SeliMeli Aug 18, 2026
b946ace
refactor(pipnn): centralize SIMD schema
SeliMeli Aug 20, 2026
52973f5
refactor(pipnn): specialize sorted insertion
SeliMeli Aug 21, 2026
f55a5d0
test(pipnn): clarify numerical contracts
SeliMeli Aug 21, 2026
2de5c86
test(pipnn): use semantic numerical fixtures
SeliMeli Aug 24, 2026
d786552
refactor(wide): keep lane arrays read-only
SeliMeli Aug 24, 2026
17ea40f
test(pipnn): clarify norm test names
SeliMeli Aug 24, 2026
a60773c
test(pipnn): cover SIMD and insertion contracts
SeliMeli Aug 24, 2026
fca286a
refactor(pipnn): use one SIMD vector type
SeliMeli Aug 24, 2026
89d6071
test(pipnn): expose production kernel calls
SeliMeli Aug 24, 2026
c35b944
fix(pipnn): align metric edge cases
SeliMeli Aug 25, 2026
816a34f
docs(pipnn): correct leaf width contract
SeliMeli Aug 25, 2026
6844cfa
ci(pipnn): run kernels under Miri
SeliMeli Aug 25, 2026
1f0a5f1
test(pipnn): cover kernel behavior contracts
SeliMeli Aug 25, 2026
056bef7
refactor(pipnn): localize SIMD lane bounds
SeliMeli Aug 26, 2026
5370050
fix(pipnn): retarget worker SIMD kernels
SeliMeli Aug 28, 2026
01b7649
fix(pipnn): unify cosine norm reduction
SeliMeli Aug 28, 2026
c452181
test(linalg): assert zero-row success
SeliMeli Sep 3, 2026
57a2b7a
test(linalg): clarify zero-dimension result
SeliMeli Sep 3, 2026
6d825d3
refactor(pipnn): simplify metric kernels
SeliMeli Sep 4, 2026
b46ecdd
refactor(pipnn): remove metric architecture input
SeliMeli Sep 4, 2026
b3aade5
refactor(pipnn): simplify numerical seams
SeliMeli Sep 7, 2026
55fd99b
refactor(pipnn): simplify leaf kernel flow
SeliMeli Sep 7, 2026
adf0897
refactor(pipnn): scan distance matrix views
SeliMeli Sep 7, 2026
b308086
refactor(pipnn): share top-k state and trim tests
SeliMeli Sep 7, 2026
5f85a35
refactor(pipnn): simplify top-k insertion
SeliMeli Sep 8, 2026
652bc9e
pipnn: assemble direct-candidate graph builder
SeliMeli Jul 28, 2026
b0c3561
pipnn: cover partition validation boundaries
SeliMeli Jul 28, 2026
7e98ca1
pipnn: harden core graph construction
SeliMeli Jul 28, 2026
2090ca6
docs(pipnn): describe integer cosine policy
SeliMeli Jul 29, 2026
69db8da
pipnn: expose core config validation
SeliMeli Jul 29, 2026
3dae642
refactor(pipnn): consume leaves during leaf build
SeliMeli Jul 29, 2026
d0412ec
fix(pipnn): preserve established replica seeds
SeliMeli Jul 29, 2026
60d2574
docs(pipnn): define graph-construction boundary
SeliMeli Jul 29, 2026
d84b805
refactor(pipnn): own partition-stage configuration
SeliMeli Jul 29, 2026
918eeda
perf(pipnn): release owned leaves after leaf stage
SeliMeli Jul 29, 2026
4b4b755
docs(pipnn): explain partition stage contract
SeliMeli Jul 29, 2026
8fb2a12
perf(pipnn): reduce partition and leaf overhead
SeliMeli Jul 30, 2026
2677d89
perf(pipnn): reuse partition scratch across work items
SeliMeli Jul 30, 2026
caa39b6
docs(pipnn): document core stage invariants
SeliMeli Jul 31, 2026
83ce737
docs(pipnn): diagram core stage ownership
SeliMeli Jul 31, 2026
749ffd8
fix(pipnn): preserve partition quality and scratch reuse
SeliMeli Aug 3, 2026
ff88632
refactor(pipnn): reuse prepared kernels
SeliMeli Aug 3, 2026
42bc69e
refactor(pipnn): name candidate lists
SeliMeli Aug 3, 2026
c06e264
refactor(pipnn): complete graph module migration
SeliMeli Aug 5, 2026
da9219f
refactor(pipnn): prepare RobustPrune inputs locally
SeliMeli Aug 5, 2026
f8be41e
refactor(pipnn): use shared robust prune core
SeliMeli Aug 5, 2026
62a4e98
test(pipnn): adapt and colocate core tests
SeliMeli Aug 6, 2026
9c334ce
test(pipnn): adapt assertions to main errors
SeliMeli Aug 6, 2026
eb84333
refactor(pipnn): consume positional robust prune
SeliMeli Aug 6, 2026
01d14cb
refactor(pipnn): use sorted prune input
SeliMeli Aug 7, 2026
78bfe0e
refactor(pipnn): use direct leaf matrix input
SeliMeli Aug 7, 2026
467c6b4
fix(pipnn): validate leaf k capacity
SeliMeli Aug 7, 2026
372c6e3
refactor(pipnn): require sorted leaf IDs
SeliMeli Aug 7, 2026
8b69ff6
refactor(pipnn): borrow partition configuration
SeliMeli Aug 7, 2026
b87230c
refactor(pipnn): dispatch partition stages once
SeliMeli Aug 7, 2026
5d1c14d
refactor(pipnn): dispatch leaf stages once
SeliMeli Aug 7, 2026
c74341d
refactor(pipnn): dispatch once per graph build
SeliMeli Aug 7, 2026
14dade2
docs(pipnn): describe the active core flow
SeliMeli Aug 7, 2026
ec55050
docs(pipnn): remove core diagrams and tuning notes
SeliMeli Aug 7, 2026
e51f2c9
refactor(pipnn): remove duplicate partition checks
SeliMeli Aug 7, 2026
b0f4630
refactor(pipnn): keep leaf shape validation local
SeliMeli Aug 7, 2026
02b4357
refactor(pipnn): propagate partition worker errors
SeliMeli Aug 7, 2026
7177087
refactor(pipnn): remove partition assertions
SeliMeli Aug 7, 2026
6485e98
docs(pipnn): state core function contracts
SeliMeli Aug 7, 2026
997e832
refactor(pipnn): use domain names in core flow
SeliMeli Aug 7, 2026
c1d447c
docs(pipnn): remove layout-restatement comments
SeliMeli Aug 7, 2026
93d35f6
docs(pipnn): define leaf domain term
SeliMeli Aug 7, 2026
55ad5b3
refactor(pipnn): inline poisoned-list errors
SeliMeli Aug 10, 2026
708ecc8
refactor(pipnn): clarify leaf policy names
SeliMeli Aug 10, 2026
1dab27d
fix(pipnn): reject malformed assignments
SeliMeli Aug 10, 2026
dbf540d
refactor(pipnn): use stage metric contracts
SeliMeli Aug 10, 2026
fca7981
refactor(pipnn): use partition metric identity
SeliMeli Aug 10, 2026
170d27b
refactor(pipnn): prepare norms before kernel calls
SeliMeli Aug 11, 2026
eee911a
refactor(pipnn): dispatch norm preparation through metric types
SeliMeli Aug 11, 2026
3a7663f
refactor(pipnn): pass metric-owned ranking context
SeliMeli Aug 11, 2026
3cd4b2e
fix(pipnn): reset reused prune states
SeliMeli Aug 11, 2026
e829fec
refactor(pipnn): prepare leaf norms in metric policy
SeliMeli Aug 11, 2026
a345bd7
refactor(pipnn): simplify graph build stages
SeliMeli Aug 12, 2026
cd69957
fix(pipnn): omit unrankable graph candidates
SeliMeli Aug 18, 2026
4068dad
test(pipnn): cover non-rankable build candidates
SeliMeli Aug 18, 2026
e009781
perf(pipnn): deduplicate direct leaf edges once
SeliMeli Aug 19, 2026
e271b79
refactor(pipnn): use the SIMD schema in stages
SeliMeli Aug 20, 2026
c0b978d
test(pipnn): clarify core graph contracts
SeliMeli Aug 21, 2026
6251b03
test(pipnn): use semantic graph fixtures
SeliMeli Aug 24, 2026
4971798
test(pipnn): name zero-k fixture inputs
SeliMeli Aug 24, 2026
a101b56
refactor(pipnn): adopt metric-owned buffers
SeliMeli Sep 4, 2026
2c26d8b
docs(pipnn): clarify ranking contracts
SeliMeli Sep 8, 2026
00b8a5c
fix(pipnn): address kernel review feedback
SeliMeli Sep 8, 2026
927ceb6
refactor(pipnn): move distance blocks to topk
SeliMeli Sep 8, 2026
5ef1097
test(pipnn): simplify partition row rejection
SeliMeli Sep 8, 2026
f803283
refactor(pipnn): merge SIMD schema traits
SeliMeli Sep 8, 2026
303ff6d
refactor(pipnn): encapsulate top-k updates
SeliMeli Sep 9, 2026
4a3aed7
test(pipnn): focus coverage on live contracts
SeliMeli Sep 9, 2026
dc10909
refactor(pipnn): borrow top-k buffers per call
SeliMeli Sep 9, 2026
78f5e95
fix(pipnn): keep SIMD scope inside top-k
SeliMeli Sep 10, 2026
c627be8
fix(ci): run relocated top-k tests under Miri
SeliMeli Sep 10, 2026
6a8d13e
perf(pipnn): specialize top-k widths through ten
SeliMeli Sep 10, 2026
acda584
refactor(pipnn): make insertion capacity explicit
SeliMeli Sep 10, 2026
5e4c08a
refactor(pipnn): model top-k width with types
SeliMeli Sep 16, 2026
2c5d769
Merge latest PiPNN kernels into core
SeliMeli Sep 11, 2026
31ef4a3
perf(pipnn): simplify core and dispatch FP16
SeliMeli Sep 11, 2026
fca1df9
perf(pipnn): dispatch vector gathers per batch
SeliMeli Sep 14, 2026
08c2fba
refactor(pipnn): localize insertion slicing
SeliMeli Sep 17, 2026
1bc033d
refactor(pipnn): name top-k update directions
SeliMeli Sep 17, 2026
fa560c3
test(pipnn): cover numerical kernel matrices
SeliMeli Sep 17, 2026
d0f048d
refactor(pipnn): simplify workspace access
SeliMeli Sep 17, 2026
4e75562
test(pipnn): clarify neighbor selection cases
SeliMeli Sep 17, 2026
d3ae858
test(pipnn): rewrite numerical kernel contracts
SeliMeli Sep 17, 2026
f489bee
Merge reviewed PiPNN kernel tests into core
SeliMeli Sep 17, 2026
4690241
refactor(pipnn): dispatch TopK with a visitor
SeliMeli Sep 18, 2026
5db5c55
Merge TopK visitor into PR3
SeliMeli Sep 18, 2026
34722b2
refactor(pipnn): reuse fast vector norms
SeliMeli Sep 18, 2026
b28aee6
Merge fast PiPNN norms into PR3
SeliMeli Sep 18, 2026
4c97081
test(linalg): share lower-product assertions
SeliMeli Sep 18, 2026
b10c2ee
Merge shared GEMM test helper into PR3
SeliMeli Sep 18, 2026
5b853e0
test(linalg): trim redundant GEMM shapes
SeliMeli Sep 18, 2026
99fc613
Merge focused GEMM cases into PR3
SeliMeli Sep 18, 2026
9660547
refactor(pipnn): defer matrix view hardening
SeliMeli Sep 18, 2026
de32660
Keep matrix view hardening outside PR3
SeliMeli Sep 18, 2026
166ac25
fix(pipnn): expect unwired kernels in PR2
SeliMeli Sep 18, 2026
4ae1c60
Merge PR2 Clippy fix into core
SeliMeli Sep 18, 2026
b59ea32
test(pipnn): rewrite core contract tests
SeliMeli Sep 21, 2026
83b618d
test(pipnn): cover partition composition gaps
SeliMeli Sep 21, 2026
354918d
docs(pipnn): track NEON validation in #1423
SeliMeli Sep 21, 2026
1bc6b69
Sync NEON tracking cleanup through PR3
SeliMeli Sep 21, 2026
08f5fd0
docs(linalg): clarify lower-product storage
SeliMeli Sep 22, 2026
8b85bf7
test(linalg): simplify lower-product assertions
SeliMeli Sep 22, 2026
8e2d9d6
test(pipnn): consolidate numeric sweeps
SeliMeli Sep 22, 2026
a439b6b
refactor(pipnn): shorten SIMD trait name
SeliMeli Sep 22, 2026
12dd73f
refactor(pipnn): align Width method naming
SeliMeli Sep 22, 2026
9d45ac7
ci(pipnn): focus Miri on TopK boundaries
SeliMeli Sep 22, 2026
6df51c8
ci(pipnn): separate ARM runner addition
SeliMeli Sep 22, 2026
f673e95
ci(pipnn): remove kernel tests from SDE
SeliMeli Sep 22, 2026
470915d
perf(pipnn): limit TopK specializations
SeliMeli Sep 22, 2026
5ecfd4a
perf(pipnn): avoid duplicate threshold fills
SeliMeli Sep 22, 2026
e4c3edd
refactor(pipnn): bind TopK storage to rankers
SeliMeli Sep 22, 2026
2e48041
merge(pipnn): carry kernel fixes into core
SeliMeli Sep 22, 2026
b0ccf73
refactor(pipnn): replace TopK rankers with direct selection
SeliMeli Sep 23, 2026
d2429d3
merge(pipnn): carry top-k simplification into core
SeliMeli Sep 23, 2026
cc6da38
refactor(pipnn): check top-k shapes only in debug builds
SeliMeli Sep 23, 2026
7882e2b
merge(pipnn): carry debug-only top-k checks into core
SeliMeli Sep 23, 2026
ea0f57f
merge(pipnn): catch core up with main after the kernels squash merge
SeliMeli Sep 24, 2026
a990ab6
fix(pipnn): finish partitioning on tied leaders; drop unreachable errors
SeliMeli Sep 28, 2026
0c1c8d4
refactor(pipnn): skip unsplittable levels; drop merge and dead errors
SeliMeli Sep 28, 2026
175f0c8
perf(pipnn): stop sorting merged leaf candidates
SeliMeli Sep 29, 2026
b45927f
perf(pipnn): use a fixed 256-point assignment stripe
SeliMeli Oct 12, 2026
a2f27ee
fix(pipnn): cap the prune pool at max_occlusion_size
SeliMeli Oct 12, 2026
5ceb790
docs(pipnn): name the child seed multiplier and explain seed values
SeliMeli Oct 12, 2026
f0e5c3b
refactor(pipnn): draw child seeds from the split RNG
SeliMeli Oct 12, 2026
2dcf68b
feat(pipnn): take the leader sampling seed from the caller
SeliMeli Oct 12, 2026
18874ae
refactor(pipnn): one name per partitioning concept
SeliMeli Oct 12, 2026
cc1d41c
docs(pipnn): document default PiPNN parameters and their effects
SeliMeli Oct 13, 2026
db08e2b
refactor(pipnn): fold buffer growth into LeafBuffers::prepare
SeliMeli Oct 13, 2026
95bf0c7
docs(pipnn): say why leaf rows can have empty slots
SeliMeli Oct 13, 2026
8559ba4
test(pipnn): cover every input type in leaf build, f16 in multi-level…
SeliMeli Oct 13, 2026
361d0f9
refactor(pipnn): drop the prune kind check, as Vamana does
SeliMeli Oct 13, 2026
375ad3b
docs(pipnn): say why only f16 gathers select instructions at run time
SeliMeli Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions diskann/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ half = { workspace = true, features = ["bytemuck", "num-traits"] }
# while other crates use default-features = true. Keeping version 0.16.0 consistent.
hashbrown = { version = "0.16.0", default-features = false, features = ["default-hasher"] }
num-traits.workspace = true
parking_lot = { version = "0.12.5", optional = true }
rand.workspace = true
rayon = { workspace = true, optional = true }
thiserror.workspace = true
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
tracing = { workspace = true, optional = true }
Expand Down Expand Up @@ -59,8 +61,8 @@ panic = "warn"
[features]
default = ["tracing"]

# Enable PiPNN numerical kernels.
pipnn = ["dep:diskann-linalg"]
# Enable PiPNN batch graph construction.
pipnn = ["dep:diskann-linalg", "dep:parking_lot", "dep:rayon", "tracing"]

# Enable "tracing" diagnostics.
tracing = ["dep:tracing"]
Expand Down
157 changes: 157 additions & 0 deletions diskann/src/graph/pipnn/conversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
*/

//! Gather dataset rows into packed `f32` storage.
//!
//! `f16` rows use the FP16 instructions of the running CPU. The generic
//! `VectorRepr::as_f32_into` path uses the instructions of the build target
//! instead. Crates that depend on `diskann` do not inherit this repository's
//! `x86-64-v3` target flag, so for them that path converts `f16` in software.
//! On an AMD EPYC 7763, software conversion made gathers 4.6 to 22 times slower
//! (128 to 1536 dimensions). With the `x86-64-v3` target, both paths are within
//! 10% of each other.
//!
//! Other element types use `VectorRepr::as_f32_into` for every target. `f32`
//! rows are copied. The baseline x86-64 target has SSE2 instructions that
//! convert `u8` and `i8` to `f32`, so the compiler vectorizes that loop without
//! the `x86-64-v3` flag. The baseline target has no `f16` conversion
//! instruction; F16C starts at `x86-64-v3`. On the AMD EPYC 7763, the baseline
//! target converted `u8` and `i8` at most 1.8 times slower than `x86-64-v3`, and
//! `f16` 16.5 times slower (rows in L2).

use std::any::TypeId;

use crate::{ANNResult, utils::VectorRepr};
use diskann_utils::views::MatrixView;
use diskann_vector::conversion::SliceCast;
use diskann_wide::{
Architecture,
arch::{self, Target2, Target3},
};
use half::f16;

/// Convert rows `ids` of `data` into consecutive rows of `output`.
///
/// `f16` input selects the CPU's instructions once for the whole batch.
pub(super) fn gather_as_f32<T: VectorRepr>(
data: MatrixView<'_, T>,
ids: &[u32],
output: &mut [f32],
) -> ANNResult<()> {
if TypeId::of::<T>() == TypeId::of::<f16>() {
arch::dispatch3(GatherFp16, data, ids, output);
} else {
for (&id, destination) in ids.iter().zip(output.chunks_exact_mut(data.ncols())) {
T::as_f32_into(data.row(id as usize), destination).map_err(Into::into)?;
}
}
Ok(())
}

struct GatherFp16;

impl<A, T> Target3<A, (), MatrixView<'_, T>, &[u32], &mut [f32]> for GatherFp16
where
A: Architecture,
T: VectorRepr,
for<'a, 'b> SliceCast<f32, f16>: Target2<A, (), &'a mut [f32], &'b [f16]>,
{
#[inline(always)]
fn run(self, arch: A, data: MatrixView<'_, T>, ids: &[u32], output: &mut [f32]) {
for (&id, destination) in ids.iter().zip(output.chunks_exact_mut(data.ncols())) {
let source = bytemuck::cast_slice(data.row(id as usize));
SliceCast::<f32, f16>::new().run(arch, destination, source);
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn gathered_rows_follow_requested_ids() {
// Row IDs are out of order and contain a repeat.
fn check<T: VectorRepr>(values: [T; 6], expected: [f32; 6]) {
let data = MatrixView::try_from(&values[..], 3, 2).unwrap();
let mut output = [f32::NAN; 6];

gather_as_f32(data, &[2, 0, 2], &mut output).unwrap();

assert_eq!(output, expected, "{}", std::any::type_name::<T>());
}

check(
[1.5_f32, -2.0, 7.0, 4.0, 0.5, 9.0],
[0.5, 9.0, 1.5, -2.0, 0.5, 9.0],
);
check([1_i8, -2, 7, 4, -5, 9], [-5.0, 9.0, 1.0, -2.0, -5.0, 9.0]);
check([1_u8, 2, 7, 4, 5, 9], [5.0, 9.0, 1.0, 2.0, 5.0, 9.0]);
check(
[1.5_f32, -2.0, 7.0, 4.0, 0.5, 9.0].map(f16::from_f32),
[0.5, 9.0, 1.5, -2.0, 0.5, 9.0],
);
}

#[test]
fn fp16_gather_converts_every_coordinate() {
// x86 converts eight values at a time. The dimensions cover a short row,
// full vectors with and without a tail, and an embedding with a tail.
for dimensions in [7, 8, 9, 32, 33, 1537] {
let mut values: Vec<_> = (0..3 * dimensions)
.map(|index| f16::from_f32((index % 31) as f32 - 15.0))
.collect();
for (row, values) in values.chunks_exact_mut(dimensions).enumerate() {
values[dimensions - 1] = f16::from_f32(100.0 + row as f32);
}
let ids = [2, 0, 2];
let expected: Vec<_> = ids
.iter()
.flat_map(|&row| {
values[row as usize * dimensions..(row as usize + 1) * dimensions]
.iter()
.map(|value| value.to_f32())
})
.collect();
let mut output = vec![f32::NAN; expected.len()];

gather_as_f32(
MatrixView::try_from(values.as_slice(), 3, dimensions).unwrap(),
&ids,
&mut output,
)
.unwrap();

assert_eq!(output, expected, "{dimensions} dimensions");
}
}

#[test]
fn fp16_gather_preserves_special_values_and_zero_signs() {
let values = [
f16::ZERO,
f16::NEG_ZERO,
f16::INFINITY,
f16::NEG_INFINITY,
f16::from_bits(1),
f16::NAN,
];
let mut output = [42.0; 6];

gather_as_f32(
MatrixView::try_from(&values[..], 2, 3).unwrap(),
&[1, 0],
&mut output,
)
.unwrap();

assert_eq!(output[0], f32::NEG_INFINITY);
assert_eq!(output[1], 2.0_f32.powi(-24));
assert!(output[2].is_nan());
assert_eq!(output[3].to_bits(), 0.0_f32.to_bits());
assert_eq!(output[4].to_bits(), (-0.0_f32).to_bits());
assert_eq!(output[5], f32::INFINITY);
}
}
Loading