Skip to content
Merged
5 changes: 4 additions & 1 deletion .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ jobs:
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2

- name: miri
run: cargo +nightly miri nextest run --locked --package diskann-quantization
run: |
cargo +nightly miri nextest run --locked \
--package diskann-quantization \
--package diskann-utils
env:
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance

Expand Down
2 changes: 1 addition & 1 deletion agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The repository uses a Cargo workspace with crates organized into functional tier

**Tier 2: Core Libraries**
- `diskann-linalg/` - Linear algebra operations
- `diskann-utils/` - Shared utilities (Reborrow, MatrixView traits)
- `diskann-utils/` - Shared utilities (Reborrow, Matrix traits)
- `diskann-quantization/` - Vector quantization (PQ, SQ)

**Tier 3: Algorithm & Storage**
Expand Down
13 changes: 8 additions & 5 deletions diskann-benchmark-core/src/build/graph/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use diskann::{
graph::{self, glue},
provider,
};
use diskann_utils::{future::AsyncFriendly, views::Matrix};
use diskann_utils::{
future::AsyncFriendly,
views::rowmajor::{self, Matrix},
};

use crate::build::{Build, ids::ToId};

Expand All @@ -27,7 +30,7 @@ where
DP: provider::DataProvider,
{
index: Arc<graph::DiskANNIndex<DP>>,
data: Arc<Matrix<T>>,
data: Arc<rowmajor::Owned<T>>,
strategy: S,
to_id: Box<dyn ToId<DP::ExternalId>>,
}
Expand All @@ -45,7 +48,7 @@ where
/// to external IDs.
pub fn new<I>(
index: Arc<graph::DiskANNIndex<DP>>,
data: Arc<Matrix<T>>,
data: Arc<rowmajor::Owned<T>>,
strategy: S,
to_id: I,
) -> Arc<Self>
Expand All @@ -64,7 +67,7 @@ where
impl<DP, T, S> Build for MultiInsert<DP, T, S>
where
DP: provider::DataProvider<Context: Default> + for<'a> provider::SetElement<&'a [T]>,
S: glue::MultiInsertStrategy<DP, Matrix<T>> + Clone + 'static,
S: glue::MultiInsertStrategy<DP, rowmajor::Owned<T>> + Clone + 'static,
T: AsyncFriendly + Clone,
{
type Output = ();
Expand Down Expand Up @@ -101,7 +104,7 @@ where
end: range.end,
})
})?
.to_owned();
.to_rowmajor_owned();

let ids: ANNResult<Arc<[_]>> = range.into_iter().map(|i| self.to_id.to_id(i)).collect();
let context = DP::Context::default();
Expand Down
9 changes: 6 additions & 3 deletions diskann-benchmark-core/src/build/graph/single.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use diskann::{
graph::{self, glue},
provider,
};
use diskann_utils::{future::AsyncFriendly, views::Matrix};
use diskann_utils::{
future::AsyncFriendly,
views::rowmajor::{self, Matrix},
};

use crate::build::{Build, ids::ToId};

Expand All @@ -23,7 +26,7 @@ where
DP: provider::DataProvider,
{
index: Arc<graph::DiskANNIndex<DP>>,
data: Arc<Matrix<T>>,
data: Arc<rowmajor::Owned<T>>,
strategy: S,
to_id: Box<dyn ToId<DP::ExternalId>>,
}
Expand All @@ -41,7 +44,7 @@ where
/// to external IDs.
pub fn new<I>(
index: Arc<graph::DiskANNIndex<DP>>,
data: Arc<Matrix<T>>,
data: Arc<rowmajor::Owned<T>>,
strategy: S,
to_id: I,
) -> Arc<Self>
Expand Down
74 changes: 37 additions & 37 deletions diskann-benchmark-core/src/recall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{

use diskann_utils::{
strided::Strided,
views::{Matrix, MatrixView},
views::rowmajor::{self, Matrix},
};
use thiserror::Error;

Expand Down Expand Up @@ -81,27 +81,27 @@ pub trait Rows<T> {
}
}

impl<T> Rows<T> for Matrix<T> {
impl<T> Rows<T> for rowmajor::Owned<T> {
fn nrows(&self) -> usize {
Matrix::<T>::nrows(self)
Matrix::nrows(self)
}
fn row(&self, i: usize) -> &[T] {
Matrix::<T>::row(self, i)
Matrix::row(self, i)
}
fn ncols(&self) -> Option<usize> {
Some(Matrix::<T>::ncols(self))
Some(Matrix::ncols(self))
}
}

impl<T> Rows<T> for MatrixView<'_, T> {
impl<T> Rows<T> for rowmajor::Ref<'_, T> {
fn nrows(&self) -> usize {
MatrixView::<'_, T>::nrows(self)
Matrix::nrows(self)
}
fn row(&self, i: usize) -> &[T] {
MatrixView::<'_, T>::row(self, i)
Matrix::row(self, i)
}
fn ncols(&self) -> Option<usize> {
Some(MatrixView::<'_, T>::ncols(self))
Some(Matrix::ncols(self))
}
}

Expand Down Expand Up @@ -364,10 +364,10 @@ where

#[cfg(test)]
mod tests {
use diskann_utils::views::Matrix;

use super::*;

use diskann_utils::views::rowmajor::MatrixMut;

fn test_rows_inner(rows: &dyn Rows<usize>, ncols: Option<usize>) {
assert_eq!(rows.ncols(), ncols);
assert_eq!(rows.nrows(), 3);
Expand All @@ -379,7 +379,7 @@ mod tests {
#[test]
fn test_rows() {
let mut i = 0usize;
let mat = Matrix::from_fn(3, 4, |_| {
let mat = rowmajor::Owned::from_fn(3, 4, |_| {
let v = i;
i += 1;
v
Expand Down Expand Up @@ -420,7 +420,7 @@ mod tests {

#[test]
fn test_happy_path() {
let groundtruth = Matrix::try_from(
let groundtruth = rowmajor::Owned::try_from_data(
vec![
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // row 0
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // row 1
Expand All @@ -433,7 +433,7 @@ mod tests {
)
.unwrap();

let distances = Matrix::try_from(
let distances = rowmajor::Owned::try_from_data(
vec![
0.0, 1.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 5.0, 6.0, // row 0
2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, // row 1
Expand All @@ -447,7 +447,7 @@ mod tests {
.unwrap();

// Shift row 0 by one and row 1 by two.
let our_results = Matrix::try_from(
let our_results = rowmajor::Owned::try_from_data(
vec![
100, 0, 1, 2, 5, 6, // row 0
100, 101, 7, 8, 9, 10, // row 1
Expand Down Expand Up @@ -480,7 +480,7 @@ mod tests {
let epsilon = 1e-6; // Define a small tolerance

for (i, expected) in expected_no_ties.iter().enumerate() {
assert_eq!(expected.components.len(), our_results.nrows());
assert_eq!(expected.components.len(), Matrix::nrows(&our_results));
let recall = knn(
&groundtruth,
None,
Expand All @@ -501,7 +501,7 @@ mod tests {
i
);

assert_eq!(recall.num_queries, our_results.nrows());
assert_eq!(recall.num_queries, Matrix::nrows(&our_results));
assert_eq!(recall.recall_k, expected.recall_k);
assert_eq!(recall.recall_n, expected.recall_n);
}
Expand All @@ -525,7 +525,7 @@ mod tests {
];

for (i, expected) in expected_with_ties.iter().enumerate() {
assert_eq!(expected.components.len(), our_results.nrows());
assert_eq!(expected.components.len(), Matrix::nrows(&our_results));
let recall = knn(
&groundtruth,
Some(distances.as_view().into()),
Expand All @@ -546,24 +546,24 @@ mod tests {
i
);

assert_eq!(recall.num_queries, our_results.nrows());
assert_eq!(recall.num_queries, Matrix::nrows(&our_results));
assert_eq!(recall.recall_k, expected.recall_k);
assert_eq!(recall.recall_n, expected.recall_n);
}
}

#[test]
fn test_error_recall_k_and_n() {
let groundtruth = Matrix::<u32>::from_element(10, 10, 0);
let results = Matrix::<u32>::from_element(10, 10, 0);
let groundtruth = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let err = knn(&groundtruth, None, &results, 11, 10, GroundTruthMode::Fixed).unwrap_err();
assert!(matches!(err, ComputeRecallError::RecallKAndNError(..)));
}

#[test]
fn test_error_rows_mismatch() {
let groundtruth = Matrix::<u32>::from_element(11, 10, 0);
let results = Matrix::<u32>::from_element(10, 10, 0);
let groundtruth = rowmajor::Owned::<u32>::from_element(11, 10, 0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let err = knn(&groundtruth, None, &results, 10, 10, GroundTruthMode::Fixed).unwrap_err();
assert!(matches!(err, ComputeRecallError::RowsMismatch(..)));
let err_allow_insufficient_results =
Expand All @@ -576,8 +576,8 @@ mod tests {

#[test]
fn test_error_not_enough_groundtruth() {
let groundtruth = Matrix::<u32>::from_element(10, 5, 0);
let results = Matrix::<u32>::from_element(10, 10, 0);
let groundtruth = rowmajor::Owned::<u32>::from_element(10, 5, 0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let err = knn(&groundtruth, None, &results, 10, 10, GroundTruthMode::Fixed).unwrap_err();
assert!(matches!(err, ComputeRecallError::NotEnoughGroundTruth(..)));
let err_allow_insufficient_results =
Expand All @@ -591,7 +591,7 @@ mod tests {
#[test]
fn test_dynamic_groundtruth_valid() {
let groundtruth: Vec<_> = (0..10).map(|_| vec![0u32; 5]).collect();
let results = Matrix::<u32>::from_element(10, 10, 0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
// Should succeed: each row uses this_recall_k = min(5, 10) = 5
// Should succeed in Flexible mode, but fail in Fixed mode
let recall_flexible = knn(
Expand All @@ -614,7 +614,7 @@ mod tests {
fn test_dynamic_groundtruth_full_match() {
let gt_row: Vec<u32> = (1..=5).collect();
let groundtruth: Vec<_> = (0..10).map(|_| gt_row.clone()).collect();
let mut results = Matrix::<u32>::from_element(10, 10, 0);
let mut results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
for i in 0..10 {
for (j, v) in (1u32..=10).enumerate() {
*results.element_mut(i, j) = v;
Expand All @@ -637,7 +637,7 @@ mod tests {
// groundtruth: [1, 2, 3, 4, 5]; results contain [1, 2, 3, 6, 7, 8, 9, 10, 11, 12]
let gt_row: Vec<u32> = (1..=5).collect();
let groundtruth: Vec<_> = (0..10).map(|_| gt_row.clone()).collect();
let mut results = Matrix::<u32>::from_element(10, 10, 0);
let mut results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let res_row: Vec<u32> = vec![1, 2, 3, 6, 7, 8, 9, 10, 11, 12];
for i in 0..10 {
for (j, &v) in res_row.iter().enumerate() {
Expand Down Expand Up @@ -668,7 +668,7 @@ mod tests {
groundtruth.push(vec![]);
}

let mut results = Matrix::<u32>::from_element(10, 10, 0);
let mut results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
for i in 0..10 {
for (j, v) in (1u32..=10).enumerate() {
*results.element_mut(i, j) = v;
Expand All @@ -691,7 +691,7 @@ mod tests {
#[test]
fn test_dynamic_groundtruth_all_zero() {
let groundtruth: Vec<Vec<u32>> = (0..10).map(|_| vec![]).collect();
let results = Matrix::<u32>::from_element(10, 10, 0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);

let recall = knn(
&groundtruth,
Expand Down Expand Up @@ -748,9 +748,9 @@ mod tests {

#[test]
fn test_error_distance_rows_mismatch() {
let groundtruth = Matrix::<u32>::from_element(10, 10, 0);
let distances = Matrix::<f32>::from_element(9, 10, 0.0);
let results = Matrix::<u32>::from_element(10, 10, 0);
let groundtruth = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let distances = rowmajor::Owned::<f32>::from_element(9, 10, 0.0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let err = knn(
&groundtruth,
Some(distances.as_view().into()),
Expand All @@ -765,9 +765,9 @@ mod tests {

#[test]
fn test_error_distance_cols_mismatch() {
let groundtruth = Matrix::<u32>::from_element(10, 10, 0);
let distances = Matrix::<f32>::from_element(10, 9, 0.0);
let results = Matrix::<u32>::from_element(10, 10, 0);
let groundtruth = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let distances = rowmajor::Owned::<f32>::from_element(10, 9, 0.0);
let results = rowmajor::Owned::<u32>::from_element(10, 10, 0);
let err = knn(
&groundtruth,
Some(distances.as_view().into()),
Expand All @@ -789,7 +789,7 @@ mod tests {
let groundtruth: Vec<Vec<u32>> = vec![vec![1, 2, 3], vec![4, 5]];
// distances: first row has 2 elements (should be 3), second row has 2 (matches)
let distances: Vec<Vec<f32>> = vec![vec![0.1, 0.2], vec![0.3, 0.4]];
let distances = Matrix::try_from(
let distances = rowmajor::Owned::try_from_data(
distances.into_iter().flatten().collect::<Vec<_>>().into(),
2,
2,
Expand Down
6 changes: 3 additions & 3 deletions diskann-benchmark-core/src/search/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use diskann::{ANNResult, graph, utils::async_tools};
use diskann_benchmark_runner::utils::MicroSeconds;
use diskann_utils::{
future::{AsyncFriendly, boxit},
views::Matrix,
views::rowmajor::{self, MatrixMut},
};

use crate::{
Expand Down Expand Up @@ -517,12 +517,12 @@ where
T: Search,
{
let mut lengths = Vec::with_capacity(range.len());
let mut ids = Matrix::try_from_fn(range.len(), num_ids.into(), |_| T::Id::default())?;
let mut ids = rowmajor::Owned::try_from_fn(range.len(), num_ids.into(), |_| T::Id::default())?;

let mut latencies = Vec::<MicroSeconds>::with_capacity(range.len());
let mut outputs = Vec::<T::Output>::with_capacity(range.len());

for (ids, index) in std::iter::zip(ids.row_iter_mut(), range) {
for (ids, index) in std::iter::zip(ids.rows_mut(), range) {
let mut buffer = internal::buffer::Buffer::slice(ids);

let start = std::time::Instant::now();
Expand Down
Loading
Loading