From 671e4bfbdbe3f46c0ff1f8acd878d4460de8b791 Mon Sep 17 00:00:00 2001 From: Suryansh Gupta Date: Fri, 17 Jul 2026 19:46:50 +0530 Subject: [PATCH 1/6] Remove T:Copy bound from diskann-quantization\multi_vector\Mat> type --- diskann-benchmark-core/src/recall.rs | 36 +- diskann-benchmark-core/src/search/api.rs | 2 +- .../src/search/graph/inline.rs | 4 +- .../src/search/graph/knn.rs | 4 +- .../src/search/graph/multihop.rs | 4 +- .../src/search/graph/range.rs | 4 +- diskann-benchmark-core/src/search/ids.rs | 10 +- diskann-benchmark-simd/src/lib.rs | 2 +- diskann-benchmark/src/exhaustive/algos.rs | 2 +- diskann-benchmark/src/exhaustive/minmax.rs | 2 +- diskann-benchmark/src/exhaustive/product.rs | 2 +- diskann-benchmark/src/exhaustive/spherical.rs | 2 +- diskann-benchmark/src/multi_vector/driver.rs | 12 +- diskann-benchmark/src/utils/datafiles.rs | 4 +- diskann-bftree/src/provider.rs | 22 +- diskann-bftree/src/quant.rs | 2 +- .../src/search/pq/quantizer_preprocess.rs | 2 +- .../src/search/provider/disk_provider.rs | 2 +- diskann-disk/src/storage/quant/generator.rs | 4 +- .../src/storage/quant/pq/pq_generation.rs | 12 +- diskann-garnet/src/provider.rs | 4 +- diskann-garnet/src/quantization.rs | 4 +- diskann-providers/src/index/diskann_async.rs | 6 +- .../provider/async_/inmem/full_precision.rs | 2 +- .../graph/provider/async_/inmem/spherical.rs | 2 +- .../graph/provider/determinant_diversity.rs | 14 +- .../src/model/pq/fixed_chunk_pq_table.rs | 4 +- .../src/model/pq/pq_construction.rs | 8 +- diskann-providers/src/model/pq/views.rs | 6 +- diskann-providers/src/storage/pq_storage.rs | 6 +- diskann-providers/src/utils/file_util.rs | 2 +- .../src/algorithms/hadamard.rs | 10 +- .../src/algorithms/kmeans/lloyds.rs | 62 +- .../src/algorithms/kmeans/plusplus.rs | 54 +- .../algorithms/transforms/random_rotation.rs | 4 +- diskann-quantization/src/binary/quantizer.rs | 2 +- .../src/minmax/multi/max_sim.rs | 4 +- diskann-quantization/src/minmax/multi/meta.rs | 16 +- diskann-quantization/src/minmax/multi/mod.rs | 6 +- .../src/multi_vector/block_transposed.rs | 44 +- .../src/multi_vector/distance/factory.rs | 64 +- .../src/multi_vector/distance/fallback.rs | 44 +- .../src/multi_vector/distance/kernel.rs | 4 +- .../src/multi_vector/distance/kernels/f16.rs | 6 +- .../multi_vector/distance/kernels/f32/mod.rs | 10 +- .../multi_vector/distance/kernels/layouts.rs | 4 +- .../distance/kernels/tiled_reduce.rs | 10 +- .../src/multi_vector/distance/max_sim.rs | 2 +- .../src/multi_vector/distance/mod.rs | 6 +- diskann-quantization/src/multi_vector/mod.rs | 14 +- .../src/product/tables/basic.rs | 67 +- .../src/product/tables/test.rs | 46 +- .../src/product/tables/transposed/pivots.rs | 10 +- .../src/product/tables/transposed/table.rs | 34 +- diskann-quantization/src/product/train.rs | 16 +- diskann-quantization/src/scalar/mod.rs | 2 +- diskann-quantization/src/scalar/quantizer.rs | 4 +- diskann-quantization/src/spherical/iface.rs | 2 +- .../src/spherical/quantizer.rs | 10 +- diskann-quantization/src/test_util.rs | 2 +- diskann-quantization/src/utils.rs | 4 +- .../tests/compile-fail/multi/mat_as_view.rs | 4 +- .../compile-fail/multi/mat_as_view_mut.rs | 4 +- .../tests/compile-fail/multi/mat_get_row.rs | 4 +- .../compile-fail/multi/mat_get_row_mut.rs | 4 +- .../tests/compile-fail/multi/mat_invariant.rs | 6 +- .../compile-fail/multi/mat_invariant.stderr | 4 +- .../tests/compile-fail/multi/mat_reborrow.rs | 4 +- .../compile-fail/multi/mat_reborrow_mut.rs | 4 +- .../tests/compile-fail/multi/mat_rows.rs | 4 +- .../tests/compile-fail/multi/mat_rows_mut.rs | 4 +- .../multi/matmut_as_view_borrows.rs | 6 +- .../compile-fail/multi/matmut_get_row.rs | 6 +- .../compile-fail/multi/matmut_get_row_mut.rs | 6 +- .../compile-fail/multi/matmut_invariant.rs | 6 +- .../multi/matmut_invariant.stderr | 4 +- .../compile-fail/multi/matmut_reborrow.rs | 6 +- .../compile-fail/multi/matmut_reborrow_mut.rs | 6 +- .../tests/compile-fail/multi/matmut_rows.rs | 6 +- .../compile-fail/multi/matmut_rows_mut.rs | 6 +- .../compile-fail/multi/matref_get_row.rs | 6 +- .../compile-fail/multi/matref_get_row.stderr | 2 +- .../tests/compile-fail/multi/matref_rows.rs | 6 +- .../compile-fail/multi/matref_rows.stderr | 2 +- diskann-utils/src/io.rs | 4 +- diskann-utils/src/lib.rs | 2 + diskann-utils/src/sampling/latin_hypercube.rs | 16 +- diskann-utils/src/sampling/medoid.rs | 26 +- diskann-utils/src/strided.rs | 76 +- diskann-utils/src/views.rs | 2144 +---------------- diskann/src/error/ann_error.rs | 24 +- diskann/src/graph/start_point.rs | 4 +- diskann/src/graph/test/synthetic.rs | 8 +- 93 files changed, 541 insertions(+), 2628 deletions(-) diff --git a/diskann-benchmark-core/src/recall.rs b/diskann-benchmark-core/src/recall.rs index 12c9f11ba..776a8edaa 100644 --- a/diskann-benchmark-core/src/recall.rs +++ b/diskann-benchmark-core/src/recall.rs @@ -379,7 +379,7 @@ mod tests { #[test] fn test_rows() { let mut i = 0usize; - let mat = Matrix::new( + let mat = Matrix::from_gen( views::Init(|| { let v = i; i += 1; @@ -558,16 +558,16 @@ mod tests { #[test] fn test_error_recall_k_and_n() { - let groundtruth = Matrix::::new(0, 10, 10); - let results = Matrix::::new(0, 10, 10); + let groundtruth = Matrix::::from_gen(0, 10, 10); + let results = Matrix::::from_gen(0, 10, 10); 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::::new(0, 11, 10); - let results = Matrix::::new(0, 10, 10); + let groundtruth = Matrix::::from_gen(0, 11, 10); + let results = Matrix::::from_gen(0, 10, 10); let err = knn(&groundtruth, None, &results, 10, 10, GroundTruthMode::Fixed).unwrap_err(); assert!(matches!(err, ComputeRecallError::RowsMismatch(..))); let err_allow_insufficient_results = @@ -580,8 +580,8 @@ mod tests { #[test] fn test_error_not_enough_groundtruth() { - let groundtruth = Matrix::::new(0, 10, 5); - let results = Matrix::::new(0, 10, 10); + let groundtruth = Matrix::::from_gen(0, 10, 5); + let results = Matrix::::from_gen(0, 10, 10); let err = knn(&groundtruth, None, &results, 10, 10, GroundTruthMode::Fixed).unwrap_err(); assert!(matches!(err, ComputeRecallError::NotEnoughGroundTruth(..))); let err_allow_insufficient_results = @@ -595,7 +595,7 @@ mod tests { #[test] fn test_dynamic_groundtruth_valid() { let groundtruth: Vec<_> = (0..10).map(|_| vec![0u32; 5]).collect(); - let results = Matrix::::new(0, 10, 10); + let results = Matrix::::from_gen(0, 10, 10); // 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( @@ -618,7 +618,7 @@ mod tests { fn test_dynamic_groundtruth_full_match() { let gt_row: Vec = (1..=5).collect(); let groundtruth: Vec<_> = (0..10).map(|_| gt_row.clone()).collect(); - let mut results = Matrix::::new(0, 10, 10); + let mut results = Matrix::::from_gen(0, 10, 10); for i in 0..10 { for (j, v) in (1u32..=10).enumerate() { results[(i, j)] = v; @@ -641,7 +641,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 = (1..=5).collect(); let groundtruth: Vec<_> = (0..10).map(|_| gt_row.clone()).collect(); - let mut results = Matrix::::new(0, 10, 10); + let mut results = Matrix::::from_gen(0, 10, 10); let res_row: Vec = vec![1, 2, 3, 6, 7, 8, 9, 10, 11, 12]; for i in 0..10 { for (j, &v) in res_row.iter().enumerate() { @@ -672,7 +672,7 @@ mod tests { groundtruth.push(vec![]); } - let mut results = Matrix::::new(0, 10, 10); + let mut results = Matrix::::from_gen(0, 10, 10); for i in 0..10 { for (j, v) in (1u32..=10).enumerate() { results[(i, j)] = v; @@ -695,7 +695,7 @@ mod tests { #[test] fn test_dynamic_groundtruth_all_zero() { let groundtruth: Vec> = (0..10).map(|_| vec![]).collect(); - let results = Matrix::::new(0, 10, 10); + let results = Matrix::::from_gen(0, 10, 10); let recall = knn( &groundtruth, @@ -752,9 +752,9 @@ mod tests { #[test] fn test_error_distance_rows_mismatch() { - let groundtruth = Matrix::::new(0, 10, 10); - let distances = Matrix::::new(0.0, 9, 10); - let results = Matrix::::new(0, 10, 10); + let groundtruth = Matrix::::from_gen(0, 10, 10); + let distances = Matrix::::from_gen(0.0, 9, 10); + let results = Matrix::::from_gen(0, 10, 10); let err = knn( &groundtruth, Some(distances.as_view().into()), @@ -769,9 +769,9 @@ mod tests { #[test] fn test_error_distance_cols_mismatch() { - let groundtruth = Matrix::::new(0, 10, 10); - let distances = Matrix::::new(0.0, 10, 9); - let results = Matrix::::new(0, 10, 10); + let groundtruth = Matrix::::from_gen(0, 10, 10); + let distances = Matrix::::from_gen(0.0, 10, 9); + let results = Matrix::::from_gen(0, 10, 10); let err = knn( &groundtruth, Some(distances.as_view().into()), diff --git a/diskann-benchmark-core/src/search/api.rs b/diskann-benchmark-core/src/search/api.rs index 636a9ab19..38e5dbd2f 100644 --- a/diskann-benchmark-core/src/search/api.rs +++ b/diskann-benchmark-core/src/search/api.rs @@ -517,7 +517,7 @@ where T: Search, { let mut lengths = Vec::with_capacity(range.len()); - let mut ids = Matrix::new(views::Init(T::Id::default), range.len(), num_ids.into()); + let mut ids = Matrix::from_gen(views::Init(T::Id::default), range.len(), num_ids.into()); let mut latencies = Vec::::with_capacity(range.len()); let mut outputs = Vec::::with_capacity(range.len()); diff --git a/diskann-benchmark-core/src/search/graph/inline.rs b/diskann-benchmark-core/src/search/graph/inline.rs index 5e32e187d..27ce21499 100644 --- a/diskann-benchmark-core/src/search/graph/inline.rs +++ b/diskann-benchmark-core/src/search/graph/inline.rs @@ -173,7 +173,7 @@ mod tests { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -273,7 +273,7 @@ mod tests { #[test] fn test_inline_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::new(0.0f32, 2, index.provider().dim())); + let queries = Arc::new(Matrix::from_gen(0.0f32, 2, index.provider().dim())); let labels: Arc<[_]> = (0..queries.nrows() + 1) .map(|_| -> Arc> { Arc::new(NoOdds {}) }) diff --git a/diskann-benchmark-core/src/search/graph/knn.rs b/diskann-benchmark-core/src/search/graph/knn.rs index f1c074d04..ba7b5526e 100644 --- a/diskann-benchmark-core/src/search/graph/knn.rs +++ b/diskann-benchmark-core/src/search/graph/knn.rs @@ -402,7 +402,7 @@ mod tests { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -488,7 +488,7 @@ mod tests { fn test_knn_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::new(0.0f32, 1, index.provider().dim())); + let queries = Arc::new(Matrix::from_gen(0.0f32, 1, index.provider().dim())); let strategy = provider::Strategy::new(); let err = KNN::new( diff --git a/diskann-benchmark-core/src/search/graph/multihop.rs b/diskann-benchmark-core/src/search/graph/multihop.rs index dba7c9925..39b6cca61 100644 --- a/diskann-benchmark-core/src/search/graph/multihop.rs +++ b/diskann-benchmark-core/src/search/graph/multihop.rs @@ -168,7 +168,7 @@ mod tests { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -265,7 +265,7 @@ mod tests { #[test] fn test_multihop_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::new(0.0f32, 2, index.provider().dim())); + let queries = Arc::new(Matrix::from_gen(0.0f32, 2, index.provider().dim())); let labels: Arc<[_]> = (0..queries.nrows() + 1) .map(|_| -> Arc> { Arc::new(NoOdds {}) }) diff --git a/diskann-benchmark-core/src/search/graph/range.rs b/diskann-benchmark-core/src/search/graph/range.rs index edf95e29a..8ff79f56f 100644 --- a/diskann-benchmark-core/src/search/graph/range.rs +++ b/diskann-benchmark-core/src/search/graph/range.rs @@ -243,7 +243,7 @@ mod tests { fn test_range() { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -314,7 +314,7 @@ mod tests { fn test_range_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::new(0.0f32, 2, index.provider().dim())); + let queries = Arc::new(Matrix::from_gen(0.0f32, 2, index.provider().dim())); let strategy = provider::Strategy::new(); let err = Range::new(index, queries.clone(), Strategy::collection([strategy])).unwrap_err(); diff --git a/diskann-benchmark-core/src/search/ids.rs b/diskann-benchmark-core/src/search/ids.rs index 28eabe1e3..75c2fb4e4 100644 --- a/diskann-benchmark-core/src/search/ids.rs +++ b/diskann-benchmark-core/src/search/ids.rs @@ -231,7 +231,7 @@ where len, num_ids, } => { - let mut dst = Matrix::new(views::Init(|| I::default()), len, num_ids); + let mut dst = Matrix::from_gen(views::Init(|| I::default()), len, num_ids); let mut lengths = Vec::with_capacity(len); let mut output_row = 0; @@ -279,7 +279,7 @@ mod tests { let nrows = data.len(); let ncols = data.iter().map(|v| v.len()).max().unwrap_or(0); - let mut matrix = Matrix::new(0u32, nrows, ncols); + let mut matrix = Matrix::from_gen(0u32, nrows, ncols); let mut lengths = Vec::with_capacity(nrows); for (row, row_data) in std::iter::zip(matrix.row_iter_mut(), data.iter()) { @@ -296,7 +296,7 @@ mod tests { #[test] fn test_bounded_new_valid() { - let matrix = Matrix::new(0u32, 3, 5); + let matrix = Matrix::from_gen(0u32, 3, 5); let lengths = vec![2, 3, 1]; let bounded = Bounded::new(matrix, lengths); @@ -305,7 +305,7 @@ mod tests { #[test] fn test_bounded_length_clamping() { - let matrix = Matrix::new(0u32, 3, 3); + let matrix = Matrix::from_gen(0u32, 3, 3); let lengths = vec![2, 3, 5]; // Last length exceeds number of columns let bounded = Bounded::new(matrix, lengths); @@ -323,7 +323,7 @@ mod tests { #[test] #[should_panic(expected = "an internal invariant was not upheld")] fn test_bounded_new_mismatched_lengths() { - let matrix = Matrix::new(0u32, 3, 5); + let matrix = Matrix::from_gen(0u32, 3, 5); let lengths = vec![2, 3]; // Only 2 lengths for 3 rows Bounded::new(matrix, lengths); } diff --git a/diskann-benchmark-simd/src/lib.rs b/diskann-benchmark-simd/src/lib.rs index 25b021d8a..5d36ed1bd 100644 --- a/diskann-benchmark-simd/src/lib.rs +++ b/diskann-benchmark-simd/src/lib.rs @@ -754,7 +754,7 @@ impl Data { let query: Box<[Q]> = (0..run.dim.get()) .map(|_| StandardUniform.sample(&mut rng)) .collect(); - let data = Matrix::::new( + let data = Matrix::::from_gen( diskann_utils::views::Init(|| StandardUniform.sample(&mut rng)), run.num_points.get(), run.dim.get(), diff --git a/diskann-benchmark/src/exhaustive/algos.rs b/diskann-benchmark/src/exhaustive/algos.rs index 1d7d56989..9433f8923 100644 --- a/diskann-benchmark/src/exhaustive/algos.rs +++ b/diskann-benchmark/src/exhaustive/algos.rs @@ -51,7 +51,7 @@ where C: CreateQuantComputer + Sync, { let mut output = - diskann_utils::views::Matrix::::new(u32::MAX, queries.nrows(), results_per_query); + diskann_utils::views::Matrix::::from_gen(u32::MAX, queries.nrows(), results_per_query); struct Times { preprocess: MicroSeconds, diff --git a/diskann-benchmark/src/exhaustive/minmax.rs b/diskann-benchmark/src/exhaustive/minmax.rs index 444d4d6be..7a5feccac 100644 --- a/diskann-benchmark/src/exhaustive/minmax.rs +++ b/diskann-benchmark/src/exhaustive/minmax.rs @@ -389,7 +389,7 @@ mod imp { // The APIs below should correctly handle these variables. let output_dim = quantizer.output_dim(); let bytes = Data::::canonical_bytes(output_dim); - let mut data = diskann_utils::views::Matrix::new(0, input.nrows(), bytes); + let mut data = diskann_utils::views::Matrix::from_gen(0, input.nrows(), bytes); // Compress the data. // diff --git a/diskann-benchmark/src/exhaustive/product.rs b/diskann-benchmark/src/exhaustive/product.rs index d05145e39..d404ab254 100644 --- a/diskann-benchmark/src/exhaustive/product.rs +++ b/diskann-benchmark/src/exhaustive/product.rs @@ -333,7 +333,7 @@ mod imp { progress: &ProgressBar, ) -> anyhow::Result { let mut data = - diskann_utils::views::Matrix::new(0, input.nrows(), quantizer.get_num_chunks()); + diskann_utils::views::Matrix::from_gen(0, input.nrows(), quantizer.get_num_chunks()); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/exhaustive/spherical.rs b/diskann-benchmark/src/exhaustive/spherical.rs index 5e009c231..22e8d2f0d 100644 --- a/diskann-benchmark/src/exhaustive/spherical.rs +++ b/diskann-benchmark/src/exhaustive/spherical.rs @@ -416,7 +416,7 @@ mod imp { let output_dim = plan.quantizer().output_dim(); let bytes = diskann_quantization::spherical::DataRef::::canonical_bytes(output_dim); - let mut data = diskann_utils::views::Matrix::new(0, input.nrows(), bytes); + let mut data = diskann_utils::views::Matrix::from_gen(0, input.nrows(), bytes); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/multi_vector/driver.rs b/diskann-benchmark/src/multi_vector/driver.rs index e69c70845..29cb5fc15 100644 --- a/diskann-benchmark/src/multi_vector/driver.rs +++ b/diskann-benchmark/src/multi_vector/driver.rs @@ -14,7 +14,7 @@ use diskann_benchmark_runner::{ }, Checker, Input, }; -use diskann_quantization::multi_vector::{Mat, MatRef, MaxSimKernel, Overflow, Standard}; +use diskann_quantization::multi_vector::{Mat, MatRef, MaxSimKernel, Overflow, RowMajor}; use rand::{ distr::{Distribution, StandardUniform}, rngs::StdRng, @@ -68,8 +68,8 @@ impl Input for MultiVectorTolerance { /// Random query / doc fixture for a single benchmark run. pub(super) struct Data { - pub(super) queries: Mat>, - pub(super) docs: Mat>, + pub(super) queries: Mat>, + pub(super) docs: Mat>, } impl Data @@ -79,11 +79,11 @@ where pub(super) fn new(run: &Run) -> Result { let mut rng = StdRng::seed_from_u64(0x12345); let queries = Mat::from_fn( - Standard::new(run.num_query_vectors.get(), run.dim.get())?, + RowMajor::new(run.num_query_vectors.get(), run.dim.get())?, || StandardUniform.sample(&mut rng), ); let docs = Mat::from_fn( - Standard::new(run.num_doc_vectors.get(), run.dim.get())?, + RowMajor::new(run.num_doc_vectors.get(), run.dim.get())?, || StandardUniform.sample(&mut rng), ); Ok(Self { queries, docs }) @@ -96,7 +96,7 @@ where pub(super) fn run_with_kernel( run: &Run, - doc: MatRef<'_, Standard>, + doc: MatRef<'_, RowMajor>, kernel: &dyn MaxSimKernel, ) -> RunResult { let mut scores = vec![0.0f32; run.num_query_vectors.get()]; diff --git a/diskann-benchmark/src/utils/datafiles.rs b/diskann-benchmark/src/utils/datafiles.rs index abfe06a7d..6d3526a13 100644 --- a/diskann-benchmark/src/utils/datafiles.rs +++ b/diskann-benchmark/src/utils/datafiles.rs @@ -76,7 +76,7 @@ impl ConvertingLoad for f32 { U: Default + Clone + From, T: Copy, { - let mut to = Matrix::new(U::default(), from.nrows(), from.ncols()); + let mut to = Matrix::from_gen(U::default(), from.nrows(), from.ncols()); std::iter::zip(to.as_mut_slice().iter_mut(), from.as_slice().iter()) .for_each(|(t, f)| *t = (*f).into()); to @@ -111,7 +111,7 @@ pub(crate) fn load_groundtruth(path: BinFile<'_>, k: Option) -> anyhow::R (num_points, dim) }; - let mut groundtruth = Matrix::::new(0, num_points, dim); + let mut groundtruth = Matrix::::from_gen(0, num_points, dim); let groundtruth_slice: &mut [u8] = bytemuck::cast_slice_mut(groundtruth.as_mut_slice()); file.read_exact(groundtruth_slice)?; diff --git a/diskann-bftree/src/provider.rs b/diskann-bftree/src/provider.rs index 1a9f773ca..35cf021b2 100644 --- a/diskann-bftree/src/provider.rs +++ b/diskann-bftree/src/provider.rs @@ -115,7 +115,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// /// // Create a table that supports 5 points and 1 start point. -/// let start_points = Matrix::new(Init(|| 0.0f32), 1, 4); +/// let start_points = Matrix::from_gen(Init(|| 0.0f32), 1, 4); /// let provider = BfTreeProvider::::new( /// parameters, /// start_points.as_view(), @@ -145,7 +145,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// use rand::SeedableRng; /// /// let dim = 4; -/// let data = Matrix::new(Init(|| 1.0f32), 4, dim); +/// let data = Matrix::from_gen(Init(|| 1.0f32), 4, dim); /// let mut rng = StdRng::seed_from_u64(42); /// let sq = SphericalQuantizer::train( /// data.as_view(), TransformKind::Null, @@ -170,7 +170,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// /// // Create a table that supports 5 points and 1 start point. -/// let start_points = Matrix::new(Init(|| 0.0f32), 1, 4); +/// let start_points = Matrix::from_gen(Init(|| 0.0f32), 1, 4); /// let provider = BfTreeProvider::::new( /// parameters, /// start_points.as_view(), @@ -2023,7 +2023,7 @@ mod tests { use diskann_utils::views::{Init, Matrix}; fn create_quant_index() -> Arc>> { - let start_point = Matrix::new(Init(|| 0.0f32), 1, 5); + let start_point = Matrix::from_gen(Init(|| 0.0f32), 1, 5); let dim = 5; let logical_max_degree = 6; let physical_max_degree = (logical_max_degree as f32 * 1.3) as u32; @@ -2100,7 +2100,7 @@ mod tests { let index = create_quant_index(); let ctx = &DefaultContext; - let data = Matrix::new( + let data = Matrix::from_gen( Init({ let mut row = 0usize; let mut col = 0usize; @@ -2196,7 +2196,7 @@ mod tests { } fn create_full_precision_index() -> Arc>> { - let start_point = Matrix::new(Init(|| 0.0f32), 1, 5); + let start_point = Matrix::from_gen(Init(|| 0.0f32), 1, 5); let logical_max_degree = 6; let physical_max_degree = (logical_max_degree as f32 * 1.3) as u32; let metric = Metric::L2; @@ -2422,7 +2422,7 @@ mod tests { let num_start_points = 2; let dim = 3; - let start_points = Matrix::new(Init(|| 0.0f32), num_start_points, dim); + let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points, dim); let provider = BfTreeProvider::::new( BfTreeProviderParameters { @@ -2559,7 +2559,7 @@ mod tests { use_snapshot: true, }; - let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); // Create provider let provider = @@ -2691,7 +2691,7 @@ mod tests { use_snapshot: true, }; - let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); // Create provider with quantization let provider = BfTreeProvider::::new( params.clone(), @@ -2810,7 +2810,7 @@ mod tests { let mut neighbor_config = Config::default(); neighbor_config.use_snapshot(true); - let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); // In-memory config (no file path needed) let provider = BfTreeProvider::::new( BfTreeProviderParameters { @@ -2925,7 +2925,7 @@ mod tests { let mut quant_config = Config::default(); quant_config.use_snapshot(true); - let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); let provider = BfTreeProvider::::new( BfTreeProviderParameters { max_points: num_points, diff --git a/diskann-bftree/src/quant.rs b/diskann-bftree/src/quant.rs index 8a37ffd19..2cfb725a5 100644 --- a/diskann-bftree/src/quant.rs +++ b/diskann-bftree/src/quant.rs @@ -243,7 +243,7 @@ pub(crate) fn create_test_quantizer(dim: usize) -> Poly { // Create training data with spread-out values. let nrows = 8; let mut counter = 0.0f32; - let data = Matrix::new( + let data = Matrix::from_gen( Init(move || { counter += 0.5; counter diff --git a/diskann-disk/src/search/pq/quantizer_preprocess.rs b/diskann-disk/src/search/pq/quantizer_preprocess.rs index c5a202630..344570ba5 100644 --- a/diskann-disk/src/search/pq/quantizer_preprocess.rs +++ b/diskann-disk/src/search/pq/quantizer_preprocess.rs @@ -22,7 +22,7 @@ pub fn quantizer_preprocess( ) -> ANNResult<()> { let table = pq_data.pq_table(); let expected_len = table.ncenters() * table.nchunks(); - let dst = diskann_utils::views::MutMatrixView::try_from( + let dst = diskann_utils::views::MatrixViewMut::try_from( &mut (*pq_scratch.aligned_pqtable_dist_scratch)[..expected_len], table.nchunks(), table.ncenters(), diff --git a/diskann-disk/src/search/provider/disk_provider.rs b/diskann-disk/src/search/provider/disk_provider.rs index c497414a6..cff431bc7 100644 --- a/diskann-disk/src/search/provider/disk_provider.rs +++ b/diskann-disk/src/search/provider/disk_provider.rs @@ -432,7 +432,7 @@ where ensure_vertex_loaded(&mut accessor.scratch.vertex_provider, &candidate_ids)?; - let mut candidate_vectors = Matrix::new(0.0f32, candidate_ids.len(), query_f32.len()); + let mut candidate_vectors = Matrix::from_gen(0.0f32, candidate_ids.len(), query_f32.len()); let mut candidate_distances = Vec::with_capacity(candidate_ids.len()); let mut associated_data = Vec::with_capacity(candidate_ids.len()); diff --git a/diskann-disk/src/storage/quant/generator.rs b/diskann-disk/src/storage/quant/generator.rs index 7c09c1182..45ed4f6bb 100644 --- a/diskann-disk/src/storage/quant/generator.rs +++ b/diskann-disk/src/storage/quant/generator.rs @@ -147,7 +147,7 @@ where // Wrap the data in `MatrixViews` so we do not need to manually construct view // in the compression loop. - let mut compressed_block = views::MutMatrixView::try_from( + let mut compressed_block = views::MatrixViewMut::try_from( block_compressed_base, cur_block_size, compressed_size, @@ -221,7 +221,7 @@ mod generator_tests { fn compress( &self, _vector: views::MatrixView, - mut output: views::MutMatrixView, + mut output: views::MatrixViewMut, ) -> ANNResult<()> { output .row_iter_mut() diff --git a/diskann-disk/src/storage/quant/pq/pq_generation.rs b/diskann-disk/src/storage/quant/pq/pq_generation.rs index b1eae30c3..e317d8e3c 100644 --- a/diskann-disk/src/storage/quant/pq/pq_generation.rs +++ b/diskann-disk/src/storage/quant/pq/pq_generation.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{BridgeErr, RayonThreadPoolRef}, }; use diskann_quantization::{product::TransposedTable, CompressInto}; -use diskann_utils::views::MatrixBase; +use diskann_utils::views::{MatrixView, MatrixViewMut}; use diskann_vector::distance::Metric; use tracing::info; @@ -119,7 +119,7 @@ where context.storage_provider, )?; - let mut full_pivot_data_mat = diskann_utils::views::MutMatrixView::try_from( + let mut full_pivot_data_mat = diskann_utils::views::MatrixViewMut::try_from( full_pivot_data.as_mut_slice(), context.num_centers, full_dim, @@ -146,8 +146,8 @@ where fn compress( &self, - vector: MatrixBase<&[f32]>, - output: MatrixBase<&mut [u8]>, + vector: MatrixView<'_, f32>, + output: MatrixViewMut<'_, u8>, ) -> Result<(), diskann::ANNError> { self.table .compress_into(vector, output) @@ -175,7 +175,7 @@ mod pq_generation_tests { use diskann_utils::{ io::{read_bin, write_bin}, test_data_root, - views::{MatrixView, MutMatrixView}, + views::{MatrixView, MatrixViewMut}, }; use diskann_vector::distance::Metric; use rstest::rstest; @@ -329,7 +329,7 @@ mod pq_generation_tests { let mut compressed_mat = vec![0_u8; num_chunks * npts]; let result = compressor.unwrap().compress( data_matrix.as_view(), - MutMatrixView::try_from(&mut compressed_mat, npts, num_chunks).unwrap(), + MatrixViewMut::try_from(&mut compressed_mat, npts, num_chunks).unwrap(), ); assert!(result.is_ok()); diff --git a/diskann-garnet/src/provider.rs b/diskann-garnet/src/provider.rs index 5024b7b9d..0ab008d37 100644 --- a/diskann-garnet/src/provider.rs +++ b/diskann-garnet/src/provider.rs @@ -449,7 +449,7 @@ impl GarnetProvider { }; let rows = quantizer.required_vectors(); - let mut data = Matrix::::new(T::default(), rows, self.dim); + let mut data = Matrix::::from_gen(T::default(), rows, self.dim); let mut row_idx = 0usize; if self @@ -499,7 +499,7 @@ impl GarnetProvider { Ok(v) => v, Err(_) => return false, }; - let view = match MatrixView::try_from(&*converted, view.nrows(), view.ncols()) { + let view = match MatrixView::try_from(&converted, view.nrows(), view.ncols()) { Ok(v) => v, Err(_) => return false, }; diff --git a/diskann-garnet/src/quantization.rs b/diskann-garnet/src/quantization.rs index 8faa876c1..74046483a 100644 --- a/diskann-garnet/src/quantization.rs +++ b/diskann-garnet/src/quantization.rs @@ -386,7 +386,7 @@ mod tests { Err(GarnetQuantizerError::NoQuantizer) )); - let mut test_data = Matrix::new(0.0f32, 1000, 2); + let mut test_data = Matrix::from_gen(0.0f32, 1000, 2); for i in 0..1000 { test_data .row_mut(i) @@ -424,7 +424,7 @@ mod tests { let test_v = [0.5f32, 0.5]; let mut test_q = vec![0u8; quantizer.bytes()]; - let mut test_data = Matrix::new(0.0f32, 1, 2); + let mut test_data = Matrix::from_gen(0.0f32, 1, 2); test_data.row_mut(0).copy_from_slice(&[1.0f32, 1.0]); // Training is a no-op, but succeeds. diff --git a/diskann-providers/src/index/diskann_async.rs b/diskann-providers/src/index/diskann_async.rs index 41389910e..99f770c8e 100644 --- a/diskann-providers/src/index/diskann_async.rs +++ b/diskann-providers/src/index/diskann_async.rs @@ -221,7 +221,7 @@ pub(crate) mod tests { { // Assume that all the vectors in `data` have the same length. // If they don't, `copy_from_slice` will panic, so we're double checking. - let mut mat = diskann_utils::views::Matrix::new(To::default(), data.len(), dim); + let mut mat = diskann_utils::views::Matrix::from_gen(To::default(), data.len(), dim); std::iter::zip(mat.row_iter_mut(), data).for_each(|(output, input)| { assert_eq!( input.len(), @@ -2236,7 +2236,7 @@ pub(crate) mod tests { } else { let mut i: u32 = 0; while let Some(data) = iter.next_n(batchsize) { - let mut vectors = Matrix::new(0.0f32, data.len(), start_vectors.ncols()); + let mut vectors = Matrix::from_gen(0.0f32, data.len(), start_vectors.ncols()); let ids: Arc<[_]> = std::iter::zip(vectors.row_iter_mut(), data.iter()) .map(|(dst, (v, _))| { dst.copy_from_slice(v); @@ -2658,7 +2658,7 @@ pub(crate) mod tests { // Randomize the vectors let rng = &mut create_rnd_from_seed_in_tests(0x7dc205fcda38d3a3); indices.shuffle(rng); - let mut queries = diskann_utils::views::Matrix::new(0.0, data.nrows(), data.ncols()); + let mut queries = diskann_utils::views::Matrix::from_gen(0.0, data.nrows(), data.ncols()); std::iter::zip(queries.row_iter_mut(), indices.iter()).for_each(|(row, i)| { row.copy_from_slice(data.row(*i)); }); diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs index 15c2d6af1..020020e7f 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs @@ -438,7 +438,7 @@ where let candidates: Vec> = candidates.collect(); let candidate_count = candidates.len(); let store: &FullPrecisionStore = accessor.as_full_precision(); - let mut vectors = Matrix::new(0.0f32, candidate_count, query.len()); + let mut vectors = Matrix::from_gen(0.0f32, candidate_count, query.len()); let mut ids = Vec::with_capacity(candidate_count); let mut distances = Vec::with_capacity(candidate_count); diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs index 10f174a87..ebdfeda2c 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs @@ -768,7 +768,7 @@ mod tests { } fn dataset(nrows: usize, ncols: usize, rng: &mut StdRng) -> Matrix { - Matrix::new( + Matrix::from_gen( diskann_utils::views::Init(|| StandardNormal {}.sample(rng)), nrows, ncols, diff --git a/diskann-providers/src/model/graph/provider/determinant_diversity.rs b/diskann-providers/src/model/graph/provider/determinant_diversity.rs index 5e35c8708..8a365fe93 100644 --- a/diskann-providers/src/model/graph/provider/determinant_diversity.rs +++ b/diskann-providers/src/model/graph/provider/determinant_diversity.rs @@ -53,7 +53,7 @@ use std::fmt; -use diskann_utils::views::MutMatrixView; +use diskann_utils::views::MatrixViewMut; use diskann_vector::{MathematicalValue, PureDistanceFunction, distance::InnerProduct}; /// Parameters for Determinant-Diversity post-processor with validation. @@ -199,7 +199,7 @@ struct DistanceRange { /// An empty candidate set, a `k` of zero, or zero-dimensional vectors yield an /// empty result. pub fn determinant_diversity( - candidates: MutMatrixView<'_, f32>, + candidates: MatrixViewMut<'_, f32>, distances: &[f32], query: &[f32], k: usize, @@ -338,7 +338,7 @@ pub fn determinant_diversity( /// O(n * k * dim) -- for each of k pivots we touch all n residual rows of /// length `dim`. Memory is O(n * dim) for the contiguous residual matrix. fn greedy_orthogonal_select( - mut candidates: MutMatrixView<'_, f32>, + mut candidates: MatrixViewMut<'_, f32>, distances: &[f32], k: usize, power: f32, @@ -530,7 +530,7 @@ mod tests { } let dim = candidates[0].2.len(); - let mut matrix = Matrix::new(0.0f32, candidates.len(), dim); + let mut matrix = Matrix::from_gen(0.0f32, candidates.len(), dim); let mut ids = Vec::with_capacity(candidates.len()); let mut distances = Vec::with_capacity(candidates.len()); @@ -564,7 +564,7 @@ mod tests { // A zero-length query against non-empty candidates is a structural // mismatch (candidate columns != query dimension), not a valid request // that trivially returns nothing. - let mut matrix = Matrix::new(0.0f32, 1, 2); + let mut matrix = Matrix::from_gen(0.0f32, 1, 2); matrix.row_mut(0).copy_from_slice(&[1.0, 2.0]); let params = DeterminantDiversityParams::new(1.0, 0.5).unwrap(); @@ -582,7 +582,7 @@ mod tests { fn test_mismatched_dimensions_errors() { // Candidate vectors are 2-D, but the query is 3-D, so // `determinant_diversity` should report a dimension mismatch. - let mut matrix = Matrix::new(0.0f32, 1, 2); + let mut matrix = Matrix::from_gen(0.0f32, 1, 2); matrix.row_mut(0).copy_from_slice(&[1.0, 2.0]); let params = DeterminantDiversityParams::new(1.0, 0.5).unwrap(); @@ -600,7 +600,7 @@ mod tests { #[test] fn test_mismatched_distances_errors() { // Two candidate rows but only one distance is a structural mismatch. - let mut matrix = Matrix::new(0.0f32, 2, 2); + let mut matrix = Matrix::from_gen(0.0f32, 2, 2); matrix.row_mut(0).copy_from_slice(&[1.0, 0.0]); matrix.row_mut(1).copy_from_slice(&[0.0, 1.0]); let params = DeterminantDiversityParams::new(1.0, 0.5).unwrap(); diff --git a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs index 2973db8fd..2ef019f73 100644 --- a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs +++ b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs @@ -9,7 +9,7 @@ use diskann_quantization::{ product::{self, BasicTable}, views::ChunkOffsetsBase, }; -use diskann_utils::views::{self, MatrixBase, MatrixView}; +use diskann_utils::views::{self, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance}; use diskann_wide::ARCH; @@ -133,7 +133,7 @@ impl FixedChunkPQTable { pub fn new(dim: usize, pq_table: Box<[f32]>, chunk_offsets: Box<[usize]>) -> ANNResult { let len = pq_table.len(); let table = BasicTable::new( - MatrixBase::try_from(pq_table, len / dim, dim).bridge_err()?, + Matrix::try_from(pq_table, len / dim, dim).bridge_err()?, ChunkOffsetsBase::new(chunk_offsets).bridge_err()?, ) .map_err(|err| ANNError::log_pq_error(diskann_quantization::error::format(&err)))?; diff --git a/diskann-providers/src/model/pq/pq_construction.rs b/diskann-providers/src/model/pq/pq_construction.rs index 8ca3f11a4..91fa6ca5e 100644 --- a/diskann-providers/src/model/pq/pq_construction.rs +++ b/diskann-providers/src/model/pq/pq_construction.rs @@ -25,7 +25,7 @@ use diskann_quantization::{ }; use diskann_utils::{ io::Metadata, - views::{MatrixView, MutMatrixView}, + views::{MatrixView, MatrixViewMut}, }; use rand::{Rng, distr::Distribution}; use rayon::prelude::*; @@ -293,7 +293,7 @@ pub fn move_train_data_by_centroid( /// # Panics /// /// Panics if `y.len() != x.ncols()`. -pub fn accum_row_inplace(mut x: MutMatrixView, y: &[T]) +pub fn accum_row_inplace(mut x: MatrixViewMut, y: &[T]) where T: Copy + std::ops::AddAssign, { @@ -362,7 +362,7 @@ where // Instead of subtracting the center from each data set component, we instead // add it to each center. let mut full_pivot_data_mat = - MutMatrixView::try_from(full_pivot_data.as_mut_slice(), num_centers, full_dim) + MatrixViewMut::try_from(full_pivot_data.as_mut_slice(), num_centers, full_dim) .bridge_err()?; accum_row_inplace(full_pivot_data_mat.as_mut_view(), centroid.as_slice()); @@ -430,7 +430,7 @@ where // Wrap the data in `MatrixViews` so we do not need to manually construct view // in the compression loop. let mut compressed_block = - MutMatrixView::try_from(&mut block_compressed_base, cur_block_size, num_pq_chunks) + MatrixViewMut::try_from(&mut block_compressed_base, cur_block_size, num_pq_chunks) .bridge_err()?; let base_block = MatrixView::try_from(block_data, cur_block_size, full_dim).bridge_err()?; diff --git a/diskann-providers/src/model/pq/views.rs b/diskann-providers/src/model/pq/views.rs index 17028de3c..52f1d362d 100644 --- a/diskann-providers/src/model/pq/views.rs +++ b/diskann-providers/src/model/pq/views.rs @@ -41,9 +41,9 @@ impl From> for ANNError { } // Compatibility with ANNError. -impl From>> for ANNError { +impl From> for ANNError { #[track_caller] - fn from(value: Bridge>) -> Self { + fn from(value: Bridge) -> Self { ANNError::log_pq_error(value.into_inner()) } } @@ -106,7 +106,7 @@ mod tests { let data = vec![0; ncols * nrows]; test_error(|| { - views::MatrixView::try_from(&*data, nrows, ncols + 1) + views::MatrixView::try_from(&data, nrows, ncols + 1) .bridge_err() .unwrap_err() }); diff --git a/diskann-providers/src/storage/pq_storage.rs b/diskann-providers/src/storage/pq_storage.rs index a2d49391b..1adcdb7a9 100644 --- a/diskann-providers/src/storage/pq_storage.rs +++ b/diskann-providers/src/storage/pq_storage.rs @@ -116,7 +116,7 @@ impl PQStorage { // Write the centroid of PQ centroid vectors let centroid_bytes = match centroid { Some(centroid) => write_bin(MatrixView::column_vector(centroid), writer)?, - None => write_bin(Matrix::::new(0.0, dim, 1).as_view(), writer)?, + None => write_bin(Matrix::::from_gen(0.0, dim, 1).as_view(), writer)?, }; cumul_bytes[2] = cumul_bytes[1] + centroid_bytes; @@ -523,7 +523,7 @@ mod pq_storage_tests { #[test] fn write_read_roundtrip_with_legacy_centroid() { use crate::model::pq::accum_row_inplace; - use diskann_utils::views::MutMatrixView; + use diskann_utils::views::MatrixViewMut; let storage_provider = VirtualStorageProvider::new_memory(); let pivot_path = "/roundtrip_legacy_centroid_pivots.bin"; @@ -563,7 +563,7 @@ mod pq_storage_tests { // Fold the centroid into the pivots — this is what production callers do. let mut pivot_mat = - MutMatrixView::try_from(loaded_pivots.as_mut_slice(), num_centers, dim).unwrap(); + MatrixViewMut::try_from(loaded_pivots.as_mut_slice(), num_centers, dim).unwrap(); accum_row_inplace(pivot_mat.as_mut_view(), &loaded_centroid); // Each pivot row should have the centroid added element-wise. diff --git a/diskann-providers/src/utils/file_util.rs b/diskann-providers/src/utils/file_util.rs index f5ebdadc6..c1b40e1ea 100644 --- a/diskann-providers/src/utils/file_util.rs +++ b/diskann-providers/src/utils/file_util.rs @@ -89,7 +89,7 @@ pub fn load_multivec_bin> = Vec::with_capacity(num_points); for &length in &vec_lengths { - let mut vectors = Matrix::::new(T::default(), length as usize, dimension); + let mut vectors = Matrix::::from_gen(T::default(), length as usize, dimension); reader.read_exact(bytemuck::must_cast_slice_mut::( vectors.as_mut_slice(), ))?; diff --git a/diskann-quantization/src/algorithms/hadamard.rs b/diskann-quantization/src/algorithms/hadamard.rs index 5be88d473..8f5dae863 100644 --- a/diskann-quantization/src/algorithms/hadamard.rs +++ b/diskann-quantization/src/algorithms/hadamard.rs @@ -395,11 +395,11 @@ mod tests { assert_ne!(dim, 0); // Base case. if dim == 1 { - Matrix::new(1.0, dim, dim) + Matrix::from_gen(1.0, dim, dim) } else { let half = dim / 2; let sub = hadamard_by_sylvester(half); - let mut m = Matrix::::new(0.0, dim, dim); + let mut m = Matrix::::from_gen(0.0, dim, dim); for c in 0..m.ncols() { for r in 0..m.nrows() { @@ -425,7 +425,7 @@ mod tests { // A naive reference implementation. fn matmul(a: MatrixView, b: MatrixView) -> Matrix { assert_eq!(a.ncols(), b.nrows()); - let mut c = Matrix::new(0.0, a.nrows(), b.ncols()); + let mut c = Matrix::from_gen(0.0, a.nrows(), b.ncols()); for i in 0..c.nrows() { for j in 0..c.ncols() { @@ -444,7 +444,7 @@ mod tests { let mut src = { let mut rng = StdRng::seed_from_u64(0xde1936d651285fc8); let init = views::Init(|| StandardUniform {}.sample(&mut rng)); - Matrix::new(init, 64, 1) + Matrix::from_gen(init, 64, 1) }; let h = hadamard_by_sylvester(64); @@ -477,7 +477,7 @@ mod tests { let src = { let mut rng = StdRng::seed_from_u64(seed); let init = views::Init(|| StandardUniform {}.sample(&mut rng)); - Matrix::new(init, dim, 1) + Matrix::from_gen(init, dim, 1) }; let h = hadamard_by_sylvester(dim); diff --git a/diskann-quantization/src/algorithms/kmeans/lloyds.rs b/diskann-quantization/src/algorithms/kmeans/lloyds.rs index f81894f1e..97c8f3605 100644 --- a/diskann-quantization/src/algorithms/kmeans/lloyds.rs +++ b/diskann-quantization/src/algorithms/kmeans/lloyds.rs @@ -9,7 +9,7 @@ use super::common::square_norm; use crate::multi_vector::{BlockTransposed, BlockTransposedRef}; use diskann_utils::{ strided::StridedView, - views::{Matrix, MatrixView, MutMatrixView}, + views::{Matrix, MatrixView, MatrixViewMut}, }; //////////////////////////////// @@ -342,8 +342,8 @@ fn update((d0, i0): (f32s, u32s), (d1, i1): (f32s, u32s)) -> (f32s, u32s) { // Update Step // ///////////////// -fn update_centroids(mut centers: MutMatrixView<'_, f32>, data: StridedView<'_, f32>, map: &[u32]) { - let mut sums = Matrix::::new(0.0, centers.nrows(), centers.ncols()); +fn update_centroids(mut centers: MatrixViewMut<'_, f32>, data: StridedView<'_, f32>, map: &[u32]) { + let mut sums = Matrix::::from_gen(0.0, centers.nrows(), centers.ncols()); let mut counts: Vec = vec![0; centers.nrows()]; data.row_iter().zip(map.iter()).for_each(|(row, ¢er)| { counts[center as usize] += 1; @@ -373,7 +373,7 @@ pub(crate) fn lloyds_inner( data: StridedView<'_, f32>, square_norms: &[f32], transpose: BlockTransposedRef<'_, f32, 16>, - mut centers: MutMatrixView<'_, f32>, + mut centers: MatrixViewMut<'_, f32>, max_reps: usize, ) -> (Vec, f32) { // Check our requirements. @@ -440,7 +440,7 @@ pub(crate) fn lloyds_inner( /// dimension. pub fn lloyds( data: MatrixView<'_, f32>, - centers: MutMatrixView<'_, f32>, + centers: MatrixViewMut<'_, f32>, max_reps: usize, ) -> (Vec, f32) { assert_eq!( @@ -494,8 +494,8 @@ mod tests { ) { let context = lazy_format!("ncenters = {}, ndata = {}, dim = {}", ncenters, ndata, dim,); - let mut centers = Matrix::new(0.0, ncenters, dim); - let mut data = Matrix::new(0.0, ndata, dim); + let mut centers = Matrix::from_gen(0.0, ncenters, dim); + let mut data = Matrix::from_gen(0.0, ndata, dim); // A list of random "nice" offsets that get applied to each center and data point // to ensure proper visitation during computation. @@ -583,8 +583,8 @@ mod tests { // We do not perform any value-dependent control-flow for memory accesses. // Therefore, the miri tests don't require any setup (this helps everything run faseter). fn test_miri_distances_in_place_impl(ndata: usize, ncenters: usize, dim: usize) { - let centers = Matrix::new(0.0, ncenters, dim); - let data = Matrix::new(0.0, ndata, dim); + let centers = Matrix::from_gen(0.0, ncenters, dim); + let data = Matrix::from_gen(0.0, ndata, dim); let data_norms = vec![0.0; ndata]; let center_norms = vec![0.0; ncenters]; let mut nearest = vec![0; ndata]; @@ -658,8 +658,8 @@ mod tests { .collect(); let mut center_order: Vec = (0..setup.ncenters).collect(); - let mut data = Matrix::new(0.0, setup.ncenters * setup.data_per_center, setup.ndim); - let mut centers = Matrix::new(0.0, setup.ncenters, setup.ndim); + let mut data = Matrix::from_gen(0.0, setup.ncenters * setup.data_per_center, setup.ndim); + let mut centers = Matrix::from_gen(0.0, setup.ncenters, setup.ndim); for trial in 0..setup.ntrials { values.shuffle(rng); @@ -751,9 +751,9 @@ mod tests { #[test] #[should_panic(expected = "dataset and data norms should have the same length")] fn distances_in_place_panics_data_norms() { - let data = Matrix::new(0.0, 5, 8); + let data = Matrix::from_gen(0.0, 5, 8); let data_norms = vec![0.0; data.nrows() + 1]; // Incorrect - let centers = Matrix::new(0.0, 2, 8); + let centers = Matrix::from_gen(0.0, 2, 8); let center_norms = vec![0.0; centers.nrows()]; let mut nearest = vec![0; data.nrows()]; distances_in_place( @@ -768,9 +768,9 @@ mod tests { #[test] #[should_panic(expected = "dataset and centers should have the same dimension")] fn distances_in_place_panics_different_dim() { - let data = Matrix::new(0.0, 5, 8); + let data = Matrix::from_gen(0.0, 5, 8); let data_norms = vec![0.0; data.nrows()]; - let centers = Matrix::new(0.0, 2, 9); // Incorrect + let centers = Matrix::from_gen(0.0, 2, 9); // Incorrect let center_norms = vec![0.0; centers.nrows()]; let mut nearest = vec![0; data.nrows()]; distances_in_place( @@ -785,9 +785,9 @@ mod tests { #[test] #[should_panic(expected = "centers and center norms should have the same length")] fn distances_in_place_panics_center_norms() { - let data = Matrix::new(0.0, 5, 8); + let data = Matrix::from_gen(0.0, 5, 8); let data_norms = vec![0.0; data.nrows()]; - let centers = Matrix::new(0.0, 2, 8); + let centers = Matrix::from_gen(0.0, 2, 8); let center_norms = vec![0.0; centers.nrows() + 1]; // Incorrect let mut nearest = vec![0; data.nrows()]; distances_in_place( @@ -802,9 +802,9 @@ mod tests { #[test] #[should_panic(expected = "dataset and nearest-buffer should have the same length")] fn distances_in_place_panics_nearest() { - let data = Matrix::new(0.0, 5, 8); + let data = Matrix::from_gen(0.0, 5, 8); let data_norms = vec![0.0; data.nrows()]; - let centers = Matrix::new(0.0, 2, 8); + let centers = Matrix::from_gen(0.0, 2, 8); let center_norms = vec![0.0; centers.nrows()]; let mut nearest = vec![0; data.nrows() + 1]; // Incorrect distances_in_place( @@ -823,9 +823,9 @@ mod tests { #[test] #[should_panic(expected = "data and norms should have the same length")] fn lloyds_inner_panics_norms_length() { - let data = Matrix::new(0.0, 5, 8); + let data = Matrix::from_gen(0.0, 5, 8); let square_norms = vec![0.0; data.nrows() + 1]; // Incorrect - let mut centers = Matrix::new(0.0, 2, 8); + let mut centers = Matrix::from_gen(0.0, 2, 8); lloyds_inner( data.as_view().into(), &square_norms, @@ -838,10 +838,10 @@ mod tests { #[test] #[should_panic(expected = "data and transpose should have the same length")] fn lloyds_inner_panics_transpose_length() { - let data = Matrix::new(0.0, 5, 8); - let data_incorrect = Matrix::new(0.0, 5 + 1, 8); // Incorrect + let data = Matrix::from_gen(0.0, 5, 8); + let data_incorrect = Matrix::from_gen(0.0, 5 + 1, 8); // Incorrect let square_norms = vec![0.0; data.nrows()]; - let mut centers = Matrix::new(0.0, 2, 8); + let mut centers = Matrix::from_gen(0.0, 2, 8); lloyds_inner( data.as_view().into(), &square_norms, @@ -854,10 +854,10 @@ mod tests { #[test] #[should_panic(expected = "data and transpose should have the same dimensions")] fn lloyds_inner_panics_transpose_dim() { - let data = Matrix::new(0.0, 5, 8); - let data_incorrect = Matrix::new(0.0, 5, 8 + 1); // Incorrect + let data = Matrix::from_gen(0.0, 5, 8); + let data_incorrect = Matrix::from_gen(0.0, 5, 8 + 1); // Incorrect let square_norms = vec![0.0; data.nrows()]; - let mut centers = Matrix::new(0.0, 2, 8); + let mut centers = Matrix::from_gen(0.0, 2, 8); lloyds_inner( data.as_view().into(), &square_norms, @@ -870,9 +870,9 @@ mod tests { #[test] #[should_panic(expected = "data and centers should have the same dimensions")] fn lloyds_inner_panics_centers_dim() { - let data = Matrix::new(0.0, 5, 8); + let data = Matrix::from_gen(0.0, 5, 8); let square_norms = vec![0.0; data.nrows()]; - let mut centers = Matrix::new(0.0, 2, 8 + 1); // Incorrect + let mut centers = Matrix::from_gen(0.0, 2, 8 + 1); // Incorrect lloyds_inner( data.as_view().into(), &square_norms, @@ -889,8 +889,8 @@ mod tests { #[test] #[should_panic(expected = "data and centers must have the same dimension")] fn lloyds_panics_dim_mismatch() { - let data = Matrix::new(0.0, 5, 8); - let mut centers = Matrix::new(0.0, 5, 8 + 1); // Incorrect + let data = Matrix::from_gen(0.0, 5, 8); + let mut centers = Matrix::from_gen(0.0, 5, 8 + 1); // Incorrect lloyds(data.as_view(), centers.as_mut_view(), 1); } } diff --git a/diskann-quantization/src/algorithms/kmeans/plusplus.rs b/diskann-quantization/src/algorithms/kmeans/plusplus.rs index 79abf0e94..868bfb2c2 100644 --- a/diskann-quantization/src/algorithms/kmeans/plusplus.rs +++ b/diskann-quantization/src/algorithms/kmeans/plusplus.rs @@ -7,7 +7,7 @@ use std::{collections::HashSet, fmt}; use diskann_utils::{ strided::StridedView, - views::{MatrixView, MutMatrixView}, + views::{MatrixView, MatrixViewMut}, }; use diskann_wide::{SIMDMulAdd, SIMDPartialOrd, SIMDSelect, SIMDVector}; use rand::{ @@ -379,7 +379,7 @@ impl KMeansPlusPlusError { } pub(crate) fn kmeans_plusplus_into_inner( - mut points: MutMatrixView<'_, f32>, + mut points: MatrixViewMut<'_, f32>, data: StridedView<'_, f32>, transpose: BlockTransposedRef<'_, f32, N>, norms: &[f32], @@ -498,7 +498,7 @@ where } pub fn kmeans_plusplus_into( - centers: MutMatrixView<'_, f32>, + centers: MatrixViewMut<'_, f32>, data: MatrixView<'_, f32>, rng: &mut dyn RngCore, ) -> Result<(), KMeansPlusPlusError> { @@ -581,7 +581,7 @@ mod tests { /// ... /// K-1, K, K+1, K+3 ... N+K-2 /// ``` - fn set_default_values(mut x: MutMatrixView<'_, f32>) { + fn set_default_values(mut x: MatrixViewMut<'_, f32>) { for (i, row) in x.row_iter_mut().enumerate() { for (j, r) in row.iter_mut().enumerate() { *r = (i + j) as f32; @@ -609,14 +609,14 @@ mod tests { dim ); - let mut data = Matrix::::new(0.0, num_points, dim); + let mut data = Matrix::::from_gen(0.0, num_points, dim); set_default_values(data.as_mut_view()); let square_norms: Vec = data.row_iter().map(square_norm).collect(); // The sample points we are computing the distances against. let num_samples = 3; - let mut samples = Matrix::::new(0.0, num_samples, dim); + let mut samples = Matrix::::from_gen(0.0, num_samples, dim); let mut distances = vec![f32::INFINITY; num_points]; let distribution = Uniform::::new(0, (num_points + dim) as u32).unwrap(); let transpose = BlockTransposed::::from_matrix_view(data.as_view()); @@ -725,12 +725,12 @@ mod tests { assert_eq!(values.len(), ndata); values.shuffle(rng); - let mut data = Matrix::new(0.0, ndata, dim); + let mut data = Matrix::from_gen(0.0, ndata, dim); for (r, v) in std::iter::zip(data.row_iter_mut(), values.iter()) { r.fill(*v); } - let mut centers = Matrix::new(f32::INFINITY, ncenters, dim); + let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, dim); kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), rng).unwrap(); // Make sure that each value was selected for a center. @@ -803,12 +803,12 @@ mod tests { assert_eq!(values.len(), ndata); values.shuffle(rng); - let mut data = Matrix::new(0.0, ndata, dim); + let mut data = Matrix::from_gen(0.0, ndata, dim); for (r, v) in std::iter::zip(data.row_iter_mut(), values.iter()) { r.fill(*v); } - let mut centers = Matrix::new(f32::INFINITY, ncenters, dim); + let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, dim); kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), rng).unwrap(); // Make sure that each value was selected for a center. @@ -868,8 +868,8 @@ mod tests { // Failure modes #[test] fn fail_empty_dataset() { - let data = Matrix::new(0.0, 0, 5); - let mut centers = Matrix::new(0.0, 10, data.ncols()); + let data = Matrix::from_gen(0.0, 0, 5); + let mut centers = Matrix::from_gen(0.0, 10, data.ncols()); let mut rng = StdRng::seed_from_u64(0xa9eae150d30845a1); @@ -889,8 +889,8 @@ mod tests { #[test] fn both_empty_is_okay() { - let data = Matrix::new(0.0, 0, 5); - let mut centers = Matrix::new(0.0, 0, data.ncols()); + let data = Matrix::from_gen(0.0, 0, 5); + let mut centers = Matrix::from_gen(0.0, 0, data.ncols()); let mut rng = StdRng::seed_from_u64(0x6f7031afd9b5aa18); let result = kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), &mut rng); assert!( @@ -905,9 +905,9 @@ mod tests { let ncenters = 10; let dim = 5; - let mut data = Matrix::new(0.0, ndata, dim); + let mut data = Matrix::from_gen(0.0, ndata, dim); set_default_values(data.as_mut_view()); - let mut centers = Matrix::new(f32::INFINITY, ncenters, data.ncols()); + let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, data.ncols()); let mut rng = StdRng::seed_from_u64(0xa9eae150d30845a1); @@ -943,12 +943,12 @@ mod tests { assert!(values.len() >= ndata); values.shuffle(&mut rng); - let mut data = Matrix::new(0.0, ndata, dim); + let mut data = Matrix::from_gen(0.0, ndata, dim); for (r, v) in std::iter::zip(data.row_iter_mut(), values.iter()) { r.fill(*v); } - let mut centers = Matrix::new(f32::INFINITY, ncenters, dim); + let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, dim); let result = kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), &mut rng); assert!( result.is_err(), @@ -965,12 +965,12 @@ mod tests { #[test] fn fail_intinity_check() { - let mut data = Matrix::new(0.0, 10, 1); + let mut data = Matrix::from_gen(0.0, 10, 1); set_default_values(data.as_mut_view()); // A very large value that will overflow to infinity when computing the norm. data[(6, 0)] = -3.4028235e38; - let mut centers = Matrix::new(0.0, 2, 1); + let mut centers = Matrix::from_gen(0.0, 2, 1); let mut rng = StdRng::seed_from_u64(0xc0449b2aa4e12f05); @@ -987,12 +987,12 @@ mod tests { #[test] fn fail_nan_check() { - let mut data = Matrix::new(0.0, 10, 1); + let mut data = Matrix::from_gen(0.0, 10, 1); set_default_values(data.as_mut_view()); // A very large value that will overflow to infinity when computing the norm. data[(6, 0)] = f32::NAN; - let mut centers = Matrix::new(0.0, 2, 1); + let mut centers = Matrix::from_gen(0.0, 2, 1); let mut rng = StdRng::seed_from_u64(0x55808c6c728c8473); @@ -1017,7 +1017,7 @@ mod tests { let npoints = 5; let dim = 8; let mut square_distances = vec![0.0; npoints]; - let data = Matrix::new(0.0, npoints, dim); + let data = Matrix::from_gen(0.0, npoints, dim); let norms = vec![0.0; npoints]; let this = vec![0.0; dim + 1]; // Incorrect let this_square_norm = 0.0; @@ -1036,7 +1036,7 @@ mod tests { let npoints = 5; let dim = 8; let mut square_distances = vec![0.0; npoints + 1]; // Incorrect - let data = Matrix::new(0.0, npoints, dim); + let data = Matrix::from_gen(0.0, npoints, dim); let norms = vec![0.0; npoints]; let this = vec![0.0; dim]; let this_square_norm = 0.0; @@ -1055,7 +1055,7 @@ mod tests { let npoints = 5; let dim = 8; let mut square_distances = vec![0.0; npoints]; - let data = Matrix::new(0.0, npoints, dim); + let data = Matrix::from_gen(0.0, npoints, dim); let norms = vec![0.0; npoints + 1]; // Incorrect let this = vec![0.0; dim]; let this_square_norm = 0.0; @@ -1077,8 +1077,8 @@ mod tests { expected = "centers output matrix should have the same dimensionality as the dataset" )] fn kmeans_plusplus_into_panics_dim_mismatch() { - let mut centers = Matrix::new(0.0, 2, 10); - let data = Matrix::new(0.0, 2, 9); + let mut centers = Matrix::from_gen(0.0, 2, 10); + let data = Matrix::from_gen(0.0, 2, 9); kmeans_plusplus_into( centers.as_mut_view(), data.as_view(), diff --git a/diskann-quantization/src/algorithms/transforms/random_rotation.rs b/diskann-quantization/src/algorithms/transforms/random_rotation.rs index dc7794151..5c416d964 100644 --- a/diskann-quantization/src/algorithms/transforms/random_rotation.rs +++ b/diskann-quantization/src/algorithms/transforms/random_rotation.rs @@ -102,7 +102,7 @@ impl RandomRotation { let indices = rand::seq::index::sample(rng, dim, target_dim); let scaling = (dim as f32 / target_dim as f32).sqrt(); - let mut transform = diskann_utils::views::Matrix::new(0.0f32, target_dim, dim); + let mut transform = diskann_utils::views::Matrix::from_gen(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), indices.iter()).for_each(|(ro, ri)| { std::iter::zip(ro.iter_mut(), initial.row(ri).iter()).for_each(|(o, i)| { *o = scaling * (*i); @@ -111,7 +111,7 @@ impl RandomRotation { transform } std::cmp::Ordering::Greater => { - let mut transform = diskann_utils::views::Matrix::new(0.0f32, target_dim, dim); + let mut transform = diskann_utils::views::Matrix::from_gen(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), initial.row_iter()) .for_each(|(o, i)| o.copy_from_slice(&i[..dim])); transform diff --git a/diskann-quantization/src/binary/quantizer.rs b/diskann-quantization/src/binary/quantizer.rs index 566c0f282..eb64ca489 100644 --- a/diskann-quantization/src/binary/quantizer.rs +++ b/diskann-quantization/src/binary/quantizer.rs @@ -137,7 +137,7 @@ mod tests { fn test_compression_impl(len: usize, rng: &mut StdRng) { let mut domain = [-10, -1, 0, 1, 10]; - let mut test_pattern = Matrix::::new(0, domain.len(), len); + let mut test_pattern = Matrix::::from_gen(0, domain.len(), len); // Fill the test patterns randomly. for col in 0..len { diff --git a/diskann-quantization/src/minmax/multi/max_sim.rs b/diskann-quantization/src/minmax/multi/max_sim.rs index 5bc0aa406..5832b9b4d 100644 --- a/diskann-quantization/src/minmax/multi/max_sim.rs +++ b/diskann-quantization/src/minmax/multi/max_sim.rs @@ -144,7 +144,7 @@ mod tests { use crate::algorithms::transforms::NullTransform; use crate::bits::{Representation, Unsigned}; use crate::minmax::{Data, MinMaxQuantizer}; - use crate::multi_vector::{Defaulted, Mat, Standard}; + use crate::multi_vector::{Defaulted, Mat, RowMajor}; use crate::num::Positive; use diskann_utils::ReborrowMut; use std::num::NonZeroUsize; @@ -202,7 +202,7 @@ mod tests { where Unsigned: Representation, { - let input_mat = MatRef::new(Standard::::new(n, dim).unwrap(), input).unwrap(); + let input_mat = MatRef::new(RowMajor::::new(n, dim).unwrap(), input).unwrap(); let mut output: Mat> = Mat::new(MinMaxMeta::new(n, dim), Defaulted).unwrap(); quantizer diff --git a/diskann-quantization/src/minmax/multi/meta.rs b/diskann-quantization/src/minmax/multi/meta.rs index 678cbd529..733367c1d 100644 --- a/diskann-quantization/src/minmax/multi/meta.rs +++ b/diskann-quantization/src/minmax/multi/meta.rs @@ -13,7 +13,7 @@ use crate::minmax::{self, Data}; use crate::multi_vector::matrix::{ Defaulted, NewMut, NewOwned, NewRef, Repr, ReprMut, ReprOwned, SliceError, }; -use crate::multi_vector::{LayoutError, Mat, MatMut, MatRef, Standard}; +use crate::multi_vector::{LayoutError, Mat, MatMut, MatRef, RowMajor}; use crate::scalar::InputContainsNaN; use crate::utils; @@ -231,7 +231,7 @@ where ////////////////// impl<'a, 'b, const NBITS: usize, T> - CompressInto>, MatMut<'b, MinMaxMeta>> for MinMaxQuantizer + CompressInto>, MatMut<'b, MinMaxMeta>> for MinMaxQuantizer where T: Copy + Into, Unsigned: Representation, @@ -257,7 +257,7 @@ where /// * The output intrinsic dimension doesn't match `self.output_dim()`. fn compress_into( &self, - from: MatRef<'a, Standard>, + from: MatRef<'a, RowMajor>, mut to: MatMut<'b, MinMaxMeta>, ) -> Result<(), Self::Error> { assert_eq!( @@ -532,7 +532,7 @@ mod tests { // Multi-vector compression let input_view = - MatRef::new(Standard::new(num_vectors, dim).unwrap(), &input_data) + MatRef::new(RowMajor::new(num_vectors, dim).unwrap(), &input_data) .expect("input view creation"); let mut multi_mat: Mat> = @@ -587,7 +587,7 @@ mod tests { let quantizer = make_quantizer(dim); let input_data = generate_test_data(num_vectors, dim); - let input_view = MatRef::new(Standard::new(num_vectors, dim).unwrap(), &input_data) + let input_view = MatRef::new(RowMajor::new(num_vectors, dim).unwrap(), &input_data) .expect("input view"); let mut mat: Mat> = @@ -627,7 +627,7 @@ mod tests { // Input has 3 vectors let input_data = generate_test_data(3, dim); let input_view = - MatRef::new(Standard::new(3, dim).unwrap(), &input_data).expect("input view"); + MatRef::new(RowMajor::new(3, dim).unwrap(), &input_data).expect("input view"); // Output has 2 vectors (mismatch) let mut mat: Mat> = @@ -645,7 +645,7 @@ mod tests { // Input has dim=8 (mismatch) let input_data = generate_test_data(2, 8); let input_view = - MatRef::new(Standard::new(2, 8).unwrap(), &input_data).expect("input view"); + MatRef::new(RowMajor::new(2, 8).unwrap(), &input_data).expect("input view"); // Output correctly has dim=4 let mut mat: Mat> = @@ -665,7 +665,7 @@ mod tests { // Input correctly has dim=4 let input_data = generate_test_data(2, 4); let input_view = - MatRef::new(Standard::new(2, 4).unwrap(), &input_data).expect("input view"); + MatRef::new(RowMajor::new(2, 4).unwrap(), &input_data).expect("input view"); // Output has intrinsic_dim=8 (mismatch) let row_bytes = Data::::canonical_bytes(8); diff --git a/diskann-quantization/src/minmax/multi/mod.rs b/diskann-quantization/src/minmax/multi/mod.rs index 0fb4e57e6..7edce3740 100644 --- a/diskann-quantization/src/minmax/multi/mod.rs +++ b/diskann-quantization/src/minmax/multi/mod.rs @@ -20,7 +20,7 @@ //! minmax::{MinMaxMeta, MinMaxQuantizer}, //! multi_vector::{ //! distance::{Chamfer, MaxSim, QueryMatRef}, -//! Defaulted, Mat, MatRef, Standard, +//! Defaulted, Mat, MatRef, RowMajor, //! }, //! num::Positive, //! CompressInto, @@ -45,7 +45,7 @@ //! 0.0, 1.0, 0.0, 0.0, // query vector 1 //! ]; //! let query_input = MatRef::new( -//! Standard::new(num_query_vectors, dim).unwrap(), &query_data +//! RowMajor::new(num_query_vectors, dim).unwrap(), &query_data //! ).unwrap(); //! //! // Full-precision document multi-vector (3 vectors × 4 dimensions) @@ -55,7 +55,7 @@ //! 0.0, 0.0, 1.0, 0.0, // doc vector 2 //! ]; //! let doc_input = MatRef::new( -//! Standard::new(num_doc_vectors, dim).unwrap(), &doc_data +//! RowMajor::new(num_doc_vectors, dim).unwrap(), &doc_data //! ).unwrap(); //! //! // Create owned matrices for quantized output using Mat::new diff --git a/diskann-quantization/src/multi_vector/block_transposed.rs b/diskann-quantization/src/multi_vector/block_transposed.rs index 6fe9a1315..3efb5ddad 100644 --- a/diskann-quantization/src/multi_vector/block_transposed.rs +++ b/diskann-quantization/src/multi_vector/block_transposed.rs @@ -82,7 +82,7 @@ use std::{alloc::Layout, marker::PhantomData, ptr::NonNull}; use diskann_utils::{ Reborrow, ReborrowMut, strided::StridedView, - views::{MatrixView, MutMatrixView}, + views::{MatrixView, MatrixViewMut}, }; use super::matrix::{ @@ -578,30 +578,24 @@ unsafe impl ReprOwned // ════════════════════════════════════════════════════════════════════ // SAFETY: The returned `Mat` contains a `Box` with exactly `self.storage_len()` elements. -unsafe impl NewOwned +// +// Only `NewOwned` is provided (no generic `NewOwned` value-fill): `Defaulted` +// now lives in `diskann-utils`, so a value-fill impl would overlap with this one under the +// intercrate coherence rules (the compiler cannot prove `Defaulted: !Default` for a foreign +// type). Block-transposed matrices are only ever default-initialized. +unsafe impl NewOwned for BlockTransposedRepr { type Error = crate::error::Infallible; - fn new_owned(self, value: T) -> Result, Self::Error> { - let b: Box<[T]> = vec![value; self.storage_len()].into_boxed_slice(); + fn new_owned(self, _: Defaulted) -> Result, Self::Error> { + let b: Box<[T]> = vec![T::default(); self.storage_len()].into_boxed_slice(); // SAFETY: By construction, `b.len() == self.storage_len()`. Ok(unsafe { self.box_to_mat(b) }) } } -// SAFETY: This safely re-uses `>`. -unsafe impl NewOwned - for BlockTransposedRepr -{ - type Error = crate::error::Infallible; - - fn new_owned(self, _: Defaulted) -> Result, Self::Error> { - self.new_owned(T::default()) - } -} - // SAFETY: This checks slice length against storage_len. unsafe impl NewRef for BlockTransposedRepr @@ -944,12 +938,12 @@ impl<'a, T: Copy, const GROUP: usize, const PACK: usize> BlockTransposedMut<'a, /// /// Panics if `block >= self.full_blocks()`. #[allow(clippy::expect_used)] - pub fn block_mut(&mut self, block: usize) -> MutMatrixView<'_, T> { + pub fn block_mut(&mut self, block: usize) -> MatrixViewMut<'_, T> { self.reborrow_mut().block_mut_inner(block) } #[allow(clippy::expect_used)] - fn block_mut_inner(mut self, block: usize) -> MutMatrixView<'a, T> { + fn block_mut_inner(mut self, block: usize) -> MatrixViewMut<'a, T> { let repr = *self.data.repr(); assert!(block < repr.full_blocks()); let offset = repr.block_offset(block); @@ -962,19 +956,19 @@ impl<'a, T: Copy, const GROUP: usize, const PACK: usize> BlockTransposedMut<'a, stride, ) }; - MutMatrixView::try_from(data, pncols / PACK, GROUP * PACK) + MatrixViewMut::try_from(data, pncols / PACK, GROUP * PACK) .expect("base data should have been sized correctly") } /// Return a mutable view over the remainder block, or `None` if there is no /// remainder. #[allow(clippy::expect_used)] - pub fn remainder_block_mut(&mut self) -> Option> { + pub fn remainder_block_mut(&mut self) -> Option> { self.reborrow_mut().remainder_block_mut_inner() } #[allow(clippy::expect_used)] - fn remainder_block_mut_inner(mut self) -> Option> { + fn remainder_block_mut_inner(mut self) -> Option> { let repr = *self.data.repr(); if repr.remainder() == 0 { None @@ -990,7 +984,7 @@ impl<'a, T: Copy, const GROUP: usize, const PACK: usize> BlockTransposedMut<'a, ) }; Some( - MutMatrixView::try_from(data, pncols / PACK, GROUP * PACK) + MatrixViewMut::try_from(data, pncols / PACK, GROUP * PACK) .expect("base data should have been sized correctly"), ) } @@ -1075,13 +1069,13 @@ impl BlockTransposed MutMatrixView<'_, T> { + pub fn block_mut(&mut self, block: usize) -> MatrixViewMut<'_, T> { self.as_view_mut().block_mut_inner(block) } /// See [`BlockTransposedMut::remainder_block_mut`]. #[allow(clippy::expect_used)] - pub fn remainder_block_mut(&mut self) -> Option> { + pub fn remainder_block_mut(&mut self) -> Option> { self.as_view_mut().remainder_block_mut_inner() } @@ -1288,7 +1282,7 @@ mod tests { // ── Construction ───────────────────────────────────────── - let mut data = Matrix::new(T::default(), nrows, ncols); + let mut data = Matrix::from_gen(T::default(), nrows, ncols); data.as_mut_slice() .iter_mut() .enumerate() @@ -1844,7 +1838,7 @@ mod tests { ncols: usize, gen_element: fn(usize) -> T, ) { - let mut data = Matrix::new(T::default(), nrows, ncols); + let mut data = Matrix::from_gen(T::default(), nrows, ncols); data.as_mut_slice() .iter_mut() .enumerate() diff --git a/diskann-quantization/src/multi_vector/distance/factory.rs b/diskann-quantization/src/multi_vector/distance/factory.rs index 5dcd4b8cd..e05016b17 100644 --- a/diskann-quantization/src/multi_vector/distance/factory.rs +++ b/diskann-quantization/src/multi_vector/distance/factory.rs @@ -20,7 +20,7 @@ use super::kernels::f16::F16Entry; use super::kernels::f32::F32Kernel; use super::max_sim::{MaxSim, MaxSimError}; use crate::multi_vector::distance::QueryMatRef; -use crate::multi_vector::{BlockTransposed, BlockTransposedRef, Mat, MatRef, Standard}; +use crate::multi_vector::{BlockTransposed, BlockTransposedRef, Mat, MatRef, RowMajor}; // ───────────────────────────────────────────────────────────────────────── // Prepared — concrete kernel for the arch-dispatched paths. @@ -39,7 +39,7 @@ where A, (), BlockTransposedRef<'a, f32, GROUP>, - MatRef<'a, Standard>, + MatRef<'a, RowMajor>, &'a mut [f32], >, { @@ -49,7 +49,7 @@ where fn compute_max_sim( &self, - doc: MatRef<'_, Standard>, + doc: MatRef<'_, RowMajor>, scores: &mut [f32], ) -> Result<(), MaxSimError> { if scores.len() != self.nrows() { @@ -81,7 +81,7 @@ where A, (), BlockTransposedRef<'a, half::f16, GROUP>, - MatRef<'a, Standard>, + MatRef<'a, RowMajor>, &'a mut [f32], >, { @@ -91,7 +91,7 @@ where fn compute_max_sim( &self, - doc: MatRef<'_, Standard>, + doc: MatRef<'_, RowMajor>, scores: &mut [f32], ) -> Result<(), MaxSimError> { if scores.len() != self.nrows() { @@ -120,7 +120,7 @@ where // ───────────────────────────────────────────────────────────────────────── struct ReferenceKernel { - query: Mat>, + query: Mat>, } impl std::fmt::Debug for ReferenceKernel { @@ -132,7 +132,7 @@ impl std::fmt::Debug for ReferenceKernel { } impl ReferenceKernel { - fn new(query: MatRef<'_, Standard>) -> Self { + fn new(query: MatRef<'_, RowMajor>) -> Self { Self { query: query.to_owned(), } @@ -150,7 +150,7 @@ where fn compute_max_sim( &self, - doc: MatRef<'_, Standard>, + doc: MatRef<'_, RowMajor>, scores: &mut [f32], ) -> Result<(), MaxSimError> { if scores.len() != self.nrows() { @@ -160,7 +160,7 @@ where scores.fill(f32::MAX); return Ok(()); } - let query: QueryMatRef<'_, Standard> = self.query.as_view().into(); + let query: QueryMatRef<'_, RowMajor> = self.query.as_view().into(); let mut max_sim = MaxSim::new(scores); max_sim.evaluate(query, doc) } @@ -174,30 +174,30 @@ struct BuildAndErase(E); // ───── f32 Target1 impls ───── -impl> diskann_wide::arch::Target1>> +impl> diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: Scalar, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: Scalar, query: MatRef<'_, RowMajor>) -> E::Output { let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); self.0.erase(Prepared { arch, prepared }) } } #[cfg(target_arch = "x86_64")] -impl> diskann_wide::arch::Target1>> +impl> diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: V3, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: V3, query: MatRef<'_, RowMajor>) -> E::Output { let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); self.0.erase(Prepared { arch, prepared }) } } #[cfg(target_arch = "x86_64")] -impl> diskann_wide::arch::Target1>> +impl> diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: V4, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: V4, query: MatRef<'_, RowMajor>) -> E::Output { // V4 dispatches to V3 (no V4-specific kernel). let arch = arch.retarget(); let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); @@ -206,10 +206,10 @@ impl> diskann_wide::arch::Target1> diskann_wide::arch::Target1>> +impl> diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: Neon, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: Neon, query: MatRef<'_, RowMajor>) -> E::Output { // Neon dispatches to Scalar (no Neon-specific kernel). let arch = arch.retarget(); let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); @@ -220,10 +220,10 @@ impl> diskann_wide::arch::Target1> - diskann_wide::arch::Target1>> + diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: Scalar, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: Scalar, query: MatRef<'_, RowMajor>) -> E::Output { let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); self.0.erase(Prepared { arch, prepared }) } @@ -231,10 +231,10 @@ impl> #[cfg(target_arch = "x86_64")] impl> - diskann_wide::arch::Target1>> + diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: V3, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: V3, query: MatRef<'_, RowMajor>) -> E::Output { let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); self.0.erase(Prepared { arch, prepared }) } @@ -242,10 +242,10 @@ impl> #[cfg(target_arch = "x86_64")] impl> - diskann_wide::arch::Target1>> + diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: V4, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: V4, query: MatRef<'_, RowMajor>) -> E::Output { // V4 dispatches to V3 (no V4-specific kernel). let arch = arch.retarget(); let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); @@ -255,10 +255,10 @@ impl> #[cfg(target_arch = "aarch64")] impl> - diskann_wide::arch::Target1>> + diskann_wide::arch::Target1>> for BuildAndErase { - fn run(self, arch: Neon, query: MatRef<'_, Standard>) -> E::Output { + fn run(self, arch: Neon, query: MatRef<'_, RowMajor>) -> E::Output { // Neon dispatches to Scalar (no Neon-specific kernel). let arch = arch.retarget(); let prepared = BlockTransposed::::from_matrix_view(query.as_matrix_view()); @@ -278,7 +278,7 @@ mod sealed { /// /// Sealed: external crates cannot add impls. Quantized representations /// (PQ, SQ, packed sub-byte) are intentionally excluded — they need -/// codebook/scale state that [`MatRef<'_, Standard>`] can't carry. +/// codebook/scale state that [`MatRef<'_, RowMajor>`] can't carry. pub trait MaxSimElement: sealed::Sealed + Sized + Copy + Send + Sync + 'static { /// Build the concrete kernel for this element type and hand it to /// `erase.erase(...)`. @@ -289,7 +289,7 @@ pub trait MaxSimElement: sealed::Sealed + Sized + Copy + Send + Sync + 'static { /// build (e.g. AVX-512 unavailable; aarch64 on x86_64). fn build>( isa: MaxSimIsa, - query: MatRef<'_, Standard>, + query: MatRef<'_, RowMajor>, erase: E, ) -> Result; } @@ -300,7 +300,7 @@ impl sealed::Sealed for half::f16 {} impl MaxSimElement for f32 { fn build>( isa: MaxSimIsa, - query: MatRef<'_, Standard>, + query: MatRef<'_, RowMajor>, erase: E, ) -> Result { match isa { @@ -351,7 +351,7 @@ impl MaxSimElement for f32 { impl MaxSimElement for half::f16 { fn build>( isa: MaxSimIsa, - query: MatRef<'_, Standard>, + query: MatRef<'_, RowMajor>, erase: E, ) -> Result { match isa { @@ -413,7 +413,7 @@ impl MaxSimElement for half::f16 { /// Returns [`NotSupported`] when the requested ISA cannot run on this build. pub fn build_max_sim>( isa: MaxSimIsa, - query: MatRef<'_, Standard>, + query: MatRef<'_, RowMajor>, erase: E, ) -> Result { T::build(isa, query, erase) @@ -443,8 +443,8 @@ mod tests { } } - fn make_mat(data: &[T], nrows: usize, ncols: usize) -> MatRef<'_, Standard> { - MatRef::new(Standard::new(nrows, ncols).unwrap(), data).unwrap() + fn make_mat(data: &[T], nrows: usize, ncols: usize) -> MatRef<'_, RowMajor> { + MatRef::new(RowMajor::new(nrows, ncols).unwrap(), data).unwrap() } fn make_test_data(len: usize, ceil: usize, shift: usize) -> Vec { diff --git a/diskann-quantization/src/multi_vector/distance/fallback.rs b/diskann-quantization/src/multi_vector/distance/fallback.rs index ed8da7a3e..22fa460e4 100644 --- a/diskann-quantization/src/multi_vector/distance/fallback.rs +++ b/diskann-quantization/src/multi_vector/distance/fallback.rs @@ -10,7 +10,7 @@ use diskann_vector::{DistanceFunctionMut, PureDistanceFunction}; use super::max_sim::{Chamfer, MaxSim}; use super::projected_eigen::ProjectedEigen; -use crate::multi_vector::{MatRef, MaxSimError, Repr, Standard}; +use crate::multi_vector::{MatRef, MaxSimError, Repr, RowMajor}; ///////////////// // QueryMatRef // @@ -25,11 +25,11 @@ use crate::multi_vector::{MatRef, MaxSimError, Repr, Standard}; /// # Example /// /// ``` -/// use diskann_quantization::multi_vector::{MatRef, Standard}; +/// use diskann_quantization::multi_vector::{MatRef, RowMajor}; /// use diskann_quantization::multi_vector::distance::QueryMatRef; /// /// let data = [1.0f32, 2.0, 3.0, 4.0]; -/// let view = MatRef::new(Standard::new(2, 2).unwrap(), &data).unwrap(); +/// let view = MatRef::new(RowMajor::new(2, 2).unwrap(), &data).unwrap(); /// let query: QueryMatRef<_> = view.into(); /// ``` #[derive(Debug, Clone, Copy)] @@ -77,8 +77,8 @@ impl FallbackKernel { /// * `f` - Callback invoked with `(query_index, similarity)` for each query vector #[inline] pub(crate) fn max_sim_kernel( - query: QueryMatRef<'_, Standard>, - doc: MatRef<'_, Standard>, + query: QueryMatRef<'_, RowMajor>, + doc: MatRef<'_, RowMajor>, mut f: F, ) where F: FnMut(usize, f32), @@ -119,8 +119,8 @@ impl FallbackKernel { /// * `f` - Callback invoked with `(query_index, score)` for each query vector #[inline] pub(crate) fn projected_eigen_kernel( - query: QueryMatRef<'_, Standard>, - doc: MatRef<'_, Standard>, + query: QueryMatRef<'_, RowMajor>, + doc: MatRef<'_, RowMajor>, mut f: F, ) where F: FnMut(usize, f32), @@ -153,8 +153,8 @@ impl FallbackKernel { impl DistanceFunctionMut< - QueryMatRef<'_, Standard>, - MatRef<'_, Standard>, + QueryMatRef<'_, RowMajor>, + MatRef<'_, RowMajor>, Result<(), MaxSimError>, > for MaxSim<'_> where @@ -163,8 +163,8 @@ where #[inline(always)] fn evaluate( &mut self, - query: QueryMatRef<'_, Standard>, - doc: MatRef<'_, Standard>, + query: QueryMatRef<'_, RowMajor>, + doc: MatRef<'_, RowMajor>, ) -> Result<(), MaxSimError> { let size = self.size(); let n_queries = query.num_vectors(); @@ -187,13 +187,13 @@ where // Chamfer // ///////////// -impl PureDistanceFunction>, MatRef<'_, Standard>, f32> +impl PureDistanceFunction>, MatRef<'_, RowMajor>, f32> for Chamfer where InnerProduct: for<'a, 'b> PureDistanceFunction<&'a [T], &'b [T], f32>, { #[inline(always)] - fn evaluate(query: QueryMatRef<'_, Standard>, doc: MatRef<'_, Standard>) -> f32 { + fn evaluate(query: QueryMatRef<'_, RowMajor>, doc: MatRef<'_, RowMajor>) -> f32 { let mut sum = 0.0f32; FallbackKernel::max_sim_kernel(query, doc, |_i, score| { @@ -208,13 +208,13 @@ where // ProjectedEigen // ///////////////////// -impl PureDistanceFunction>, MatRef<'_, Standard>, f32> +impl PureDistanceFunction>, MatRef<'_, RowMajor>, f32> for ProjectedEigen where InnerProduct: for<'a, 'b> PureDistanceFunction<&'a [T], &'b [T], f32>, { #[inline(always)] - fn evaluate(query: QueryMatRef<'_, Standard>, doc: MatRef<'_, Standard>) -> f32 { + fn evaluate(query: QueryMatRef<'_, RowMajor>, doc: MatRef<'_, RowMajor>) -> f32 { let mut sum = 0.0f32; FallbackKernel::projected_eigen_kernel(query, doc, |_i, score| { @@ -230,19 +230,19 @@ mod tests { use super::*; /// Helper to create a QueryMatRef from raw data - fn make_query(data: &[f32], nrows: usize, ncols: usize) -> QueryMatRef<'_, Standard> { - MatRef::new(Standard::new(nrows, ncols).unwrap(), data) + fn make_query(data: &[f32], nrows: usize, ncols: usize) -> QueryMatRef<'_, RowMajor> { + MatRef::new(RowMajor::new(nrows, ncols).unwrap(), data) .unwrap() .into() } /// Helper to create a MatRef from raw data - fn make_doc(data: &[f32], nrows: usize, ncols: usize) -> MatRef<'_, Standard> { - MatRef::new(Standard::new(nrows, ncols).unwrap(), data).unwrap() + fn make_doc(data: &[f32], nrows: usize, ncols: usize) -> MatRef<'_, RowMajor> { + MatRef::new(RowMajor::new(nrows, ncols).unwrap(), data).unwrap() } /// Naive implementation of max-sim for a single query vector against all doc vectors. - fn naive_max_sim_single(query_vec: &[f32], doc: &MatRef<'_, Standard>) -> f32 { + fn naive_max_sim_single(query_vec: &[f32], doc: &MatRef<'_, RowMajor>) -> f32 { doc.rows() .map(|d_vec| { let ip: f32 = query_vec.iter().zip(d_vec.iter()).map(|(a, b)| a * b).sum(); @@ -253,7 +253,7 @@ mod tests { /// Naive implementation of projected-eigen for a single query vector /// against all doc vectors: `\sum_{j} -IP(q, d_{j})^2`. - fn naive_projected_eigen_single(query_vec: &[f32], doc: &MatRef<'_, Standard>) -> f32 { + fn naive_projected_eigen_single(query_vec: &[f32], doc: &MatRef<'_, RowMajor>) -> f32 { doc.rows() .map(|d_vec| { let ip: f32 = query_vec.iter().zip(d_vec.iter()).map(|(a, b)| a * b).sum(); @@ -273,7 +273,7 @@ mod tests { #[test] fn from_mat_ref_and_deref() { let data = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; - let view = MatRef::new(Standard::new(2, 3).unwrap(), &data).unwrap(); + let view = MatRef::new(RowMajor::new(2, 3).unwrap(), &data).unwrap(); let query: QueryMatRef<_> = view.into(); // Deref access works diff --git a/diskann-quantization/src/multi_vector/distance/kernel.rs b/diskann-quantization/src/multi_vector/distance/kernel.rs index b292def54..f663b115e 100644 --- a/diskann-quantization/src/multi_vector/distance/kernel.rs +++ b/diskann-quantization/src/multi_vector/distance/kernel.rs @@ -3,7 +3,7 @@ //! Object-safe kernel boundary trait plus BYOTE visitor trait. -use crate::multi_vector::{MatRef, MaxSimError, Standard}; +use crate::multi_vector::{MatRef, MaxSimError, RowMajor}; /// Object-safe interface for computing per-query MaxSim scores. pub trait MaxSimKernel: Send + Sync + std::fmt::Debug { @@ -18,7 +18,7 @@ pub trait MaxSimKernel: Send + Sync + std::fmt::Debug { /// [`MaxSimError::InvalidBufferLength`] if `scores.len() != self.nrows()`. fn compute_max_sim( &self, - doc: MatRef<'_, Standard>, + doc: MatRef<'_, RowMajor>, scores: &mut [f32], ) -> Result<(), MaxSimError>; } diff --git a/diskann-quantization/src/multi_vector/distance/kernels/f16.rs b/diskann-quantization/src/multi_vector/distance/kernels/f16.rs index a535c68dc..ccbe652c3 100644 --- a/diskann-quantization/src/multi_vector/distance/kernels/f16.rs +++ b/diskann-quantization/src/multi_vector/distance/kernels/f16.rs @@ -19,7 +19,7 @@ use super::Kernel; use super::TileBudget; use super::f32::{F32Kernel, max_ip_kernel}; use super::layouts; -use crate::multi_vector::{BlockTransposedRef, MatRef, Standard}; +use crate::multi_vector::{BlockTransposedRef, MatRef, RowMajor}; pub(crate) struct F16Entry; @@ -28,7 +28,7 @@ impl A, (), BlockTransposedRef<'_, half::f16, GROUP>, - MatRef<'_, Standard>, + MatRef<'_, RowMajor>, &mut [f32], > for F16Entry where @@ -44,7 +44,7 @@ where self, arch: A, lhs: BlockTransposedRef<'_, half::f16, GROUP>, - rhs: MatRef<'_, Standard>, + rhs: MatRef<'_, RowMajor>, scratch: &mut [f32], ) { max_ip_kernel(arch, lhs, rhs, scratch, TileBudget::default()); diff --git a/diskann-quantization/src/multi_vector/distance/kernels/f32/mod.rs b/diskann-quantization/src/multi_vector/distance/kernels/f32/mod.rs index a900ea356..07051e11a 100644 --- a/diskann-quantization/src/multi_vector/distance/kernels/f32/mod.rs +++ b/diskann-quantization/src/multi_vector/distance/kernels/f32/mod.rs @@ -23,7 +23,7 @@ use super::Kernel; use super::TileBudget; use super::layouts::{self, DescribeLayout}; use super::tiled_reduce::tiled_reduce; -use crate::multi_vector::{BlockTransposedRef, MatRef, Standard}; +use crate::multi_vector::{BlockTransposedRef, MatRef, RowMajor}; mod scalar; #[cfg(target_arch = "x86_64")] @@ -61,7 +61,7 @@ fn max_ip_kernel_panic(scratch_len: usize, padded_nrows: usize, a_ncols: usize, pub(super) fn max_ip_kernel( arch: A, a: BlockTransposedRef<'_, T, GROUP>, - b: MatRef<'_, Standard>, + b: MatRef<'_, RowMajor>, scratch: &mut [f32], budget: TileBudget, ) where @@ -86,7 +86,7 @@ pub(super) fn max_ip_kernel( // SAFETY: // - a.as_ptr() is valid for a.padded_nrows() * k elements of T. - // - MatRef> stores nrows * ncols contiguous T elements. + // - MatRef> stores nrows * ncols contiguous T elements. // - scratch.len() == a.padded_nrows() (checked above). // - a.padded_nrows() is always a multiple of GROUP, and the const assert above // verifies A_PANEL == GROUP at compile time. @@ -111,7 +111,7 @@ impl A, (), BlockTransposedRef<'_, f32, GROUP>, - MatRef<'_, Standard>, + MatRef<'_, RowMajor>, &mut [f32], > for F32Kernel where @@ -127,7 +127,7 @@ where self, arch: A, lhs: BlockTransposedRef<'_, f32, GROUP>, - rhs: MatRef<'_, Standard>, + rhs: MatRef<'_, RowMajor>, scratch: &mut [f32], ) { max_ip_kernel(arch, lhs, rhs, scratch, TileBudget::default()); diff --git a/diskann-quantization/src/multi_vector/distance/kernels/layouts.rs b/diskann-quantization/src/multi_vector/distance/kernels/layouts.rs index e1ec8dd36..e0306fcbb 100644 --- a/diskann-quantization/src/multi_vector/distance/kernels/layouts.rs +++ b/diskann-quantization/src/multi_vector/distance/kernels/layouts.rs @@ -45,7 +45,7 @@ impl Layout for BlockTransposed< type Element = T; } -/// Dense row-major tile layout. Matches [`MatRef>`](crate::multi_vector::MatRef). +/// Dense row-major tile layout. Matches [`MatRef>`](crate::multi_vector::MatRef). pub(super) struct RowMajor(PhantomData); impl RowMajor { @@ -86,7 +86,7 @@ impl DescribeLayout } } -impl DescribeLayout for crate::multi_vector::MatRef<'_, crate::multi_vector::Standard> { +impl DescribeLayout for crate::multi_vector::MatRef<'_, crate::multi_vector::RowMajor> { type Layout = RowMajor; fn layout(&self) -> Self::Layout { diff --git a/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs b/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs index 6e4b76e9c..e7d3ebf07 100644 --- a/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs +++ b/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs @@ -246,7 +246,7 @@ mod tests { use super::super::f32::{F32Kernel, max_ip_kernel}; use super::super::layouts; - use crate::multi_vector::{BlockTransposed, MatRef, Standard}; + use crate::multi_vector::{BlockTransposed, MatRef, RowMajor}; #[test] fn basic_panel_counts() { @@ -521,9 +521,9 @@ mod tests { layouts::RowMajor: ConvertTo as Kernel>::Right> + Layout, { - let a_mat = MatRef::new(Standard::new(a_nrows, dim).unwrap(), a_data).unwrap(); + let a_mat = MatRef::new(RowMajor::new(a_nrows, dim).unwrap(), a_data).unwrap(); let a_bt = BlockTransposed::::from_matrix_view(a_mat.as_matrix_view()); - let b_mat = MatRef::new(Standard::new(b_nrows, dim).unwrap(), b_data).unwrap(); + let b_mat = MatRef::new(RowMajor::new(b_nrows, dim).unwrap(), b_data).unwrap(); let mut scratch = vec![f32::MIN; a_bt.padded_nrows()]; max_ip_kernel::( @@ -741,9 +741,9 @@ mod tests { let b_data = gen_data(b_nrows * dim, ceil); let expected = naive(&a_data, a_nrows, &b_data, b_nrows, dim); - let a_mat = MatRef::new(Standard::new(a_nrows, dim).unwrap(), &a_data).unwrap(); + let a_mat = MatRef::new(RowMajor::new(a_nrows, dim).unwrap(), &a_data).unwrap(); let a_bt = BlockTransposed::::from_matrix_view(a_mat.as_matrix_view()); - let b_mat = MatRef::new(Standard::new(b_nrows, dim).unwrap(), &b_data).unwrap(); + let b_mat = MatRef::new(RowMajor::new(b_nrows, dim).unwrap(), &b_data).unwrap(); let mut scratch = vec![f32::MIN; a_bt.padded_nrows()]; max_ip_kernel::(arch, a_bt.as_view(), b_mat, &mut scratch, budget); diff --git a/diskann-quantization/src/multi_vector/distance/max_sim.rs b/diskann-quantization/src/multi_vector/distance/max_sim.rs index d9a4fb541..92715a4dd 100644 --- a/diskann-quantization/src/multi_vector/distance/max_sim.rs +++ b/diskann-quantization/src/multi_vector/distance/max_sim.rs @@ -28,7 +28,7 @@ pub enum MaxSimError { /// ``` /// /// Implements `DistanceFnMut` for various matrix types -/// (e.g., [`MatRef>`](crate::multi_vector::MatRef)). +/// (e.g., [`MatRef>`](crate::multi_vector::MatRef)). /// /// # Usage /// - Create with [`MaxSim::new`], providing a mutable scores buffer. diff --git a/diskann-quantization/src/multi_vector/distance/mod.rs b/diskann-quantization/src/multi_vector/distance/mod.rs index 178e8cad0..af96642b3 100644 --- a/diskann-quantization/src/multi_vector/distance/mod.rs +++ b/diskann-quantization/src/multi_vector/distance/mod.rs @@ -12,21 +12,21 @@ //! ``` //! use diskann_quantization::multi_vector::{ //! distance::{Chamfer, MaxSim, QueryMatRef}, -//! MatRef, Standard, +//! MatRef, RowMajor, //! }; //! use diskann_vector::{DistanceFunctionMut, PureDistanceFunction}; //! //! // Query: 2 vectors of dim 3 (wrapped as QueryMatRef) //! let query_data = [1.0f32, 0.0, 0.0, 0.0, 1.0, 0.0]; //! let query: QueryMatRef<_> = MatRef::new( -//! Standard::new(2, 3).unwrap(), +//! RowMajor::new(2, 3).unwrap(), //! &query_data, //! ).unwrap().into(); //! //! // Doc: 2 vectors of dim 3 //! let doc_data = [1.0f32, 0.0, 0.0, 0.0, 0.0, 1.0]; //! let doc = MatRef::new( -//! Standard::new(2, 3).unwrap(), +//! RowMajor::new(2, 3).unwrap(), //! &doc_data, //! ).unwrap(); //! diff --git a/diskann-quantization/src/multi_vector/mod.rs b/diskann-quantization/src/multi_vector/mod.rs index 0afe5180e..51f7a3049 100644 --- a/diskann-quantization/src/multi_vector/mod.rs +++ b/diskann-quantization/src/multi_vector/mod.rs @@ -13,13 +13,13 @@ //! ``` //! use diskann_quantization::multi_vector::{ //! distance::QueryMatRef, -//! Chamfer, Mat, MatMut, MatRef, MaxSim, Standard, +//! Chamfer, Mat, MatMut, MatRef, MaxSim, RowMajor, //! }; //! use diskann_utils::ReborrowMut; //! use diskann_vector::{DistanceFunctionMut, PureDistanceFunction}; //! //! // Create an owned matrix (2 vectors, dim 3, initialized to 0.0) -//! let mut owned = Mat::new(Standard::new(2, 3).unwrap(), 0.0f32).unwrap(); +//! let mut owned = Mat::new(RowMajor::new(2, 3).unwrap(), 0.0f32).unwrap(); //! assert_eq!(owned.num_vectors(), 2); //! //! // Modify via mutable view @@ -34,10 +34,10 @@ //! //! // Wrap query as QueryMatRef for type-safe asymmetric distance //! let query: QueryMatRef<_> = MatRef::new( -//! Standard::new(2, 2).unwrap(), +//! RowMajor::new(2, 2).unwrap(), //! &query_data, //! ).unwrap().into(); -//! let doc = MatRef::new(Standard::new(2, 2).unwrap(), &doc_data).unwrap(); +//! let doc = MatRef::new(RowMajor::new(2, 2).unwrap(), &doc_data).unwrap(); //! //! // Chamfer distance (sum of max similarities) //! let distance = Chamfer::evaluate(query, doc); @@ -53,14 +53,14 @@ pub mod block_transposed; pub mod distance; -pub(crate) mod matrix; +pub(crate) use diskann_utils::matrix; pub use block_transposed::{BlockTransposed, BlockTransposedMut, BlockTransposedRef}; pub use distance::{ BoxErase, Chamfer, Erase, MaxSim, MaxSimElement, MaxSimError, MaxSimIsa, MaxSimKernel, NotSupported, ProjectedEigen, QueryMatRef, build_max_sim, }; -pub use matrix::{ +pub use diskann_utils::matrix::{ Defaulted, LayoutError, Mat, MatMut, MatRef, NewCloned, NewMut, NewOwned, NewRef, Overflow, - Repr, ReprMut, ReprOwned, SliceError, Standard, + Repr, ReprMut, ReprOwned, SliceError, RowMajor, }; diff --git a/diskann-quantization/src/product/tables/basic.rs b/diskann-quantization/src/product/tables/basic.rs index 9469fa58d..e22ee04d8 100644 --- a/diskann-quantization/src/product/tables/basic.rs +++ b/diskann-quantization/src/product/tables/basic.rs @@ -5,7 +5,7 @@ use crate::traits::CompressInto; use crate::views::{ChunkOffsetsBase, ChunkOffsetsView}; -use diskann_utils::views::{DenseData, MatrixBase, MatrixView}; +use diskann_utils::views::{DenseData, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use thiserror::Error; @@ -29,7 +29,9 @@ where T: DenseData, U: DenseData, { - pivots: MatrixBase, + pivots: T, + num_pivots: usize, + pivot_dim: usize, offsets: ChunkOffsetsBase, } @@ -62,11 +64,12 @@ where /// # Error /// /// Returns an error if `pivots.ncols() != offsets.dim()` or if `pivots.nrows() == 0`. - pub fn new( - pivots: MatrixBase, + fn from_parts( + pivots: T, + num_pivots: usize, + pivot_dim: usize, offsets: ChunkOffsetsBase, ) -> Result { - let pivot_dim = pivots.ncols(); let offsets_dim = offsets.dim(); if pivot_dim != offsets_dim { @@ -74,16 +77,23 @@ where pivot_dim, offsets_dim, }) - } else if pivots.nrows() == 0 { + } else if num_pivots == 0 { Err(BasicTableError::PivotsEmpty) } else { - Ok(Self { pivots, offsets }) + Ok(Self { + pivots, + num_pivots, + pivot_dim, + offsets, + }) } } /// Return a view over the pivot table. + #[allow(clippy::expect_used)] pub fn view_pivots(&self) -> MatrixView<'_, f32> { - self.pivots.as_view() + MatrixView::try_from(self.pivots.as_slice(), self.num_pivots, self.pivot_dim) + .expect("valid pivot dimensions") } /// Return a view over the schema offsets. @@ -93,7 +103,7 @@ where /// Return the number of pivots in each PQ chunk. pub fn ncenters(&self) -> usize { - self.pivots.nrows() + self.num_pivots } /// Return the number of PQ chunks. @@ -103,7 +113,29 @@ where /// Return the dimensionality of the full-precision vectors associated with this table. pub fn dim(&self) -> usize { - self.pivots.ncols() + self.pivot_dim + } +} + +impl BasicTable { + /// Construct an owned table over `pivots` and `offsets`. + pub fn new( + pivots: Matrix, + offsets: ChunkOffsetsBase>, + ) -> Result { + let (num_pivots, pivot_dim) = (pivots.nrows(), pivots.ncols()); + Self::from_parts(pivots.into_inner(), num_pivots, pivot_dim, offsets) + } +} + +impl<'a> BasicTableView<'a> { + /// Construct a borrowed table over `pivots` and `offsets`. + pub fn new( + pivots: MatrixView<'a, f32>, + offsets: ChunkOffsetsView<'a>, + ) -> Result { + let (num_pivots, pivot_dim) = (pivots.nrows(), pivots.ncols()); + Self::from_parts(pivots.as_slice(), num_pivots, pivot_dim, offsets) } } @@ -169,13 +201,14 @@ where return Err(Self::Error::InvalidOutputDim(self.nchunks(), to.len())); } + let pivots = self.view_pivots(); to.iter_mut().enumerate().try_for_each(|(chunk, to)| { let mut min_distance = f32::INFINITY; let mut min_index = usize::MAX; let range = self.offsets.at(chunk); let slice = &from[range.clone()]; - self.pivots.row_iter().enumerate().for_each(|(index, row)| { + pivots.row_iter().enumerate().for_each(|(index, row)| { let distance: f32 = SquaredL2::evaluate(slice, &row[range.clone()]); if distance < min_distance { min_distance = distance; @@ -219,7 +252,7 @@ mod tests { // disagree. #[test] fn error_on_mismatch_dim() { - let pivots = views::Matrix::new(0.0, 3, 5); + let pivots = views::Matrix::from_gen(0.0, 3, 5); let offsets = crate::views::ChunkOffsets::new(Box::new([0, 1, 6])).unwrap(); let result = BasicTable::new(pivots, offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -232,7 +265,7 @@ mod tests { // Test that the table constructor errors when there are no pivots. #[test] fn error_on_no_pivots() { - let pivots = views::Matrix::new(0.0, 0, 5); + let pivots = views::Matrix::from_gen(0.0, 0, 5); let offsets = crate::views::ChunkOffsets::new(Box::new([0, 1, 2, 5])).unwrap(); let result = BasicTable::new(pivots, offsets); assert!(result.is_err(), "pivots is empty"); @@ -244,7 +277,7 @@ mod tests { let mut rng = rand::rngs::StdRng::seed_from_u64(0xd96bac968083ec29); for dim in [5, 10, 12] { for total in [1, 2, 3] { - let pivots = views::Matrix::new( + let pivots = views::Matrix::from_gen( views::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), total, dim, @@ -322,7 +355,7 @@ mod tests { // Set up `ncenters > 256`. { - let pivots = views::Matrix::new(0.0, 257, dim); + let pivots = views::Matrix::from_gen(0.0, 257, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim]; @@ -341,7 +374,7 @@ mod tests { // Setup input dim not equal to expected. { - let pivots = views::Matrix::new(0.0, 10, dim); + let pivots = views::Matrix::from_gen(0.0, 10, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim - 1]; @@ -360,7 +393,7 @@ mod tests { // Setup output dim not equal to expected. { - let pivots = views::Matrix::new(0.0, 10, dim); + let pivots = views::Matrix::from_gen(0.0, 10, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim]; diff --git a/diskann-quantization/src/product/tables/test.rs b/diskann-quantization/src/product/tables/test.rs index c8faec00c..feb6b3bd9 100644 --- a/diskann-quantization/src/product/tables/test.rs +++ b/diskann-quantization/src/product/tables/test.rs @@ -6,7 +6,7 @@ // A collection of test helpers to ensure uniformity across tables. use diskann_utils::views::Matrix; #[cfg(not(miri))] -use diskann_utils::views::{MatrixView, MutMatrixView}; +use diskann_utils::views::{MatrixView, MatrixViewMut}; #[cfg(not(miri))] use rand::seq::IndexedRandom; use rand::{ @@ -84,7 +84,7 @@ pub(super) fn create_pivot_tables( schema: ChunkOffsets, num_centers: usize, ) -> (Matrix, ChunkOffsets) { - let mut pivots = Matrix::::new(0.0, num_centers, schema.dim()); + let mut pivots = Matrix::::from_gen(0.0, num_centers, schema.dim()); (0..schema.len()).for_each(|chunk| { let range = schema.at(chunk); @@ -126,8 +126,8 @@ pub(super) fn create_dataset( num_data: usize, rng: &mut R, ) -> (Matrix, Matrix) { - let mut data = Matrix::::new(0.0, num_data, schema.dim()); - let mut expected = Matrix::::new(0, num_data, schema.len()); + let mut data = Matrix::::from_gen(0.0, num_data, schema.dim()); + let mut expected = Matrix::::from_gen(0, num_data, schema.len()); let dist = Uniform::new(0, num_centers).unwrap(); for row_index in 0..data.nrows() { @@ -171,7 +171,7 @@ pub(super) fn check_pqtable_single_compression_errors( // Set up `ncenters > 256`. { - let pivots = Matrix::new(0.0, 257, dim); + let pivots = Matrix::from_gen(0.0, 257, dim); let table = build(pivots, offsets.clone()); let input = vec![f32::default(); dim]; @@ -193,7 +193,7 @@ pub(super) fn check_pqtable_single_compression_errors( // Setup input dim not equal to expected. { - let pivots = Matrix::new(0.0, 10, dim); + let pivots = Matrix::from_gen(0.0, 10, dim); let table = build(pivots, offsets.clone()); let input = vec![f32::default(); dim - 1]; @@ -215,7 +215,7 @@ pub(super) fn check_pqtable_single_compression_errors( // Setup output dim not equal to expected. { - let pivots = Matrix::new(0.0, 10, dim); + let pivots = Matrix::from_gen(0.0, 10, dim); let table = build(pivots, offsets.clone()); let input = vec![f32::default(); dim]; @@ -298,7 +298,7 @@ pub(super) fn check_pqtable_batch_compression_errors( build: &dyn Fn(Matrix, ChunkOffsets) -> T, context: &dyn std::fmt::Display, ) where - T: for<'a> CompressInto, MutMatrixView<'a, u8>>, + T: for<'a> CompressInto, MatrixViewMut<'a, u8>>, { let dim = 10; let num_chunks = 3; @@ -308,11 +308,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Set up `ncenters > 256`. { - let pivots = Matrix::new(0.0, 257, dim); + let pivots = Matrix::from_gen(0.0, 257, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::new(f32::default(), batchsize, dim); - let mut output = Matrix::new(u8::MAX, batchsize, num_chunks); + let input = Matrix::from_gen(f32::default(), batchsize, dim); + let mut output = Matrix::from_gen(u8::MAX, batchsize, num_chunks); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); assert_eq!( @@ -330,11 +330,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Setup input dim not equal to expected. { - let pivots = Matrix::new(0.0, 10, dim); + let pivots = Matrix::from_gen(0.0, 10, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::new(f32::default(), batchsize, dim - 1); - let mut output = Matrix::new(u8::MAX, batchsize, num_chunks); + let input = Matrix::from_gen(f32::default(), batchsize, dim - 1); + let mut output = Matrix::from_gen(u8::MAX, batchsize, num_chunks); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); assert_eq!( @@ -352,11 +352,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Setup output dim not equal to expected. { - let pivots = Matrix::new(0.0, 10, dim); + let pivots = Matrix::from_gen(0.0, 10, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::new(f32::default(), batchsize, dim); - let mut output = Matrix::new(u8::MAX, batchsize, num_chunks - 1); + let input = Matrix::from_gen(f32::default(), batchsize, dim); + let mut output = Matrix::from_gen(u8::MAX, batchsize, num_chunks - 1); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); @@ -379,11 +379,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Num rows are different. { - let pivots = Matrix::new(0.0, 10, dim); + let pivots = Matrix::from_gen(0.0, 10, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::new(f32::default(), batchsize, dim); - let mut output = Matrix::new(u8::MAX, batchsize - 1, num_chunks); + let input = Matrix::from_gen(f32::default(), batchsize, dim); + let mut output = Matrix::from_gen(u8::MAX, batchsize - 1, num_chunks); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); @@ -416,10 +416,10 @@ pub(super) fn check_pqtable_batch_compression_errors( let table = build(pivots, o); let num_points = 15; - let mut buf = Matrix::::new(0.0, num_points, offsets.dim()); - let mut output = Matrix::::new(0, num_points, offsets.len()); + let mut buf = Matrix::::from_gen(0.0, num_points, offsets.dim()); + let mut output = Matrix::::from_gen(0, num_points, offsets.len()); - fn clear(mut x: MutMatrixView) { + fn clear(mut x: MatrixViewMut) { x.as_mut_slice().iter_mut().for_each(|i| *i = T::default()); } diff --git a/diskann-quantization/src/product/tables/transposed/pivots.rs b/diskann-quantization/src/product/tables/transposed/pivots.rs index c76c5c519..c4b063a9d 100644 --- a/diskann-quantization/src/product/tables/transposed/pivots.rs +++ b/diskann-quantization/src/product/tables/transposed/pivots.rs @@ -1520,7 +1520,7 @@ mod tests { #[test] #[should_panic(expected = "row 5 must be less than 5")] fn get_panics_on_row() { - let data = views::Matrix::new(0.0, 5, 10); + let data = views::Matrix::from_gen(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); chunk.get(5, 1); } @@ -1528,7 +1528,7 @@ mod tests { #[test] #[should_panic(expected = "col 5 must be less than 5")] fn get_panics_on_col() { - let data = views::Matrix::new(0.0, 10, 5); + let data = views::Matrix::from_gen(0.0, 10, 5); let chunk = Chunk::new(data.as_view().into()).unwrap(); chunk.get(1, 5); } @@ -1548,7 +1548,7 @@ mod tests { fn test_process_into_impl(dim: usize, total: usize, rng: &mut StdRng) { let distribution = Uniform::::new(-10, 10).unwrap(); let base = - views::Matrix::::new(views::Init(|| distribution.sample(rng) as f32), total, dim); + views::Matrix::::from_gen(views::Init(|| distribution.sample(rng) as f32), total, dim); let chunk = Chunk::new(base.as_view().into()).unwrap(); let mut input = vec![0.0; dim]; @@ -1597,7 +1597,7 @@ mod tests { #[test] #[should_panic] fn test_process_into_panics_on_from() { - let data = views::Matrix::::new(0.0, 5, 10); + let data = views::Matrix::::from_gen(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); assert_eq!(chunk.dimension(), 10); assert_eq!(chunk.num_centers(), 5); @@ -1611,7 +1611,7 @@ mod tests { #[test] #[should_panic] fn test_process_into_panics_on_into() { - let data = views::Matrix::::new(0.0, 5, 10); + let data = views::Matrix::::from_gen(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); assert_eq!(chunk.dimension(), 10); assert_eq!(chunk.num_centers(), 5); diff --git a/diskann-quantization/src/product/tables/transposed/table.rs b/diskann-quantization/src/product/tables/transposed/table.rs index bc527fd8a..1a2bd34d6 100644 --- a/diskann-quantization/src/product/tables/transposed/table.rs +++ b/diskann-quantization/src/product/tables/transposed/table.rs @@ -13,7 +13,7 @@ use crate::{ }; use diskann_utils::{ strided, - views::{self, MatrixView, MutMatrixView}, + views::{self, MatrixView, MatrixViewMut}, }; use thiserror::Error; @@ -187,7 +187,7 @@ impl TransposedTable { let range = self.offsets.at(i); if let Some(chunk_dim) = NonZeroUsize::new(range.len()) { // Construct a view for the packing buffer for this chunk. - let mut packing_view = views::MutMatrixView::try_from( + let mut packing_view = views::MatrixViewMut::try_from( &mut packing_buffer[..SUB_BATCH_SIZE * chunk_dim.get()], SUB_BATCH_SIZE, chunk_dim.get(), @@ -282,7 +282,7 @@ impl TransposedTable { /// * `query.len() != self.dim()`. /// * `partisl.nrows() != self.nchunks()`. /// * `partisl.ncols() != self.ncenters()`. - pub fn process_into(&self, query: &[f32], mut partials: MutMatrixView<'_, f32>) + pub fn process_into(&self, query: &[f32], mut partials: MatrixViewMut<'_, f32>) where T: pivots::ProcessInto, { @@ -422,7 +422,7 @@ pub enum TableBatchCompressionError { InfinityOrNaN(usize, usize), } -impl CompressInto, MutMatrixView<'_, u8>> for TransposedTable +impl CompressInto, MatrixViewMut<'_, u8>> for TransposedTable where T: Copy + Into, { @@ -465,7 +465,7 @@ where fn compress_into( &self, from: MatrixView<'_, T>, - mut to: MutMatrixView<'_, u8>, + mut to: MatrixViewMut<'_, u8>, ) -> Result<(), Self::Error> { if self.ncenters() > 256 { return Err(Self::Error::CannotCompressToByte(self.ncenters())); @@ -530,7 +530,7 @@ mod test_compression { // disagree. #[test] fn error_on_mismatch_dim() { - let pivots = views::Matrix::new(0.0, 3, 5); + let pivots = views::Matrix::from_gen(0.0, 3, 5); let offsets = ChunkOffsets::new(Box::new([0, 1, 6])).unwrap(); let result = TransposedTable::from_parts(pivots.as_view(), offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -544,7 +544,7 @@ mod test_compression { // disagree. #[test] fn error_on_empty() { - let pivots = views::Matrix::new(0.0, 0, 5); + let pivots = views::Matrix::from_gen(0.0, 0, 5); let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); let result = TransposedTable::from_parts(pivots.as_view(), offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -564,7 +564,7 @@ mod test_compression { for dim in [5, 10, 12] { // Sweep over enough totals to ensure the inner chunks have a non-trivial layout. for total in [1, 2, 3, 7, 8, 9, 10] { - let pivots = views::Matrix::new( + let pivots = views::Matrix::from_gen( views::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), total, dim, @@ -684,7 +684,7 @@ mod test_compression { assert_eq!(called.len(), num_data * schema.len()); // Trait Interface. - let mut output = views::Matrix::new(0, num_data, schema.len()); + let mut output = views::Matrix::from_gen(0, num_data, schema.len()); table .compress_into(data.as_view(), output.as_mut_view()) .unwrap(); @@ -856,7 +856,7 @@ mod test_compression { let offsets = ChunkOffsets::new(offsets.into()).unwrap(); let dim = offsets.dim(); - let pivots = views::Matrix::::new( + let pivots = views::Matrix::::from_gen( views::Init(|| value_distribution.sample(rng) as f32), num_centers, dim, @@ -864,7 +864,7 @@ mod test_compression { let table = TransposedTable::from_parts(pivots.as_view(), offsets.clone()).unwrap(); - let mut output = views::Matrix::::new(0.0, num_chunks, num_centers); + let mut output = views::Matrix::::from_gen(0.0, num_chunks, num_centers); let query: Vec<_> = (0..dim) .map(|_| value_distribution.sample(rng) as f32) .collect(); @@ -936,13 +936,13 @@ mod test_compression { #[should_panic(expected = "query has the wrong number of dimensions")] fn test_process_into_panics_query() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = views::Matrix::::new(0.0, 3, 5); + let data = views::Matrix::::from_gen(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); // query has the wrong length. let query = vec![0.0; table.dim() - 1]; - let mut partials = views::Matrix::new(0.0, table.nchunks(), table.ncenters()); + let mut partials = views::Matrix::from_gen(0.0, table.nchunks(), table.ncenters()); table.process_into::(&query, partials.as_mut_view()); } @@ -950,13 +950,13 @@ mod test_compression { #[should_panic(expected = "output has the wrong number of rows")] fn test_process_into_panics_partials_rows() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = views::Matrix::::new(0.0, 3, 5); + let data = views::Matrix::::from_gen(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); let query = vec![0.0; table.dim()]; // partials has the wrong numbers of rows. - let mut partials = views::Matrix::new(0.0, table.nchunks() - 1, table.ncenters()); + let mut partials = views::Matrix::from_gen(0.0, table.nchunks() - 1, table.ncenters()); table.process_into::(&query, partials.as_mut_view()); } @@ -964,13 +964,13 @@ mod test_compression { #[should_panic(expected = "output has the wrong number of columns")] fn test_process_into_panics_partials_cols() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = views::Matrix::::new(0.0, 3, 5); + let data = views::Matrix::::from_gen(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); let query = vec![0.0; table.dim()]; // partials has the wrong numbers of rows. - let mut partials = views::Matrix::new(0.0, table.nchunks(), table.ncenters() - 1); + let mut partials = views::Matrix::from_gen(0.0, table.nchunks(), table.ncenters() - 1); table.process_into::(&query, partials.as_mut_view()); } } diff --git a/diskann-quantization/src/product/train.rs b/diskann-quantization/src/product/train.rs index 3d9a1a47d..c853f9e4a 100644 --- a/diskann-quantization/src/product/train.rs +++ b/diskann-quantization/src/product/train.rs @@ -44,7 +44,7 @@ pub struct SimplePivots { } fn flatten(pivots: &[Matrix], ncenters: usize, dim: usize) -> Matrix { - let mut flattened = Matrix::new(T::default(), ncenters, dim); + let mut flattened = Matrix::from_gen(T::default(), ncenters, dim); let mut col_start = 0; for matrix in pivots { assert_eq!(matrix.nrows(), flattened.nrows()); @@ -169,7 +169,7 @@ impl TrainQuantizer for LightPQTrainingParameters { // Allocate scratch data structures. let norms: Vec = view.row_iter().map(square_norm).collect(); let transpose = BlockTransposed::::from_strided(view); - let mut centers = Matrix::new(0.0, trainer.ncenters, range.len()); + let mut centers = Matrix::from_gen(0.0, trainer.ncenters, range.len()); // Construct the random number generator seeded by the PQ chunk. let mut rng = rng_builder.build_boxed_rng(i); @@ -302,7 +302,7 @@ mod tests { // Create the sub matrices. let matrices: Vec> = std::iter::zip(sub_dims.iter(), prefix_sum.iter()) .map(|(&this_dim, &offset)| { - let mut m = Matrix::new(0, nrows, this_dim); + let mut m = Matrix::from_gen(0, nrows, this_dim); for r in 0..nrows { for c in 0..this_dim { m[(r, c)] = dim * r + offset + c; @@ -358,8 +358,8 @@ mod tests { .map(|chunk| { let dim = schema.at(chunk).len(); - let mut initial = Matrix::new(0.0, ndata, dim); - let mut centers = Matrix::new(0.0, self.nclusters, 1); + let mut initial = Matrix::from_gen(0.0, ndata, dim); + let mut centers = Matrix::from_gen(0.0, self.nclusters, 1); // The starting offset for clusters. let offset = offsets_distribution.sample(rng); @@ -380,7 +380,7 @@ mod tests { // Shuffle the dataset. indices.shuffle(rng); - let mut piece = Matrix::new(0.0, ndata, dim); + let mut piece = Matrix::from_gen(0.0, ndata, dim); for (dst, src) in indices.iter().enumerate() { piece.row_mut(dst).copy_from_slice(initial.row(*src)); } @@ -579,7 +579,7 @@ mod tests { // pivots exceeds the number of dataset items. #[test] fn tests_succeeded_with_too_many_pivots() { - let data = Matrix::::new(1.0, 10, 5); + let data = Matrix::::from_gen(1.0, 10, 5); let offsets: Vec = vec![0, 1, 4, 5]; let trainer = LightPQTrainingParameters::new(2 * data.nrows(), 6); @@ -650,7 +650,7 @@ mod tests { assert!(format(&err).contains("infinity")); }; - let mut data = Matrix::::new(1.0, nrows, ncols); + let mut data = Matrix::::from_gen(1.0, nrows, ncols); // Positive Infinity data[(r, c)] = f32::INFINITY; diff --git a/diskann-quantization/src/scalar/mod.rs b/diskann-quantization/src/scalar/mod.rs index 284a285be..c9a3afe8a 100644 --- a/diskann-quantization/src/scalar/mod.rs +++ b/diskann-quantization/src/scalar/mod.rs @@ -74,7 +74,7 @@ //! // Construct a set of offsets for each dimension. //! let offset: Vec = (0..dim).map(|_| distribution.sample(&mut rng)).collect(); //! // The output dataset. -//! let mut data = Matrix::::new(0.0, nvectors, dim); +//! let mut data = Matrix::::from_gen(0.0, nvectors, dim); //! for row in data.row_iter_mut() { //! std::iter::zip(row.iter_mut(), offset.iter()).for_each(|(r, i)| { //! let v: f32 = distribution.sample(&mut rng); diff --git a/diskann-quantization/src/scalar/quantizer.rs b/diskann-quantization/src/scalar/quantizer.rs index 6c86fc228..711fcceac 100644 --- a/diskann-quantization/src/scalar/quantizer.rs +++ b/diskann-quantization/src/scalar/quantizer.rs @@ -42,7 +42,7 @@ use crate::{ /// use diskann_vector::DistanceFunction; /// /// // A small training set consisting of two 5-dimensional vectors. -/// let mut data = Matrix::::new(0.0, 2, 5); +/// let mut data = Matrix::::from_gen(0.0, 2, 5); /// data.row_mut(0).copy_from_slice(&[-1.0, -1.0, -1.0, -1.0, -1.0]); /// data.row_mut(1).copy_from_slice(&[1.0, 1.0, 1.0, 1.0, 1.0]); /// @@ -607,7 +607,7 @@ mod tests { // Push one more to have one point above `range_max`. base.push(i); - let mut output = views::Matrix::new(0.0, base.len(), dim); + let mut output = views::Matrix::from_gen(0.0, base.len(), dim); (0..dim).for_each(|j| { base.shuffle(rng); for (i, b) in base.iter().enumerate() { diff --git a/diskann-quantization/src/spherical/iface.rs b/diskann-quantization/src/spherical/iface.rs index 2662f84bf..42822bf7a 100644 --- a/diskann-quantization/src/spherical/iface.rs +++ b/diskann-quantization/src/spherical/iface.rs @@ -43,7 +43,7 @@ //! use diskann_utils::views::Matrix; //! //! // For illustration purposes, the dataset consists of just a single vector. -//! let mut data = Matrix::new(1.0, 1, 4); +//! let mut data = Matrix::from_gen(1.0, 1, 4); //! let quantizer = SphericalQuantizer::train( //! data.as_view(), //! TransformKind::Null, diff --git a/diskann-quantization/src/spherical/quantizer.rs b/diskann-quantization/src/spherical/quantizer.rs index ec82b48ce..554b4432a 100644 --- a/diskann-quantization/src/spherical/quantizer.rs +++ b/diskann-quantization/src/spherical/quantizer.rs @@ -2273,7 +2273,7 @@ mod tests { #[test] fn err_dim_cannot_be_zero() { - let data = Matrix::new(0.0f32, 10, 0); + let data = Matrix::from_gen(0.0f32, 10, 0); let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); let err = SphericalQuantizer::train( data.as_view(), @@ -2291,7 +2291,7 @@ mod tests { #[test] fn err_norm_must_be_positive() { - let data = Matrix::new(0.0f32, 10, 10); + let data = Matrix::from_gen(0.0f32, 10, 10); let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); let err = SphericalQuantizer::train( data.as_view(), @@ -2309,7 +2309,7 @@ mod tests { #[test] fn err_norm_cannot_be_infinity() { - let mut data = Matrix::new(0.0f32, 10, 10); + let mut data = Matrix::from_gen(0.0f32, 10, 10); data[(2, 5)] = f32::INFINITY; let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); @@ -2329,7 +2329,7 @@ mod tests { #[test] fn err_reciprocal_norm_cannot_be_infinity() { - let mut data = Matrix::new(0.0f32, 10, 10); + let mut data = Matrix::from_gen(0.0f32, 10, 10); data[(2, 5)] = 2.93863e-39; let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); @@ -2388,7 +2388,7 @@ mod tests { #[test] fn compression_errors_data() { let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); - let data = Matrix::::new(views::Init(|| StandardNormal {}.sample(&mut rng)), 16, 12); + let data = Matrix::::from_gen(views::Init(|| StandardNormal {}.sample(&mut rng)), 16, 12); let quantizer = SphericalQuantizer::train( data.as_view(), diff --git a/diskann-quantization/src/test_util.rs b/diskann-quantization/src/test_util.rs index 6cde8e6d6..3a0728c41 100644 --- a/diskann-quantization/src/test_util.rs +++ b/diskann-quantization/src/test_util.rs @@ -169,7 +169,7 @@ pub(crate) fn create_test_problem(nrows: usize, ncols: usize, rng: &mut StdRng) }) .collect(); - let mut data = Matrix::::new(0.0, nrows, ncols); + let mut data = Matrix::::from_gen(0.0, nrows, ncols); for col in 0..ncols { offsets.shuffle(rng); for row in 0..nrows { diff --git a/diskann-quantization/src/utils.rs b/diskann-quantization/src/utils.rs index 2e30ea3ae..fd9ee16f8 100644 --- a/diskann-quantization/src/utils.rs +++ b/diskann-quantization/src/utils.rs @@ -317,12 +317,12 @@ mod tests { #[test] fn test_normalized_means_corner_cases() { // If the input data has no columns, the returned vector should be empty. - let data = Matrix::new(1.0f32, 10, 0); + let data = Matrix::from_gen(1.0f32, 10, 0); let means = compute_normalized_means(data.as_view()).unwrap(); assert!(means.is_empty()); // If the data has no rows, an error should be returned. - let data = Matrix::new(1.0f32, 0, 10); + let data = Matrix::from_gen(1.0f32, 0, 10); let _: CannotBeEmpty = compute_normalized_means(data.as_view()).unwrap_err(); } diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs b/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs index 02d26d026..549859c76 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs @@ -3,12 +3,12 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `as_view` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the view is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.as_view(); // This should fail: we cannot mutably borrow `mat` while `view` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs index 534c8b5ac..32a39a38f 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs @@ -3,12 +3,12 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `as_view_mut` on Mat correctly captures a mutable lifetime, // preventing the Mat from being used while the mutable view is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.as_view_mut(); // This should fail: we cannot use `mat` while `view` is still alive let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs b/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs index d07a49cf3..2ca8cc4a1 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs @@ -3,12 +3,12 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `get_row` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let row = mat.get_row(0).unwrap(); // This should fail: we cannot mutably borrow `mat` while `row` exists let _ = mat.get_row_mut(1); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs index 469d9349e..099a99b73 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs @@ -3,12 +3,12 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `get_row_mut` on Mat correctly captures a mutable // lifetime, preventing the Mat from being used while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let row = mat.get_row_mut(0).unwrap(); // This should fail: we cannot use `mat` while `row` is still borrowed let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs b/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs index 813de1817..6c3792c8b 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Verify that `Mat` is invariant in any generic parameters. // // This must not compile because it would allow assigning references with a shorter lifetime // into the matrix -fn bad<'long, 'short>(v: Mat>) -> Mat> +fn bad<'long, 'short>(v: Mat>) -> Mat> where 'long: 'short, { @@ -18,6 +18,6 @@ where fn main() { let b = 0u8; - let m = Mat::new(Standard::new(4, 3).unwrap(), &b).unwrap(); + let m = Mat::new(RowMajor::new(4, 3).unwrap(), &b).unwrap(); bad(m); } diff --git a/diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr b/diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr index c27439227..69edbb050 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr +++ b/diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr @@ -1,7 +1,7 @@ error: lifetime may not live long enough --> tests/compile-fail/multi/mat_invariant.rs:16:5 | -12 | fn bad<'long, 'short>(v: Mat>) -> Mat> +12 | fn bad<'long, 'short>(v: Mat>) -> Mat> | ----- ------ lifetime `'short` defined here | | | lifetime `'long` defined here @@ -10,6 +10,6 @@ error: lifetime may not live long enough | ^ function was supposed to return data with lifetime `'long` but it is returning data with lifetime `'short` | = help: consider adding the following bound: `'short: 'long` - = note: requirement occurs because of the type `Mat>`, which makes the generic argument `Standard<&u8>` invariant + = note: requirement occurs because of the type `Mat>`, which makes the generic argument `RowMajor<&u8>` invariant = note: the struct `Mat` is invariant over the parameter `T` = help: see for more information about variance diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs b/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs index c1c56b0f2..806d9b7dd 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; use diskann_utils::Reborrow; // Test that `reborrow` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.reborrow(); // This should fail: we cannot mutably borrow `mat` while `view` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs index 98c49fb28..b4e1336c5 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; use diskann_utils::ReborrowMut; // Test that `reborrow_mut` on Mat correctly captures a mutable borrow, // preventing use of the Mat while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.reborrow_mut(); // This should fail: we cannot use `mat` while `view` exists let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows.rs b/diskann-quantization/tests/compile-fail/multi/mat_rows.rs index 95be7e6a6..a5f86bf48 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_rows.rs @@ -3,12 +3,12 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `rows` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let iter = mat.rows(); // This should fail: we cannot mutably borrow `mat` while `iter` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs index 0ce872998..f06ebf4e4 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs @@ -3,12 +3,12 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, Standard}; +use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that the `rows_mut` iterator correctly captures a mutable lifetime, // preventing the Mat from being used while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let iter = mat.rows_mut(); // This should fail: we cannot use `mat` while the mutable iterator is alive let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs b/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs index 6faacbf71..77fbae2a2 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `as_view` on MatMut correctly captures an immutable lifetime, // preventing mutating the MatMut while the immutable view is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let immut_view = view.as_view(); // This should fail: we cannot mutate `view` while `immut_view` exists let _ = view.get_row_mut(0); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs b/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs index e792b7ad5..bb28a6aaa 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `get_row` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let row = view.get_row(0).unwrap(); // This should fail: we cannot mutably borrow `view` while `row` exists let _ = view.get_row_mut(1); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs b/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs index c24afb6e2..43db3d592 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `get_row_mut` on MatMut correctly captures a mutable lifetime, // preventing the MatMut from being used while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let row = view.get_row_mut(0).unwrap(); // This should fail: we cannot use `view` while `row` is still borrowed let _ = view.get_row_mut(1).unwrap(); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs b/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs index b5a0a5577..52112d5a6 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Verify that `MatMut` is invariant in any generic parameters. // // This must not compile because it would allow assigning references with a shorter lifetime // into the matrix -fn bad<'long, 'short, 'a>(v: MatMut<'a, Standard<&'long u8>>) -> MatMut<'a, Standard<&'short u8>> +fn bad<'long, 'short, 'a>(v: MatMut<'a, RowMajor<&'long u8>>) -> MatMut<'a, RowMajor<&'short u8>> where 'long: 'short, { @@ -18,6 +18,6 @@ where fn main() { let b = 0u8; - let mut m = Mat::new(Standard::new(4, 3).unwrap(), &b).unwrap(); + let mut m = Mat::new(RowMajor::new(4, 3).unwrap(), &b).unwrap(); bad(m.as_view_mut()); } diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr b/diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr index 762febdab..6bbea4f59 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr +++ b/diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr @@ -1,7 +1,7 @@ error: lifetime may not live long enough --> tests/compile-fail/multi/matmut_invariant.rs:16:5 | -12 | fn bad<'long, 'short, 'a>(v: MatMut<'a, Standard<&'long u8>>) -> MatMut<'a, Standard<&'short u8>> +12 | fn bad<'long, 'short, 'a>(v: MatMut<'a, RowMajor<&'long u8>>) -> MatMut<'a, RowMajor<&'short u8>> | ----- ------ lifetime `'short` defined here | | | lifetime `'long` defined here @@ -10,6 +10,6 @@ error: lifetime may not live long enough | ^ function was supposed to return data with lifetime `'long` but it is returning data with lifetime `'short` | = help: consider adding the following bound: `'short: 'long` - = note: requirement occurs because of the type `MatMut<'_, Standard<&u8>>`, which makes the generic argument `Standard<&u8>` invariant + = note: requirement occurs because of the type `MatMut<'_, RowMajor<&u8>>`, which makes the generic argument `RowMajor<&u8>` invariant = note: the struct `MatMut<'a, T>` is invariant over the parameter `T` = help: see for more information about variance diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs index f4bbd58b3..892fe830d 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs @@ -3,14 +3,14 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; use diskann_utils::Reborrow; // Test that `reborrow` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let immut_view = view.reborrow(); // This should fail: we cannot mutably borrow `view` while `immut_view` exists let _ = view.get_row_mut(0); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs index 7b26f0a5c..0c5627b33 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs @@ -3,14 +3,14 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; use diskann_utils::ReborrowMut; // Test that `reborrow_mut` on MatMut correctly captures a mutable lifetime, // preventing the original MatMut from being used while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let reborrowed = view.reborrow_mut(); // This should fail: we cannot use `view` while `reborrowed` is still alive let _ = view.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs b/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs index bbb37ef44..43fa5534c 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `rows` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let iter = view.rows(); // This should fail: we cannot mutably borrow `view` while `iter` exists let _ = view.get_row_mut(0); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs b/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs index b4668e5fc..3144f15ad 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, Standard}; +use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that the `rows_mut` iterator on MatMut correctly captures a mutable lifetime, // preventing the MatMut from being used while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let mut view: MatMut<'_, Standard> = mat.as_view_mut(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let iter = view.rows_mut(); // This should fail: we cannot use `view` while the mutable iterator is alive let _ = view.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs b/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs index 5478adee8..e3d8cd98a 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs +++ b/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatRef, Standard}; +use diskann_quantization::multi_vector::{Mat, MatRef, RowMajor}; // Test that `get_row` on MatRef returns a row with the correct lifetime, // and that an immutable borrow is held while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let view: MatRef<'_, Standard> = mat.as_view(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let view: MatRef<'_, RowMajor> = mat.as_view(); let row = view.get_row(0).unwrap(); // This should fail: we cannot mutably borrow `mat` while `row` exists // (since `row` holds a reference derived from `mat`) diff --git a/diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr b/diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr index 1d83c312b..13c0fa549 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr +++ b/diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr @@ -1,7 +1,7 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable --> tests/compile-fail/multi/matref_get_row.rs:16:13 | -12 | let view: MatRef<'_, Standard> = mat.as_view(); +12 | let view: MatRef<'_, RowMajor> = mat.as_view(); | --- immutable borrow occurs here ... 16 | let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/matref_rows.rs b/diskann-quantization/tests/compile-fail/multi/matref_rows.rs index 82f2dc02c..56ae5e940 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_rows.rs +++ b/diskann-quantization/tests/compile-fail/multi/matref_rows.rs @@ -3,13 +3,13 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatRef, Standard}; +use diskann_quantization::multi_vector::{Mat, MatRef, RowMajor}; // Test that `rows` on MatRef returns an iterator with the correct lifetime, // preventing mutation of the underlying Mat while iterating. fn main() { - let mut mat: Mat> = Mat::new(Standard::new(4, 3).unwrap(), 0.0f32).unwrap(); - let view: MatRef<'_, Standard> = mat.as_view(); + let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let view: MatRef<'_, RowMajor> = mat.as_view(); let iter = view.rows(); // This should fail: we cannot mutably borrow `mat` while `iter` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/matref_rows.stderr b/diskann-quantization/tests/compile-fail/multi/matref_rows.stderr index d2a19baaa..c4b10f866 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_rows.stderr +++ b/diskann-quantization/tests/compile-fail/multi/matref_rows.stderr @@ -1,7 +1,7 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable --> tests/compile-fail/multi/matref_rows.rs:15:13 | -12 | let view: MatRef<'_, Standard> = mat.as_view(); +12 | let view: MatRef<'_, RowMajor> = mat.as_view(); | --- immutable borrow occurs here ... 15 | let _ = mat.as_view_mut(); diff --git a/diskann-utils/src/io.rs b/diskann-utils/src/io.rs index 0ac45b03f..b442b4bfe 100644 --- a/diskann-utils/src/io.rs +++ b/diskann-utils/src/io.rs @@ -53,7 +53,7 @@ where }); } - let mut data = Matrix::new(::zeroed(), npoints, ndims); + let mut data = Matrix::from_gen(::zeroed(), npoints, ndims); reader.read_exact(bytemuck::must_cast_slice_mut::(data.as_mut_slice()))?; Ok(data) @@ -216,7 +216,7 @@ mod tests { #[test] fn round_trip_f32() { let mut counter = 1.0f32; - let matrix = Matrix::::new( + let matrix = Matrix::::from_gen( Init(|| { let v = counter; counter += 1.0; diff --git a/diskann-utils/src/lib.rs b/diskann-utils/src/lib.rs index 089e0dece..762a4b3a0 100644 --- a/diskann-utils/src/lib.rs +++ b/diskann-utils/src/lib.rs @@ -22,6 +22,8 @@ pub mod sampling; pub mod strided; pub mod views; +pub mod matrix; + mod lazystring; pub use lazystring::LazyString; diff --git a/diskann-utils/src/sampling/latin_hypercube.rs b/diskann-utils/src/sampling/latin_hypercube.rs index 3318d3b7f..ecb416e20 100644 --- a/diskann-utils/src/sampling/latin_hypercube.rs +++ b/diskann-utils/src/sampling/latin_hypercube.rs @@ -25,12 +25,12 @@ impl SampleLatinHyperCube for T { let nrows = data.nrows(); let ncols = data.ncols(); if ncols == 0 || nrows == 0 { - return Matrix::new(T::default(), num_samples, ncols); + return Matrix::from_gen(T::default(), num_samples, ncols); } let seed = seed.unwrap_or(0xaf2f5fa0b5161acf); let mut rng = StdRng::seed_from_u64(seed); - let mut result: Matrix = Matrix::new(T::default(), num_samples, ncols); + let mut result: Matrix = Matrix::from_gen(T::default(), num_samples, ncols); // sample a random partitions down the diagonal for (s, res) in result.row_iter_mut().enumerate() { @@ -178,17 +178,17 @@ mod tests { StandardUniform: Distribution, { // No Rows - let x = Matrix::::new(T::default(), 0, 10); + let x = Matrix::::from_gen(T::default(), 0, 10); assert_eq!( T::sample_latin_hypercube(x.as_view(), 1, None), - Matrix::::new(T::default(), 1, x.ncols()) + Matrix::::from_gen(T::default(), 1, x.ncols()) ); // No Cols0 - let x = Matrix::::new(T::default(), 1, 0); + let x = Matrix::::from_gen(T::default(), 1, 0); assert_eq!( T::sample_latin_hypercube(x.as_view(), 1, None), - Matrix::::new(T::default(), 1, x.ncols()) + Matrix::::from_gen(T::default(), 1, x.ncols()) ); let mut rng: StdRng = StdRng::seed_from_u64(0xaf2f5fa0b5161acf); @@ -196,7 +196,7 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!( T::sample_latin_hypercube(x.as_view(), 1, None), Matrix::::try_from(x.row(0).to_vec().into_boxed_slice(), 1, dim).unwrap() @@ -234,7 +234,7 @@ mod tests { #[test] fn test_f16() { let data = example_dataset(); - let mut data_f16 = Matrix::::new(f16::default(), data.nrows(), data.ncols()); + let mut data_f16 = Matrix::::from_gen(f16::default(), data.nrows(), data.ncols()); data_f16.as_mut_slice().cast_from_slice(data.as_slice()); test_for_type(data_f16); } diff --git a/diskann-utils/src/sampling/medoid.rs b/diskann-utils/src/sampling/medoid.rs index a4a537fe9..69d176550 100644 --- a/diskann-utils/src/sampling/medoid.rs +++ b/diskann-utils/src/sampling/medoid.rs @@ -242,11 +242,11 @@ mod tests { #[test] fn test_f32() { // No Rows - let x = Matrix::::new(0.0f32, 0, 10); + let x = Matrix::::from_gen(0.0f32, 0, 10); assert_eq!(f32::compute_medoid(x.as_view()), vec![0.0; x.ncols()]); // No Cols - let x = Matrix::::new(0.0f32, 10, 0); + let x = Matrix::::from_gen(0.0f32, 10, 0); assert_eq!(f32::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0xaf2f5fa0b5161acf); @@ -254,7 +254,7 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!(&*f32::compute_medoid(x.as_view()), x.row(0)); } @@ -267,14 +267,14 @@ mod tests { #[test] fn test_f16() { // No Rows - let x = Matrix::::new(f16::default(), 0, 10); + let x = Matrix::::from_gen(f16::default(), 0, 10); assert_eq!( f16::compute_medoid(x.as_view()), vec![f16::default(); x.ncols()] ); // No Cols - let x = Matrix::::new(f16::default(), 10, 0); + let x = Matrix::::from_gen(f16::default(), 10, 0); assert_eq!(f16::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0x88e2f7096fc9b90e); @@ -282,13 +282,13 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::new(Init(|| f16::from_f32(dist.sample(&mut rng))), 1, dim); + let x = Matrix::::from_gen(Init(|| f16::from_f32(dist.sample(&mut rng))), 1, dim); assert_eq!(&*f16::compute_medoid(x.as_view()), x.row(0)); } // Example dataset let (data, expected) = example_dataset(); - let mut data_f16 = Matrix::::new(f16::default(), data.nrows(), data.ncols()); + let mut data_f16 = Matrix::::from_gen(f16::default(), data.nrows(), data.ncols()); data_f16.as_mut_slice().cast_from_slice(data.as_slice()); let mut expected_f16 = vec![f16::default(); expected.len()]; @@ -316,18 +316,18 @@ mod tests { #[test] fn test_u8() { // No Rows - let x = Matrix::::new(0u8, 0, 10); + let x = Matrix::::from_gen(0u8, 0, 10); assert_eq!(u8::compute_medoid(x.as_view()), vec![0u8; x.ncols()]); // No Cols - let x = Matrix::::new(0u8, 10, 0); + let x = Matrix::::from_gen(0u8, 10, 0); assert_eq!(u8::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0x8f2f5fa0b5161acf); // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!(&*u8::compute_medoid(x.as_view()), x.row(0)); } @@ -356,11 +356,11 @@ mod tests { #[test] fn test_i8() { // No Rows - let x = Matrix::::new(0i8, 0, 10); + let x = Matrix::::from_gen(0i8, 0, 10); assert_eq!(i8::compute_medoid(x.as_view()), vec![0i8; x.ncols()]); // No Cols - let x = Matrix::::new(0i8, 10, 0); + let x = Matrix::::from_gen(0i8, 10, 0); assert_eq!(i8::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0x8f2f5fa0b5161acf); @@ -368,7 +368,7 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!(&*i8::compute_medoid(x.as_view()), x.row(0)); } diff --git a/diskann-utils/src/strided.rs b/diskann-utils/src/strided.rs index efbfd621e..ced09bece 100644 --- a/diskann-utils/src/strided.rs +++ b/diskann-utils/src/strided.rs @@ -9,11 +9,11 @@ use std::{ }; use thiserror::Error; -use crate::views::{self, DenseData, MutDenseData}; +use crate::views::{DenseData, MutDenseData}; /// A row-major strided matrix. /// -/// This is a generalization of the `MatrixBase` class as it does not mandate a dense +/// This is a generalization of the dense [`Matrix`](crate::views::Matrix) type as it does not mandate a dense /// layout in memory. /// /// ```text @@ -75,7 +75,7 @@ pub struct TryFromErrorLight { data.as_slice().len(), linear_length(self.nrows, self.ncols, self.cstride) )] -pub struct TryFromError { +pub struct TryFromError { data: T, nrows: usize, ncols: usize, @@ -94,7 +94,7 @@ impl fmt::Debug for TryFromError { } } -impl TryFromError { +impl TryFromError { /// Consume the error and return the base data. pub fn into_inner(self) -> T { self.data @@ -497,17 +497,30 @@ where } } -impl From> for StridedBase -where - T: DenseData, - U: DenseData, - T: Into, +// Dense (row-major) views convert to strided views with `cstride == ncols`. +impl<'a, T> From>> for StridedBase<&'a [T]> { + fn from(m: crate::matrix::MatRef<'a, crate::matrix::RowMajor>) -> Self { + let (nrows, ncols) = (m.nrows(), m.ncols()); + Self { + data: m.as_slice(), + nrows, + ncols, + cstride: ncols, + } + } +} + +impl<'a, T> From>> + for StridedBase<&'a mut [T]> { - fn from(matrix: views::MatrixBase) -> Self { - let nrows = matrix.nrows(); - let ncols = matrix.ncols(); + fn from(mut m: crate::matrix::MatMut<'a, crate::matrix::RowMajor>) -> Self { + let (nrows, ncols) = (m.nrows(), m.ncols()); + let ptr = m.as_mut_slice().as_mut_ptr(); + // SAFETY: `m` owns an exclusive `&'a mut` borrow of `nrows * ncols` contiguous `T`; + // consuming `m` (a non-owning view with no `Drop`) transfers that borrow here. + let data: &'a mut [T] = unsafe { std::slice::from_raw_parts_mut(ptr, nrows * ncols) }; Self { - data: matrix.into_inner().into(), + data, nrows, ncols, cstride: ncols, @@ -518,6 +531,7 @@ where #[cfg(test)] mod tests { use super::*; + use crate::views; #[test] fn test_linear_length() { @@ -630,7 +644,7 @@ mod tests { // ``` fn create_test_matrix(nrows: usize, ncols: usize) -> views::Matrix { let mut i = 0; - views::Matrix::new( + views::Matrix::from_gen( views::Init(|| { let v = i; i += 1; @@ -666,7 +680,7 @@ mod tests { assert_eq!(v.as_ptr(), ptr, "base pointer was not preserved"); // Create the expected matrix. - let mut expected = views::Matrix::new(0, 5, 2); + let mut expected = views::Matrix::from_gen(0, 5, 2); for row in 0..expected.nrows() { for col in 0..expected.ncols() { expected[(row, col)] = m[(row, col)]; @@ -676,7 +690,7 @@ mod tests { // Create a strided view over the last two columns. let v = StridedView::try_from(&(m.as_slice()[1..]), m.nrows(), 2, m.ncols()).unwrap(); - let mut expected = views::Matrix::new(0, 5, 2); + let mut expected = views::Matrix::from_gen(0, 5, 2); for row in 0..expected.nrows() { for col in 0..expected.ncols() { expected[(row, col)] = m[(row, col + 1)]; @@ -692,7 +706,7 @@ mod tests { // Initialize using 2d indexing. { - let mut dst = views::Matrix::::new(0, 5, 10); + let mut dst = views::Matrix::::from_gen(0, 5, 10); let ptr = dst.as_ptr(); @@ -722,7 +736,7 @@ mod tests { // Initialize using row-wise indexing. { - let mut dst = views::Matrix::::new(0, 5, 10); + let mut dst = views::Matrix::::from_gen(0, 5, 10); let ptr = dst.as_ptr(); @@ -750,7 +764,7 @@ mod tests { // Initialize using row-iterator indexing. { - let mut dst = views::Matrix::::new(0, 5, 10); + let mut dst = views::Matrix::::from_gen(0, 5, 10); let offset = 2; // SAFETY: The underlying allocation is valid for much more than 2 elements. @@ -831,7 +845,7 @@ mod tests { #[test] fn test_try_shrink_from() { // Exact is okay. - let m = views::Matrix::::new(0, 10, 10); + let m = views::Matrix::::from_gen(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); let s = StridedView::try_shrink_from(m.as_slice(), nrows, ncols, ncols).unwrap(); @@ -855,14 +869,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_shink_from_panics() { - let m = views::Matrix::::new(0, 4, 4); + let m = views::Matrix::::from_gen(0, 4, 4); let _ = StridedView::try_shrink_from(m.as_slice(), 2, 2, 1); } #[test] fn test_try_shrink_from_mut() { // Exact is okay. - let mut m = views::Matrix::::new(0, 10, 10); + let mut m = views::Matrix::::from_gen(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); @@ -890,14 +904,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_shink_from_mut_panics() { - let mut m = views::Matrix::::new(0, 4, 4); + let mut m = views::Matrix::::from_gen(0, 4, 4); let _ = MutStridedView::try_shrink_from_mut(m.as_mut_slice(), 2, 2, 1); } #[test] fn test_try_from() { // Exact is okay. - let m = views::Matrix::::new(0, 10, 10); + let m = views::Matrix::::from_gen(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); let s = StridedView::try_from(m.as_slice(), nrows, ncols, ncols).unwrap(); @@ -926,14 +940,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_frompanics() { - let mut m = views::Matrix::::new(0, 4, 4); + let mut m = views::Matrix::::from_gen(0, 4, 4); let _ = MutStridedView::try_from(m.as_mut_slice(), 2, 2, 1); } #[test] #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] fn test_get_row_panics() { - let m = views::Matrix::::new(0, 3, 7); + let m = views::Matrix::::from_gen(0, 3, 7); let v: StridedView<_> = m.as_view().into(); v.row(3); } @@ -941,7 +955,7 @@ mod tests { #[test] #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] fn test_get_row_mut_panics() { - let mut m = views::Matrix::::new(0, 3, 7); + let mut m = views::Matrix::::from_gen(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v.row_mut(3); } @@ -949,7 +963,7 @@ mod tests { #[test] #[should_panic(expected = "row 3 is out of bounds (max: 3)")] fn test_index_panics_row() { - let m = views::Matrix::::new(0, 3, 7); + let m = views::Matrix::::from_gen(0, 3, 7); let v: StridedView<_> = m.as_view().into(); let _ = v[(3, 2)]; } @@ -957,7 +971,7 @@ mod tests { #[test] #[should_panic(expected = "col 7 is out of bounds (max: 7)")] fn test_index_panics_col() { - let m = views::Matrix::::new(0, 3, 7); + let m = views::Matrix::::from_gen(0, 3, 7); let v: StridedView<_> = m.as_view().into(); let _ = v[(2, 7)]; } @@ -965,7 +979,7 @@ mod tests { #[test] #[should_panic(expected = "row 3 is out of bounds (max: 3)")] fn test_index_mut_panics_row() { - let mut m = views::Matrix::::new(0, 3, 7); + let mut m = views::Matrix::::from_gen(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v[(3, 2)] = 1; } @@ -973,7 +987,7 @@ mod tests { #[test] #[should_panic(expected = "col 7 is out of bounds (max: 7)")] fn test_index_mut_panics_col() { - let mut m = views::Matrix::::new(0, 3, 7); + let mut m = views::Matrix::::from_gen(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v[(2, 7)] = 1; } diff --git a/diskann-utils/src/views.rs b/diskann-utils/src/views.rs index a9352918c..7a899c1e0 100644 --- a/diskann-utils/src/views.rs +++ b/diskann-utils/src/views.rs @@ -3,30 +3,20 @@ * Licensed under the MIT license. */ -use std::{ - fmt, - ops::{Index, IndexMut}, -}; +//! Dense matrix types and the `DenseData` container abstraction. +//! +//! The [`Matrix`], [`MatrixView`], and [`MatrixViewMut`] types are re-exported from +//! [`crate::matrix`]. [`DenseData`]/[`MutDenseData`] abstract over owned and borrowed +//! contiguous storage and are used by [`crate::strided`]. -#[cfg(feature = "rayon")] -use rayon::prelude::{IndexedParallelIterator, ParallelIterator, ParallelSlice, ParallelSliceMut}; -use thiserror::Error; +pub use crate::matrix::{Generator, Init, Matrix, MatrixView, MatrixViewMut, TryFromError}; -/// Various view types (types such as [`MatrixView`] that add semantic meaning to blobs -/// of data) need both immutable and mutable variants. -/// -/// This trait can be implemented by wrappers for immutable and mutable slice references, -/// allowing for a common code path for immutable and mutable view types. -/// -/// The main goal is to provide a way of retrieving an underlying dense slice, which can -/// then be used as the building block for higher level abstractions. +/// Abstraction over a type that can yield a dense slice of its contents. /// /// # Safety /// -/// This trait is unsafe because it requires `as_slice` to be idempotent (and unsafe code -/// relies on this). -/// -/// In other words: `as_slice` must **always** return the same slice with the same length. +/// `as_slice` must be idempotent: it must **always** return the same slice with the same +/// length (unsafe code relies on this). pub unsafe trait DenseData { type Elem; @@ -34,24 +24,17 @@ pub unsafe trait DenseData { fn as_slice(&self) -> &[Self::Elem]; } -/// A mutable companion to `DenseData`. -/// -/// This trait allows mutable methods on view types to be selectively enabled when data -/// underlying the type is mutable. +/// A mutable companion to [`DenseData`]. /// /// # Safety /// -/// This trait is unsafe because it requires `as_slice` to be idempotent (and unsafe code -/// relies on this). -/// -/// In other words: `as_slice` must **always** return the same slice with the same length. -/// -/// Additionally, the returned slice must span the exact same memory as `as_slice`. +/// `as_mut_slice` must be idempotent and must span the exact same memory as +/// [`DenseData::as_slice`]. pub unsafe trait MutDenseData: DenseData { fn as_mut_slice(&mut self) -> &mut [Self::Elem]; } -// SAFETY: This fulfills the idempotency requirement. +// SAFETY: fulfills the idempotency requirement. unsafe impl DenseData for &[T] { type Elem = T; fn as_slice(&self) -> &[Self::Elem] { @@ -59,7 +42,7 @@ unsafe impl DenseData for &[T] { } } -// SAFETY: This fulfills the idempotency requirement. +// SAFETY: fulfills the idempotency requirement. unsafe impl DenseData for &mut [T] { type Elem = T; fn as_slice(&self) -> &[Self::Elem] { @@ -67,15 +50,14 @@ unsafe impl DenseData for &mut [T] { } } -// SAFETY: This fulfills the idempotency requirement and returns a slice spanning the same -// range as `as_slice`. +// SAFETY: fulfills the idempotency requirement and spans the same memory as `as_slice`. unsafe impl MutDenseData for &mut [T] { fn as_mut_slice(&mut self) -> &mut [Self::Elem] { self } } -// SAFETY: This fulfills the idempotency requirement. +// SAFETY: fulfills the idempotency requirement. unsafe impl DenseData for Box<[T]> { type Elem = T; fn as_slice(&self) -> &[Self::Elem] { @@ -83,2101 +65,9 @@ unsafe impl DenseData for Box<[T]> { } } -// SAFETY: This fulfills the idempotency requirement and returns a slice spanning the same -// memory as `as_slice`. +// SAFETY: fulfills the idempotency requirement and spans the same memory as `as_slice`. unsafe impl MutDenseData for Box<[T]> { fn as_mut_slice(&mut self) -> &mut [Self::Elem] { self } } - -//////////// -// Matrix // -//////////// - -/// A view over dense chunk of memory, interpreting that memory as a 2-dimensional matrix -/// laid out in row-major order. -/// -/// When this class view immutable memory, it is `Copy`. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct MatrixBase -where - T: DenseData, -{ - data: T, - nrows: usize, - ncols: usize, -} - -#[derive(Debug, Error)] -#[non_exhaustive] -#[error( - "tried to construct a matrix view with {nrows} rows and {ncols} columns over a slice \ - of length {len}" -)] -pub struct TryFromErrorLight { - len: usize, - nrows: usize, - ncols: usize, -} - -#[derive(Error)] -#[non_exhaustive] -#[error( - "tried to construct a matrix view with {nrows} rows and {ncols} columns over a slice \ - of length {}", data.as_slice().len() -)] -pub struct TryFromError { - data: T, - nrows: usize, - ncols: usize, -} - -// Manually implement `fmt::Debug` so we don't require `T::Debug`. -impl fmt::Debug for TryFromError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryFromError") - .field("data_len", &self.data.as_slice().len()) - .field("nrows", &self.nrows) - .field("ncols", &self.ncols) - .finish() - } -} - -impl TryFromError { - /// Consume the error and return the base data. - pub fn into_inner(self) -> T { - self.data - } - - /// Return a variation of `Self` that is guaranteed to be `'static` by removing the - /// data that was passed to the original constructor. - pub fn as_static(&self) -> TryFromErrorLight { - TryFromErrorLight { - len: self.data.as_slice().len(), - nrows: self.nrows, - ncols: self.ncols, - } - } -} - -/// A generator for initializing the entries in a matrix via `Matrix::new`. -pub trait Generator { - fn generate(&mut self) -> T; -} - -impl Generator for T -where - T: Clone, -{ - fn generate(&mut self) -> T { - self.clone() - } -} - -/// A matrix initializer that invokes the provided lambda to initialize each element. -pub struct Init(pub F); - -impl Generator for Init -where - F: FnMut() -> T, -{ - fn generate(&mut self) -> T { - (self.0)() - } -} - -impl MatrixBase> { - /// Construct a new Matrix initialized with the contents of the generator. - /// - /// Elements are initialized in memory order. - pub fn new(mut generator: U, nrows: usize, ncols: usize) -> Self - where - U: Generator, - { - let data: Box<[T]> = (0..nrows * ncols).map(|_| generator.generate()).collect(); - debug_assert_eq!(data.len(), nrows * ncols); - Self { data, nrows, ncols } - } -} - -impl MatrixBase -where - T: DenseData, -{ - /// Try to construct a `MatrixBase` over the provided base. If the size of the base - /// is incorrect, return a `TryFromError` containing the base. - /// - /// The length of the base must be equal to `nrows * ncols`. - pub fn try_from(data: T, nrows: usize, ncols: usize) -> Result> { - let len = data.as_slice().len(); - if len != nrows * ncols { - Err(TryFromError { data, nrows, ncols }) - } else { - Ok(Self { data, nrows, ncols }) - } - } - - /// Return the number of columns in the matrix. - pub fn ncols(&self) -> usize { - self.ncols - } - - /// Return the number of rows in the matrix. - pub fn nrows(&self) -> usize { - self.nrows - } - - /// Create a new [`Matrix`] by applying the closure `f` to each element. - /// - /// The returned matrix has the same shape as `self`. - pub fn map(&self, f: F) -> Matrix - where - F: FnMut(&T::Elem) -> R, - { - let data: Box<[_]> = self.as_slice().iter().map(f).collect(); - Matrix { - data, - nrows: self.nrows(), - ncols: self.ncols(), - } - } - - /// Return the underlying data as a slice. - pub fn as_slice(&self) -> &[T::Elem] { - self.data.as_slice() - } - - /// Return the underlying data as a mutable slice. - pub fn as_mut_slice(&mut self) -> &mut [T::Elem] - where - T: MutDenseData, - { - self.data.as_mut_slice() - } - - /// Return row `row` as a slice. - /// - /// # Panic - /// - /// Panics if `row >= self.nrows()`. - pub fn row(&self, row: usize) -> &[T::Elem] { - assert!( - row < self.nrows(), - "tried to access row {row} of a matrix with {} rows", - self.nrows() - ); - - // SAFETY: `row` is in-bounds. - unsafe { self.get_row_unchecked(row) } - } - - /// Construct a new `MatrixBase` over the raw data. - /// - /// The returned `MatrixBase` will only have a single row with contents equal to `data`. - pub fn row_vector(data: T) -> Self { - let ncols = data.as_slice().len(); - Self { - data, - nrows: 1, - ncols, - } - } - - /// Construct a new `MatrixBase` over the raw data. - /// - /// The returned `MatrixBase` will only have a single column with contents equal to `data`. - pub fn column_vector(data: T) -> Self { - let nrows = data.as_slice().len(); - Self { - data, - nrows, - ncols: 1, - } - } - - /// Return row `row` if `row < self.nrows()`. Otherwise, return `None`. - pub fn get_row(&self, row: usize) -> Option<&[T::Elem]> { - if row < self.nrows() { - // SAFETY: `row` is in-bounds. - Some(unsafe { self.get_row_unchecked(row) }) - } else { - None - } - } - - /// Returns the requested row without boundschecking. - /// - /// # Safety - /// - /// The following conditions must hold to avoid undefined behavior: - /// * `row < self.nrows()`. - pub unsafe fn get_row_unchecked(&self, row: usize) -> &[T::Elem] { - debug_assert!(row < self.nrows); - let ncols = self.ncols; - let start = row * ncols; - - debug_assert!(start + ncols <= self.as_slice().len()); - // SAFETY: The idempotency requirement of `as_slice` and our audited constructors - // mean that `self.as_slice()` has a length of `self.nrows * self.ncols`. - // - // Therefore, this access is in-bounds. - unsafe { self.as_slice().get_unchecked(start..start + ncols) } - } - - /// Return row `row` as a mutable slice. - /// - /// # Panics - /// - /// Panics if `row >= self.nrows()`. - pub fn row_mut(&mut self, row: usize) -> &mut [T::Elem] - where - T: MutDenseData, - { - assert!( - row < self.nrows(), - "tried to access row {row} of a matrix with {} rows", - self.nrows() - ); - - // SAFETY: `row` is in-bounds. - unsafe { self.get_row_unchecked_mut(row) } - } - - /// Returns the requested row without boundschecking. - /// - /// # Safety - /// - /// The following conditions must hold to avoid undefined behavior: - /// * `row < self.nrows()`. - pub unsafe fn get_row_unchecked_mut(&mut self, row: usize) -> &mut [T::Elem] - where - T: MutDenseData, - { - debug_assert!(row < self.nrows); - let ncols = self.ncols; - let start = row * ncols; - - debug_assert!(start + ncols <= self.as_slice().len()); - // SAFETY: The idempotency requirement of `as_mut_slice` and our audited constructors - // mean that `self.as_mut_slice()` has a length of `self.nrows * self.ncols`. - // - // Therefore, this access is in-bounds. - unsafe { - self.data - .as_mut_slice() - .get_unchecked_mut(start..start + ncols) - } - } - - /// Return a iterator over all rows in the matrix. - /// - /// Rows are yielded sequentially beginning with row 0. - pub fn row_iter(&self) -> impl ExactSizeIterator { - self.data.as_slice().chunks_exact(self.ncols()) - } - - /// Return a mutable iterator over all rows in the matrix. - /// - /// Rows are yielded sequentially beginning with row 0. - pub fn row_iter_mut(&mut self) -> impl ExactSizeIterator - where - T: MutDenseData, - { - let ncols = self.ncols(); - self.data.as_mut_slice().chunks_exact_mut(ncols) - } - - /// Return an iterator that divides the matrix into sub-matrices with (up to) - /// `batchsize` rows with `self.ncols()` columns. - /// - /// It is possible for yielded sub-matrices to have fewer than `batchsize` rows if the - /// number of rows in the parent matrix is not evenly divisible by `batchsize`. - /// - /// # Panics - /// - /// Panics if `batchsize = 0`. - pub fn window_iter(&self, batchsize: usize) -> impl Iterator> - where - T::Elem: Sync, - { - assert!(batchsize != 0, "window_iter batchsize cannot be zero"); - let ncols = self.ncols(); - self.data - .as_slice() - .chunks(ncols * batchsize) - .map(move |data| { - let blobsize = data.len(); - let nrows = blobsize / ncols; - assert_eq!(blobsize % ncols, 0); - MatrixView { data, nrows, ncols } - }) - } - - /// Return a parallel iterator that divides the matrix into sub-matrices with (up to) - /// `batchsize` rows with `self.ncols()` columns. - /// - /// This allows workers in parallel algorithms to work on dense subsets of the whole - /// matrix for better locality. - /// - /// It is possible for yielded sub-matrices to have fewer than `batchsize` rows if the - /// number of rows in the parent matrix is not evenly divisible by `batchsize`. - /// - /// # Panics - /// - /// Panics if `batchsize = 0`. - #[cfg(feature = "rayon")] - pub fn par_window_iter( - &self, - batchsize: usize, - ) -> impl IndexedParallelIterator> - where - T::Elem: Sync, - { - assert!(batchsize != 0, "par_window_iter batchsize cannot be zero"); - let ncols = self.ncols(); - self.data - .as_slice() - .par_chunks(ncols * batchsize) - .map(move |data| { - let blobsize = data.len(); - let nrows = blobsize / ncols; - assert_eq!(blobsize % ncols, 0); - MatrixView { data, nrows, ncols } - }) - } - - /// Return a parallel iterator that divides the matrix into mutable sub-matrices with - /// (up to) `batchsize` rows with `self.ncols()` columns. - /// - /// This allows workers in parallel algorithms to work on dense subsets of the whole - /// matrix for better locality. - /// - /// It is possible for yielded sub-matrices to have fewer than `batchsize` rows if the - /// number of rows in the parent matrix is not evenly divisible by `batchsize`. - /// - /// # Panics - /// - /// Panics if `batchsize = 0`. - #[cfg(feature = "rayon")] - pub fn par_window_iter_mut( - &mut self, - batchsize: usize, - ) -> impl IndexedParallelIterator> - where - T: MutDenseData, - T::Elem: Send, - { - assert!( - batchsize != 0, - "par_window_iter_mut batchsize cannot be zero" - ); - let ncols = self.ncols(); - self.data - .as_mut_slice() - .par_chunks_mut(ncols * batchsize) - .map(move |data| { - let blobsize = data.len(); - let nrows = blobsize / ncols; - assert_eq!(blobsize % ncols, 0); - MutMatrixView { data, nrows, ncols } - }) - } - - /// Return a parallel iterator over the rows of the matrix. - #[cfg(feature = "rayon")] - pub fn par_row_iter(&self) -> impl IndexedParallelIterator - where - T::Elem: Sync, - { - self.as_slice().par_chunks_exact(self.ncols()) - } - - /// Return a parallel iterator over the rows of the matrix. - #[cfg(feature = "rayon")] - pub fn par_row_iter_mut(&mut self) -> impl IndexedParallelIterator - where - T: MutDenseData, - T::Elem: Send, - { - let ncols = self.ncols(); - self.as_mut_slice().par_chunks_exact_mut(ncols) - } - - /// Consume the matrix, returning the inner representation. - /// - /// This loses the information about the number of rows and columnts. - pub fn into_inner(self) -> T { - self.data - } - - /// Return a view over the matrix. - pub fn as_view(&self) -> MatrixView<'_, T::Elem> { - MatrixBase { - data: self.as_slice(), - nrows: self.nrows(), - ncols: self.ncols(), - } - } - - /// Return a mutable view over the matrix. - pub fn as_mut_view(&mut self) -> MutMatrixView<'_, T::Elem> - where - T: MutDenseData, - { - let nrows = self.nrows(); - let ncols = self.ncols(); - MatrixBase { - data: self.as_mut_slice(), - nrows, - ncols, - } - } - - /// Return a view over the specified rows of the matrix. - /// - /// If the specified range is out of bounds, return `None`. - /// - /// ```rust - /// use diskann_utils::views::Matrix; - /// - /// let mut mat = Matrix::new(0usize, 4, 3); - /// - /// // Fill the matrix with some data. - /// mat.row_iter_mut().enumerate().for_each(|(i, row)| row.fill(i)); - /// - /// // Creating a subview into an offset portion of the matrix. - /// let subview = mat.subview(1..3).unwrap(); - /// assert_eq!(subview.nrows(), 2); - /// assert_eq!(subview.row(0), &[1, 1, 1]); - /// assert_eq!(subview.row(1), &[2, 2, 2]); - /// - /// // A trying to access out-of-bounds returns `None` - /// assert!(mat.subview(3..5).is_none()); - /// ``` - pub fn subview(&self, rows: std::ops::Range) -> Option> { - let ncols = self.ncols(); - - let lower = rows.start.checked_mul(ncols)?; - let upper = rows.end.checked_mul(ncols)?; - - if let Some(data) = self.as_slice().get(lower..upper) { - Some(MatrixBase { - data, - nrows: rows.len(), - ncols: self.ncols(), - }) - } else { - None - } - } - - /// Return a pointer to the base of the matrix. - pub fn as_ptr(&self) -> *const T::Elem { - self.as_slice().as_ptr() - } - - /// Return a pointer to the base of the matrix. - pub fn as_mut_ptr(&mut self) -> *mut T::Elem - where - T: MutDenseData, - { - self.as_mut_slice().as_mut_ptr() - } - - /// Return the value at the specified `row` and `col`. - /// - /// If either index is out-of-bounds, return `None`. - pub fn try_get(&self, row: usize, col: usize) -> Option<&T::Elem> { - if row >= self.nrows() || col >= self.ncols() { - None - } else { - // SAFETY: We just verified that `row` and `col` are in-bounds. - Some(unsafe { self.get_unchecked(row, col) }) - } - } - - /// Returns a reference to an element without boundschecking. - /// - /// # Safety - /// - /// The following conditions must hold to avoid undefined behavior: - /// * `row < self.nrows()`. - /// * `col < self.ncols()`. - pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T::Elem { - debug_assert!(row < self.nrows); - debug_assert!(col < self.ncols); - self.as_slice().get_unchecked(row * self.ncols + col) - } - - /// Returns a mutable reference to an element without boundschecking. - /// - /// # Safety - /// - /// The following conditions must hold to avoid undefined behavior: - /// * `row < self.nrows()`. - /// * `col < self.ncols()`. - pub unsafe fn get_unchecked_mut(&mut self, row: usize, col: usize) -> &mut T::Elem - where - T: MutDenseData, - { - let ncols = self.ncols; - debug_assert!(row < self.nrows); - debug_assert!(col < self.ncols); - self.as_mut_slice().get_unchecked_mut(row * ncols + col) - } - - pub fn to_owned(&self) -> Matrix - where - T::Elem: Clone, - { - Matrix { - data: self.data.as_slice().into(), - nrows: self.nrows, - ncols: self.ncols, - } - } -} - -/// Represents an owning, 2-dimensional view of a contiguous block of memory, -/// interpreted as a matrix in row-major order. -pub type Matrix = MatrixBase>; - -/// Represents a non-owning, 2-dimensional view of a contiguous block of memory, -/// interpreted as a matrix in row-major order. -/// -/// This type is useful for functions that need to read matrix data without taking ownership. -/// By accepting a `MatrixView`, such functions can operate on both owned matrices (by converting them -/// to a `MatrixView`) and existing non-owning views. -pub type MatrixView<'a, T> = MatrixBase<&'a [T]>; - -/// Represents a mutable non-owning, 2-dimensional view of a contiguous block of memory, -/// interpreted as a matrix in row-major order. -/// -/// This type is useful for functions that need to modify matrix data without taking ownership. -/// By accepting a `MutMatrixView`, such functions can operate on both owned matrices (by converting them -/// to a `MutMatrixView`) and existing non-owning mutable views. -pub type MutMatrixView<'a, T> = MatrixBase<&'a mut [T]>; - -/// Allow matrix views to be converted directly to slices. -impl<'a, T> From> for &'a [T] { - fn from(view: MatrixView<'a, T>) -> Self { - view.data - } -} - -/// Allow mutable matrix views to be converted directly to slices. -impl<'a, T> From> for &'a [T] { - fn from(view: MutMatrixView<'a, T>) -> Self { - view.data - } -} - -/// Return a reference to the item at entry `(row, col)` in the matrix. -/// -/// # Panics -/// -/// Panics if `row >= self.nrows()` or `col >= self.ncols()`. -impl Index<(usize, usize)> for MatrixBase -where - T: DenseData, -{ - type Output = T::Elem; - - fn index(&self, (row, col): (usize, usize)) -> &Self::Output { - assert!( - row < self.nrows(), - "row {row} is out of bounds (max: {})", - self.nrows() - ); - assert!( - col < self.ncols(), - "col {col} is out of bounds (max: {})", - self.ncols() - ); - - // SAFETY: We have checked that `row` and `col` are in-bounds. - unsafe { self.get_unchecked(row, col) } - } -} - -/// Return a mutable reference to the item at entry `(row, col)` in the matrix. -/// -/// # Panics -/// -/// Panics if `row >= self.nrows()` or `col >= self.ncols()`. -impl IndexMut<(usize, usize)> for MatrixBase -where - T: MutDenseData, -{ - fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output { - assert!( - row < self.nrows(), - "row {row} is out of bounds (max: {})", - self.nrows() - ); - assert!( - col < self.ncols(), - "col {col} is out of bounds (max: {})", - self.ncols() - ); - - // SAFETY: We have checked that `row` and `col` are in-bounds. - unsafe { self.get_unchecked_mut(row, col) } - } -} - -/////////// -// Tests // -/////////// - -#[cfg(test)] -mod tests { - use super::*; - use crate::lazy_format; - - /// This function is only callable with copyable types. - /// - /// This lets us test for types we expect to be `Copy`. - fn is_copyable(_x: T) -> bool { - true - } - - /// Test the that provided representation yields a slice with the expected base pointer - /// and length. - fn test_dense_data_repr( - ptr: *const T, - len: usize, - repr: Repr, - context: &dyn std::fmt::Display, - ) where - T: Copy, - Repr: DenseData, - { - let retrieved = repr.as_slice(); - assert_eq!(retrieved.len(), len, "{}", context); - assert_eq!(retrieved.as_ptr(), ptr, "{}", context); - } - - /// Set the underlying data for the provided representation to the following: - /// - /// [base, base + increment, base + increment + increment, ...] - fn set_mut_dense_data_repr(repr: &mut Repr, base: T, increment: T) - where - T: Copy + std::ops::Add, - Repr: DenseData + MutDenseData, - { - let slice = repr.as_mut_slice(); - for i in 0..slice.len() { - if i == 0 { - slice[i] = base; - } else { - slice[i] = slice[i - 1] + increment; - } - } - } - - #[test] - fn slice_implements_dense_data_repr() { - for len in 0..10 { - let context = lazy_format!("len = {}", len); - let data: Vec = vec![0.0; len]; - let slice = data.as_slice(); - test_dense_data_repr(slice.as_ptr(), slice.len(), slice, &context); - } - } - - #[test] - fn mut_slice_mplements_dense_data_repr() { - for len in 0..10 { - let context = lazy_format!("len = {}", len); - let mut data: Vec = vec![0.0; len]; - let slice = data.as_mut_slice(); - - let ptr = slice.as_ptr(); - let len = slice.len(); - test_dense_data_repr(ptr, len, slice, &context); - } - } - - #[test] - fn mut_slice_implements_mut_dense_data_repr() { - for len in 0..10 { - let context = lazy_format!("len = {}", len); - let mut data: Vec = vec![0.0; len]; - let mut slice = data.as_mut_slice(); - - let base = 2.0; - let increment = 1.0; - set_mut_dense_data_repr(&mut slice, base, increment); - - for (i, &v) in slice.iter().enumerate() { - let context = lazy_format!("entry {}, {}", i, context); - assert_eq!(v, base + increment * (i as f32), "{}", context); - } - } - } - - ///////////////// - // Matrix View // - ///////////////// - - #[test] - fn try_from_error_misc() { - let x = TryFromError::<&[f32]> { - data: &[], - nrows: 1, - ncols: 2, - }; - - let debug = format!("{:?}", x); - println!("debug = {}", debug); - assert!(debug.contains("TryFromError")); - assert!(debug.contains("data_len: 0")); - assert!(debug.contains("nrows: 1")); - assert!(debug.contains("ncols: 2")); - } - - fn make_test_matrix() -> Vec { - // Construct a matrix with 4 rows of length 3. - // The expected layout is as follows: - // - // 0, 1, 2, - // 1, 2, 3, - // 2, 3, 4, - // 3, 4, 5 - // - vec![0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5] - } - - #[cfg(feature = "rayon")] - fn test_basic_indexing_parallel(m: MatrixView<'_, usize>) { - // Par window iters. - let batchsize = 2; - m.par_window_iter(batchsize) - .enumerate() - .for_each(|(i, submatrix)| { - assert_eq!(submatrix.nrows(), batchsize); - assert_eq!(submatrix.ncols(), m.ncols()); - - // Make sure we are in the correct window of the original matrix. - let base = i * batchsize; - assert_eq!(submatrix[(0, 0)], base); - assert_eq!(submatrix[(0, 1)], base + 1); - assert_eq!(submatrix[(0, 2)], base + 2); - - assert_eq!(submatrix[(1, 0)], base + 1); - assert_eq!(submatrix[(1, 1)], base + 2); - assert_eq!(submatrix[(1, 2)], base + 3); - }); - - // Try again, but with a batch size of 3 to ensure that we correctly handle cases - // where the last block is under-sized. - let batchsize = 3; - m.par_window_iter(batchsize) - .enumerate() - .for_each(|(i, submatrix)| { - if i == 0 { - assert_eq!(submatrix.nrows(), batchsize); - assert_eq!(submatrix.ncols(), m.ncols()); - - // Check indexing - assert_eq!(submatrix[(0, 0)], 0); - assert_eq!(submatrix[(0, 1)], 1); - assert_eq!(submatrix[(0, 2)], 2); - - assert_eq!(submatrix[(1, 0)], 1); - assert_eq!(submatrix[(1, 1)], 2); - assert_eq!(submatrix[(1, 2)], 3); - - assert_eq!(submatrix[(2, 0)], 2); - assert_eq!(submatrix[(2, 1)], 3); - assert_eq!(submatrix[(2, 2)], 4); - } else { - assert_eq!(submatrix.nrows(), 1); - assert_eq!(submatrix.ncols(), m.ncols()); - - // Check indexing - assert_eq!(submatrix[(0, 0)], 3); - assert_eq!(submatrix[(0, 1)], 4); - assert_eq!(submatrix[(0, 2)], 5); - } - }); - - // par-row-iter - let seen_rows: Box<[usize]> = m - .par_row_iter() - .enumerate() - .map(|(i, row)| { - let expected: Box<[usize]> = (0..m.ncols()).map(|j| j + i).collect(); - assert_eq!(row, &*expected); - i - }) - .collect(); - - let expected: Box<[usize]> = (0..m.nrows()).collect(); - assert_eq!(seen_rows, expected); - } - - fn test_basic_indexing(m: &MatrixBase) - where - T: DenseData + Sync, - { - assert_eq!(m.nrows(), 4); - assert_eq!(m.ncols(), 3); - - // Basic indexing - assert_eq!(m[(0, 0)], 0); - assert_eq!(m[(0, 1)], 1); - assert_eq!(m[(0, 2)], 2); - - assert_eq!(m[(1, 0)], 1); - assert_eq!(m[(1, 1)], 2); - assert_eq!(m[(1, 2)], 3); - - assert_eq!(m[(2, 0)], 2); - assert_eq!(m[(2, 1)], 3); - assert_eq!(m[(2, 2)], 4); - - assert_eq!(m[(3, 0)], 3); - assert_eq!(m[(3, 1)], 4); - assert_eq!(m[(3, 2)], 5); - - // Row indexing. - assert_eq!(m.row(0), &[0, 1, 2]); - assert_eq!(m.row(1), &[1, 2, 3]); - assert_eq!(m.row(2), &[2, 3, 4]); - assert_eq!(m.row(3), &[3, 4, 5]); - - let rows: Vec> = m.row_iter().map(|x| x.to_vec()).collect(); - assert_eq!(m.row(0), &rows[0]); - assert_eq!(m.row(1), &rows[1]); - assert_eq!(m.row(2), &rows[2]); - assert_eq!(m.row(3), &rows[3]); - - // Window Iters. - let batchsize = 2; - m.window_iter(batchsize) - .enumerate() - .for_each(|(i, submatrix)| { - assert_eq!(submatrix.nrows(), batchsize); - assert_eq!(submatrix.ncols(), m.ncols()); - - // Make sure we are in the correct window of the original matrix. - let base = i * batchsize; - assert_eq!(submatrix[(0, 0)], base); - assert_eq!(submatrix[(0, 1)], base + 1); - assert_eq!(submatrix[(0, 2)], base + 2); - - assert_eq!(submatrix[(1, 0)], base + 1); - assert_eq!(submatrix[(1, 1)], base + 2); - assert_eq!(submatrix[(1, 2)], base + 3); - }); - - // Try again, but with a batch size of 3 to ensure that we correctly handle cases - // where the last block is under-sized. - let batchsize = 3; - m.window_iter(batchsize) - .enumerate() - .for_each(|(i, submatrix)| { - if i == 0 { - assert_eq!(submatrix.nrows(), batchsize); - assert_eq!(submatrix.ncols(), m.ncols()); - - // Check indexing - assert_eq!(submatrix[(0, 0)], 0); - assert_eq!(submatrix[(0, 1)], 1); - assert_eq!(submatrix[(0, 2)], 2); - - assert_eq!(submatrix[(1, 0)], 1); - assert_eq!(submatrix[(1, 1)], 2); - assert_eq!(submatrix[(1, 2)], 3); - - assert_eq!(submatrix[(2, 0)], 2); - assert_eq!(submatrix[(2, 1)], 3); - assert_eq!(submatrix[(2, 2)], 4); - } else { - assert_eq!(submatrix.nrows(), 1); - assert_eq!(submatrix.ncols(), m.ncols()); - - // Check indexing - assert_eq!(submatrix[(0, 0)], 3); - assert_eq!(submatrix[(0, 1)], 4); - assert_eq!(submatrix[(0, 2)], 5); - } - }); - - #[cfg(all(not(miri), feature = "rayon"))] - test_basic_indexing_parallel(m.as_view()); - } - - #[test] - fn matrix_happy_path() { - let data = make_test_matrix(); - let m = Matrix::try_from(data.into(), 4, 3).unwrap(); - test_basic_indexing(&m); - - // Get the base pointer of the matrix and make sure view-conversion preserves this - // value. - let ptr = m.as_ptr(); - let view = m.as_view(); - assert!(is_copyable(view)); - assert_eq!(view.as_ptr(), ptr); - assert_eq!(view.nrows(), m.nrows()); - assert_eq!(view.ncols(), m.ncols()); - test_basic_indexing(&view); - } - - #[test] - fn matrix_try_from_construction_error() { - let data = make_test_matrix(); - let ptr = data.as_ptr(); - let len = data.len(); - - let m = Matrix::try_from(data.into(), 5, 4); - assert!(m.is_err()); - let err = m.unwrap_err(); - assert_eq!( - err.to_string(), - "tried to construct a matrix view with 5 rows and 4 columns over a slice of length 12" - ); - - // Make sure that we can retrieve the original allocation from the interior. - let data = err.into_inner(); - assert_eq!(data.as_ptr(), ptr); - assert_eq!(data.len(), len); - - let m = MatrixView::try_from(&data, 5, 4); - assert!(m.is_err()); - assert_eq!( - m.unwrap_err().to_string(), - "tried to construct a matrix view with 5 rows and 4 columns over a slice of length 12" - ); - } - - #[test] - fn matrix_mut_view() { - let mut m = Matrix::::new(0, 4, 3); - assert_eq!(m.nrows(), 4); - assert_eq!(m.ncols(), 3); - assert!(m.as_slice().iter().all(|&i| i == 0)); - let ptr = m.as_ptr(); - let mut_ptr = m.as_mut_ptr(); - assert_eq!(ptr, mut_ptr); - - let mut view = m.as_mut_view(); - assert_eq!(view.nrows(), 4); - assert_eq!(view.ncols(), 3); - assert_eq!(view.as_ptr(), ptr); - assert_eq!(view.as_mut_ptr(), mut_ptr); - - // Construct the test matrix manually. - for i in 0..view.nrows() { - for j in 0..view.ncols() { - view[(i, j)] = i + j; - } - } - - // Drop the view and test the original matrix. - test_basic_indexing(&m); - - let inner = m.into_inner(); - assert_eq!(inner.as_ptr(), ptr); - assert_eq!(inner.len(), 4 * 3); - } - - #[test] - fn matrix_view_zero_sizes() { - let data: Vec = vec![]; - // Zero rows, but non-zero columns. - let m = MatrixView::try_from(data.as_slice(), 0, 10).unwrap(); - assert_eq!(m.nrows(), 0); - assert_eq!(m.ncols(), 10); - - // Non-zero rows, but zero columns. - let m = MatrixView::try_from(data.as_slice(), 3, 0).unwrap(); - assert_eq!(m.nrows(), 3); - assert_eq!(m.ncols(), 0); - let empty: &[usize] = &[]; - assert_eq!(m.row(0), empty); - assert_eq!(m.row(1), empty); - assert_eq!(m.row(2), empty); - - // Zero rows and columns. - let m = MatrixView::try_from(data.as_slice(), 0, 0).unwrap(); - assert_eq!(m.nrows(), 0); - assert_eq!(m.ncols(), 0); - } - - #[test] - fn matrix_view_construction_elementwise() { - let mut m = Matrix::::new(0, 4, 3); - - // Construct the test matrix manually. - for i in 0..m.nrows() { - for j in 0..m.ncols() { - m[(i, j)] = i + j; - } - } - test_basic_indexing(&m); - } - - #[test] - fn matrix_construction_by_row() { - let mut m = Matrix::::new(0, 4, 3); - assert!(m.as_slice().iter().all(|i| *i == 0)); - - let ncols = m.ncols(); - for i in 0..m.nrows() { - let row = m.row_mut(i); - assert_eq!(row.len(), ncols); - row[0] = i; - row[1] = i + 1; - row[2] = i + 2; - } - test_basic_indexing(&m); - } - - #[test] - fn matrix_construction_by_rowiter() { - let mut m = Matrix::::new(0, 4, 3); - assert!(m.as_slice().iter().all(|i| *i == 0)); - - let ncols = m.ncols(); - m.row_iter_mut().enumerate().for_each(|(i, row)| { - assert_eq!(row.len(), ncols); - row[0] = i; - row[1] = i + 1; - row[2] = i + 2; - }); - test_basic_indexing(&m); - } - - #[cfg(all(not(miri), feature = "rayon"))] - #[test] - fn matrix_construction_by_par_windows() { - let mut m = Matrix::::new(0, 4, 3); - assert!(m.as_slice().iter().all(|i| *i == 0)); - - let ncols = m.ncols(); - for batchsize in 1..=4 { - m.par_window_iter_mut(batchsize) - .enumerate() - .for_each(|(i, mut submatrix)| { - let base = i * batchsize; - submatrix.row_iter_mut().enumerate().for_each(|(j, row)| { - assert_eq!(row.len(), ncols); - row[0] = base + j; - row[1] = base + j + 1; - row[2] = base + j + 2; - }); - }); - test_basic_indexing(&m); - } - } - - #[test] - fn matrix_construction_happens_in_memory_order() { - let mut i = 0; - let ncols = 3; - let initializer = Init(|| { - let value = (i % ncols) + (i / ncols); - i += 1; - value - }); - - let m = Matrix::new(initializer, 4, 3); - test_basic_indexing(&m); - } - - // Panics - #[test] - #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] - fn test_get_row_panics() { - let m = Matrix::::new(0, 3, 7); - m.row(3); - } - - #[test] - #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] - fn test_get_row_mut_panics() { - let mut m = Matrix::::new(0, 3, 7); - m.row_mut(3); - } - - #[test] - #[should_panic(expected = "row 3 is out of bounds (max: 3)")] - fn test_index_panics_row() { - let m = Matrix::::new(0, 3, 7); - assert!(m.try_get(3, 2).is_none()); - let _ = m[(3, 2)]; - } - - #[test] - #[should_panic(expected = "col 7 is out of bounds (max: 7)")] - fn test_index_panics_col() { - let m = Matrix::::new(0, 3, 7); - assert!(m.try_get(2, 7).is_none()); - let _ = m[(2, 7)]; - } - - #[test] - #[should_panic(expected = "row 3 is out of bounds (max: 3)")] - fn test_index_mut_panics_row() { - let mut m = Matrix::::new(0, 3, 7); - m[(3, 2)] = 1; - } - - #[test] - #[should_panic(expected = "col 7 is out of bounds (max: 7)")] - fn test_index_mut_panics_col() { - let mut m = Matrix::::new(0, 3, 7); - m[(2, 7)] = 1; - } - - #[test] - #[cfg(feature = "rayon")] - #[should_panic(expected = "par_window_iter batchsize cannot be zero")] - fn test_par_window_iter_panics() { - let m = Matrix::::new(0, 4, 4); - let _ = m.par_window_iter(0); - } - - #[test] - #[cfg(feature = "rayon")] - #[should_panic(expected = "par_window_iter_mut batchsize cannot be zero")] - fn test_par_window_iter_mut_panics() { - let mut m = Matrix::::new(0, 4, 4); - let _ = m.par_window_iter_mut(0); - } - - // Additional tests for better coverage - - #[test] - fn test_box_slice_dense_data_impls() { - // Test Box<[T]> implementations - let data: Box<[f32]> = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0].into(); - let ptr = data.as_ptr(); - let len = data.len(); - - // Test DenseData impl for Box<[T]> - test_dense_data_repr(ptr, len, data, &lazy_format!("Box<[T]> DenseData")); - - // Test MutDenseData impl for Box<[T]> - let mut data: Box<[f32]> = vec![0.0; 6].into(); - set_mut_dense_data_repr(&mut data, 1.0, 2.0); - for (i, &v) in data.iter().enumerate() { - assert_eq!( - v, - 1.0 + 2.0 * (i as f32), - "Box<[T]> MutDenseData at index {}", - i - ); - } - } - - #[test] - fn test_try_from_error_light() { - let data = vec![1, 2, 3]; - let err = MatrixView::try_from(data.as_slice(), 2, 3).unwrap_err(); - - // Test as_static method - let static_err = err.as_static(); - assert_eq!(static_err.len, 3); - assert_eq!(static_err.nrows, 2); - assert_eq!(static_err.ncols, 3); - - // Test Display for TryFromErrorLight - let display_msg = format!("{}", static_err); - assert!(display_msg.contains("tried to construct a matrix view with 2 rows and 3 columns")); - assert!(display_msg.contains("slice of length 3")); - - // Test into_inner method - let recovered_data = err.into_inner(); - assert_eq!(recovered_data, data.as_slice()); - } - - #[test] - fn test_get_row_optional() { - let data = make_test_matrix(); - let m = MatrixView::try_from(data.as_slice(), 4, 3).unwrap(); - - // Test successful get_row - assert_eq!(m.get_row(0), Some(&[0, 1, 2][..])); - assert_eq!(m.get_row(1), Some(&[1, 2, 3][..])); - assert_eq!(m.get_row(3), Some(&[3, 4, 5][..])); - - // Test out-of-bounds get_row - assert_eq!(m.get_row(4), None); - assert_eq!(m.get_row(100), None); - } - - #[test] - fn test_unsafe_get_unchecked_methods() { - let data = make_test_matrix(); - let mut m = Matrix::try_from(data.into(), 4, 3).unwrap(); - - // Safety: derives from known size of matrix and access element ids - unsafe { - assert_eq!(*m.get_unchecked(0, 0), 0); - assert_eq!(*m.get_unchecked(1, 2), 3); - assert_eq!(*m.get_unchecked(3, 1), 4); - } - - // Safety: derives from known size of matrix and access element ids - unsafe { - *m.get_unchecked_mut(0, 0) = 100; - *m.get_unchecked_mut(1, 2) = 200; - } - - assert_eq!(m[(0, 0)], 100); - assert_eq!(m[(1, 2)], 200); - - // Safety: derives from known size of matrix and access element ids - unsafe { - let row0 = m.get_row_unchecked(0); - assert_eq!(row0[0], 100); - assert_eq!(row0[1], 1); - assert_eq!(row0[2], 2); - } - - // Safety: derives from known size of matrix and access element ids - unsafe { - let row1 = m.get_row_unchecked_mut(1); - row1[0] = 300; - } - - assert_eq!(m[(1, 0)], 300); - } - - #[test] - fn test_to_owned() { - let data = make_test_matrix(); - let view = MatrixView::try_from(data.as_slice(), 4, 3).unwrap(); - - // Test to_owned creates a proper clone - let owned = view.to_owned(); - assert_eq!(owned.nrows(), view.nrows()); - assert_eq!(owned.ncols(), view.ncols()); - assert_eq!(owned.as_slice(), view.as_slice()); - - // Verify it's actually owned (different memory location) - assert_ne!(owned.as_ptr(), view.as_ptr()); - - // Test the owned matrix works properly - test_basic_indexing(&owned); - } - - #[test] - fn test_generator_trait_impls() { - // Test Generator impl for T where T: Clone - let mut gen = 42i32; - assert_eq!(gen.generate(), 42); - assert_eq!(gen.generate(), 42); // Should be same value since it's cloned - - // Test Generator impl for Init - let mut counter = 0; - let mut gen = Init(|| { - counter += 1; - counter - }); - assert_eq!(gen.generate(), 1); - assert_eq!(gen.generate(), 2); - assert_eq!(gen.generate(), 3); - } - - #[test] - fn test_matrix_from_conversions() { - let data = make_test_matrix(); - let m = Matrix::try_from(data.into(), 4, 3).unwrap(); - - // Test MatrixView to slice conversion - let view = m.as_view(); - let slice: &[usize] = view.into(); - assert_eq!(slice.len(), 12); - assert_eq!(slice[0], 0); - assert_eq!(slice[11], 5); - - // Test MutMatrixView to slice conversion - let data2 = make_test_matrix(); - let mut m2 = Matrix::try_from(data2.into(), 4, 3).unwrap(); - let mut_view = m2.as_mut_view(); - let slice2: &[usize] = mut_view.into(); - assert_eq!(slice2.len(), 12); - assert_eq!(slice2[0], 0); - assert_eq!(slice2[11], 5); - } - - #[test] - fn test_matrix_construction_edge_cases() { - // Test 1x1 matrix - let m = Matrix::new(42, 1, 1); - assert_eq!(m.nrows(), 1); - assert_eq!(m.ncols(), 1); - assert_eq!(m[(0, 0)], 42); - assert_eq!(*m.try_get(0, 0).unwrap(), 42); - - // Test single row matrix - let m = Matrix::new(7, 1, 5); - assert_eq!(m.nrows(), 1); - assert_eq!(m.ncols(), 5); - assert!(m.as_slice().iter().all(|&x| x == 7)); - - // Test single column matrix - let m = Matrix::new(9, 5, 1); - assert_eq!(m.nrows(), 5); - assert_eq!(m.ncols(), 1); - assert!(m.as_slice().iter().all(|&x| x == 9)); - } - - #[test] - fn test_matrix_view_edge_cases_with_data() { - // Test matrix with actual data for edge cases - let data = vec![10, 20]; - - // 2x1 matrix - let m = MatrixView::try_from(data.as_slice(), 2, 1).unwrap(); - assert_eq!(m.nrows(), 2); - assert_eq!(m.ncols(), 1); - assert_eq!(m[(0, 0)], 10); - assert_eq!(m[(1, 0)], 20); - assert_eq!(*m.try_get(0, 0).unwrap(), 10); - assert_eq!(*m.try_get(1, 0).unwrap(), 20); - assert_eq!(m.row(0), &[10]); - assert_eq!(m.row(1), &[20]); - - // 1x2 matrix - let m = MatrixView::try_from(data.as_slice(), 1, 2).unwrap(); - assert_eq!(m.nrows(), 1); - assert_eq!(m.ncols(), 2); - assert_eq!(m[(0, 0)], 10); - assert_eq!(m[(0, 1)], 20); - assert_eq!(*m.try_get(0, 0).unwrap(), 10); - assert_eq!(*m.try_get(0, 1).unwrap(), 20); - assert_eq!(m.row(0), &[10, 20]); - } - - #[test] - fn test_row_vector() { - let data = vec![1, 2, 3]; - let m = MatrixView::row_vector(data.as_slice()); - assert_eq!(m.nrows(), 1); - assert_eq!(m.ncols(), 3); - assert_eq!(m.as_slice(), &[1, 2, 3]); - assert_eq!(m.row(0), &[1, 2, 3]); - - // Empty - let empty: &[i32] = &[]; - let m = MatrixView::row_vector(empty); - assert_eq!(m.nrows(), 1); - assert_eq!(m.ncols(), 0); - - // Owned - let m = Matrix::row_vector(vec![10u64, 20].into_boxed_slice()); - assert_eq!(m.nrows(), 1); - assert_eq!(m.ncols(), 2); - assert_eq!(m[(0, 0)], 10); - assert_eq!(m[(0, 1)], 20); - } - - #[test] - fn test_column_vector() { - let data = vec![1, 2, 3]; - let m = MatrixView::column_vector(data.as_slice()); - assert_eq!(m.nrows(), 3); - assert_eq!(m.ncols(), 1); - assert_eq!(m.as_slice(), &[1, 2, 3]); - assert_eq!(m[(0, 0)], 1); - assert_eq!(m[(1, 0)], 2); - assert_eq!(m[(2, 0)], 3); - assert_eq!(m.row(0), &[1]); - assert_eq!(m.row(1), &[2]); - assert_eq!(m.row(2), &[3]); - - // Empty - let empty: &[i32] = &[]; - let m = MatrixView::column_vector(empty); - assert_eq!(m.nrows(), 0); - assert_eq!(m.ncols(), 1); - - // Owned - let m = Matrix::column_vector(vec![10u64, 20].into_boxed_slice()); - assert_eq!(m.nrows(), 2); - assert_eq!(m.ncols(), 1); - assert_eq!(m[(0, 0)], 10); - assert_eq!(m[(1, 0)], 20); - } - - #[test] - fn test_map() { - let m = Matrix::try_from(vec![1u32, 2, 3, 4].into(), 2, 2).unwrap(); - let doubled = m.map(|&x| x * 2); - assert_eq!(doubled.as_slice(), &[2, 4, 6, 8]); - assert_eq!(doubled.nrows(), 2); - assert_eq!(doubled.ncols(), 2); - - // Type-changing map - let as_f64 = m.map(|&x| x as f64); - assert_eq!(as_f64.as_slice(), &[1.0, 2.0, 3.0, 4.0]); - } - - #[test] - fn test_try_get() { - let m = Matrix::try_from(vec![1, 2, 3, 4, 5, 6].into(), 2, 3).unwrap(); - assert_eq!(m.try_get(0, 0), Some(&1)); - assert_eq!(m.try_get(1, 2), Some(&6)); - assert_eq!(m.try_get(2, 0), None); - assert_eq!(m.try_get(0, 3), None); - } - - #[test] - fn test_subview() { - let data = make_test_matrix(); - let m = Matrix::try_from(data.into(), 4, 3).unwrap(); - - // Create a subview of the first two rows - { - let subview = m.subview(0..4).unwrap(); - assert_eq!(subview.nrows(), 4); - assert_eq!(subview.ncols(), 3); - - assert_eq!(subview.row(0), &[0, 1, 2]); - assert_eq!(subview.row(1), &[1, 2, 3]); - assert_eq!(subview.row(2), &[2, 3, 4]); - assert_eq!(subview.row(3), &[3, 4, 5]); - assert!(subview.get_row(4).is_none()); - } - - // Sub view over a subset that touches the end. - { - let subview = m.subview(1..4).unwrap(); - assert_eq!(subview.nrows(), 3); - assert_eq!(subview.ncols(), 3); - - assert_eq!(subview.row(0), &[1, 2, 3]); - assert_eq!(subview.row(1), &[2, 3, 4]); - assert_eq!(subview.row(2), &[3, 4, 5]); - assert!(subview.get_row(3).is_none()); - } - - // Sub view over a subset that is in the middle - { - let subview = m.subview(1..3).unwrap(); - assert_eq!(subview.nrows(), 2); - assert_eq!(subview.ncols(), 3); - - assert_eq!(subview.row(0), &[1, 2, 3]); - assert_eq!(subview.row(1), &[2, 3, 4]); - assert!(subview.get_row(2).is_none()); - } - - // Empty sub-view. - { - let subview = m.subview(2..2).unwrap(); - assert_eq!(subview.nrows(), 0); - assert_eq!(subview.ncols(), 3); - } - - // Empty subview in bounds - { - let subview = m.subview(0..0).unwrap(); - assert_eq!(subview.nrows(), 0); - assert_eq!(subview.ncols(), 3); - - let subview = m.subview(4..4).unwrap(); - assert_eq!(subview.nrows(), 0); - assert_eq!(subview.ncols(), 3); - } - - // Empty out-of-bounds subview - assert!(m.subview(5..5).is_none()); - - // View too-large - assert!(m.subview(0..6).is_none()); - assert!(m.subview(2..10).is_none()); - - // View disjoint. - assert!(m.subview(10..100).is_none()); - - // Negative bounds - #[expect( - clippy::reversed_empty_ranges, - reason = "we want to make sure it doesn't work" - )] - let empty = 3..2; - assert!(m.subview(empty).is_none()); - - #[expect( - clippy::reversed_empty_ranges, - reason = "we want to make sure it doesn't work" - )] - let empty = 3..1; - assert!(m.subview(empty).is_none()); - - // Bounds that overflow. - assert!(m.subview(usize::MAX - 1..usize::MAX).is_none()); - assert!(m.subview(0..usize::MAX).is_none()); - } - - #[test] - #[cfg(all(not(miri), feature = "rayon"))] - fn test_parallel_methods_edge_cases() { - let data = make_test_matrix(); - let m = Matrix::try_from(data.into(), 4, 3).unwrap(); - - // Test par_window_iter with batchsize larger than matrix - let windows: Vec<_> = m.par_window_iter(10).collect(); - assert_eq!(windows.len(), 1); - assert_eq!(windows[0].nrows(), 4); - assert_eq!(windows[0].ncols(), 3); - - // Test par_row_iter - let rows: Vec<_> = m.par_row_iter().collect(); - assert_eq!(rows.len(), 4); - assert_eq!(rows[0], &[0, 1, 2]); - assert_eq!(rows[3], &[3, 4, 5]); - - // Test par_window_iter_mut and par_row_iter_mut - let mut m2 = Matrix::new(0, 4, 3); - - // Use par_row_iter_mut to set values - m2.par_row_iter_mut().enumerate().for_each(|(i, row)| { - for (j, elem) in row.iter_mut().enumerate() { - *elem = i + j; - } - }); - test_basic_indexing(&m2); - - // Test par_window_iter_mut with larger batchsize - let mut m3 = Matrix::new(0, 4, 3); - m3.par_window_iter_mut(10) - .enumerate() - .for_each(|(_, mut window)| { - window.row_iter_mut().enumerate().for_each(|(i, row)| { - for (j, elem) in row.iter_mut().enumerate() { - *elem = i + j; - } - }); - }); - test_basic_indexing(&m3); - } - - #[test] - fn test_matrix_pointers() { - let mut m = Matrix::new(42, 3, 4); - - // Test as_ptr and as_mut_ptr return the same address - let const_ptr = m.as_ptr(); - let mut_ptr = m.as_mut_ptr(); - assert_eq!(const_ptr, mut_ptr as *const _); - - // Test that view pointers match original - let view = m.as_view(); - assert_eq!(view.as_ptr(), const_ptr); - - let mut mut_view = m.as_mut_view(); - assert_eq!(mut_view.as_ptr(), const_ptr); - assert_eq!(mut_view.as_mut_ptr(), mut_ptr); - } - - #[test] - fn test_matrix_iteration_empty_cases() { - // Test construction of empty matrices (we don't iterate over 0x0 matrices - // since chunks_exact requires non-zero chunk size) - let empty_data: Vec = vec![]; - - // Matrix with 0 rows but non-zero cols can be constructed - let _empty_matrix = MatrixView::try_from(empty_data.as_slice(), 0, 5).unwrap(); - - // Test with actual single row to verify iterator works normally - let data = vec![1, 2, 3]; - let single_row = MatrixView::try_from(data.as_slice(), 1, 3).unwrap(); - let rows: Vec<_> = single_row.row_iter().collect(); - assert_eq!(rows.len(), 1); - assert_eq!(rows[0], &[1, 2, 3]); - - // Test iteration over matrix with multiple rows but single column - let data = vec![1, 2, 3]; - let single_col = MatrixView::try_from(data.as_slice(), 3, 1).unwrap(); - let rows: Vec<_> = single_col.row_iter().collect(); - assert_eq!(rows.len(), 3); - assert_eq!(rows[0], &[1]); - assert_eq!(rows[1], &[2]); - assert_eq!(rows[2], &[3]); - } - - #[test] - fn test_matrix_init_generator_various_types() { - // Test with different types and generators - use std::sync::atomic::{AtomicUsize, Ordering}; - - let counter = AtomicUsize::new(0); - let m = Matrix::new(Init(|| counter.fetch_add(1, Ordering::SeqCst)), 2, 3); - - // Should be filled in memory order - assert_eq!(m[(0, 0)], 0); - assert_eq!(m[(0, 1)], 1); - assert_eq!(m[(0, 2)], 2); - assert_eq!(m[(1, 0)], 3); - assert_eq!(m[(1, 1)], 4); - assert_eq!(m[(1, 2)], 5); - } - - #[test] - fn test_debug_error_formatting() { - // Test Debug implementation for TryFromError - let data = vec![1, 2, 3]; - let err = Matrix::try_from(data.into(), 2, 3).unwrap_err(); - - let debug_str = format!("{:?}", err); - assert!(debug_str.contains("TryFromError")); - assert!(debug_str.contains("data_len: 3")); - assert!(debug_str.contains("nrows: 2")); - assert!(debug_str.contains("ncols: 3")); - - // Ensure Debug doesn't require T: Debug by using a non-Debug type - #[derive(Clone, Debug)] - struct NonDebug(#[allow(dead_code)] i32); - - let non_debug_data: Box<[NonDebug]> = vec![NonDebug(1), NonDebug(2)].into(); - let non_debug_err = Matrix::try_from(non_debug_data, 1, 3).unwrap_err(); - let debug_str = format!("{:?}", non_debug_err); - assert!(debug_str.contains("TryFromError")); - } - - // Comprehensive tests for rayon-specific functionality - - #[test] - #[cfg(feature = "rayon")] - fn test_par_window_iter_comprehensive() { - use rayon::prelude::*; - - // Create a larger test matrix for more comprehensive testing - let data: Vec = (0..24).collect(); // 6x4 matrix - let m = MatrixView::try_from(data.as_slice(), 6, 4).unwrap(); - - // Test various batch sizes - for batchsize in 1..=8 { - let context = lazy_format!("batchsize = {}", batchsize); - let windows: Vec<_> = m.par_window_iter(batchsize).collect(); - - // Calculate expected number of windows - let expected_windows = (m.nrows()).div_ceil(batchsize); - assert_eq!(windows.len(), expected_windows, "{}", context); - - // Verify each window's properties - let mut total_rows_seen = 0; - for (window_idx, window) in windows.iter().enumerate() { - let expected_rows = if window_idx == windows.len() - 1 { - // Last window may have fewer rows - m.nrows() - (windows.len() - 1) * batchsize - } else { - batchsize - }; - - assert_eq!( - window.nrows(), - expected_rows, - "window {} - {}", - window_idx, - context - ); - assert_eq!( - window.ncols(), - m.ncols(), - "window {} - {}", - window_idx, - context - ); - - // Verify data integrity - for (row_idx, row) in window.row_iter().enumerate() { - let global_row = window_idx * batchsize + row_idx; - let expected: Vec = - (0..m.ncols()).map(|j| global_row * m.ncols() + j).collect(); - assert_eq!( - row, - expected.as_slice(), - "window {}, row {} - {}", - window_idx, - row_idx, - context - ); - } - - total_rows_seen += window.nrows(); - } - - assert_eq!(total_rows_seen, m.nrows(), "{}", context); - } - - // Test with batchsize equal to matrix rows - let windows: Vec<_> = m.par_window_iter(m.nrows()).collect(); - assert_eq!(windows.len(), 1); - assert_eq!(windows[0].nrows(), m.nrows()); - assert_eq!(windows[0].ncols(), m.ncols()); - - // Test with batchsize larger than matrix rows - let windows: Vec<_> = m.par_window_iter(m.nrows() * 2).collect(); - assert_eq!(windows.len(), 1); - assert_eq!(windows[0].nrows(), m.nrows()); - assert_eq!(windows[0].ncols(), m.ncols()); - } - - #[test] - #[cfg(feature = "rayon")] - fn test_par_window_iter_mut_comprehensive() { - use rayon::prelude::*; - - // Test various matrix sizes and batch sizes - for nrows in [1, 2, 3, 5, 8, 10] { - for ncols in [1, 3, 4] { - for batchsize in [1, 2, 3, 7] { - let context = lazy_format!("{}x{}, batchsize={}", nrows, ncols, batchsize); - - let mut m = Matrix::new(0usize, nrows, ncols); - - // Use par_window_iter_mut to fill matrix - m.par_window_iter_mut(batchsize).enumerate().for_each( - |(window_idx, mut window)| { - let base_row = window_idx * batchsize; - window - .row_iter_mut() - .enumerate() - .for_each(|(row_offset, row)| { - let global_row = base_row + row_offset; - for (col, elem) in row.iter_mut().enumerate() { - *elem = global_row * ncols + col; - } - }); - }, - ); - - // Verify the matrix was filled correctly - for row in 0..nrows { - for col in 0..ncols { - let expected = row * ncols + col; - assert_eq!( - m[(row, col)], - expected, - "pos ({}, {}) - {}", - row, - col, - context - ); - } - } - } - } - } - } - - #[test] - #[cfg(feature = "rayon")] - fn test_par_row_iter_comprehensive() { - use rayon::prelude::*; - - // Create test matrix with predictable pattern - let nrows = 7; - let ncols = 5; - let data: Vec = (0..(nrows * ncols) as i32).collect(); - let m = MatrixView::try_from(data.as_slice(), nrows, ncols).unwrap(); - - // Test that par_row_iter preserves order and data - let collected_rows: Vec> = m.par_row_iter().map(|row| row.to_vec()).collect(); - - assert_eq!(collected_rows.len(), nrows); - - for (row_idx, row) in collected_rows.iter().enumerate() { - assert_eq!(row.len(), ncols); - let expected: Vec = ((row_idx * ncols)..((row_idx + 1) * ncols)) - .map(|x| x as i32) - .collect(); - assert_eq!(row, &expected, "row {} mismatch", row_idx); - } - - // Test parallel enumeration - let enumerated_rows: Vec<(usize, Vec)> = m - .par_row_iter() - .enumerate() - .map(|(idx, row)| (idx, row.to_vec())) - .collect(); - - // Sort by index to ensure we got all indices - let mut sorted_rows = enumerated_rows; - sorted_rows.sort_by_key(|(idx, _)| *idx); - - assert_eq!(sorted_rows.len(), nrows); - for (expected_idx, (actual_idx, row)) in sorted_rows.iter().enumerate() { - assert_eq!(*actual_idx, expected_idx); - assert_eq!(row.len(), ncols); - } - - // Test parallel reduction operations - let sum: i32 = m.par_row_iter().map(|row| row.iter().sum::()).sum(); - - let expected_sum: i32 = data.iter().sum(); - assert_eq!(sum, expected_sum); - - // Test parallel find operations - let target_row = 3; - let found_row = m - .par_row_iter() - .enumerate() - .find_any(|(idx, _)| *idx == target_row) - .map(|(_, row)| row.to_vec()); - - assert!(found_row.is_some()); - let expected_row: Vec = ((target_row * ncols)..((target_row + 1) * ncols)) - .map(|x| x as i32) - .collect(); - assert_eq!(found_row.unwrap(), expected_row); - } - - #[test] - #[cfg(feature = "rayon")] - fn test_par_row_iter_mut_comprehensive() { - use rayon::prelude::*; - use std::sync::atomic::{AtomicUsize, Ordering}; - - let nrows = 6; - let ncols = 4; - let mut m = Matrix::new(0u32, nrows, ncols); - - // Test parallel modification - m.par_row_iter_mut().enumerate().for_each(|(row_idx, row)| { - for (col_idx, elem) in row.iter_mut().enumerate() { - *elem = (row_idx * ncols + col_idx) as u32; - } - }); - - // Verify modifications were applied correctly - for row in 0..nrows { - for col in 0..ncols { - let expected = (row * ncols + col) as u32; - assert_eq!(m[(row, col)], expected, "pos ({}, {})", row, col); - } - } - - // Test parallel accumulation with atomic counter - let counter = AtomicUsize::new(0); - m.par_row_iter_mut().for_each(|row| { - counter.fetch_add(1, Ordering::Relaxed); - // Multiply each element by 2 - for elem in row { - *elem *= 2; - } - }); - - assert_eq!(counter.load(Ordering::Relaxed), nrows); - - // Verify all elements were doubled - for row in 0..nrows { - for col in 0..ncols { - let expected = ((row * ncols + col) * 2) as u32; - assert_eq!(m[(row, col)], expected, "doubled pos ({}, {})", row, col); - } - } - } - - #[test] - #[cfg(feature = "rayon")] - fn test_parallel_iterators_with_single_dimensions() { - use rayon::prelude::*; - - // Test single row matrix - let data = vec![1, 2, 3, 4, 5]; - let single_row = MatrixView::try_from(data.as_slice(), 1, 5).unwrap(); - - let windows: Vec<_> = single_row.par_window_iter(1).collect(); - assert_eq!(windows.len(), 1); - assert_eq!(windows[0].nrows(), 1); - assert_eq!(windows[0].ncols(), 5); - - let rows: Vec<_> = single_row.par_row_iter().collect(); - assert_eq!(rows.len(), 1); - assert_eq!(rows[0], &[1, 2, 3, 4, 5]); - - // Test single column matrix - let data = vec![1, 2, 3, 4, 5]; - let single_col = MatrixView::try_from(data.as_slice(), 5, 1).unwrap(); - - let windows: Vec<_> = single_col.par_window_iter(2).collect(); - assert_eq!(windows.len(), 3); // ceil(5/2) = 3 - assert_eq!(windows[0].nrows(), 2); - assert_eq!(windows[1].nrows(), 2); - assert_eq!(windows[2].nrows(), 1); // Last window has remainder - - let rows: Vec<_> = single_col.par_row_iter().collect(); - assert_eq!(rows.len(), 5); - for (i, row) in rows.iter().enumerate() { - assert_eq!(row, &[i + 1]); - } - - // Test 1x1 matrix - let data = vec![42]; - let tiny = MatrixView::try_from(data.as_slice(), 1, 1).unwrap(); - - let windows: Vec<_> = tiny.par_window_iter(1).collect(); - assert_eq!(windows.len(), 1); - assert_eq!(windows[0][(0, 0)], 42); - - let rows: Vec<_> = tiny.par_row_iter().collect(); - assert_eq!(rows.len(), 1); - assert_eq!(rows[0], &[42]); - } - - #[test] - #[cfg(feature = "rayon")] - fn test_parallel_window_properties() { - use rayon::prelude::*; - - // Test that windows maintain proper matrix properties - let data: Vec = (0..30).collect(); - let m = MatrixView::try_from(data.as_slice(), 6, 5).unwrap(); - - // Test window indexing works correctly - m.par_window_iter(2) - .enumerate() - .for_each(|(window_idx, window)| { - for row_idx in 0..window.nrows() { - for col_idx in 0..window.ncols() { - let global_row = window_idx * 2 + row_idx; - let expected = global_row * 5 + col_idx; - assert_eq!( - window[(row_idx, col_idx)], - expected, - "window {}, pos ({}, {})", - window_idx, - row_idx, - col_idx - ); - } - } - }); - - // Test window as_slice consistency - m.par_window_iter(3) - .enumerate() - .for_each(|(window_idx, window)| { - let slice = window.as_slice(); - assert_eq!(slice.len(), window.nrows() * window.ncols()); - - for (slice_idx, &value) in slice.iter().enumerate() { - let row = slice_idx / window.ncols(); - let col = slice_idx % window.ncols(); - assert_eq!( - value, - window[(row, col)], - "window {}, slice_idx {}", - window_idx, - slice_idx - ); - } - }); - - // Test window row iteration - m.par_window_iter(2).for_each(|window| { - let rows_via_iter: Vec<_> = window.row_iter().collect(); - assert_eq!(rows_via_iter.len(), window.nrows()); - - for (row_idx, row) in rows_via_iter.iter().enumerate() { - assert_eq!(row.len(), window.ncols()); - for (col_idx, &value) in row.iter().enumerate() { - assert_eq!(value, window[(row_idx, col_idx)]); - } - } - }); - } - - #[test] - #[cfg(feature = "rayon")] - fn test_parallel_performance_characteristics() { - use rayon::prelude::*; - use std::sync::atomic::{AtomicUsize, Ordering}; - - // Create a larger matrix to test parallelism benefits - let nrows = 100; - let ncols = 10; - let mut m = Matrix::new(0usize, nrows, ncols); - - // Test that parallel operations can be chained - let work_counter = AtomicUsize::new(0); - - m.par_window_iter_mut(10) - .enumerate() - .for_each(|(window_idx, mut window)| { - work_counter.fetch_add(1, Ordering::Relaxed); - - // Nested parallel operation within window - window - .row_iter_mut() - .enumerate() - .for_each(|(row_offset, row)| { - let global_row = window_idx * 10 + row_offset; - for (col, elem) in row.iter_mut().enumerate() { - *elem = global_row * ncols + col; - } - }); - }); - - // Should have processed 10 windows (100 rows / 10 batch size) - assert_eq!(work_counter.load(Ordering::Relaxed), 10); - - // Verify correctness - for row in 0..nrows { - for col in 0..ncols { - assert_eq!(m[(row, col)], row * ncols + col); - } - } - - // Test parallel reduction across windows - let total_sum: usize = m - .par_window_iter(15) - .map(|window| { - window - .row_iter() - .map(|row| row.iter().sum::()) - .sum::() - }) - .sum(); - - let expected_sum: usize = (0..(nrows * ncols)).sum(); - assert_eq!(total_sum, expected_sum); - } - - #[test] - #[cfg(feature = "rayon")] - fn test_rayon_trait_bounds_validation() { - use rayon::prelude::*; - - // Test that the Sync/Send bounds work correctly - let data: Vec = (0..20).collect(); - let m = MatrixView::try_from(data.as_slice(), 4, 5).unwrap(); - - // This should compile because u64 is Sync - let _: Vec<_> = m.par_window_iter(2).collect(); - let _: Vec<_> = m.par_row_iter().collect(); - - // Test with mutable matrix - let mut m = Matrix::new(0u64, 4, 5); - - // This should compile because u64 is Send - m.par_window_iter_mut(2).for_each(|mut window| { - window.row_iter_mut().for_each(|row| { - for elem in row { - *elem = 42; - } - }); - }); - - m.par_row_iter_mut().for_each(|row| { - for elem in row { - *elem += 1; - } - }); - - // Verify all elements are 43 - assert!(m.as_slice().iter().all(|&x| x == 43)); - } -} diff --git a/diskann/src/error/ann_error.rs b/diskann/src/error/ann_error.rs index c27e622c1..afb5ca098 100644 --- a/diskann/src/error/ann_error.rs +++ b/diskann/src/error/ann_error.rs @@ -588,23 +588,13 @@ where } } -impl From for ANNError { +impl From for ANNError { #[track_caller] - fn from(err: diskann_utils::views::TryFromErrorLight) -> Self { + fn from(err: diskann_utils::views::TryFromError) -> Self { ANNError::new(ANNErrorKind::DimensionMismatchError, err) } } -impl From> for ANNError -where - T: diskann_utils::views::DenseData, -{ - #[track_caller] - fn from(err: diskann_utils::views::TryFromError) -> Self { - Self::from(err.as_static()) - } -} - /// An internal wrapper for error types that also tracks the file and line information /// for where the error was first converted and where context was propagated. #[derive(Debug)] @@ -1541,16 +1531,6 @@ Caused by: assert_eq!(ann_err.kind(), ANNErrorKind::IOError); } - #[test] - fn from_try_from_error_light() { - let data: &[f32] = &[1.0, 2.0, 3.0]; - let light = diskann_utils::views::MatrixView::try_from(data, 2, 2) - .unwrap_err() - .as_static(); - let ann_err = ANNError::from(light); - assert_eq!(ann_err.kind(), ANNErrorKind::DimensionMismatchError); - } - #[test] fn from_try_from_error() { let data: &[f32] = &[1.0, 2.0, 3.0]; diff --git a/diskann/src/graph/start_point.rs b/diskann/src/graph/start_point.rs index c829b9dcf..37d197915 100644 --- a/diskann/src/graph/start_point.rs +++ b/diskann/src/graph/start_point.rs @@ -98,7 +98,7 @@ impl StartPointStrategy { let indices = rand::seq::index::sample(&mut rng, train_data.nrows(), nsamples.get()); - let mut points = Matrix::new(T::default(), nsamples.get(), train_data.ncols()); + let mut points = Matrix::from_gen(T::default(), nsamples.get(), train_data.ncols()); std::iter::zip(points.row_iter_mut(), indices).for_each(|(dst, src)| { dst.copy_from_slice(train_data.row(src)); }); @@ -115,7 +115,7 @@ impl StartPointStrategy { } => { let mut rng = StdRng::seed_from_u64(*seed); let dim = train_data.ncols(); - let mut points = Matrix::new(T::default(), nsamples.get(), dim); + let mut points = Matrix::from_gen(T::default(), nsamples.get(), dim); points.row_iter_mut().for_each(|row| { row.copy_from_slice(&WithApproximateNorm::with_approximate_norm( dim, *norm, &mut rng, diff --git a/diskann/src/graph/test/synthetic.rs b/diskann/src/graph/test/synthetic.rs index d3c822b09..1d2851c90 100644 --- a/diskann/src/graph/test/synthetic.rs +++ b/diskann/src/graph/test/synthetic.rs @@ -111,7 +111,7 @@ impl Grid { i += 1; this }); - Matrix::new(init, size, 1) + Matrix::from_gen(init, size, 1) } Self::Two => { let mut v = [0; 2]; @@ -126,7 +126,7 @@ impl Grid { value }); - Matrix::new(init, size.pow(self.dim().into()), 2) + Matrix::from_gen(init, size.pow(self.dim().into()), 2) } Self::Three => { // The whole we do with the array here is to avoid a `Default` bound on `R` @@ -145,7 +145,7 @@ impl Grid { value }); - Matrix::new(init, size.pow(self.dim().into()), 3) + Matrix::from_gen(init, size.pow(self.dim().into()), 3) } Self::Four => { let mut v = [0; 4]; @@ -160,7 +160,7 @@ impl Grid { value }); - Matrix::new(init, size.pow(self.dim().into()), 4) + Matrix::from_gen(init, size.pow(self.dim().into()), 4) } } } From c6abb1e5d130bd42210e71f08452cfca636af8ad Mon Sep 17 00:00:00 2001 From: Suryansh Gupta Date: Tue, 21 Jul 2026 20:55:51 +0530 Subject: [PATCH 2/6] Main merge --- diskann-disk/src/storage/quant/compressor.rs | 4 +- .../src}/matrix.rs | 801 +++++++++++++++--- 2 files changed, 707 insertions(+), 98 deletions(-) rename {diskann-quantization/src/multi_vector => diskann-utils/src}/matrix.rs (70%) diff --git a/diskann-disk/src/storage/quant/compressor.rs b/diskann-disk/src/storage/quant/compressor.rs index acddd8994..dfd82b3a3 100644 --- a/diskann-disk/src/storage/quant/compressor.rs +++ b/diskann-disk/src/storage/quant/compressor.rs @@ -4,7 +4,7 @@ */ use diskann::{utils::VectorRepr, ANNResult}; -use diskann_utils::views::{MatrixView, MutMatrixView}; +use diskann_utils::views::{MatrixView, MatrixViewMut}; /// [`QuantCompressor`] defines the interface for quantizer with [`QuantDataGenerator`] /// @@ -30,6 +30,6 @@ where type CompressorContext; fn new(context: &Self::CompressorContext) -> ANNResult; - fn compress(&self, vector: MatrixView, output: MutMatrixView) -> ANNResult<()>; + fn compress(&self, vector: MatrixView, output: MatrixViewMut) -> ANNResult<()>; fn compressed_bytes(&self) -> usize; } diff --git a/diskann-quantization/src/multi_vector/matrix.rs b/diskann-utils/src/matrix.rs similarity index 70% rename from diskann-quantization/src/multi_vector/matrix.rs rename to diskann-utils/src/matrix.rs index b0cf0954b..bcda8c706 100644 --- a/diskann-quantization/src/multi_vector/matrix.rs +++ b/diskann-utils/src/matrix.rs @@ -29,10 +29,27 @@ use std::{alloc::Layout, iter::FusedIterator, marker::PhantomData, ptr::NonNull}; -use diskann_utils::{Reborrow, ReborrowMut, views::MatrixView}; +use crate::{Reborrow, ReborrowMut}; use thiserror::Error; -use crate::utils; +#[cfg(feature = "rayon")] +use rayon::iter::ParallelIterator; + +// Pointer helpers, kept private so the matrix framework is self-contained in diskann-utils. +fn as_nonnull(slice: &[T]) -> NonNull { + // SAFETY: Slices guarantee non-null pointers. + unsafe { NonNull::new_unchecked(slice.as_ptr().cast_mut()) } +} + +fn as_nonnull_mut(slice: &mut [T]) -> NonNull { + // SAFETY: Slices guarantee non-null pointers. + unsafe { NonNull::new_unchecked(slice.as_mut_ptr()) } +} + +fn box_into_nonnull(b: Box<[T]>) -> NonNull { + // SAFETY: `Box::into_raw` guarantees the returned pointer is non-null. + unsafe { NonNull::new_unchecked(Box::into_raw(b).cast::()) } +} /// Representation trait describing the layout and access patterns for a matrix. /// @@ -235,8 +252,8 @@ pub unsafe trait NewOwned: ReprOwned { /// to initialize a matrix. /// /// ```rust -/// use diskann_quantization::multi_vector::{Mat, Standard, Defaulted}; -/// let mat = Mat::new(Standard::::new(4, 3).unwrap(), Defaulted).unwrap(); +/// use diskann_utils::matrix::{Mat, RowMajor, Defaulted}; +/// let mat = Mat::new(RowMajor::::new(4, 3).unwrap(), Defaulted).unwrap(); /// for i in 0..4 { /// assert!(mat.get_row(i).unwrap().iter().all(|&x| x == 0.0f32)); /// } @@ -253,7 +270,7 @@ pub trait NewCloned: ReprOwned { } ////////////// -// Standard // +// RowMajor // ////////////// /// Metadata for dense row-major matrices. @@ -266,33 +283,33 @@ pub trait NewCloned: ReprOwned { /// - `Row<'a>`: `&'a [T]` /// - `RowMut<'a>`: `&'a mut [T]` #[derive(Debug)] -pub struct Standard { +pub struct RowMajor { nrows: usize, ncols: usize, _elem: PhantomData, } -// Hand-written so `Standard` is `Copy`/`Clone`/`PartialEq`/`Eq` for every `T`: it only +// Hand-written so `RowMajor` is `Copy`/`Clone`/`PartialEq`/`Eq` for every `T`: it only // stores two `usize` and a `PhantomData`, so derives would spuriously require the same // bound on `T` (and the `Repr: Copy` supertrait must hold regardless of the element type). -impl Copy for Standard {} +impl Copy for RowMajor {} -impl Clone for Standard { +impl Clone for RowMajor { fn clone(&self) -> Self { *self } } -impl PartialEq for Standard { +impl PartialEq for RowMajor { fn eq(&self, other: &Self) -> bool { self.nrows == other.nrows && self.ncols == other.ncols } } -impl Eq for Standard {} +impl Eq for RowMajor {} -impl Standard { - /// Create a new `Standard` for data of type `T`. +impl RowMajor { + /// Create a new `RowMajor` for data of type `T`. /// /// Successful construction requires: /// @@ -346,11 +363,11 @@ impl Standard { /// /// # Safety /// - /// The length of `b` must be exactly [`Standard::num_elements`]. + /// The length of `b` must be exactly [`RowMajor::num_elements`]. unsafe fn box_to_mat(self, b: Box<[T]>) -> Mat { debug_assert_eq!(b.len(), self.num_elements(), "safety contract violated"); - let ptr = utils::box_into_nonnull(b).cast::(); + let ptr = box_into_nonnull(b).cast::(); // SAFETY: `ptr` is properly aligned and points to a slice of the required length. // Additionally, it is dropped via `Box::from_raw`, which is compatible with obtaining @@ -359,7 +376,7 @@ impl Standard { } } -/// Error for [`Standard::new`]. +/// Error for [`RowMajor::new`]. #[derive(Debug, Clone, Copy)] pub struct Overflow { nrows: usize, @@ -369,7 +386,7 @@ pub struct Overflow { impl Overflow { /// Construct an `Overflow` error for the given dimensions and element type. - pub(crate) fn for_type(nrows: usize, ncols: usize) -> Self { + pub fn for_type(nrows: usize, ncols: usize) -> Self { Self { nrows, ncols, @@ -382,7 +399,7 @@ impl Overflow { /// /// On failure the error reports the original `(nrows, ncols)` dimensions rather /// than the padded capacity. - pub(crate) fn check_byte_budget( + pub fn check_byte_budget( capacity: usize, nrows: usize, ncols: usize, @@ -425,7 +442,7 @@ impl std::fmt::Display for Overflow { impl std::error::Error for Overflow {} -/// Error types for [`Standard`]. +/// Error types for [`RowMajor`]. #[derive(Debug, Clone, Copy, Error)] #[non_exhaustive] pub enum SliceError { @@ -436,7 +453,7 @@ pub enum SliceError { // SAFETY: The implementation correctly computes row offsets as `i * ncols` and // constructs valid slices of the appropriate length. The `layout` method correctly // reports the memory layout requirements. -unsafe impl Repr for Standard { +unsafe impl Repr for RowMajor { type Row<'a> = &'a [T] where @@ -466,7 +483,7 @@ unsafe impl Repr for Standard { // SAFETY: The implementation correctly computes row offsets and constructs valid mutable // slices. -unsafe impl ReprMut for Standard { +unsafe impl ReprMut for RowMajor { type RowMut<'a> = &'a mut [T] where @@ -490,7 +507,7 @@ unsafe impl ReprMut for Standard { // SAFETY: The drop implementation correctly reconstructs a Box from the raw pointer // using the same length (nrows * ncols) that was used for allocation, allowing Box // to properly deallocate the memory. -unsafe impl ReprOwned for Standard { +unsafe impl ReprOwned for RowMajor { unsafe fn drop(self, ptr: NonNull) { // SAFETY: The caller guarantees that `ptr` was obtained from an implementation of // `NewOwned` for an equivalent instance of `self`. @@ -509,11 +526,11 @@ unsafe impl ReprOwned for Standard { // SAFETY: The implementation uses guarantees from `Box` to ensure that the pointer // initialized by it is non-null and properly aligned to the underlying type. -unsafe impl NewOwned for Standard +unsafe impl NewOwned for RowMajor where T: Clone, { - type Error = crate::error::Infallible; + type Error = std::convert::Infallible; fn new_owned(self, value: T) -> Result, Self::Error> { let b: Box<[T]> = std::iter::repeat_n(value, self.num_elements()).collect(); @@ -524,11 +541,11 @@ where // SAFETY: The implementation uses guarantees from `Box` to ensure that the pointer // initialized by it is non-null and properly aligned to the underlying type. -unsafe impl NewOwned for Standard +unsafe impl NewOwned for RowMajor where T: Default, { - type Error = crate::error::Infallible; + type Error = std::convert::Infallible; fn new_owned(self, _: Defaulted) -> Result, Self::Error> { let b: Box<[T]> = std::iter::repeat_with(T::default) .take(self.num_elements()) @@ -541,35 +558,35 @@ where // SAFETY: This checks that the slice has the correct length, which is all that is // required for [`Repr`]. -unsafe impl NewRef for Standard { +unsafe impl NewRef for RowMajor { type Error = SliceError; fn new_ref(self, data: &[T]) -> Result, Self::Error> { self.check_slice(data)?; // SAFETY: The function `check_slice` verifies that `data` is compatible with - // the layout requirement of `Standard`. + // the layout requirement of `RowMajor`. // // We've properly checked that the underlying pointer is okay. - Ok(unsafe { MatRef::from_raw_parts(self, utils::as_nonnull(data).cast::()) }) + Ok(unsafe { MatRef::from_raw_parts(self, as_nonnull(data).cast::()) }) } } // SAFETY: This checks that the slice has the correct length, which is all that is // required for [`ReprMut`]. -unsafe impl NewMut for Standard { +unsafe impl NewMut for RowMajor { type Error = SliceError; fn new_mut(self, data: &mut [T]) -> Result, Self::Error> { self.check_slice(data)?; // SAFETY: The function `check_slice` verifies that `data` is compatible with - // the layout requirement of `Standard`. + // the layout requirement of `RowMajor`. // // We've properly checked that the underlying pointer is okay. - Ok(unsafe { MatMut::from_raw_parts(self, utils::as_nonnull_mut(data).cast::()) }) + Ok(unsafe { MatMut::from_raw_parts(self, as_nonnull_mut(data).cast::()) }) } } -impl NewCloned for Standard +impl NewCloned for RowMajor where T: Clone, { @@ -635,7 +652,10 @@ impl Mat { } } - pub(crate) unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { + /// # Safety + /// + /// `i` must be less than `self.num_vectors()`. + pub unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { // SAFETY: Caller must ensure i < self.num_vectors(). The constructors for this type // ensure that `ptr` is compatible with `T`. unsafe { self.repr.get_row(self.ptr, i) } @@ -697,7 +717,7 @@ impl Mat { /// /// 1. Point to memory compatible with [`Repr::layout`]. /// 2. Be compatible with the drop logic in [`ReprOwned`]. - pub(crate) unsafe fn from_raw_parts(repr: T, ptr: NonNull) -> Self { + pub unsafe fn from_raw_parts(repr: T, ptr: NonNull) -> Self { Self { ptr, repr, @@ -711,7 +731,7 @@ impl Mat { } /// Return a mutable base pointer for the [`Mat`]. - pub(crate) fn as_raw_mut_ptr(&mut self) -> *mut u8 { + pub fn as_raw_mut_ptr(&mut self) -> *mut u8 { self.ptr.as_ptr() } } @@ -730,10 +750,11 @@ impl Clone for Mat { } } -impl Mat> { - /// Construct a [`Mat`] by calling `f` once per element in row-major order. - pub fn from_fn T>(repr: Standard, mut f: F) -> Self { - let b: Box<[T]> = (0..repr.num_elements()).map(|_| f()).collect(); +impl Mat> { + /// Construct a [`Mat`] by filling each element in row-major order from `gen`. + pub fn from_gen>(mut gen: U, nrows: usize, ncols: usize) -> Self { + let repr = RowMajor::new(nrows, ncols).expect("dimension overflow"); + let b: Box<[T]> = (0..repr.num_elements()).map(|_| gen.generate()).collect(); // SAFETY: `b` has length `repr.num_elements()` by construction. unsafe { repr.box_to_mat(b) } } @@ -827,7 +848,10 @@ impl<'a, T: Repr> MatRef<'a, T> { /// /// `i` must be less than `self.num_vectors()`. #[inline] - pub(crate) unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { + /// # Safety + /// + /// `i` must be less than `self.num_vectors()`. + pub unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { // SAFETY: Caller must ensure i < self.num_vectors(). unsafe { self.repr.get_row(self.ptr, i) } } @@ -866,7 +890,7 @@ impl<'a, T: Repr> MatRef<'a, T> { } } -impl<'a, T> MatRef<'a, Standard> { +impl<'a, T> MatRef<'a, RowMajor> { /// Returns the raw dimension (columns) of the vectors in the matrix. #[inline] pub fn vector_dim(&self) -> usize { @@ -879,19 +903,15 @@ impl<'a, T> MatRef<'a, Standard> { #[inline] pub fn as_slice(&self) -> &'a [T] { let len = self.repr.num_elements(); - // SAFETY: `Standard` guarantees `nrows * ncols` contiguous `T` elements + // SAFETY: `RowMajor` guarantees `nrows * ncols` contiguous `T` elements // starting at `self.ptr`. The lifetime `'a` is tied to the original data. unsafe { std::slice::from_raw_parts(self.ptr.as_ptr().cast::(), len) } } /// Return a [`MatrixView`] over the backing data. - #[allow(clippy::expect_used)] #[inline] pub fn as_matrix_view(&self) -> MatrixView<'a, T> { - // `Standard::new` validates that `nrows * ncols` does not overflow, - // so `try_from` is infallible here. - MatrixView::try_from(self.as_slice(), self.num_vectors(), self.vector_dim()) - .expect("Standard has valid dimensions") + *self } } @@ -994,7 +1014,10 @@ impl<'a, T: ReprMut> MatMut<'a, T> { /// /// `i` must be less than `self.num_vectors()`. #[inline] - pub(crate) unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { + /// # Safety + /// + /// `i` must be less than `self.num_vectors()`. + pub unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { // SAFETY: Caller must ensure i < self.num_vectors(). unsafe { self.repr.get_row(self.ptr, i) } } @@ -1070,7 +1093,7 @@ impl<'a, T: ReprMut> MatMut<'a, T> { } /// Return a mutable base pointer for the [`MatMut`]. - pub(crate) fn as_raw_mut_ptr(&mut self) -> *mut u8 { + pub fn as_raw_mut_ptr(&mut self) -> *mut u8 { self.ptr.as_ptr() } } @@ -1097,7 +1120,7 @@ impl<'this, 'a, T: ReprMut> ReborrowMut<'this> for MatMut<'a, T> { } } -impl<'a, T> MatMut<'a, Standard> { +impl<'a, T> MatMut<'a, RowMajor> { /// Returns the raw dimension (columns) of the vectors in the matrix. #[inline] pub fn vector_dim(&self) -> usize { @@ -1119,6 +1142,592 @@ impl<'a, T> MatMut<'a, Standard> { } } +////////////////////////////// +// Dense (RowMajor) API + aliases +////////////////////////////// + +/// A generator for initializing matrix entries via [`Matrix::from_gen`]. +pub trait Generator { + fn generate(&mut self) -> T; +} + +impl Generator for T +where + T: Clone, +{ + fn generate(&mut self) -> T { + self.clone() + } +} + +/// A [`Generator`] that invokes a closure to initialize each element. +pub struct Init(pub F); + +impl Generator for Init +where + F: FnMut() -> T, +{ + fn generate(&mut self) -> T { + (self.0)() + } +} + +/// Owned dense row-major matrix. +pub type Matrix = Mat>; + +/// Shared dense row-major view. +pub type MatrixView<'a, T> = MatRef<'a, RowMajor>; + +/// Mutable dense row-major view. +pub type MatrixViewMut<'a, T> = MatMut<'a, RowMajor>; + +/// Error returned when a slice length is incompatible with the requested dimensions. +#[derive(Debug, Error)] +#[error("cannot view a slice of length {len} as a {nrows}x{ncols} matrix")] +pub struct TryFromError { + pub len: usize, + pub nrows: usize, + pub ncols: usize, +} + +impl<'a, T> MatRef<'a, RowMajor> { + /// View `data` as an `nrows x ncols` matrix. + pub fn try_from(data: &'a [T], nrows: usize, ncols: usize) -> Result { + let err = || TryFromError { len: data.len(), nrows, ncols }; + let repr = RowMajor::new(nrows, ncols).map_err(|_| err())?; + MatRef::new(repr, data).map_err(|_| err()) + } + + /// View `data` as a single-row matrix. + pub fn row_vector(data: &'a [T]) -> Self { + let ncols = data.len(); + Self::try_from(data, 1, ncols).expect("row vector length") + } + + /// View `data` as a single-column matrix. + pub fn column_vector(data: &'a [T]) -> Self { + let nrows = data.len(); + Self::try_from(data, nrows, 1).expect("column vector length") + } + + /// Number of rows. + #[inline] + pub fn nrows(&self) -> usize { + self.num_vectors() + } + + /// Number of columns. + #[inline] + pub fn ncols(&self) -> usize { + self.vector_dim() + } + + /// Row `i`. Panics if `i >= self.nrows()`. + pub fn row(&self, i: usize) -> &'a [T] { + let ncols = self.ncols(); + &self.as_slice()[i * ncols..i * ncols + ncols] + } + + /// Iterator over rows. + pub fn row_iter(&self) -> impl ExactSizeIterator { + self.as_slice().chunks_exact(self.ncols()) + } + + /// Iterator over sub-matrices of up to `batchsize` rows. + /// + /// # Panics + /// Panics if `batchsize == 0`. + pub fn window_iter(&self, batchsize: usize) -> impl Iterator> { + assert!(batchsize != 0, "window_iter batchsize cannot be zero"); + let ncols = self.ncols(); + self.as_slice() + .chunks(ncols * batchsize) + .map(move |d| MatrixView::try_from(d, d.len() / ncols, ncols).expect("exact chunk")) + } + + /// Parallel iterator over rows. + #[cfg(feature = "rayon")] + pub fn par_row_iter(&self) -> impl rayon::iter::IndexedParallelIterator + where + T: Sync, + { + use rayon::slice::ParallelSlice; + self.as_slice().par_chunks_exact(self.ncols()) + } + + /// Parallel iterator over sub-matrices of up to `batchsize` rows. + /// + /// # Panics + /// Panics if `batchsize == 0`. + #[cfg(feature = "rayon")] + pub fn par_window_iter( + &self, + batchsize: usize, + ) -> impl rayon::iter::IndexedParallelIterator> + where + T: Send + Sync, + { + use rayon::slice::ParallelSlice; + assert!(batchsize != 0, "par_window_iter batchsize cannot be zero"); + let ncols = self.ncols(); + self.as_slice() + .par_chunks(ncols * batchsize) + .map(move |d| MatrixView::try_from(d, d.len() / ncols, ncols).expect("exact chunk")) + } + + /// View of the rows in `rows`, or `None` if out of bounds. + pub fn subview(&self, rows: std::ops::Range) -> Option> { + let ncols = self.ncols(); + let lo = rows.start.checked_mul(ncols)?; + let hi = rows.end.checked_mul(ncols)?; + let data = self.as_slice().get(lo..hi)?; + Some(MatrixView::try_from(data, rows.len(), ncols).expect("exact subview")) + } + + /// Element at `(row, col)`, or `None` if out of bounds. + pub fn try_get(&self, row: usize, col: usize) -> Option<&'a T> { + if row >= self.nrows() || col >= self.ncols() { + None + } else { + let ncols = self.ncols(); + self.as_slice().get(row * ncols + col) + } + } + + /// Base pointer of the backing data. + pub fn as_ptr(&self) -> *const T { + self.as_slice().as_ptr() + } + + /// Apply `f` to every element, producing a new owned matrix of the same shape. + pub fn map(&self, f: F) -> Matrix + where + F: FnMut(&T) -> R, + { + let data: Box<[R]> = self.as_slice().iter().map(f).collect(); + Matrix::try_from(data, self.nrows(), self.ncols()).expect("same shape") + } +} + +impl<'a, T> MatMut<'a, RowMajor> { + /// View `data` as an `nrows x ncols` mutable matrix. + pub fn try_from( + data: &'a mut [T], + nrows: usize, + ncols: usize, + ) -> Result { + let len = data.len(); + let err = || TryFromError { len, nrows, ncols }; + let repr = RowMajor::new(nrows, ncols).map_err(|_| err())?; + MatMut::new(repr, data).map_err(|_| err()) + } + + /// Number of rows. + #[inline] + pub fn nrows(&self) -> usize { + self.num_vectors() + } + + /// Number of columns. + #[inline] + pub fn ncols(&self) -> usize { + self.vector_dim() + } + + /// Backing data as a mutable slice. + pub fn as_mut_slice(&mut self) -> &mut [T] { + let len = self.nrows() * self.ncols(); + // SAFETY: the backing allocation holds `len` contiguous `T`, and `&mut self` grants + // exclusive access for the returned slice's lifetime. + unsafe { std::slice::from_raw_parts_mut(self.as_raw_mut_ptr().cast::(), len) } + } + + /// Row `i`. Panics if `i >= self.nrows()`. + pub fn row(&self, i: usize) -> &[T] { + self.as_view().row(i) + } + + /// Iterator over rows. + pub fn row_iter(&self) -> impl ExactSizeIterator { + let ncols = self.ncols(); + self.as_slice().chunks_exact(ncols) + } + + /// Mutable row `i`. Panics if `i >= self.nrows()`. + pub fn row_mut(&mut self, i: usize) -> &mut [T] { + let ncols = self.ncols(); + &mut self.as_mut_slice()[i * ncols..i * ncols + ncols] + } + + /// Iterator over mutable rows. + pub fn row_iter_mut(&mut self) -> impl ExactSizeIterator { + let ncols = self.ncols(); + self.as_mut_slice().chunks_exact_mut(ncols) + } + + /// Parallel iterator over mutable rows. + #[cfg(feature = "rayon")] + pub fn par_row_iter_mut( + &mut self, + ) -> impl rayon::iter::IndexedParallelIterator + where + T: Send, + { + use rayon::slice::ParallelSliceMut; + let ncols = self.ncols(); + self.as_mut_slice().par_chunks_exact_mut(ncols) + } + + /// Element at `(row, col)`, or `None` if out of bounds. + pub fn try_get(&self, row: usize, col: usize) -> Option<&T> { + self.as_view().try_get(row, col) + } + + /// Base pointer of the backing data. + pub fn as_mut_ptr(&mut self) -> *mut T { + self.as_mut_slice().as_mut_ptr() + } +} + +impl Mat> { + /// Fill a new `nrows x ncols` matrix with clones of `value`. + pub fn filled(value: T, nrows: usize, ncols: usize) -> Self + where + T: Clone, + { + Self::from_gen(value, nrows, ncols) + } + + /// Take ownership of `data`, interpreting it as an `nrows x ncols` matrix. + pub fn try_from(data: Box<[T]>, nrows: usize, ncols: usize) -> Result { + let err = TryFromError { + len: data.len(), + nrows, + ncols, + }; + let repr = match RowMajor::new(nrows, ncols) { + Ok(repr) if repr.num_elements() == data.len() => repr, + _ => return Err(err), + }; + // SAFETY: `data.len()` was checked to equal `repr.num_elements()`. + Ok(unsafe { repr.box_to_mat(data) }) + } + + /// Take ownership of `data` as a single-row matrix. + pub fn row_vector(data: Box<[T]>) -> Self { + let ncols = data.len(); + Self::try_from(data, 1, ncols).expect("row vector length") + } + + /// Take ownership of `data` as a single-column matrix. + pub fn column_vector(data: Box<[T]>) -> Self { + let nrows = data.len(); + Self::try_from(data, nrows, 1).expect("column vector length") + } + + /// Number of rows. + #[inline] + pub fn nrows(&self) -> usize { + self.num_vectors() + } + + /// Number of columns. + #[inline] + pub fn ncols(&self) -> usize { + self.vector_dim() + } + + /// Backing data as a mutable slice. + pub fn as_mut_slice(&mut self) -> &mut [T] { + let len = self.nrows() * self.ncols(); + // SAFETY: the backing allocation holds `len` contiguous `T`, and `&mut self` grants + // exclusive access for the returned slice's lifetime. + unsafe { std::slice::from_raw_parts_mut(self.as_raw_mut_ptr().cast::(), len) } + } + + /// Mutable view over the whole matrix. + pub fn as_mut_view(&mut self) -> MatrixViewMut<'_, T> { + self.as_view_mut() + } + + /// Row `i`. Panics if `i >= self.nrows()`. + pub fn row(&self, i: usize) -> &[T] { + self.as_view().row(i) + } + + /// Iterator over rows. + pub fn row_iter(&self) -> impl ExactSizeIterator { + let ncols = self.ncols(); + self.as_slice().chunks_exact(ncols) + } + + /// Mutable row `i`. Panics if `i >= self.nrows()`. + pub fn row_mut(&mut self, i: usize) -> &mut [T] { + let ncols = self.ncols(); + &mut self.as_mut_slice()[i * ncols..i * ncols + ncols] + } + + /// Iterator over mutable rows. + pub fn row_iter_mut(&mut self) -> impl ExactSizeIterator { + let ncols = self.ncols(); + self.as_mut_slice().chunks_exact_mut(ncols) + } + + /// Iterator over sub-matrices of up to `batchsize` rows. + pub fn window_iter(&self, batchsize: usize) -> impl Iterator> { + assert!(batchsize != 0, "window_iter batchsize cannot be zero"); + let ncols = self.ncols(); + self.as_slice() + .chunks(ncols * batchsize) + .map(move |d| MatrixView::try_from(d, d.len() / ncols, ncols).expect("exact chunk")) + } + + /// Parallel iterator over rows. + #[cfg(feature = "rayon")] + pub fn par_row_iter(&self) -> impl rayon::iter::IndexedParallelIterator + where + T: Sync, + { + use rayon::slice::ParallelSlice; + let ncols = self.ncols(); + self.as_slice().par_chunks_exact(ncols) + } + + /// Parallel iterator over mutable rows. + #[cfg(feature = "rayon")] + pub fn par_row_iter_mut(&mut self) -> impl rayon::iter::IndexedParallelIterator + where + T: Send, + { + use rayon::slice::ParallelSliceMut; + let ncols = self.ncols(); + self.as_mut_slice().par_chunks_exact_mut(ncols) + } + + /// Parallel iterator over sub-matrices of up to `batchsize` rows. + #[cfg(feature = "rayon")] + pub fn par_window_iter( + &self, + batchsize: usize, + ) -> impl rayon::iter::IndexedParallelIterator> + where + T: Send + Sync, + { + use rayon::slice::ParallelSlice; + assert!(batchsize != 0, "par_window_iter batchsize cannot be zero"); + let ncols = self.ncols(); + self.as_slice() + .par_chunks(ncols * batchsize) + .map(move |d| MatrixView::try_from(d, d.len() / ncols, ncols).expect("exact chunk")) + } + + /// Parallel iterator over mutable sub-matrices of up to `batchsize` rows. + #[cfg(feature = "rayon")] + pub fn par_window_iter_mut( + &mut self, + batchsize: usize, + ) -> impl rayon::iter::IndexedParallelIterator> + where + T: Send, + { + use rayon::slice::ParallelSliceMut; + assert!(batchsize != 0, "par_window_iter_mut batchsize cannot be zero"); + let ncols = self.ncols(); + self.as_mut_slice() + .par_chunks_mut(ncols * batchsize) + .map(move |d| { + let nrows = d.len() / ncols; + MatrixViewMut::try_from(d, nrows, ncols).expect("exact chunk") + }) + } + + /// View of the rows in `rows`, or `None` if out of bounds. + pub fn subview(&self, rows: std::ops::Range) -> Option> { + self.as_view().subview(rows) + } + + /// Element at `(row, col)`, or `None` if out of bounds. + pub fn try_get(&self, row: usize, col: usize) -> Option<&T> { + self.as_view().try_get(row, col) + } + + /// Base pointer of the backing data. + pub fn as_ptr(&self) -> *const T { + self.as_slice().as_ptr() + } + + /// Mutable base pointer of the backing data. + pub fn as_mut_ptr(&mut self) -> *mut T { + self.as_mut_slice().as_mut_ptr() + } + + /// Apply `f` to every element, producing a new owned matrix of the same shape. + pub fn map(&self, f: F) -> Matrix + where + F: FnMut(&T) -> R, + { + self.as_view().map(f) + } +} + +// Indexing by `(row, col)`. +impl std::ops::Index<(usize, usize)> for Mat> { + type Output = T; + fn index(&self, (row, col): (usize, usize)) -> &T { + self.try_get(row, col).expect("index out of bounds") + } +} + +impl std::ops::IndexMut<(usize, usize)> for Mat> { + fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T { + let ncols = self.ncols(); + assert!(row < self.nrows() && col < ncols, "index out of bounds"); + &mut self.as_mut_slice()[row * ncols + col] + } +} + +impl std::ops::Index<(usize, usize)> for MatRef<'_, RowMajor> { + type Output = T; + fn index(&self, (row, col): (usize, usize)) -> &T { + self.try_get(row, col).expect("index out of bounds") + } +} + +impl std::ops::Index<(usize, usize)> for MatMut<'_, RowMajor> { + type Output = T; + fn index(&self, (row, col): (usize, usize)) -> &T { + self.try_get(row, col).expect("index out of bounds") + } +} + +impl std::ops::IndexMut<(usize, usize)> for MatMut<'_, RowMajor> { + fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T { + let ncols = self.ncols(); + assert!(row < self.nrows() && col < ncols, "index out of bounds"); + &mut self.as_mut_slice()[row * ncols + col] + } +} + +// Equality compares shape and contents. +impl PartialEq for Mat> { + fn eq(&self, other: &Self) -> bool { + self.ncols() == other.ncols() && self.as_slice() == other.as_slice() + } +} + +impl PartialEq for MatRef<'_, RowMajor> { + fn eq(&self, other: &Self) -> bool { + self.ncols() == other.ncols() && self.as_slice() == other.as_slice() + } +} + +impl PartialEq for MatMut<'_, RowMajor> { + fn eq(&self, other: &Self) -> bool { + self.ncols() == other.ncols() && self.as_slice() == other.as_slice() + } +} + +impl<'a, T> MatRef<'a, RowMajor> { + /// Reborrow as a shorter-lived view. + pub fn as_view(&self) -> MatrixView<'_, T> { + self.reborrow() + } + + /// Element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &'a T { + let ncols = self.ncols(); + // SAFETY: guaranteed in-bounds by the caller. + unsafe { self.as_slice().get_unchecked(row * ncols + col) } + } +} + +impl<'a, T> MatMut<'a, RowMajor> { + /// Reborrow as a shorter-lived mutable view. + pub fn as_mut_view(&mut self) -> MatrixViewMut<'_, T> { + self.reborrow_mut() + } + + /// Element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T { + // SAFETY: guaranteed in-bounds by the caller. + unsafe { self.as_view().get_unchecked(row, col) } + } + + /// Mutable element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + pub unsafe fn get_unchecked_mut(&mut self, row: usize, col: usize) -> &mut T { + let ncols = self.ncols(); + // SAFETY: guaranteed in-bounds by the caller. + unsafe { self.as_mut_slice().get_unchecked_mut(row * ncols + col) } + } + + /// Parallel iterator over mutable sub-matrices of up to `batchsize` rows. + #[cfg(feature = "rayon")] + pub fn par_window_iter_mut( + &mut self, + batchsize: usize, + ) -> impl rayon::iter::IndexedParallelIterator> + where + T: Send, + { + use rayon::slice::ParallelSliceMut; + assert!(batchsize != 0, "par_window_iter_mut batchsize cannot be zero"); + let ncols = self.ncols(); + self.as_mut_slice() + .par_chunks_mut(ncols * batchsize) + .map(move |d| { + let nrows = d.len() / ncols; + MatrixViewMut::try_from(d, nrows, ncols).expect("exact chunk") + }) + } +} + +impl Mat> { + /// Element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T { + // SAFETY: guaranteed in-bounds by the caller. + unsafe { self.as_view().get_unchecked(row, col) } + } + + /// Mutable element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + pub unsafe fn get_unchecked_mut(&mut self, row: usize, col: usize) -> &mut T { + let ncols = self.ncols(); + // SAFETY: guaranteed in-bounds by the caller. + unsafe { self.as_mut_slice().get_unchecked_mut(row * ncols + col) } + } + + /// Consume the matrix, returning its backing storage as a `Box<[T]>`. + pub fn into_inner(self) -> Box<[T]> { + let len = self.nrows() * self.ncols(); + let this = core::mem::ManuallyDrop::new(self); + let ptr = this.as_raw_ptr().cast::().cast_mut(); + // SAFETY: the matrix is backed by a `Box<[T]>` of `len` elements (see + // `RowMajor::box_to_mat`); `ManuallyDrop` prevents a double free via `Mat`'s `Drop`. + unsafe { Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr, len)) } + } +} + +// A dense view converts directly to its backing slice. +impl<'a, T> From>> for &'a [T] { + fn from(m: MatRef<'a, RowMajor>) -> Self { + m.as_slice() + } +} + ////////// // Rows // ////////// @@ -1236,7 +1845,7 @@ mod tests { use std::fmt::Display; - use diskann_utils::lazy_format; + use crate::lazy_format; /// Helper to assert a type is Copy. fn assert_copy(_: &T) {} @@ -1256,10 +1865,10 @@ mod tests { v } - /// `MatRef` is covariant in `T`: `Standard<&'long u8>` → `Standard<&'short u8>`. + /// `MatRef` is covariant in `T`: `RowMajor<&'long u8>` → `RowMajor<&'short u8>`. fn _assert_matref_covariant_repr<'long: 'short, 'short, 'a>( - v: MatRef<'a, Standard<&'long u8>>, - ) -> MatRef<'a, Standard<&'short u8>> { + v: MatRef<'a, RowMajor<&'long u8>>, + ) -> MatRef<'a, RowMajor<&'short u8>> { v } @@ -1285,7 +1894,7 @@ mod tests { ] } - fn fill_mat(x: &mut Mat>, repr: Standard) { + fn fill_mat(x: &mut Mat>, repr: RowMajor) { assert_eq!(x.repr(), &repr); assert_eq!(x.num_vectors(), repr.nrows()); assert_eq!(x.vector_dim(), repr.ncols()); @@ -1303,7 +1912,7 @@ mod tests { } } - fn fill_mat_mut(mut x: MatMut<'_, Standard>, repr: Standard) { + fn fill_mat_mut(mut x: MatMut<'_, RowMajor>, repr: RowMajor) { assert_eq!(x.repr(), &repr); assert_eq!(x.num_vectors(), repr.nrows()); assert_eq!(x.vector_dim(), repr.ncols()); @@ -1322,7 +1931,7 @@ mod tests { } } - fn fill_rows_mut(x: RowsMut<'_, Standard>, repr: Standard) { + fn fill_rows_mut(x: RowsMut<'_, RowMajor>, repr: RowMajor) { assert_eq!(x.len(), repr.nrows()); // Materialize all rows at once. let mut all_rows: Vec<_> = x.collect(); @@ -1335,7 +1944,7 @@ mod tests { } } - fn check_mat(x: &Mat>, repr: Standard, ctx: &dyn Display) { + fn check_mat(x: &Mat>, repr: RowMajor, ctx: &dyn Display) { assert_eq!(x.repr(), &repr); assert_eq!(x.num_vectors(), repr.nrows()); assert_eq!(x.vector_dim(), repr.ncols()); @@ -1361,7 +1970,7 @@ mod tests { } } - fn check_mat_ref(x: MatRef<'_, Standard>, repr: Standard, ctx: &dyn Display) { + fn check_mat_ref(x: MatRef<'_, RowMajor>, repr: RowMajor, ctx: &dyn Display) { assert_eq!(x.repr(), &repr); assert_eq!(x.num_vectors(), repr.nrows()); assert_eq!(x.vector_dim(), repr.ncols()); @@ -1388,7 +1997,7 @@ mod tests { } } - fn check_mat_mut(x: MatMut<'_, Standard>, repr: Standard, ctx: &dyn Display) { + fn check_mat_mut(x: MatMut<'_, RowMajor>, repr: RowMajor, ctx: &dyn Display) { assert_eq!(x.repr(), &repr); assert_eq!(x.num_vectors(), repr.nrows()); assert_eq!(x.vector_dim(), repr.ncols()); @@ -1414,7 +2023,7 @@ mod tests { } } - fn check_rows(x: Rows<'_, Standard>, repr: Standard, ctx: &dyn Display) { + fn check_rows(x: Rows<'_, RowMajor>, repr: RowMajor, ctx: &dyn Display) { assert_eq!(x.len(), repr.nrows(), "ctx: {ctx}"); let all_rows: Vec<_> = x.collect(); assert_eq!(all_rows.len(), repr.nrows(), "ctx: {ctx}"); @@ -1434,12 +2043,12 @@ mod tests { } ////////////// - // Standard // + // RowMajor // ////////////// #[test] fn standard_representation() { - let repr = Standard::::new(4, 3).unwrap(); + let repr = RowMajor::::new(4, 3).unwrap(); assert_eq!(repr.nrows(), 4); assert_eq!(repr.ncols(), 3); @@ -1451,7 +2060,7 @@ mod tests { #[test] fn standard_zero_dimensions() { for (nrows, ncols) in [(0, 0), (0, 5), (5, 0)] { - let repr = Standard::::new(nrows, ncols).unwrap(); + let repr = RowMajor::::new(nrows, ncols).unwrap(); assert_eq!(repr.nrows(), nrows); assert_eq!(repr.ncols(), ncols); let layout = repr.layout().unwrap(); @@ -1461,7 +2070,7 @@ mod tests { #[test] fn standard_check_slice() { - let repr = Standard::::new(3, 4).unwrap(); + let repr = RowMajor::::new(3, 4).unwrap(); // Correct length succeeds let data = vec![0u32; 12]; @@ -1488,31 +2097,31 @@ mod tests { )); // Overflow case - let overflow_repr = Standard::::new(usize::MAX, 2).unwrap_err(); + let overflow_repr = RowMajor::::new(usize::MAX, 2).unwrap_err(); assert!(matches!(overflow_repr, Overflow { .. })); } #[test] fn standard_new_rejects_element_count_overflow() { // nrows * ncols overflows usize even though per-element size is small. - assert!(Standard::::new(usize::MAX, 2).is_err()); - assert!(Standard::::new(2, usize::MAX).is_err()); - assert!(Standard::::new(usize::MAX, usize::MAX).is_err()); + assert!(RowMajor::::new(usize::MAX, 2).is_err()); + assert!(RowMajor::::new(2, usize::MAX).is_err()); + assert!(RowMajor::::new(usize::MAX, usize::MAX).is_err()); } #[test] fn standard_new_rejects_byte_count_exceeding_isize_max() { // Element count fits in usize, but total bytes exceed isize::MAX. let half = (isize::MAX as usize / std::mem::size_of::()) + 1; - assert!(Standard::::new(half, 1).is_err()); - assert!(Standard::::new(1, half).is_err()); + assert!(RowMajor::::new(half, 1).is_err()); + assert!(RowMajor::::new(1, half).is_err()); } #[test] fn standard_new_accepts_boundary_below_isize_max() { // Largest allocation that still fits in isize::MAX bytes. let max_elems = isize::MAX as usize / std::mem::size_of::(); - let repr = Standard::::new(max_elems, 1).unwrap(); + let repr = RowMajor::::new(max_elems, 1).unwrap(); assert_eq!(repr.num_elements(), max_elems); } @@ -1520,25 +2129,25 @@ mod tests { fn standard_new_zst_rejects_element_count_overflow() { // For ZSTs the byte count is always 0, but element-count overflow // must still be caught so that `num_elements()` never wraps. - assert!(Standard::<()>::new(usize::MAX, 2).is_err()); - assert!(Standard::<()>::new(usize::MAX / 2 + 1, 3).is_err()); + assert!(RowMajor::<()>::new(usize::MAX, 2).is_err()); + assert!(RowMajor::<()>::new(usize::MAX / 2 + 1, 3).is_err()); } #[test] fn standard_new_zst_accepts_large_non_overflowing() { // Large-but-valid ZST matrix: element count fits in usize. - let repr = Standard::<()>::new(usize::MAX, 1).unwrap(); + let repr = RowMajor::<()>::new(usize::MAX, 1).unwrap(); assert_eq!(repr.num_elements(), usize::MAX); assert_eq!(repr.layout().unwrap().size(), 0); } #[test] fn standard_new_overflow_error_display() { - let err = Standard::::new(usize::MAX, 2).unwrap_err(); + let err = RowMajor::::new(usize::MAX, 2).unwrap_err(); let msg = err.to_string(); assert!(msg.contains("would exceed isize::MAX bytes"), "{msg}"); - let zst_err = Standard::<()>::new(usize::MAX, 2).unwrap_err(); + let zst_err = RowMajor::<()>::new(usize::MAX, 2).unwrap_err(); let zst_msg = zst_err.to_string(); assert!(zst_msg.contains("ZST matrix"), "{zst_msg}"); assert!(zst_msg.contains("usize::MAX"), "{zst_msg}"); @@ -1550,7 +2159,7 @@ mod tests { #[test] fn mat_new_and_basic_accessors() { - let mat = Mat::new(Standard::::new(3, 4).unwrap(), 42usize).unwrap(); + let mat = Mat::new(RowMajor::::new(3, 4).unwrap(), 42usize).unwrap(); let base: *const u8 = mat.as_raw_ptr(); assert_eq!(mat.num_vectors(), 3); @@ -1572,7 +2181,7 @@ mod tests { #[test] fn mat_new_with_default() { - let mat = Mat::new(Standard::::new(2, 3).unwrap(), Defaulted).unwrap(); + let mat = Mat::new(RowMajor::::new(2, 3).unwrap(), Defaulted).unwrap(); let base: *const u8 = mat.as_raw_ptr(); assert_eq!(mat.num_vectors(), 2); @@ -1594,7 +2203,7 @@ mod tests { fn test_mat() { for nrows in ROWS { for ncols in COLS { - let repr = Standard::::new(*nrows, *ncols).unwrap(); + let repr = RowMajor::::new(*nrows, *ncols).unwrap(); let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols); // Populate the matrix using `&mut Mat` @@ -1653,7 +2262,7 @@ mod tests { fn test_mat_clone() { for nrows in ROWS { for ncols in COLS { - let repr = Standard::::new(*nrows, *ncols).unwrap(); + let repr = RowMajor::::new(*nrows, *ncols).unwrap(); let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols); let mut mat = Mat::new(repr, Defaulted).unwrap(); @@ -1712,7 +2321,7 @@ mod tests { fn test_mat_refmut() { for nrows in ROWS { for ncols in COLS { - let repr = Standard::::new(*nrows, *ncols).unwrap(); + let repr = RowMajor::::new(*nrows, *ncols).unwrap(); let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols); // Populate the matrix using `&mut Mat` @@ -1781,7 +2390,7 @@ mod tests { for nrows in rows { for ncols in cols { - let m = Mat::new(Standard::new(nrows, ncols).unwrap(), 1usize).unwrap(); + let m = Mat::new(RowMajor::new(nrows, ncols).unwrap(), 1usize).unwrap(); let rows_iter = m.rows(); let len = <_ as ExactSizeIterator>::len(&rows_iter); assert_eq!(len, nrows); @@ -1801,11 +2410,11 @@ mod tests { for nrows in rows { for ncols in cols { let mut counter = 0u32; - let m = Mat::from_fn(Standard::new(nrows, ncols).unwrap(), || { + let m = Mat::from_gen(Init(|| { let v = counter; counter += 1; v - }); + }), nrows, ncols); assert_eq!(counter as usize, nrows * ncols); for (i, row) in m.rows().enumerate() { @@ -1820,7 +2429,7 @@ mod tests { #[test] fn matref_new_slice_length_error() { - let repr = Standard::::new(3, 4).unwrap(); + let repr = RowMajor::::new(3, 4).unwrap(); // Correct length succeeds let data = vec![0u32; 12]; @@ -1849,7 +2458,7 @@ mod tests { #[test] fn matmut_new_slice_length_error() { - let repr = Standard::::new(3, 4).unwrap(); + let repr = RowMajor::::new(3, 4).unwrap(); // Correct length succeeds let mut data = vec![0u32; 12]; @@ -1881,7 +2490,7 @@ mod tests { let data = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; // MatRef - let matref = MatRef::new(Standard::new(2, 3).unwrap(), &data).unwrap(); + let matref = MatRef::new(RowMajor::new(2, 3).unwrap(), &data).unwrap(); let view = matref.as_matrix_view(); assert_eq!(view.nrows(), 2); assert_eq!(view.ncols(), 3); @@ -1893,7 +2502,7 @@ mod tests { assert_eq!(matref.as_slice(), &data); // Mat - let mut mat = Mat::new(Standard::::new(2, 3).unwrap(), 0.0f32).unwrap(); + let mut mat = Mat::new(RowMajor::::new(2, 3).unwrap(), 0.0f32).unwrap(); for i in 0..2 { let r = mat.get_row_mut(i).unwrap(); for j in 0..3 { @@ -1912,7 +2521,7 @@ mod tests { // MatMut let mut buf = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; - let matmut = MatMut::new(Standard::new(2, 3).unwrap(), &mut buf).unwrap(); + let matmut = MatMut::new(RowMajor::new(2, 3).unwrap(), &mut buf).unwrap(); let view = matmut.as_matrix_view(); assert_eq!(view.nrows(), 2); assert_eq!(view.ncols(), 3); @@ -1926,7 +2535,7 @@ mod tests { #[test] fn test_standard_non_copy_element() { - let repr = Standard::::new(2, 3).unwrap(); + let repr = RowMajor::::new(2, 3).unwrap(); // Owned fill via NewOwned (Clone). let filled = Mat::new(repr, String::from("x")).unwrap(); @@ -1939,11 +2548,11 @@ mod tests { // from_fn. let mut counter = 0usize; - let mut mat = Mat::from_fn(repr, || { + let mut mat = Mat::from_gen(Init(|| { let s = counter.to_string(); counter += 1; s - }); + }), 2, 3); assert_eq!(counter, 6); assert_eq!(mat.get_row(1).unwrap()[0], "3"); @@ -1958,12 +2567,12 @@ mod tests { // Immutable view over a non-Copy slice (NewRef). let data = [String::from("a"), String::from("b")]; - let view = MatRef::new(Standard::new(2, 1).unwrap(), &data).unwrap(); + let view = MatRef::new(RowMajor::new(2, 1).unwrap(), &data).unwrap(); assert_eq!(view.get_row(1).unwrap()[0], "b"); // Mutable view over a non-Copy slice (NewMut). let mut data_mut = [String::from("a"), String::from("b")]; - let mut view_mut = MatMut::new(Standard::new(1, 2).unwrap(), &mut data_mut).unwrap(); + let mut view_mut = MatMut::new(RowMajor::new(1, 2).unwrap(), &mut data_mut).unwrap(); view_mut.get_row_mut(0).unwrap()[1] = String::from("z"); assert_eq!(data_mut[1], "z"); } From 440645748f7868841c76f9ebbe0f05062b01001c Mon Sep 17 00:00:00 2001 From: Suryansh Gupta Date: Wed, 22 Jul 2026 03:22:54 +0530 Subject: [PATCH 3/6] Improve module structure --- .../src/build/graph/multi.rs | 2 +- .../src/build/graph/single.rs | 2 +- diskann-benchmark-core/src/recall.rs | 42 ++-- diskann-benchmark-core/src/search/api.rs | 4 +- .../src/search/graph/inline.rs | 6 +- .../src/search/graph/knn.rs | 6 +- .../src/search/graph/multihop.rs | 6 +- .../src/search/graph/range.rs | 6 +- diskann-benchmark-core/src/search/ids.rs | 12 +- .../streaming/executors/bigann/withdata.rs | 2 +- diskann-benchmark-simd/src/lib.rs | 6 +- diskann-benchmark/src/disk_index/search.rs | 2 +- diskann-benchmark/src/exhaustive/algos.rs | 6 +- diskann-benchmark/src/exhaustive/minmax.rs | 6 +- diskann-benchmark/src/exhaustive/product.rs | 7 +- diskann-benchmark/src/exhaustive/spherical.rs | 6 +- diskann-benchmark/src/flat/search.rs | 2 +- diskann-benchmark/src/index/benchmarks.rs | 2 +- .../index/bftree/full_precision_streaming.rs | 2 +- .../src/index/bftree/spherical.rs | 2 +- .../src/index/bftree/spherical_streaming.rs | 2 +- diskann-benchmark/src/index/build.rs | 2 +- diskann-benchmark/src/index/inmem/product.rs | 2 +- diskann-benchmark/src/index/inmem/scalar.rs | 2 +- .../src/index/inmem/spherical.rs | 2 +- .../src/index/streaming/full_precision.rs | 2 +- .../src/index/streaming/managed.rs | 2 +- diskann-benchmark/src/utils/datafiles.rs | 8 +- diskann-bftree/src/provider.rs | 30 +-- diskann-bftree/src/quant.rs | 6 +- diskann-disk/src/build/builder/quantizer.rs | 2 +- .../src/search/pq/quantizer_preprocess.rs | 2 +- .../src/search/provider/disk_provider.rs | 4 +- diskann-disk/src/storage/quant/compressor.rs | 2 +- diskann-disk/src/storage/quant/generator.rs | 12 +- .../src/storage/quant/pq/pq_dataset.rs | 2 +- .../src/storage/quant/pq/pq_generation.rs | 6 +- diskann-garnet/src/provider.rs | 6 +- diskann-garnet/src/quantization.rs | 8 +- diskann-providers/src/index/diskann_async.rs | 24 +-- .../provider/async_/inmem/full_precision.rs | 4 +- .../graph/provider/async_/inmem/scalar.rs | 2 +- .../graph/provider/async_/inmem/spherical.rs | 6 +- .../graph/provider/determinant_diversity.rs | 12 +- diskann-providers/src/model/pq/debug.rs | 10 +- .../src/model/pq/fixed_chunk_pq_table.rs | 4 +- .../src/model/pq/pq_construction.rs | 2 +- diskann-providers/src/model/pq/strided.rs | 4 +- diskann-providers/src/model/pq/views.rs | 8 +- .../src/storage/index_storage.rs | 2 +- diskann-providers/src/storage/pq_storage.rs | 6 +- .../src/test_utils/search_utils.rs | 2 +- diskann-providers/src/utils/file_util.rs | 4 +- diskann-providers/src/utils/storage_utils.rs | 2 +- .../src/algorithms/hadamard.rs | 16 +- .../src/algorithms/kmeans/lloyds.rs | 58 +++--- .../src/algorithms/kmeans/plusplus.rs | 50 ++--- .../algorithms/transforms/random_rotation.rs | 10 +- diskann-quantization/src/binary/quantizer.rs | 4 +- .../src/minmax/multi/max_sim.rs | 8 +- diskann-quantization/src/minmax/multi/meta.rs | 45 ++-- diskann-quantization/src/minmax/multi/mod.rs | 10 +- .../src/multi_vector/block_transposed.rs | 18 +- .../src/multi_vector/distance/factory.rs | 2 +- .../src/multi_vector/distance/fallback.rs | 8 +- .../distance/kernels/tiled_reduce.rs | 8 +- .../src/multi_vector/distance/mod.rs | 4 +- diskann-quantization/src/multi_vector/mod.rs | 14 +- .../src/product/tables/basic.rs | 107 +++++----- .../src/product/tables/test.rs | 44 ++-- .../src/product/tables/transposed/pivots.rs | 17 +- .../src/product/tables/transposed/table.rs | 44 ++-- diskann-quantization/src/product/train.rs | 24 +-- diskann-quantization/src/scalar/mod.rs | 4 +- diskann-quantization/src/scalar/quantizer.rs | 10 +- diskann-quantization/src/scalar/train.rs | 4 +- diskann-quantization/src/spherical/iface.rs | 6 +- .../src/spherical/quantizer.rs | 14 +- diskann-quantization/src/test_util.rs | 4 +- diskann-quantization/src/utils.rs | 8 +- diskann-quantization/src/views.rs | 2 +- .../tests/compile-fail/multi/mat_as_view.rs | 2 +- .../compile-fail/multi/mat_as_view_mut.rs | 2 +- .../tests/compile-fail/multi/mat_get_row.rs | 2 +- .../compile-fail/multi/mat_get_row_mut.rs | 2 +- .../tests/compile-fail/multi/mat_invariant.rs | 2 +- .../tests/compile-fail/multi/mat_reborrow.rs | 2 +- .../compile-fail/multi/mat_reborrow_mut.rs | 2 +- .../tests/compile-fail/multi/mat_rows.rs | 2 +- .../tests/compile-fail/multi/mat_rows_mut.rs | 2 +- .../multi/matmut_as_view_borrows.rs | 2 +- .../compile-fail/multi/matmut_get_row.rs | 2 +- .../compile-fail/multi/matmut_get_row_mut.rs | 2 +- .../compile-fail/multi/matmut_invariant.rs | 2 +- .../compile-fail/multi/matmut_reborrow.rs | 2 +- .../compile-fail/multi/matmut_reborrow_mut.rs | 2 +- .../tests/compile-fail/multi/matmut_rows.rs | 2 +- .../compile-fail/multi/matmut_rows_mut.rs | 2 +- .../compile-fail/multi/matref_get_row.rs | 2 +- .../tests/compile-fail/multi/matref_rows.rs | 2 +- diskann-tools/src/utils/ground_truth.rs | 2 +- diskann-utils/src/io.rs | 8 +- diskann-utils/src/lib.rs | 3 +- diskann-utils/src/matrix.rs | 194 ++++++++++++------ diskann-utils/src/sampling/latin_hypercube.rs | 20 +- diskann-utils/src/sampling/medoid.rs | 30 +-- diskann-utils/src/strided.rs | 49 +++-- diskann-utils/src/views.rs | 73 ------- diskann/src/error/ann_error.rs | 6 +- diskann/src/flat/test/provider.rs | 2 +- diskann/src/graph/glue.rs | 4 +- diskann/src/graph/start_point.rs | 6 +- diskann/src/graph/test/cases/grid_insert.rs | 2 +- diskann/src/graph/test/provider.rs | 2 +- diskann/src/graph/test/synthetic.rs | 10 +- diskann/src/graph/workingset/map.rs | 6 +- 116 files changed, 650 insertions(+), 671 deletions(-) delete mode 100644 diskann-utils/src/views.rs diff --git a/diskann-benchmark-core/src/build/graph/multi.rs b/diskann-benchmark-core/src/build/graph/multi.rs index f5eed11bc..62153b067 100644 --- a/diskann-benchmark-core/src/build/graph/multi.rs +++ b/diskann-benchmark-core/src/build/graph/multi.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, glue}, provider, }; -use diskann_utils::{future::AsyncFriendly, views::Matrix}; +use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; use crate::build::{Build, ids::ToId}; diff --git a/diskann-benchmark-core/src/build/graph/single.rs b/diskann-benchmark-core/src/build/graph/single.rs index 96a367b6a..906b0cf2f 100644 --- a/diskann-benchmark-core/src/build/graph/single.rs +++ b/diskann-benchmark-core/src/build/graph/single.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, glue}, provider, }; -use diskann_utils::{future::AsyncFriendly, views::Matrix}; +use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; use crate::build::{Build, ids::ToId}; diff --git a/diskann-benchmark-core/src/recall.rs b/diskann-benchmark-core/src/recall.rs index 776a8edaa..f284100d3 100644 --- a/diskann-benchmark-core/src/recall.rs +++ b/diskann-benchmark-core/src/recall.rs @@ -9,8 +9,8 @@ use std::{ }; use diskann_utils::{ + matrix::{Matrix, MatrixView}, strided::StridedView, - views::{Matrix, MatrixView}, }; use thiserror::Error; @@ -364,7 +364,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::views::{self, Matrix}; + use diskann_utils::{Matrix, matrix}; use super::*; @@ -379,8 +379,8 @@ mod tests { #[test] fn test_rows() { let mut i = 0usize; - let mat = Matrix::from_gen( - views::Init(|| { + let mat = Matrix::new( + matrix::Init(|| { let v = i; i += 1; v @@ -558,16 +558,16 @@ mod tests { #[test] fn test_error_recall_k_and_n() { - let groundtruth = Matrix::::from_gen(0, 10, 10); - let results = Matrix::::from_gen(0, 10, 10); + let groundtruth = Matrix::::new(0, 10, 10); + let results = Matrix::::new(0, 10, 10); 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::::from_gen(0, 11, 10); - let results = Matrix::::from_gen(0, 10, 10); + let groundtruth = Matrix::::new(0, 11, 10); + let results = Matrix::::new(0, 10, 10); let err = knn(&groundtruth, None, &results, 10, 10, GroundTruthMode::Fixed).unwrap_err(); assert!(matches!(err, ComputeRecallError::RowsMismatch(..))); let err_allow_insufficient_results = @@ -580,8 +580,8 @@ mod tests { #[test] fn test_error_not_enough_groundtruth() { - let groundtruth = Matrix::::from_gen(0, 10, 5); - let results = Matrix::::from_gen(0, 10, 10); + let groundtruth = Matrix::::new(0, 10, 5); + let results = Matrix::::new(0, 10, 10); let err = knn(&groundtruth, None, &results, 10, 10, GroundTruthMode::Fixed).unwrap_err(); assert!(matches!(err, ComputeRecallError::NotEnoughGroundTruth(..))); let err_allow_insufficient_results = @@ -595,7 +595,7 @@ mod tests { #[test] fn test_dynamic_groundtruth_valid() { let groundtruth: Vec<_> = (0..10).map(|_| vec![0u32; 5]).collect(); - let results = Matrix::::from_gen(0, 10, 10); + let results = Matrix::::new(0, 10, 10); // 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( @@ -618,7 +618,7 @@ mod tests { fn test_dynamic_groundtruth_full_match() { let gt_row: Vec = (1..=5).collect(); let groundtruth: Vec<_> = (0..10).map(|_| gt_row.clone()).collect(); - let mut results = Matrix::::from_gen(0, 10, 10); + let mut results = Matrix::::new(0, 10, 10); for i in 0..10 { for (j, v) in (1u32..=10).enumerate() { results[(i, j)] = v; @@ -641,7 +641,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 = (1..=5).collect(); let groundtruth: Vec<_> = (0..10).map(|_| gt_row.clone()).collect(); - let mut results = Matrix::::from_gen(0, 10, 10); + let mut results = Matrix::::new(0, 10, 10); let res_row: Vec = vec![1, 2, 3, 6, 7, 8, 9, 10, 11, 12]; for i in 0..10 { for (j, &v) in res_row.iter().enumerate() { @@ -672,7 +672,7 @@ mod tests { groundtruth.push(vec![]); } - let mut results = Matrix::::from_gen(0, 10, 10); + let mut results = Matrix::::new(0, 10, 10); for i in 0..10 { for (j, v) in (1u32..=10).enumerate() { results[(i, j)] = v; @@ -695,7 +695,7 @@ mod tests { #[test] fn test_dynamic_groundtruth_all_zero() { let groundtruth: Vec> = (0..10).map(|_| vec![]).collect(); - let results = Matrix::::from_gen(0, 10, 10); + let results = Matrix::::new(0, 10, 10); let recall = knn( &groundtruth, @@ -752,9 +752,9 @@ mod tests { #[test] fn test_error_distance_rows_mismatch() { - let groundtruth = Matrix::::from_gen(0, 10, 10); - let distances = Matrix::::from_gen(0.0, 9, 10); - let results = Matrix::::from_gen(0, 10, 10); + let groundtruth = Matrix::::new(0, 10, 10); + let distances = Matrix::::new(0.0, 9, 10); + let results = Matrix::::new(0, 10, 10); let err = knn( &groundtruth, Some(distances.as_view().into()), @@ -769,9 +769,9 @@ mod tests { #[test] fn test_error_distance_cols_mismatch() { - let groundtruth = Matrix::::from_gen(0, 10, 10); - let distances = Matrix::::from_gen(0.0, 10, 9); - let results = Matrix::::from_gen(0, 10, 10); + let groundtruth = Matrix::::new(0, 10, 10); + let distances = Matrix::::new(0.0, 10, 9); + let results = Matrix::::new(0, 10, 10); let err = knn( &groundtruth, Some(distances.as_view().into()), diff --git a/diskann-benchmark-core/src/search/api.rs b/diskann-benchmark-core/src/search/api.rs index 38e5dbd2f..1888eacf2 100644 --- a/diskann-benchmark-core/src/search/api.rs +++ b/diskann-benchmark-core/src/search/api.rs @@ -9,7 +9,7 @@ use diskann::{ANNResult, graph, utils::async_tools}; use diskann_benchmark_runner::utils::MicroSeconds; use diskann_utils::{ future::{AsyncFriendly, boxit}, - views::{self, Matrix}, + matrix::{self, Matrix}, }; use crate::{ @@ -517,7 +517,7 @@ where T: Search, { let mut lengths = Vec::with_capacity(range.len()); - let mut ids = Matrix::from_gen(views::Init(T::Id::default), range.len(), num_ids.into()); + let mut ids = Matrix::new(matrix::Init(T::Id::default), range.len(), num_ids.into()); let mut latencies = Vec::::with_capacity(range.len()); let mut outputs = Vec::::with_capacity(range.len()); diff --git a/diskann-benchmark-core/src/search/graph/inline.rs b/diskann-benchmark-core/src/search/graph/inline.rs index 27ce21499..838fb44a8 100644 --- a/diskann-benchmark-core/src/search/graph/inline.rs +++ b/diskann-benchmark-core/src/search/graph/inline.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, ext::labeled, glue, search::AdaptiveL}, provider, }; -use diskann_utils::{future::AsyncFriendly, views::Matrix}; +use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; use crate::search::{self, Search, graph::Strategy}; @@ -173,7 +173,7 @@ mod tests { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -273,7 +273,7 @@ mod tests { #[test] fn test_inline_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::from_gen(0.0f32, 2, index.provider().dim())); + let queries = Arc::new(Matrix::new(0.0f32, 2, index.provider().dim())); let labels: Arc<[_]> = (0..queries.nrows() + 1) .map(|_| -> Arc> { Arc::new(NoOdds {}) }) diff --git a/diskann-benchmark-core/src/search/graph/knn.rs b/diskann-benchmark-core/src/search/graph/knn.rs index ba7b5526e..936f6ae96 100644 --- a/diskann-benchmark-core/src/search/graph/knn.rs +++ b/diskann-benchmark-core/src/search/graph/knn.rs @@ -13,7 +13,7 @@ use diskann::{ provider, }; use diskann_benchmark_runner::utils::{MicroSeconds, percentiles}; -use diskann_utils::{future::AsyncFriendly, views::Matrix}; +use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; use crate::{ recall, @@ -402,7 +402,7 @@ mod tests { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -488,7 +488,7 @@ mod tests { fn test_knn_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::from_gen(0.0f32, 1, index.provider().dim())); + let queries = Arc::new(Matrix::new(0.0f32, 1, index.provider().dim())); let strategy = provider::Strategy::new(); let err = KNN::new( diff --git a/diskann-benchmark-core/src/search/graph/multihop.rs b/diskann-benchmark-core/src/search/graph/multihop.rs index 39b6cca61..09323651d 100644 --- a/diskann-benchmark-core/src/search/graph/multihop.rs +++ b/diskann-benchmark-core/src/search/graph/multihop.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, ext::labeled, glue}, provider, }; -use diskann_utils::{future::AsyncFriendly, views::Matrix}; +use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; use crate::search::{self, Search, graph::Strategy}; @@ -168,7 +168,7 @@ mod tests { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -265,7 +265,7 @@ mod tests { #[test] fn test_multihop_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::from_gen(0.0f32, 2, index.provider().dim())); + let queries = Arc::new(Matrix::new(0.0f32, 2, index.provider().dim())); let labels: Arc<[_]> = (0..queries.nrows() + 1) .map(|_| -> Arc> { Arc::new(NoOdds {}) }) diff --git a/diskann-benchmark-core/src/search/graph/range.rs b/diskann-benchmark-core/src/search/graph/range.rs index 8ff79f56f..dab8d799a 100644 --- a/diskann-benchmark-core/src/search/graph/range.rs +++ b/diskann-benchmark-core/src/search/graph/range.rs @@ -11,7 +11,7 @@ use diskann::{ provider, }; use diskann_benchmark_runner::utils::{MicroSeconds, percentiles}; -use diskann_utils::{future::AsyncFriendly, views::Matrix}; +use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; use crate::{ recall, @@ -243,7 +243,7 @@ mod tests { fn test_range() { let index = search::graph::test_grid_provider(); - let mut queries = Matrix::from_gen(0.0f32, 5, index.provider().dim()); + let mut queries = Matrix::new(0.0f32, 5, index.provider().dim()); queries.row_mut(0).copy_from_slice(&[0.0, 0.0, 0.0, 0.0]); queries.row_mut(1).copy_from_slice(&[4.0, 0.0, 0.0, 0.0]); queries.row_mut(2).copy_from_slice(&[0.0, 4.0, 0.0, 0.0]); @@ -314,7 +314,7 @@ mod tests { fn test_range_error() { let index = search::graph::test_grid_provider(); - let queries = Arc::new(Matrix::from_gen(0.0f32, 2, index.provider().dim())); + let queries = Arc::new(Matrix::new(0.0f32, 2, index.provider().dim())); let strategy = provider::Strategy::new(); let err = Range::new(index, queries.clone(), Strategy::collection([strategy])).unwrap_err(); diff --git a/diskann-benchmark-core/src/search/ids.rs b/diskann-benchmark-core/src/search/ids.rs index 75c2fb4e4..7a24f37b7 100644 --- a/diskann-benchmark-core/src/search/ids.rs +++ b/diskann-benchmark-core/src/search/ids.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_utils::views::{self, Matrix}; +use diskann_utils::{Matrix, matrix}; use crate::recall; @@ -231,7 +231,7 @@ where len, num_ids, } => { - let mut dst = Matrix::from_gen(views::Init(|| I::default()), len, num_ids); + let mut dst = Matrix::new(matrix::Init(|| I::default()), len, num_ids); let mut lengths = Vec::with_capacity(len); let mut output_row = 0; @@ -279,7 +279,7 @@ mod tests { let nrows = data.len(); let ncols = data.iter().map(|v| v.len()).max().unwrap_or(0); - let mut matrix = Matrix::from_gen(0u32, nrows, ncols); + let mut matrix = Matrix::new(0u32, nrows, ncols); let mut lengths = Vec::with_capacity(nrows); for (row, row_data) in std::iter::zip(matrix.row_iter_mut(), data.iter()) { @@ -296,7 +296,7 @@ mod tests { #[test] fn test_bounded_new_valid() { - let matrix = Matrix::from_gen(0u32, 3, 5); + let matrix = Matrix::new(0u32, 3, 5); let lengths = vec![2, 3, 1]; let bounded = Bounded::new(matrix, lengths); @@ -305,7 +305,7 @@ mod tests { #[test] fn test_bounded_length_clamping() { - let matrix = Matrix::from_gen(0u32, 3, 3); + let matrix = Matrix::new(0u32, 3, 3); let lengths = vec![2, 3, 5]; // Last length exceeds number of columns let bounded = Bounded::new(matrix, lengths); @@ -323,7 +323,7 @@ mod tests { #[test] #[should_panic(expected = "an internal invariant was not upheld")] fn test_bounded_new_mismatched_lengths() { - let matrix = Matrix::from_gen(0u32, 3, 5); + let matrix = Matrix::new(0u32, 3, 5); let lengths = vec![2, 3]; // Only 2 lengths for 3 rows Bounded::new(matrix, lengths); } diff --git a/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs b/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs index b30229362..cf76affd0 100644 --- a/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs +++ b/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs @@ -5,7 +5,7 @@ use std::{ops::Range, path::Path, sync::Arc}; -use diskann_utils::views::{Matrix, MatrixView}; +use diskann_utils::{Matrix, MatrixView}; use crate::{recall, streaming}; diff --git a/diskann-benchmark-simd/src/lib.rs b/diskann-benchmark-simd/src/lib.rs index 5d36ed1bd..0e2928304 100644 --- a/diskann-benchmark-simd/src/lib.rs +++ b/diskann-benchmark-simd/src/lib.rs @@ -7,7 +7,7 @@ use std::{io::Write, num::NonZeroUsize}; -use diskann_utils::views::{Matrix, MatrixView}; +use diskann_utils::{Matrix, MatrixView}; use diskann_vector::distance::simd; use diskann_wide::Architecture; use half::f16; @@ -754,8 +754,8 @@ impl Data { let query: Box<[Q]> = (0..run.dim.get()) .map(|_| StandardUniform.sample(&mut rng)) .collect(); - let data = Matrix::::from_gen( - diskann_utils::views::Init(|| StandardUniform.sample(&mut rng)), + let data = Matrix::::new( + diskann_utils::Init(|| StandardUniform.sample(&mut rng)), run.num_points.get(), run.dim.get(), ); diff --git a/diskann-benchmark/src/disk_index/search.rs b/diskann-benchmark/src/disk_index/search.rs index 8cd0f5e60..c907875c2 100644 --- a/diskann-benchmark/src/disk_index/search.rs +++ b/diskann-benchmark/src/disk_index/search.rs @@ -31,7 +31,7 @@ use diskann_providers::{ utils::{create_thread_pool, ParallelIteratorInPool}, }; use diskann_tools::utils::{search_index_utils, KRecallAtN}; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; use serde::{Deserialize, Serialize}; use crate::{ diff --git a/diskann-benchmark/src/exhaustive/algos.rs b/diskann-benchmark/src/exhaustive/algos.rs index 9433f8923..36f8d35b2 100644 --- a/diskann-benchmark/src/exhaustive/algos.rs +++ b/diskann-benchmark/src/exhaustive/algos.rs @@ -33,7 +33,7 @@ where #[derive(Debug, Clone)] pub(super) struct LinearSearch { - pub(super) ids: diskann_utils::views::Matrix, + pub(super) ids: diskann_utils::Matrix, pub(super) preprocess: Vec, pub(super) search: Vec, pub(super) total: MicroSeconds, @@ -41,7 +41,7 @@ pub(super) struct LinearSearch { pub(super) fn linear_search( store: &Q, - queries: diskann_utils::views::MatrixView, + queries: diskann_utils::MatrixView, builder: &C, results_per_query: usize, progress: &indicatif::ProgressBar, @@ -51,7 +51,7 @@ where C: CreateQuantComputer + Sync, { let mut output = - diskann_utils::views::Matrix::::from_gen(u32::MAX, queries.nrows(), results_per_query); + diskann_utils::Matrix::::new(u32::MAX, queries.nrows(), results_per_query); struct Times { preprocess: MicroSeconds, diff --git a/diskann-benchmark/src/exhaustive/minmax.rs b/diskann-benchmark/src/exhaustive/minmax.rs index 7a5feccac..a5f392401 100644 --- a/diskann-benchmark/src/exhaustive/minmax.rs +++ b/diskann-benchmark/src/exhaustive/minmax.rs @@ -370,7 +370,7 @@ mod imp { pub(super) struct Store { // The number of bytes to take from each row. bytes: usize, - data: diskann_utils::views::Matrix, + data: diskann_utils::Matrix, quantizer: diskann_quantization::minmax::MinMaxQuantizer, } @@ -379,7 +379,7 @@ mod imp { Unsigned: Representation, { fn new( - input: diskann_utils::views::MatrixView, + input: diskann_utils::MatrixView, quantizer: diskann_quantization::minmax::MinMaxQuantizer, progress: &ProgressBar, ) -> anyhow::Result { @@ -389,7 +389,7 @@ mod imp { // The APIs below should correctly handle these variables. let output_dim = quantizer.output_dim(); let bytes = Data::::canonical_bytes(output_dim); - let mut data = diskann_utils::views::Matrix::from_gen(0, input.nrows(), bytes); + let mut data = diskann_utils::Matrix::new(0, input.nrows(), bytes); // Compress the data. // diff --git a/diskann-benchmark/src/exhaustive/product.rs b/diskann-benchmark/src/exhaustive/product.rs index d404ab254..59ef2cc9f 100644 --- a/diskann-benchmark/src/exhaustive/product.rs +++ b/diskann-benchmark/src/exhaustive/product.rs @@ -322,18 +322,17 @@ mod imp { /// A store for quantized data. pub(super) struct Store { - data: diskann_utils::views::Matrix, + data: diskann_utils::Matrix, quantizer: diskann_providers::model::pq::FixedChunkPQTable, } impl Store { fn new( - input: diskann_utils::views::MatrixView, + input: diskann_utils::MatrixView, quantizer: diskann_providers::model::pq::FixedChunkPQTable, progress: &ProgressBar, ) -> anyhow::Result { - let mut data = - diskann_utils::views::Matrix::from_gen(0, input.nrows(), quantizer.get_num_chunks()); + let mut data = diskann_utils::Matrix::new(0, input.nrows(), quantizer.get_num_chunks()); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/exhaustive/spherical.rs b/diskann-benchmark/src/exhaustive/spherical.rs index 22e8d2f0d..1a7d4f4cf 100644 --- a/diskann-benchmark/src/exhaustive/spherical.rs +++ b/diskann-benchmark/src/exhaustive/spherical.rs @@ -394,7 +394,7 @@ mod imp { pub(super) struct Store { // The number of bytes to take from each row. bytes: usize, - data: diskann_utils::views::Matrix, + data: diskann_utils::Matrix, plan: diskann_quantization::spherical::iface::Impl, } @@ -405,7 +405,7 @@ mod imp { for<'a> CompressIntoWith<&'a [f32], DataMut<'a, NBITS>, ScopedAllocator<'a>>, { fn new( - input: diskann_utils::views::MatrixView, + input: diskann_utils::MatrixView, plan: diskann_quantization::spherical::iface::Impl, progress: &ProgressBar, ) -> anyhow::Result { @@ -416,7 +416,7 @@ mod imp { let output_dim = plan.quantizer().output_dim(); let bytes = diskann_quantization::spherical::DataRef::::canonical_bytes(output_dim); - let mut data = diskann_utils::views::Matrix::from_gen(0, input.nrows(), bytes); + let mut data = diskann_utils::Matrix::new(0, input.nrows(), bytes); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/flat/search.rs b/diskann-benchmark/src/flat/search.rs index a670d0df4..1730af248 100644 --- a/diskann-benchmark/src/flat/search.rs +++ b/diskann-benchmark/src/flat/search.rs @@ -24,7 +24,7 @@ use diskann_benchmark_runner::{ utils::{datatype::AsDataType, percentiles, MicroSeconds}, Benchmark, Checkpoint, Registry, }; -use diskann_utils::{future::SendFuture, views::Matrix}; +use diskann_utils::{future::SendFuture, matrix::Matrix}; use diskann_vector::{distance::Metric, PreprocessedDistanceFunction}; use half::f16; use serde::Serialize; diff --git a/diskann-benchmark/src/index/benchmarks.rs b/diskann-benchmark/src/index/benchmarks.rs index 4307f2e5b..63457b6eb 100644 --- a/diskann-benchmark/src/index/benchmarks.rs +++ b/diskann-benchmark/src/index/benchmarks.rs @@ -31,7 +31,7 @@ use diskann_providers::{ }; use diskann_utils::{ future::AsyncFriendly, - views::{Matrix, MatrixView}, + matrix::{Matrix, MatrixView}, }; use half::f16; diff --git a/diskann-benchmark/src/index/bftree/full_precision_streaming.rs b/diskann-benchmark/src/index/bftree/full_precision_streaming.rs index 1d39e59cb..5d1605beb 100644 --- a/diskann-benchmark/src/index/bftree/full_precision_streaming.rs +++ b/diskann-benchmark/src/index/bftree/full_precision_streaming.rs @@ -24,7 +24,7 @@ use diskann_providers::{ model::graph::provider::async_::common::FullPrecision, storage::{FileStorageProvider, SaveWith}, }; -use diskann_utils::views::{Matrix, MatrixView}; +use diskann_utils::{Matrix, MatrixView}; use crate::{ index::{ diff --git a/diskann-benchmark/src/index/bftree/spherical.rs b/diskann-benchmark/src/index/bftree/spherical.rs index 54bee04af..7cf0d076d 100644 --- a/diskann-benchmark/src/index/bftree/spherical.rs +++ b/diskann-benchmark/src/index/bftree/spherical.rs @@ -23,7 +23,7 @@ use diskann_quantization::{ SphericalQuantizer, }, }; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; use rand::SeedableRng; use crate::{ diff --git a/diskann-benchmark/src/index/bftree/spherical_streaming.rs b/diskann-benchmark/src/index/bftree/spherical_streaming.rs index d676b9994..e15c3dde8 100644 --- a/diskann-benchmark/src/index/bftree/spherical_streaming.rs +++ b/diskann-benchmark/src/index/bftree/spherical_streaming.rs @@ -30,7 +30,7 @@ use diskann_quantization::spherical::{ iface::{self as spherical_iface, Quantizer}, SphericalQuantizer, }; -use diskann_utils::views::{Matrix, MatrixView}; +use diskann_utils::{Matrix, MatrixView}; use rand::SeedableRng; use crate::{ diff --git a/diskann-benchmark/src/index/build.rs b/diskann-benchmark/src/index/build.rs index 8625f4975..1a3b9a141 100644 --- a/diskann-benchmark/src/index/build.rs +++ b/diskann-benchmark/src/index/build.rs @@ -23,7 +23,7 @@ use diskann_providers::{ }; use diskann_utils::{ future::AsyncFriendly, - views::{Matrix, MatrixView}, + matrix::{Matrix, MatrixView}, }; use indicatif::{ProgressBar, ProgressStyle}; use serde::Serialize; diff --git a/diskann-benchmark/src/index/inmem/product.rs b/diskann-benchmark/src/index/inmem/product.rs index 931ca725c..b727b42bf 100644 --- a/diskann-benchmark/src/index/inmem/product.rs +++ b/diskann-benchmark/src/index/inmem/product.rs @@ -49,7 +49,7 @@ mod imp { IndexConfiguration, }, }; - use diskann_utils::views::{Matrix, MatrixView}; + use diskann_utils::{Matrix, MatrixView}; use diskann_benchmark_runner::{ benchmark::{MatchContext, Score}, diff --git a/diskann-benchmark/src/index/inmem/scalar.rs b/diskann-benchmark/src/index/inmem/scalar.rs index b10fd874b..390a5722c 100644 --- a/diskann-benchmark/src/index/inmem/scalar.rs +++ b/diskann-benchmark/src/index/inmem/scalar.rs @@ -69,7 +69,7 @@ mod imp { graph::provider::async_::{common, inmem}, }, }; - use diskann_utils::views::{Matrix, MatrixView}; + use diskann_utils::{Matrix, MatrixView}; use crate::{ index::{ diff --git a/diskann-benchmark/src/index/inmem/spherical.rs b/diskann-benchmark/src/index/inmem/spherical.rs index e69025f8c..f926d9746 100644 --- a/diskann-benchmark/src/index/inmem/spherical.rs +++ b/diskann-benchmark/src/index/inmem/spherical.rs @@ -75,7 +75,7 @@ mod imp { model::graph::provider::async_::{common, inmem}, }; use diskann_quantization::alloc::GlobalAllocator; - use diskann_utils::views::Matrix; + use diskann_utils::Matrix; use rand::SeedableRng; use serde::Serialize; use std::{io::Write, sync::Arc}; diff --git a/diskann-benchmark/src/index/streaming/full_precision.rs b/diskann-benchmark/src/index/streaming/full_precision.rs index 4e3d62a25..3ff75f603 100644 --- a/diskann-benchmark/src/index/streaming/full_precision.rs +++ b/diskann-benchmark/src/index/streaming/full_precision.rs @@ -19,7 +19,7 @@ use diskann_providers::model::graph::provider::async_::{ }; use diskann_utils::{ future::AsyncFriendly, - views::{Matrix, MatrixView}, + matrix::{Matrix, MatrixView}, }; use super::{ diff --git a/diskann-benchmark/src/index/streaming/managed.rs b/diskann-benchmark/src/index/streaming/managed.rs index cbe7188d9..515ccaff2 100644 --- a/diskann-benchmark/src/index/streaming/managed.rs +++ b/diskann-benchmark/src/index/streaming/managed.rs @@ -11,7 +11,7 @@ use diskann_benchmark_core::{ streaming::{self, executors}, }; use diskann_benchmark_runner::{timed, utils::MicroSeconds}; -use diskann_utils::views::{Matrix, MatrixView}; +use diskann_utils::{Matrix, MatrixView}; use crate::utils::streaming::TagSlotManager; diff --git a/diskann-benchmark/src/utils/datafiles.rs b/diskann-benchmark/src/utils/datafiles.rs index 6d3526a13..db252801d 100644 --- a/diskann-benchmark/src/utils/datafiles.rs +++ b/diskann-benchmark/src/utils/datafiles.rs @@ -10,7 +10,7 @@ use bit_set::BitSet; use diskann::utils::IntoUsize; use diskann_benchmark_runner::utils::datatype::DataType; use diskann_providers::storage::StorageReadProvider; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; use serde::{Deserialize, Serialize}; pub(crate) struct BinFile<'a>(pub(crate) &'a Path); @@ -71,12 +71,12 @@ impl ConvertingLoad for f32 { ))] fn converting_load(path: BinFile<'_>, data_type: DataType) -> anyhow::Result> { #[inline(never)] - fn convert(from: diskann_utils::views::MatrixView) -> Matrix + fn convert(from: diskann_utils::MatrixView) -> Matrix where U: Default + Clone + From, T: Copy, { - let mut to = Matrix::from_gen(U::default(), from.nrows(), from.ncols()); + let mut to = Matrix::new(U::default(), from.nrows(), from.ncols()); std::iter::zip(to.as_mut_slice().iter_mut(), from.as_slice().iter()) .for_each(|(t, f)| *t = (*f).into()); to @@ -111,7 +111,7 @@ pub(crate) fn load_groundtruth(path: BinFile<'_>, k: Option) -> anyhow::R (num_points, dim) }; - let mut groundtruth = Matrix::::from_gen(0, num_points, dim); + let mut groundtruth = Matrix::::new(0, num_points, dim); let groundtruth_slice: &mut [u8] = bytemuck::cast_slice_mut(groundtruth.as_mut_slice()); file.read_exact(groundtruth_slice)?; diff --git a/diskann-bftree/src/provider.rs b/diskann-bftree/src/provider.rs index 35cf021b2..612f81def 100644 --- a/diskann-bftree/src/provider.rs +++ b/diskann-bftree/src/provider.rs @@ -37,7 +37,7 @@ use diskann::{ }; use diskann_utils::{ future::{AsyncFriendly, SendFuture}, - views::MatrixView, + matrix::MatrixView, }; use diskann_vector::{distance::Metric, DistanceFunction, PreprocessedDistanceFunction}; @@ -97,7 +97,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// use diskann_bftree::NoStore; /// use diskann_vector::distance::Metric; -/// use diskann_utils::views::{Init, Matrix}; +/// use diskann_utils::{Init, Matrix}; /// use bf_tree::Config; /// use std::num::NonZeroUsize; /// @@ -115,7 +115,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// /// // Create a table that supports 5 points and 1 start point. -/// let start_points = Matrix::from_gen(Init(|| 0.0f32), 1, 4); +/// let start_points = Matrix::new(Init(|| 0.0f32), 1, 4); /// let provider = BfTreeProvider::::new( /// parameters, /// start_points.as_view(), @@ -134,7 +134,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// algorithms::TransformKind, /// spherical::{iface, SphericalQuantizer, SupportedMetric, PreScale}, /// }; -/// use diskann_utils::views::{Init, Matrix}; +/// use diskann_utils::{Init, Matrix}; /// use diskann_bftree::provider::{ /// BfTreeProvider, BfTreeProviderParameters /// }; @@ -145,7 +145,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// use rand::SeedableRng; /// /// let dim = 4; -/// let data = Matrix::from_gen(Init(|| 1.0f32), 4, dim); +/// let data = Matrix::new(Init(|| 1.0f32), 4, dim); /// let mut rng = StdRng::seed_from_u64(42); /// let sq = SphericalQuantizer::train( /// data.as_view(), TransformKind::Null, @@ -170,7 +170,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// /// // Create a table that supports 5 points and 1 start point. -/// let start_points = Matrix::from_gen(Init(|| 0.0f32), 1, 4); +/// let start_points = Matrix::new(Init(|| 0.0f32), 1, 4); /// let provider = BfTreeProvider::::new( /// parameters, /// start_points.as_view(), @@ -2020,10 +2020,10 @@ mod tests { neighbor::BackInserter, }; use diskann_providers::storage::FileStorageProvider; - use diskann_utils::views::{Init, Matrix}; + use diskann_utils::{Init, Matrix}; fn create_quant_index() -> Arc>> { - let start_point = Matrix::from_gen(Init(|| 0.0f32), 1, 5); + let start_point = Matrix::new(Init(|| 0.0f32), 1, 5); let dim = 5; let logical_max_degree = 6; let physical_max_degree = (logical_max_degree as f32 * 1.3) as u32; @@ -2100,7 +2100,7 @@ mod tests { let index = create_quant_index(); let ctx = &DefaultContext; - let data = Matrix::from_gen( + let data = Matrix::new( Init({ let mut row = 0usize; let mut col = 0usize; @@ -2196,7 +2196,7 @@ mod tests { } fn create_full_precision_index() -> Arc>> { - let start_point = Matrix::from_gen(Init(|| 0.0f32), 1, 5); + let start_point = Matrix::new(Init(|| 0.0f32), 1, 5); let logical_max_degree = 6; let physical_max_degree = (logical_max_degree as f32 * 1.3) as u32; let metric = Metric::L2; @@ -2422,7 +2422,7 @@ mod tests { let num_start_points = 2; let dim = 3; - let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points, dim); + let start_points = Matrix::new(Init(|| 0.0f32), num_start_points, dim); let provider = BfTreeProvider::::new( BfTreeProviderParameters { @@ -2559,7 +2559,7 @@ mod tests { use_snapshot: true, }; - let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); // Create provider let provider = @@ -2691,7 +2691,7 @@ mod tests { use_snapshot: true, }; - let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); // Create provider with quantization let provider = BfTreeProvider::::new( params.clone(), @@ -2810,7 +2810,7 @@ mod tests { let mut neighbor_config = Config::default(); neighbor_config.use_snapshot(true); - let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); // In-memory config (no file path needed) let provider = BfTreeProvider::::new( BfTreeProviderParameters { @@ -2925,7 +2925,7 @@ mod tests { let mut quant_config = Config::default(); quant_config.use_snapshot(true); - let start_points = Matrix::from_gen(Init(|| 0.0f32), num_start_points.into(), dim); + let start_points = Matrix::new(Init(|| 0.0f32), num_start_points.into(), dim); let provider = BfTreeProvider::::new( BfTreeProviderParameters { max_points: num_points, diff --git a/diskann-bftree/src/quant.rs b/diskann-bftree/src/quant.rs index 2cfb725a5..4926358bf 100644 --- a/diskann-bftree/src/quant.rs +++ b/diskann-bftree/src/quant.rs @@ -236,14 +236,14 @@ pub(crate) fn create_test_quantizer(dim: usize) -> Poly { alloc::poly, spherical::{iface, PreScale, SphericalQuantizer, SupportedMetric}, }; - use diskann_utils::views::Init; - use diskann_utils::views::Matrix; + use diskann_utils::Init; + use diskann_utils::Matrix; use rand::{rngs::StdRng, SeedableRng}; // Create training data with spread-out values. let nrows = 8; let mut counter = 0.0f32; - let data = Matrix::from_gen( + let data = Matrix::new( Init(move || { counter += 0.5; counter diff --git a/diskann-disk/src/build/builder/quantizer.rs b/diskann-disk/src/build/builder/quantizer.rs index 7bbfacf3c..68fa659a0 100644 --- a/diskann-disk/src/build/builder/quantizer.rs +++ b/diskann-disk/src/build/builder/quantizer.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{create_thread_pool, BridgeErr, PQPathNames}, }; use diskann_quantization::scalar::train::ScalarQuantizationParameters; -use diskann_utils::views::MatrixView; +use diskann_utils::MatrixView; use tracing::info; use crate::QuantizationType; diff --git a/diskann-disk/src/search/pq/quantizer_preprocess.rs b/diskann-disk/src/search/pq/quantizer_preprocess.rs index 344570ba5..1c7d96dd8 100644 --- a/diskann-disk/src/search/pq/quantizer_preprocess.rs +++ b/diskann-disk/src/search/pq/quantizer_preprocess.rs @@ -22,7 +22,7 @@ pub fn quantizer_preprocess( ) -> ANNResult<()> { let table = pq_data.pq_table(); let expected_len = table.ncenters() * table.nchunks(); - let dst = diskann_utils::views::MatrixViewMut::try_from( + let dst = diskann_utils::MatrixViewMut::try_from( &mut (*pq_scratch.aligned_pqtable_dist_scratch)[..expected_len], table.nchunks(), table.ncenters(), diff --git a/diskann-disk/src/search/provider/disk_provider.rs b/diskann-disk/src/search/provider/disk_provider.rs index cff431bc7..bde832489 100644 --- a/diskann-disk/src/search/provider/disk_provider.rs +++ b/diskann-disk/src/search/provider/disk_provider.rs @@ -37,8 +37,8 @@ use diskann_providers::{ storage::{get_compressed_pq_file, get_disk_index_file, get_pq_pivot_file, LoadWith}, }; use diskann_utils::{ + matrix::Matrix, object_pool::{ObjectPool, PoolOption, TryAsPooled}, - views::Matrix, }; use crate::search::pq::{quantizer_preprocess, PQData, PQScratch}; @@ -432,7 +432,7 @@ where ensure_vertex_loaded(&mut accessor.scratch.vertex_provider, &candidate_ids)?; - let mut candidate_vectors = Matrix::from_gen(0.0f32, candidate_ids.len(), query_f32.len()); + let mut candidate_vectors = Matrix::new(0.0f32, candidate_ids.len(), query_f32.len()); let mut candidate_distances = Vec::with_capacity(candidate_ids.len()); let mut associated_data = Vec::with_capacity(candidate_ids.len()); diff --git a/diskann-disk/src/storage/quant/compressor.rs b/diskann-disk/src/storage/quant/compressor.rs index dfd82b3a3..0d5ea9dac 100644 --- a/diskann-disk/src/storage/quant/compressor.rs +++ b/diskann-disk/src/storage/quant/compressor.rs @@ -4,7 +4,7 @@ */ use diskann::{utils::VectorRepr, ANNResult}; -use diskann_utils::views::{MatrixView, MatrixViewMut}; +use diskann_utils::{MatrixView, MatrixViewMut}; /// [`QuantCompressor`] defines the interface for quantizer with [`QuantDataGenerator`] /// diff --git a/diskann-disk/src/storage/quant/generator.rs b/diskann-disk/src/storage/quant/generator.rs index 45ed4f6bb..796aa93a0 100644 --- a/diskann-disk/src/storage/quant/generator.rs +++ b/diskann-disk/src/storage/quant/generator.rs @@ -14,7 +14,7 @@ use diskann_providers::{ storage::{StorageReadProvider, StorageWriteProvider}, utils::{load_metadata_from_file, BridgeErr, ParallelIteratorInPool, RayonThreadPoolRef}, }; -use diskann_utils::{io::Metadata, views}; +use diskann_utils::{io::Metadata, matrix}; use rayon::iter::IndexedParallelIterator; use tracing::info; @@ -147,14 +147,14 @@ where // Wrap the data in `MatrixViews` so we do not need to manually construct view // in the compression loop. - let mut compressed_block = views::MatrixViewMut::try_from( + let mut compressed_block = matrix::MatrixViewMut::try_from( block_compressed_base, cur_block_size, compressed_size, ) .bridge_err()?; let base_block = - views::MatrixView::try_from(&block_data, cur_block_size, full_dim).bridge_err()?; + matrix::MatrixView::try_from(&block_data, cur_block_size, full_dim).bridge_err()?; base_block .par_window_iter(BATCH_SIZE) .zip_eq(compressed_block.par_window_iter_mut(BATCH_SIZE)) @@ -193,7 +193,7 @@ mod generator_tests { use diskann_providers::utils::create_thread_pool_for_test; use diskann_utils::{ io::{write_bin, Metadata}, - views::MatrixView, + matrix::MatrixView, }; use rstest::rstest; use vfs::{FileSystem, MemoryFS}; @@ -220,8 +220,8 @@ mod generator_tests { fn compress( &self, - _vector: views::MatrixView, - mut output: views::MatrixViewMut, + _vector: matrix::MatrixView, + mut output: matrix::MatrixViewMut, ) -> ANNResult<()> { output .row_iter_mut() diff --git a/diskann-disk/src/storage/quant/pq/pq_dataset.rs b/diskann-disk/src/storage/quant/pq/pq_dataset.rs index 5dc31e3b3..fb451292c 100644 --- a/diskann-disk/src/storage/quant/pq/pq_dataset.rs +++ b/diskann-disk/src/storage/quant/pq/pq_dataset.rs @@ -8,7 +8,7 @@ use core::fmt::Debug; use diskann::{ANNError, ANNResult}; use diskann_providers::model::FixedChunkPQTable; use diskann_quantization::product::TransposedTable; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; #[derive(Debug)] pub struct PQData { diff --git a/diskann-disk/src/storage/quant/pq/pq_generation.rs b/diskann-disk/src/storage/quant/pq/pq_generation.rs index e317d8e3c..d3f76e0ae 100644 --- a/diskann-disk/src/storage/quant/pq/pq_generation.rs +++ b/diskann-disk/src/storage/quant/pq/pq_generation.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{BridgeErr, RayonThreadPoolRef}, }; use diskann_quantization::{product::TransposedTable, CompressInto}; -use diskann_utils::views::{MatrixView, MatrixViewMut}; +use diskann_utils::{MatrixView, MatrixViewMut}; use diskann_vector::distance::Metric; use tracing::info; @@ -119,7 +119,7 @@ where context.storage_provider, )?; - let mut full_pivot_data_mat = diskann_utils::views::MatrixViewMut::try_from( + let mut full_pivot_data_mat = diskann_utils::MatrixViewMut::try_from( full_pivot_data.as_mut_slice(), context.num_centers, full_dim, @@ -174,8 +174,8 @@ mod pq_generation_tests { use diskann_providers::utils::{create_thread_pool_for_test, RayonThreadPoolRef}; use diskann_utils::{ io::{read_bin, write_bin}, + matrix::{MatrixView, MatrixViewMut}, test_data_root, - views::{MatrixView, MatrixViewMut}, }; use diskann_vector::distance::Metric; use rstest::rstest; diff --git a/diskann-garnet/src/provider.rs b/diskann-garnet/src/provider.rs index 0ab008d37..aeae077e8 100644 --- a/diskann-garnet/src/provider.rs +++ b/diskann-garnet/src/provider.rs @@ -24,10 +24,10 @@ use diskann::{ utils::VectorRepr, }; use diskann_quantization::alloc::{AllocatorError, Poly}; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; use diskann_utils::{ + matrix::MatrixView, object_pool::{AsPooled, ObjectPool, PooledRef, Undef}, - views::MatrixView, }; use diskann_vector::{ DistanceFunction, PreprocessedDistanceFunction, contains::ContainsSimd, distance::Metric, @@ -449,7 +449,7 @@ impl GarnetProvider { }; let rows = quantizer.required_vectors(); - let mut data = Matrix::::from_gen(T::default(), rows, self.dim); + let mut data = Matrix::::new(T::default(), rows, self.dim); let mut row_idx = 0usize; if self diff --git a/diskann-garnet/src/quantization.rs b/diskann-garnet/src/quantization.rs index 74046483a..c9716992f 100644 --- a/diskann-garnet/src/quantization.rs +++ b/diskann-garnet/src/quantization.rs @@ -12,7 +12,7 @@ use diskann_quantization::{ iface::{self, Opaque, OpaqueMut, Quantizer}, }, }; -use diskann_utils::views::MatrixView; +use diskann_utils::MatrixView; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; @@ -357,7 +357,7 @@ impl DynQueryComputer for MinMax8BitQueryComputer { #[cfg(test)] mod tests { - use diskann_utils::views::Matrix; + use diskann_utils::Matrix; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use crate::quantization::{GarnetQuantizer, GarnetQuantizerError, MinMax8Bit, Spherical1Bit}; @@ -386,7 +386,7 @@ mod tests { Err(GarnetQuantizerError::NoQuantizer) )); - let mut test_data = Matrix::from_gen(0.0f32, 1000, 2); + let mut test_data = Matrix::new(0.0f32, 1000, 2); for i in 0..1000 { test_data .row_mut(i) @@ -424,7 +424,7 @@ mod tests { let test_v = [0.5f32, 0.5]; let mut test_q = vec![0u8; quantizer.bytes()]; - let mut test_data = Matrix::from_gen(0.0f32, 1, 2); + let mut test_data = Matrix::new(0.0f32, 1, 2); test_data.row_mut(0).copy_from_slice(&[1.0f32, 1.0]); // Training is a no-op, but succeeds. diff --git a/diskann-providers/src/index/diskann_async.rs b/diskann-providers/src/index/diskann_async.rs index 99f770c8e..79b95b0d8 100644 --- a/diskann-providers/src/index/diskann_async.rs +++ b/diskann-providers/src/index/diskann_async.rs @@ -59,7 +59,7 @@ pub(crate) fn simplified_builder( } pub fn train_pq( - data: diskann_utils::views::MatrixView, + data: diskann_utils::MatrixView, num_pq_chunks: usize, rng: &mut dyn rand::RngCore, pool: crate::utils::RayonThreadPoolRef<'_>, @@ -179,7 +179,7 @@ pub(crate) mod tests { utils::{IntoUsize, ONE}, }; use diskann_quantization::scalar::train::ScalarQuantizationParameters; - use diskann_utils::{test_data_root, views::Matrix}; + use diskann_utils::{matrix::Matrix, test_data_root}; use diskann_vector::{ DistanceFunction, PureDistanceFunction, distance::{Metric, SquaredL2}, @@ -213,7 +213,7 @@ pub(crate) mod tests { /// Convert an iterator of vectors into a single Matrix. All elements in `data` must /// have the same length, otherwise this function panics. - pub(crate) fn squish<'a, To, T, Itr>(data: Itr, dim: usize) -> diskann_utils::views::Matrix + pub(crate) fn squish<'a, To, T, Itr>(data: Itr, dim: usize) -> diskann_utils::Matrix where To: Clone + Default, T: Clone + Into + 'a, @@ -221,7 +221,7 @@ pub(crate) mod tests { { // Assume that all the vectors in `data` have the same length. // If they don't, `copy_from_slice` will panic, so we're double checking. - let mut mat = diskann_utils::views::Matrix::from_gen(To::default(), data.len(), dim); + let mut mat = diskann_utils::Matrix::new(To::default(), data.len(), dim); std::iter::zip(mat.row_iter_mut(), data).for_each(|(output, input)| { assert_eq!( input.len(), @@ -621,8 +621,7 @@ pub(crate) mod tests { // // So, when we compute the corpus used during groundtruth generation, we take all // but this last point. - let corpus: diskann_utils::views::Matrix = - squish(vectors.iter().take(num_points), dim); + let corpus: diskann_utils::Matrix = squish(vectors.iter().take(num_points), dim); let mut paged_tests = Vec::new(); @@ -875,7 +874,7 @@ pub(crate) mod tests { let data = T::generate_spherical(num, dim, radius, rng); let table = { - let train_data: diskann_utils::views::Matrix = squish(data.iter(), dim); + let train_data: diskann_utils::Matrix = squish(data.iter(), dim); train_pq( train_data.as_view(), 2.min(dim), @@ -1066,8 +1065,7 @@ pub(crate) mod tests { let beta = 0.5; - let corpus: diskann_utils::views::Matrix = - squish(vectors.iter().take(num_points), dim); + let corpus: diskann_utils::Matrix = squish(vectors.iter().take(num_points), dim); let query = vec![grid_size as f32; dim]; // The strategy we use here for checking is that we pull in a lot of neighbors and @@ -2204,7 +2202,7 @@ pub(crate) mod tests { parameters: InitParams, file: &str, start_strategy: StartPointStrategy, - train_data: diskann_utils::views::MatrixView<'_, f32>, + train_data: diskann_utils::MatrixView<'_, f32>, ) where DefaultProvider: DataProvider + for<'a> SetElement<&'a [f32]> @@ -2236,7 +2234,7 @@ pub(crate) mod tests { } else { let mut i: u32 = 0; while let Some(data) = iter.next_n(batchsize) { - let mut vectors = Matrix::from_gen(0.0f32, data.len(), start_vectors.ncols()); + let mut vectors = Matrix::new(0.0f32, data.len(), start_vectors.ncols()); let ids: Arc<[_]> = std::iter::zip(vectors.row_iter_mut(), data.iter()) .map(|(dst, (v, _))| { dst.copy_from_slice(v); @@ -2260,7 +2258,7 @@ pub(crate) mod tests { file: &str, num_pq_chunks: usize, startpoint: StartPointStrategy, - ) -> (Arc, diskann_utils::views::Matrix) + ) -> (Arc, diskann_utils::Matrix) where S: for<'a> InsertStrategy<'a, TestProvider, &'a [f32]> + MultiInsertStrategy> @@ -2658,7 +2656,7 @@ pub(crate) mod tests { // Randomize the vectors let rng = &mut create_rnd_from_seed_in_tests(0x7dc205fcda38d3a3); indices.shuffle(rng); - let mut queries = diskann_utils::views::Matrix::from_gen(0.0, data.nrows(), data.ncols()); + let mut queries = diskann_utils::Matrix::new(0.0, data.nrows(), data.ncols()); std::iter::zip(queries.row_iter_mut(), indices.iter()).for_each(|(row, i)| { row.copy_from_slice(data.row(*i)); }); diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs index 020020e7f..acb729e93 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs @@ -22,8 +22,8 @@ use diskann::{ utils::{IntoUsize, VectorRepr}, }; +use diskann_utils::Matrix; use diskann_utils::future::AsyncFriendly; -use diskann_utils::views::Matrix; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use crate::model::graph::provider::async_::{ @@ -438,7 +438,7 @@ where let candidates: Vec> = candidates.collect(); let candidate_count = candidates.len(); let store: &FullPrecisionStore = accessor.as_full_precision(); - let mut vectors = Matrix::from_gen(0.0f32, candidate_count, query.len()); + let mut vectors = Matrix::new(0.0f32, candidate_count, query.len()); let mut ids = Vec::with_capacity(candidate_count); let mut distances = Vec::with_capacity(candidate_count); diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs index 561eaaec5..ccbf94108 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs @@ -892,7 +892,7 @@ mod tests { use crate::storage::VirtualStorageProvider; use diskann::utils::ONE; use diskann_quantization::scalar::train::ScalarQuantizationParameters; - use diskann_utils::views::MatrixView; + use diskann_utils::MatrixView; use diskann_vector::distance::Metric; use rstest::rstest; diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs index ebdfeda2c..b50f0053a 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs @@ -725,7 +725,7 @@ mod tests { alloc::GlobalAllocator, spherical::{SphericalQuantizer, SupportedMetric}, }; - use diskann_utils::views::{Matrix, MatrixView}; + use diskann_utils::{Matrix, MatrixView}; use diskann_vector::{ DistanceFunction, PreprocessedDistanceFunction, PureDistanceFunction, distance::{InnerProduct, Metric, SquaredL2}, @@ -768,8 +768,8 @@ mod tests { } fn dataset(nrows: usize, ncols: usize, rng: &mut StdRng) -> Matrix { - Matrix::from_gen( - diskann_utils::views::Init(|| StandardNormal {}.sample(rng)), + Matrix::new( + diskann_utils::Init(|| StandardNormal {}.sample(rng)), nrows, ncols, ) diff --git a/diskann-providers/src/model/graph/provider/determinant_diversity.rs b/diskann-providers/src/model/graph/provider/determinant_diversity.rs index 8a365fe93..de776caab 100644 --- a/diskann-providers/src/model/graph/provider/determinant_diversity.rs +++ b/diskann-providers/src/model/graph/provider/determinant_diversity.rs @@ -53,7 +53,7 @@ use std::fmt; -use diskann_utils::views::MatrixViewMut; +use diskann_utils::MatrixViewMut; use diskann_vector::{MathematicalValue, PureDistanceFunction, distance::InnerProduct}; /// Parameters for Determinant-Diversity post-processor with validation. @@ -481,7 +481,7 @@ fn dot_product(a: &[f32], b: &[f32]) -> f32 { mod tests { use super::*; use diskann_quantization::num::Positive; - use diskann_utils::views::Matrix; + use diskann_utils::Matrix; #[test] fn test_valid_params() { @@ -530,7 +530,7 @@ mod tests { } let dim = candidates[0].2.len(); - let mut matrix = Matrix::from_gen(0.0f32, candidates.len(), dim); + let mut matrix = Matrix::new(0.0f32, candidates.len(), dim); let mut ids = Vec::with_capacity(candidates.len()); let mut distances = Vec::with_capacity(candidates.len()); @@ -564,7 +564,7 @@ mod tests { // A zero-length query against non-empty candidates is a structural // mismatch (candidate columns != query dimension), not a valid request // that trivially returns nothing. - let mut matrix = Matrix::from_gen(0.0f32, 1, 2); + let mut matrix = Matrix::new(0.0f32, 1, 2); matrix.row_mut(0).copy_from_slice(&[1.0, 2.0]); let params = DeterminantDiversityParams::new(1.0, 0.5).unwrap(); @@ -582,7 +582,7 @@ mod tests { fn test_mismatched_dimensions_errors() { // Candidate vectors are 2-D, but the query is 3-D, so // `determinant_diversity` should report a dimension mismatch. - let mut matrix = Matrix::from_gen(0.0f32, 1, 2); + let mut matrix = Matrix::new(0.0f32, 1, 2); matrix.row_mut(0).copy_from_slice(&[1.0, 2.0]); let params = DeterminantDiversityParams::new(1.0, 0.5).unwrap(); @@ -600,7 +600,7 @@ mod tests { #[test] fn test_mismatched_distances_errors() { // Two candidate rows but only one distance is a structural mismatch. - let mut matrix = Matrix::from_gen(0.0f32, 2, 2); + let mut matrix = Matrix::new(0.0f32, 2, 2); matrix.row_mut(0).copy_from_slice(&[1.0, 0.0]); matrix.row_mut(1).copy_from_slice(&[0.0, 1.0]); let params = DeterminantDiversityParams::new(1.0, 0.5).unwrap(); diff --git a/diskann-providers/src/model/pq/debug.rs b/diskann-providers/src/model/pq/debug.rs index 5ecbe8c80..b033b4155 100644 --- a/diskann-providers/src/model/pq/debug.rs +++ b/diskann-providers/src/model/pq/debug.rs @@ -4,7 +4,7 @@ */ use diskann::utils::IntoUsize; -use diskann_utils::views; +use diskann_utils::matrix; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; pub struct MismatchRecord { @@ -48,12 +48,12 @@ impl std::fmt::Display for MismatchRecord { /// on the sizes of the provided arguments, but can be helpful for writing test routines /// and as such is still marked as public. pub fn compare_pq( - data: views::MatrixView<'_, T>, + data: matrix::MatrixView<'_, T>, schema: diskann_quantization::views::ChunkOffsetsView<'_>, - pivots: views::MatrixView<'_, f32>, + pivots: matrix::MatrixView<'_, f32>, center: &[f32], - a: views::MatrixView<'_, U>, - b: views::MatrixView<'_, U>, + a: matrix::MatrixView<'_, U>, + b: matrix::MatrixView<'_, U>, ) -> Vec where T: Copy + Into, diff --git a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs index 2ef019f73..5bf363aed 100644 --- a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs +++ b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs @@ -9,7 +9,7 @@ use diskann_quantization::{ product::{self, BasicTable}, views::ChunkOffsetsBase, }; -use diskann_utils::views::{self, Matrix, MatrixView}; +use diskann_utils::{Matrix, MatrixView, matrix}; use diskann_vector::{PureDistanceFunction, distance}; use diskann_wide::ARCH; @@ -417,7 +417,7 @@ impl FixedChunkPQTable { } /// Return the pivots as a `MatrixView`. - pub fn view_pivots(&self) -> views::MatrixView<'_, f32> { + pub fn view_pivots(&self) -> matrix::MatrixView<'_, f32> { self.table.view_pivots() } diff --git a/diskann-providers/src/model/pq/pq_construction.rs b/diskann-providers/src/model/pq/pq_construction.rs index 91fa6ca5e..28beff8f9 100644 --- a/diskann-providers/src/model/pq/pq_construction.rs +++ b/diskann-providers/src/model/pq/pq_construction.rs @@ -25,7 +25,7 @@ use diskann_quantization::{ }; use diskann_utils::{ io::Metadata, - views::{MatrixView, MatrixViewMut}, + matrix::{MatrixView, MatrixViewMut}, }; use rand::{Rng, distr::Distribution}; use rayon::prelude::*; diff --git a/diskann-providers/src/model/pq/strided.rs b/diskann-providers/src/model/pq/strided.rs index 4930e6b79..cea96d69f 100644 --- a/diskann-providers/src/model/pq/strided.rs +++ b/diskann-providers/src/model/pq/strided.rs @@ -4,12 +4,12 @@ */ use diskann::ANNError; -use diskann_utils::{strided, views}; +use diskann_utils::{matrix, strided}; use crate::utils::Bridge; // Compatibility with ANNError. -impl From>> for ANNError { +impl From>> for ANNError { #[track_caller] fn from(value: Bridge>) -> Self { ANNError::log_pq_error(value.into_inner()) diff --git a/diskann-providers/src/model/pq/views.rs b/diskann-providers/src/model/pq/views.rs index 52f1d362d..76fd222d8 100644 --- a/diskann-providers/src/model/pq/views.rs +++ b/diskann-providers/src/model/pq/views.rs @@ -4,7 +4,7 @@ */ use diskann::ANNError; -use diskann_utils::views; +use diskann_utils::matrix; use crate::utils::Bridge; @@ -41,9 +41,9 @@ impl From> for ANNError { } // Compatibility with ANNError. -impl From> for ANNError { +impl From> for ANNError { #[track_caller] - fn from(value: Bridge) -> Self { + fn from(value: Bridge) -> Self { ANNError::log_pq_error(value.into_inner()) } } @@ -106,7 +106,7 @@ mod tests { let data = vec![0; ncols * nrows]; test_error(|| { - views::MatrixView::try_from(&data, nrows, ncols + 1) + matrix::MatrixView::try_from(&data, nrows, ncols + 1) .bridge_err() .unwrap_err() }); diff --git a/diskann-providers/src/storage/index_storage.rs b/diskann-providers/src/storage/index_storage.rs index fc526aa1f..8f01023f9 100644 --- a/diskann-providers/src/storage/index_storage.rs +++ b/diskann-providers/src/storage/index_storage.rs @@ -222,7 +222,7 @@ mod tests { provider::SetElement, utils::{IntoUsize, ONE}, }; - use diskann_utils::{test_data_root, views::MatrixView}; + use diskann_utils::{matrix::MatrixView, test_data_root}; use diskann_vector::distance::Metric; use super::*; diff --git a/diskann-providers/src/storage/pq_storage.rs b/diskann-providers/src/storage/pq_storage.rs index 1adcdb7a9..46fa8ace7 100644 --- a/diskann-providers/src/storage/pq_storage.rs +++ b/diskann-providers/src/storage/pq_storage.rs @@ -11,7 +11,7 @@ use diskann::{ }; use diskann_utils::{ io::{Metadata, read_bin, write_bin}, - views::{Matrix, MatrixView}, + matrix::{Matrix, MatrixView}, }; use rand::Rng; use tracing::info; @@ -116,7 +116,7 @@ impl PQStorage { // Write the centroid of PQ centroid vectors let centroid_bytes = match centroid { Some(centroid) => write_bin(MatrixView::column_vector(centroid), writer)?, - None => write_bin(Matrix::::from_gen(0.0, dim, 1).as_view(), writer)?, + None => write_bin(Matrix::::new(0.0, dim, 1).as_view(), writer)?, }; cumul_bytes[2] = cumul_bytes[1] + centroid_bytes; @@ -523,7 +523,7 @@ mod pq_storage_tests { #[test] fn write_read_roundtrip_with_legacy_centroid() { use crate::model::pq::accum_row_inplace; - use diskann_utils::views::MatrixViewMut; + use diskann_utils::MatrixViewMut; let storage_provider = VirtualStorageProvider::new_memory(); let pivot_path = "/roundtrip_legacy_centroid_pivots.bin"; diff --git a/diskann-providers/src/test_utils/search_utils.rs b/diskann-providers/src/test_utils/search_utils.rs index 1cf74fd22..5f1700514 100644 --- a/diskann-providers/src/test_utils/search_utils.rs +++ b/diskann-providers/src/test_utils/search_utils.rs @@ -4,7 +4,7 @@ */ use diskann::neighbor::Neighbor; -use diskann_utils::views::MatrixView; +use diskann_utils::MatrixView; /// Compute the ground truth for a small dataset. /// diff --git a/diskann-providers/src/utils/file_util.rs b/diskann-providers/src/utils/file_util.rs index c1b40e1ea..105c52cb4 100644 --- a/diskann-providers/src/utils/file_util.rs +++ b/diskann-providers/src/utils/file_util.rs @@ -10,7 +10,7 @@ use std::io::Read; use crate::storage::StorageReadProvider; use diskann::{ANNError, ANNResult, utils::IntoUsize}; -use diskann_utils::{io::Metadata, views::Matrix}; +use diskann_utils::{io::Metadata, matrix::Matrix}; /// Read metadata of data file. pub fn load_metadata_from_file( @@ -89,7 +89,7 @@ pub fn load_multivec_bin> = Vec::with_capacity(num_points); for &length in &vec_lengths { - let mut vectors = Matrix::::from_gen(T::default(), length as usize, dimension); + let mut vectors = Matrix::::new(T::default(), length as usize, dimension); reader.read_exact(bytemuck::must_cast_slice_mut::( vectors.as_mut_slice(), ))?; diff --git a/diskann-providers/src/utils/storage_utils.rs b/diskann-providers/src/utils/storage_utils.rs index 40064368a..58521d1c3 100644 --- a/diskann-providers/src/utils/storage_utils.rs +++ b/diskann-providers/src/utils/storage_utils.rs @@ -13,7 +13,7 @@ use byteorder::{LittleEndian, ReadBytesExt}; use diskann::ANNResult; use diskann_utils::{ io::{Metadata, ReadBinError, SaveBinError, read_bin, write_bin}, - views::{Matrix, MatrixView}, + matrix::{Matrix, MatrixView}, }; /// Load a list of vector ids from the stream. diff --git a/diskann-quantization/src/algorithms/hadamard.rs b/diskann-quantization/src/algorithms/hadamard.rs index 8f5dae863..d057973de 100644 --- a/diskann-quantization/src/algorithms/hadamard.rs +++ b/diskann-quantization/src/algorithms/hadamard.rs @@ -383,7 +383,7 @@ mod tests { }; use super::*; - use diskann_utils::views::{self, Matrix, MatrixView}; + use diskann_utils::{Matrix, MatrixView, matrix}; /// Retrieve the 8x8 hadamard matrix as a `Matrix`. fn get_hadamard_8() -> Matrix { @@ -395,11 +395,11 @@ mod tests { assert_ne!(dim, 0); // Base case. if dim == 1 { - Matrix::from_gen(1.0, dim, dim) + Matrix::new(1.0, dim, dim) } else { let half = dim / 2; let sub = hadamard_by_sylvester(half); - let mut m = Matrix::::from_gen(0.0, dim, dim); + let mut m = Matrix::::new(0.0, dim, dim); for c in 0..m.ncols() { for r in 0..m.nrows() { @@ -425,7 +425,7 @@ mod tests { // A naive reference implementation. fn matmul(a: MatrixView, b: MatrixView) -> Matrix { assert_eq!(a.ncols(), b.nrows()); - let mut c = Matrix::from_gen(0.0, a.nrows(), b.ncols()); + let mut c = Matrix::new(0.0, a.nrows(), b.ncols()); for i in 0..c.nrows() { for j in 0..c.ncols() { @@ -443,8 +443,8 @@ mod tests { fn test_micro_kernel_64() { let mut src = { let mut rng = StdRng::seed_from_u64(0xde1936d651285fc8); - let init = views::Init(|| StandardUniform {}.sample(&mut rng)); - Matrix::from_gen(init, 64, 1) + let init = matrix::Init(|| StandardUniform {}.sample(&mut rng)); + Matrix::new(init, 64, 1) }; let h = hadamard_by_sylvester(64); @@ -476,8 +476,8 @@ mod tests { fn test_hadamard_transform(dim: usize, seed: u64) { let src = { let mut rng = StdRng::seed_from_u64(seed); - let init = views::Init(|| StandardUniform {}.sample(&mut rng)); - Matrix::from_gen(init, dim, 1) + let init = matrix::Init(|| StandardUniform {}.sample(&mut rng)); + Matrix::new(init, dim, 1) }; let h = hadamard_by_sylvester(dim); diff --git a/diskann-quantization/src/algorithms/kmeans/lloyds.rs b/diskann-quantization/src/algorithms/kmeans/lloyds.rs index 97c8f3605..9ff1ad9c8 100644 --- a/diskann-quantization/src/algorithms/kmeans/lloyds.rs +++ b/diskann-quantization/src/algorithms/kmeans/lloyds.rs @@ -8,8 +8,8 @@ use diskann_wide::{SIMDMask, SIMDMulAdd, SIMDPartialOrd, SIMDSelect, SIMDSumTree use super::common::square_norm; use crate::multi_vector::{BlockTransposed, BlockTransposedRef}; use diskann_utils::{ + matrix::{Matrix, MatrixView, MatrixViewMut}, strided::StridedView, - views::{Matrix, MatrixView, MatrixViewMut}, }; //////////////////////////////// @@ -343,7 +343,7 @@ fn update((d0, i0): (f32s, u32s), (d1, i1): (f32s, u32s)) -> (f32s, u32s) { ///////////////// fn update_centroids(mut centers: MatrixViewMut<'_, f32>, data: StridedView<'_, f32>, map: &[u32]) { - let mut sums = Matrix::::from_gen(0.0, centers.nrows(), centers.ncols()); + let mut sums = Matrix::::new(0.0, centers.nrows(), centers.ncols()); let mut counts: Vec = vec![0; centers.nrows()]; data.row_iter().zip(map.iter()).for_each(|(row, ¢er)| { counts[center as usize] += 1; @@ -462,9 +462,9 @@ pub fn lloyds( #[cfg(test)] mod tests { + use diskann_utils::Matrix; #[cfg(not(miri))] use diskann_utils::lazy_format; - use diskann_utils::views::Matrix; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom}; #[cfg(not(miri))] @@ -494,8 +494,8 @@ mod tests { ) { let context = lazy_format!("ncenters = {}, ndata = {}, dim = {}", ncenters, ndata, dim,); - let mut centers = Matrix::from_gen(0.0, ncenters, dim); - let mut data = Matrix::from_gen(0.0, ndata, dim); + let mut centers = Matrix::new(0.0, ncenters, dim); + let mut data = Matrix::new(0.0, ndata, dim); // A list of random "nice" offsets that get applied to each center and data point // to ensure proper visitation during computation. @@ -583,8 +583,8 @@ mod tests { // We do not perform any value-dependent control-flow for memory accesses. // Therefore, the miri tests don't require any setup (this helps everything run faseter). fn test_miri_distances_in_place_impl(ndata: usize, ncenters: usize, dim: usize) { - let centers = Matrix::from_gen(0.0, ncenters, dim); - let data = Matrix::from_gen(0.0, ndata, dim); + let centers = Matrix::new(0.0, ncenters, dim); + let data = Matrix::new(0.0, ndata, dim); let data_norms = vec![0.0; ndata]; let center_norms = vec![0.0; ncenters]; let mut nearest = vec![0; ndata]; @@ -658,8 +658,8 @@ mod tests { .collect(); let mut center_order: Vec = (0..setup.ncenters).collect(); - let mut data = Matrix::from_gen(0.0, setup.ncenters * setup.data_per_center, setup.ndim); - let mut centers = Matrix::from_gen(0.0, setup.ncenters, setup.ndim); + let mut data = Matrix::new(0.0, setup.ncenters * setup.data_per_center, setup.ndim); + let mut centers = Matrix::new(0.0, setup.ncenters, setup.ndim); for trial in 0..setup.ntrials { values.shuffle(rng); @@ -751,9 +751,9 @@ mod tests { #[test] #[should_panic(expected = "dataset and data norms should have the same length")] fn distances_in_place_panics_data_norms() { - let data = Matrix::from_gen(0.0, 5, 8); + let data = Matrix::new(0.0, 5, 8); let data_norms = vec![0.0; data.nrows() + 1]; // Incorrect - let centers = Matrix::from_gen(0.0, 2, 8); + let centers = Matrix::new(0.0, 2, 8); let center_norms = vec![0.0; centers.nrows()]; let mut nearest = vec![0; data.nrows()]; distances_in_place( @@ -768,9 +768,9 @@ mod tests { #[test] #[should_panic(expected = "dataset and centers should have the same dimension")] fn distances_in_place_panics_different_dim() { - let data = Matrix::from_gen(0.0, 5, 8); + let data = Matrix::new(0.0, 5, 8); let data_norms = vec![0.0; data.nrows()]; - let centers = Matrix::from_gen(0.0, 2, 9); // Incorrect + let centers = Matrix::new(0.0, 2, 9); // Incorrect let center_norms = vec![0.0; centers.nrows()]; let mut nearest = vec![0; data.nrows()]; distances_in_place( @@ -785,9 +785,9 @@ mod tests { #[test] #[should_panic(expected = "centers and center norms should have the same length")] fn distances_in_place_panics_center_norms() { - let data = Matrix::from_gen(0.0, 5, 8); + let data = Matrix::new(0.0, 5, 8); let data_norms = vec![0.0; data.nrows()]; - let centers = Matrix::from_gen(0.0, 2, 8); + let centers = Matrix::new(0.0, 2, 8); let center_norms = vec![0.0; centers.nrows() + 1]; // Incorrect let mut nearest = vec![0; data.nrows()]; distances_in_place( @@ -802,9 +802,9 @@ mod tests { #[test] #[should_panic(expected = "dataset and nearest-buffer should have the same length")] fn distances_in_place_panics_nearest() { - let data = Matrix::from_gen(0.0, 5, 8); + let data = Matrix::new(0.0, 5, 8); let data_norms = vec![0.0; data.nrows()]; - let centers = Matrix::from_gen(0.0, 2, 8); + let centers = Matrix::new(0.0, 2, 8); let center_norms = vec![0.0; centers.nrows()]; let mut nearest = vec![0; data.nrows() + 1]; // Incorrect distances_in_place( @@ -823,9 +823,9 @@ mod tests { #[test] #[should_panic(expected = "data and norms should have the same length")] fn lloyds_inner_panics_norms_length() { - let data = Matrix::from_gen(0.0, 5, 8); + let data = Matrix::new(0.0, 5, 8); let square_norms = vec![0.0; data.nrows() + 1]; // Incorrect - let mut centers = Matrix::from_gen(0.0, 2, 8); + let mut centers = Matrix::new(0.0, 2, 8); lloyds_inner( data.as_view().into(), &square_norms, @@ -838,10 +838,10 @@ mod tests { #[test] #[should_panic(expected = "data and transpose should have the same length")] fn lloyds_inner_panics_transpose_length() { - let data = Matrix::from_gen(0.0, 5, 8); - let data_incorrect = Matrix::from_gen(0.0, 5 + 1, 8); // Incorrect + let data = Matrix::new(0.0, 5, 8); + let data_incorrect = Matrix::new(0.0, 5 + 1, 8); // Incorrect let square_norms = vec![0.0; data.nrows()]; - let mut centers = Matrix::from_gen(0.0, 2, 8); + let mut centers = Matrix::new(0.0, 2, 8); lloyds_inner( data.as_view().into(), &square_norms, @@ -854,10 +854,10 @@ mod tests { #[test] #[should_panic(expected = "data and transpose should have the same dimensions")] fn lloyds_inner_panics_transpose_dim() { - let data = Matrix::from_gen(0.0, 5, 8); - let data_incorrect = Matrix::from_gen(0.0, 5, 8 + 1); // Incorrect + let data = Matrix::new(0.0, 5, 8); + let data_incorrect = Matrix::new(0.0, 5, 8 + 1); // Incorrect let square_norms = vec![0.0; data.nrows()]; - let mut centers = Matrix::from_gen(0.0, 2, 8); + let mut centers = Matrix::new(0.0, 2, 8); lloyds_inner( data.as_view().into(), &square_norms, @@ -870,9 +870,9 @@ mod tests { #[test] #[should_panic(expected = "data and centers should have the same dimensions")] fn lloyds_inner_panics_centers_dim() { - let data = Matrix::from_gen(0.0, 5, 8); + let data = Matrix::new(0.0, 5, 8); let square_norms = vec![0.0; data.nrows()]; - let mut centers = Matrix::from_gen(0.0, 2, 8 + 1); // Incorrect + let mut centers = Matrix::new(0.0, 2, 8 + 1); // Incorrect lloyds_inner( data.as_view().into(), &square_norms, @@ -889,8 +889,8 @@ mod tests { #[test] #[should_panic(expected = "data and centers must have the same dimension")] fn lloyds_panics_dim_mismatch() { - let data = Matrix::from_gen(0.0, 5, 8); - let mut centers = Matrix::from_gen(0.0, 5, 8 + 1); // Incorrect + let data = Matrix::new(0.0, 5, 8); + let mut centers = Matrix::new(0.0, 5, 8 + 1); // Incorrect lloyds(data.as_view(), centers.as_mut_view(), 1); } } diff --git a/diskann-quantization/src/algorithms/kmeans/plusplus.rs b/diskann-quantization/src/algorithms/kmeans/plusplus.rs index 868bfb2c2..bb399237c 100644 --- a/diskann-quantization/src/algorithms/kmeans/plusplus.rs +++ b/diskann-quantization/src/algorithms/kmeans/plusplus.rs @@ -6,8 +6,8 @@ use std::{collections::HashSet, fmt}; use diskann_utils::{ + matrix::{MatrixView, MatrixViewMut}, strided::StridedView, - views::{MatrixView, MatrixViewMut}, }; use diskann_wide::{SIMDMulAdd, SIMDPartialOrd, SIMDSelect, SIMDVector}; use rand::{ @@ -521,7 +521,7 @@ pub fn kmeans_plusplus_into( #[cfg(test)] mod tests { - use diskann_utils::{lazy_format, views::Matrix}; + use diskann_utils::{lazy_format, matrix::Matrix}; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom}; @@ -609,14 +609,14 @@ mod tests { dim ); - let mut data = Matrix::::from_gen(0.0, num_points, dim); + let mut data = Matrix::::new(0.0, num_points, dim); set_default_values(data.as_mut_view()); let square_norms: Vec = data.row_iter().map(square_norm).collect(); // The sample points we are computing the distances against. let num_samples = 3; - let mut samples = Matrix::::from_gen(0.0, num_samples, dim); + let mut samples = Matrix::::new(0.0, num_samples, dim); let mut distances = vec![f32::INFINITY; num_points]; let distribution = Uniform::::new(0, (num_points + dim) as u32).unwrap(); let transpose = BlockTransposed::::from_matrix_view(data.as_view()); @@ -725,12 +725,12 @@ mod tests { assert_eq!(values.len(), ndata); values.shuffle(rng); - let mut data = Matrix::from_gen(0.0, ndata, dim); + let mut data = Matrix::new(0.0, ndata, dim); for (r, v) in std::iter::zip(data.row_iter_mut(), values.iter()) { r.fill(*v); } - let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, dim); + let mut centers = Matrix::new(f32::INFINITY, ncenters, dim); kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), rng).unwrap(); // Make sure that each value was selected for a center. @@ -803,12 +803,12 @@ mod tests { assert_eq!(values.len(), ndata); values.shuffle(rng); - let mut data = Matrix::from_gen(0.0, ndata, dim); + let mut data = Matrix::new(0.0, ndata, dim); for (r, v) in std::iter::zip(data.row_iter_mut(), values.iter()) { r.fill(*v); } - let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, dim); + let mut centers = Matrix::new(f32::INFINITY, ncenters, dim); kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), rng).unwrap(); // Make sure that each value was selected for a center. @@ -868,8 +868,8 @@ mod tests { // Failure modes #[test] fn fail_empty_dataset() { - let data = Matrix::from_gen(0.0, 0, 5); - let mut centers = Matrix::from_gen(0.0, 10, data.ncols()); + let data = Matrix::new(0.0, 0, 5); + let mut centers = Matrix::new(0.0, 10, data.ncols()); let mut rng = StdRng::seed_from_u64(0xa9eae150d30845a1); @@ -889,8 +889,8 @@ mod tests { #[test] fn both_empty_is_okay() { - let data = Matrix::from_gen(0.0, 0, 5); - let mut centers = Matrix::from_gen(0.0, 0, data.ncols()); + let data = Matrix::new(0.0, 0, 5); + let mut centers = Matrix::new(0.0, 0, data.ncols()); let mut rng = StdRng::seed_from_u64(0x6f7031afd9b5aa18); let result = kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), &mut rng); assert!( @@ -905,9 +905,9 @@ mod tests { let ncenters = 10; let dim = 5; - let mut data = Matrix::from_gen(0.0, ndata, dim); + let mut data = Matrix::new(0.0, ndata, dim); set_default_values(data.as_mut_view()); - let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, data.ncols()); + let mut centers = Matrix::new(f32::INFINITY, ncenters, data.ncols()); let mut rng = StdRng::seed_from_u64(0xa9eae150d30845a1); @@ -943,12 +943,12 @@ mod tests { assert!(values.len() >= ndata); values.shuffle(&mut rng); - let mut data = Matrix::from_gen(0.0, ndata, dim); + let mut data = Matrix::new(0.0, ndata, dim); for (r, v) in std::iter::zip(data.row_iter_mut(), values.iter()) { r.fill(*v); } - let mut centers = Matrix::from_gen(f32::INFINITY, ncenters, dim); + let mut centers = Matrix::new(f32::INFINITY, ncenters, dim); let result = kmeans_plusplus_into(centers.as_mut_view(), data.as_view(), &mut rng); assert!( result.is_err(), @@ -965,12 +965,12 @@ mod tests { #[test] fn fail_intinity_check() { - let mut data = Matrix::from_gen(0.0, 10, 1); + let mut data = Matrix::new(0.0, 10, 1); set_default_values(data.as_mut_view()); // A very large value that will overflow to infinity when computing the norm. data[(6, 0)] = -3.4028235e38; - let mut centers = Matrix::from_gen(0.0, 2, 1); + let mut centers = Matrix::new(0.0, 2, 1); let mut rng = StdRng::seed_from_u64(0xc0449b2aa4e12f05); @@ -987,12 +987,12 @@ mod tests { #[test] fn fail_nan_check() { - let mut data = Matrix::from_gen(0.0, 10, 1); + let mut data = Matrix::new(0.0, 10, 1); set_default_values(data.as_mut_view()); // A very large value that will overflow to infinity when computing the norm. data[(6, 0)] = f32::NAN; - let mut centers = Matrix::from_gen(0.0, 2, 1); + let mut centers = Matrix::new(0.0, 2, 1); let mut rng = StdRng::seed_from_u64(0x55808c6c728c8473); @@ -1017,7 +1017,7 @@ mod tests { let npoints = 5; let dim = 8; let mut square_distances = vec![0.0; npoints]; - let data = Matrix::from_gen(0.0, npoints, dim); + let data = Matrix::new(0.0, npoints, dim); let norms = vec![0.0; npoints]; let this = vec![0.0; dim + 1]; // Incorrect let this_square_norm = 0.0; @@ -1036,7 +1036,7 @@ mod tests { let npoints = 5; let dim = 8; let mut square_distances = vec![0.0; npoints + 1]; // Incorrect - let data = Matrix::from_gen(0.0, npoints, dim); + let data = Matrix::new(0.0, npoints, dim); let norms = vec![0.0; npoints]; let this = vec![0.0; dim]; let this_square_norm = 0.0; @@ -1055,7 +1055,7 @@ mod tests { let npoints = 5; let dim = 8; let mut square_distances = vec![0.0; npoints]; - let data = Matrix::from_gen(0.0, npoints, dim); + let data = Matrix::new(0.0, npoints, dim); let norms = vec![0.0; npoints + 1]; // Incorrect let this = vec![0.0; dim]; let this_square_norm = 0.0; @@ -1077,8 +1077,8 @@ mod tests { expected = "centers output matrix should have the same dimensionality as the dataset" )] fn kmeans_plusplus_into_panics_dim_mismatch() { - let mut centers = Matrix::from_gen(0.0, 2, 10); - let data = Matrix::from_gen(0.0, 2, 9); + let mut centers = Matrix::new(0.0, 2, 10); + let data = Matrix::new(0.0, 2, 9); kmeans_plusplus_into( centers.as_mut_view(), data.as_view(), diff --git a/diskann-quantization/src/algorithms/transforms/random_rotation.rs b/diskann-quantization/src/algorithms/transforms/random_rotation.rs index 5c416d964..16265d0c9 100644 --- a/diskann-quantization/src/algorithms/transforms/random_rotation.rs +++ b/diskann-quantization/src/algorithms/transforms/random_rotation.rs @@ -31,7 +31,7 @@ use crate::flatbuffers as fb; #[cfg_attr(test, derive(PartialEq))] pub struct RandomRotation { /// This data structure maintains the invariant that this **must** be a square matrix. - transform: diskann_utils::views::Matrix, + transform: diskann_utils::Matrix, } impl RandomRotation { @@ -88,7 +88,7 @@ impl RandomRotation { // Lint: By construction, the matrix returned from // `diskann_linalg::random_distance_preserving_matrix` will by `matrix_dim x matrix_dim`. #[allow(clippy::unwrap_used)] - let initial = diskann_utils::views::Matrix::try_from( + let initial = diskann_utils::Matrix::try_from( diskann_linalg::random_distance_preserving_matrix(matrix_dim, rng).into(), matrix_dim, matrix_dim, @@ -102,7 +102,7 @@ impl RandomRotation { let indices = rand::seq::index::sample(rng, dim, target_dim); let scaling = (dim as f32 / target_dim as f32).sqrt(); - let mut transform = diskann_utils::views::Matrix::from_gen(0.0f32, target_dim, dim); + let mut transform = diskann_utils::Matrix::new(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), indices.iter()).for_each(|(ro, ri)| { std::iter::zip(ro.iter_mut(), initial.row(ri).iter()).for_each(|(o, i)| { *o = scaling * (*i); @@ -111,7 +111,7 @@ impl RandomRotation { transform } std::cmp::Ordering::Greater => { - let mut transform = diskann_utils::views::Matrix::from_gen(0.0f32, target_dim, dim); + let mut transform = diskann_utils::Matrix::new(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), initial.row_iter()) .for_each(|(o, i)| o.copy_from_slice(&i[..dim])); transform @@ -220,7 +220,7 @@ impl RandomRotation { let data = proto.data().into_iter().collect(); let transform = - diskann_utils::views::Matrix::try_from(data, nrows as usize, ncols as usize) + diskann_utils::Matrix::try_from(data, nrows as usize, ncols as usize) .map_err(|_| RandomRotationError::IncorrectDim)?; Ok(Self { transform }) diff --git a/diskann-quantization/src/binary/quantizer.rs b/diskann-quantization/src/binary/quantizer.rs index eb64ca489..a059543d1 100644 --- a/diskann-quantization/src/binary/quantizer.rs +++ b/diskann-quantization/src/binary/quantizer.rs @@ -129,7 +129,7 @@ impl AsFunctor for BinaryQuantizer { #[cfg(test)] mod tests { - use diskann_utils::{ReborrowMut, views::Matrix}; + use diskann_utils::{ReborrowMut, matrix::Matrix}; use rand::{SeedableRng, rngs::StdRng, seq::SliceRandom}; use super::*; @@ -137,7 +137,7 @@ mod tests { fn test_compression_impl(len: usize, rng: &mut StdRng) { let mut domain = [-10, -1, 0, 1, 10]; - let mut test_pattern = Matrix::::from_gen(0, domain.len(), len); + let mut test_pattern = Matrix::::new(0, domain.len(), len); // Fill the test patterns randomly. for col in 0..len { diff --git a/diskann-quantization/src/minmax/multi/max_sim.rs b/diskann-quantization/src/minmax/multi/max_sim.rs index 5832b9b4d..44382f00b 100644 --- a/diskann-quantization/src/minmax/multi/max_sim.rs +++ b/diskann-quantization/src/minmax/multi/max_sim.rs @@ -202,9 +202,9 @@ mod tests { where Unsigned: Representation, { - let input_mat = MatRef::new(RowMajor::::new(n, dim).unwrap(), input).unwrap(); + let input_mat = MatRef::from_repr(RowMajor::::new(n, dim).unwrap(), input).unwrap(); let mut output: Mat> = - Mat::new(MinMaxMeta::new(n, dim), Defaulted).unwrap(); + Mat::from_repr(MinMaxMeta::new(n, dim), Defaulted).unwrap(); quantizer .compress_into(input_mat, output.reborrow_mut()) .unwrap(); @@ -301,10 +301,10 @@ mod tests { let query_data = vec![0u8; 2 * row_bytes]; let doc_data = vec![0u8; 3 * row_bytes]; - let query: QueryMatRef<_> = MatRef::new(MinMaxMeta::<8>::new(2, dim), &query_data) + let query: QueryMatRef<_> = MatRef::from_repr(MinMaxMeta::<8>::new(2, dim), &query_data) .unwrap() .into(); - let doc = MatRef::new(MinMaxMeta::<8>::new(3, dim), &doc_data).unwrap(); + let doc = MatRef::from_repr(MinMaxMeta::<8>::new(3, dim), &doc_data).unwrap(); let mut scores = vec![0.0f32; 5]; // Wrong size MaxSim::new(&mut scores).evaluate(query, doc); diff --git a/diskann-quantization/src/minmax/multi/meta.rs b/diskann-quantization/src/minmax/multi/meta.rs index 733367c1d..d0dd693b7 100644 --- a/diskann-quantization/src/minmax/multi/meta.rs +++ b/diskann-quantization/src/minmax/multi/meta.rs @@ -171,7 +171,7 @@ where { type Error = crate::error::Infallible; fn new_owned(self, _: Defaulted) -> Result, Self::Error> { - let b: Box<[u8]> = (0..self.bytes()).map(|_| u8::default()).collect(); + let b: Box<[u8]> = vec![0u8; self.bytes()].into_boxed_slice(); let ptr = utils::box_into_nonnull(b).cast::(); @@ -372,7 +372,7 @@ mod tests { mod construction { use super::*; - /// Tests NewOwned (Mat::new with Defaulted) for various dimensions and sizes. + /// Tests NewOwned (Mat::from_repr with Defaulted) for various dimensions and sizes. fn test_new_owned() where Unsigned: Representation, @@ -381,7 +381,7 @@ mod tests { for &num_vectors in TEST_NVECS { let meta = MinMaxMeta::::new(num_vectors, dim); let mat: Mat> = - Mat::new(meta, Defaulted).expect("NewOwned should succeed"); + Mat::from_repr(meta, Defaulted).expect("NewOwned should succeed"); // Verify num_vectors and intrinsic_dim assert_eq!(mat.num_vectors(), num_vectors); @@ -412,7 +412,7 @@ mod tests { expand_to_bitrates!(new_owned, test_new_owned); - /// Tests NewRef (MatRef::new) for valid slices. + /// Tests NewRef (MatRef::from_repr) for valid slices. fn test_new_ref() where Unsigned: Representation, @@ -425,7 +425,7 @@ mod tests { // Valid slice let data = vec![0u8; expected_bytes]; - let mat_ref = MatRef::new(meta, &data); + let mat_ref = MatRef::from_repr(meta, &data); assert!(mat_ref.is_ok(), "NewRef should succeed for correct size"); let mat_ref = mat_ref.unwrap(); @@ -446,7 +446,7 @@ mod tests { expand_to_bitrates!(new_ref, test_new_ref); - /// Tests NewMut (MatMut::new) for valid slices. + /// Tests NewMut (MatMut::from_repr) for valid slices. fn test_new_mut() where Unsigned: Representation, @@ -458,7 +458,7 @@ mod tests { let expected_bytes = expected_row_bytes * num_vectors; let mut data = vec![0u8; expected_bytes]; - let mat_mut = MatMut::new(meta, &mut data); + let mat_mut = MatMut::from_repr(meta, &mut data); assert!(mat_mut.is_ok(), "NewMut should succeed for correct size"); let mat_mut = mat_mut.unwrap(); @@ -488,7 +488,7 @@ mod tests { // Too short let short_data = vec![0u8; expected_bytes - 1]; - let result = MatRef::new(meta, &short_data); + let result = MatRef::from_repr(meta, &short_data); assert!( matches!(result, Err(SliceError::LengthMismatch { .. })), "should fail for too-short slice" @@ -496,7 +496,7 @@ mod tests { // Too long let long_data = vec![0u8; expected_bytes + 1]; - let result = MatRef::new(meta, &long_data); + let result = MatRef::from_repr(meta, &long_data); assert!( matches!(result, Err(SliceError::LengthMismatch { .. })), "should fail for too-long slice" @@ -504,7 +504,7 @@ mod tests { // Mutable version - too short let mut short_mut = vec![0u8; expected_bytes - 1]; - let result = MatMut::new(meta, &mut short_mut); + let result = MatMut::from_repr(meta, &mut short_mut); assert!( matches!(result, Err(SliceError::LengthMismatch { .. })), "MatMut should fail for too-short slice" @@ -532,11 +532,11 @@ mod tests { // Multi-vector compression let input_view = - MatRef::new(RowMajor::new(num_vectors, dim).unwrap(), &input_data) + MatRef::from_repr(RowMajor::new(num_vectors, dim).unwrap(), &input_data) .expect("input view creation"); let mut multi_mat: Mat> = - Mat::new(MinMaxMeta::new(num_vectors, dim), Defaulted) + Mat::from_repr(MinMaxMeta::new(num_vectors, dim), Defaulted) .expect("output mat creation"); quantizer @@ -587,11 +587,12 @@ mod tests { let quantizer = make_quantizer(dim); let input_data = generate_test_data(num_vectors, dim); - let input_view = MatRef::new(RowMajor::new(num_vectors, dim).unwrap(), &input_data) - .expect("input view"); + let input_view = + MatRef::from_repr(RowMajor::new(num_vectors, dim).unwrap(), &input_data) + .expect("input view"); let mut mat: Mat> = - Mat::new(MinMaxMeta::new(num_vectors, dim), Defaulted).expect("mat creation"); + Mat::from_repr(MinMaxMeta::new(num_vectors, dim), Defaulted).expect("mat creation"); quantizer .compress_into(input_view, mat.reborrow_mut()) @@ -627,11 +628,11 @@ mod tests { // Input has 3 vectors let input_data = generate_test_data(3, dim); let input_view = - MatRef::new(RowMajor::new(3, dim).unwrap(), &input_data).expect("input view"); + MatRef::from_repr(RowMajor::new(3, dim).unwrap(), &input_data).expect("input view"); // Output has 2 vectors (mismatch) let mut mat: Mat> = - Mat::new(MinMaxMeta::new(2, dim), Defaulted).expect("mat creation"); + Mat::from_repr(MinMaxMeta::new(2, dim), Defaulted).expect("mat creation"); let _ = quantizer.compress_into(input_view, mat.reborrow_mut()); } @@ -645,11 +646,11 @@ mod tests { // Input has dim=8 (mismatch) let input_data = generate_test_data(2, 8); let input_view = - MatRef::new(RowMajor::new(2, 8).unwrap(), &input_data).expect("input view"); + MatRef::from_repr(RowMajor::new(2, 8).unwrap(), &input_data).expect("input view"); // Output correctly has dim=4 let mut mat: Mat> = - Mat::new(MinMaxMeta::new(2, 4), Defaulted).expect("mat creation"); + Mat::from_repr(MinMaxMeta::new(2, 4), Defaulted).expect("mat creation"); let _ = quantizer.compress_into(input_view, mat.reborrow_mut()); } @@ -665,13 +666,13 @@ mod tests { // Input correctly has dim=4 let input_data = generate_test_data(2, 4); let input_view = - MatRef::new(RowMajor::new(2, 4).unwrap(), &input_data).expect("input view"); + MatRef::from_repr(RowMajor::new(2, 4).unwrap(), &input_data).expect("input view"); // Output has intrinsic_dim=8 (mismatch) let row_bytes = Data::::canonical_bytes(8); let mut output_data = vec![0u8; 2 * row_bytes]; - let output_view = - MatMut::new(MinMaxMeta::::new(2, 8), &mut output_data).expect("output view"); + let output_view = MatMut::from_repr(MinMaxMeta::::new(2, 8), &mut output_data) + .expect("output view"); let _ = quantizer.compress_into(input_view, output_view); } diff --git a/diskann-quantization/src/minmax/multi/mod.rs b/diskann-quantization/src/minmax/multi/mod.rs index 7edce3740..793d8316e 100644 --- a/diskann-quantization/src/minmax/multi/mod.rs +++ b/diskann-quantization/src/minmax/multi/mod.rs @@ -44,7 +44,7 @@ //! 1.0, 0.0, 0.0, 0.0, // query vector 0 //! 0.0, 1.0, 0.0, 0.0, // query vector 1 //! ]; -//! let query_input = MatRef::new( +//! let query_input = MatRef::from_repr( //! RowMajor::new(num_query_vectors, dim).unwrap(), &query_data //! ).unwrap(); //! @@ -54,15 +54,15 @@ //! 1.0, 0.0, 0.0, 0.0, // doc vector 1 //! 0.0, 0.0, 1.0, 0.0, // doc vector 2 //! ]; -//! let doc_input = MatRef::new( +//! let doc_input = MatRef::from_repr( //! RowMajor::new(num_doc_vectors, dim).unwrap(), &doc_data //! ).unwrap(); //! -//! // Create owned matrices for quantized output using Mat::new +//! // Create owned matrices for quantized output using Mat::from_repr //! let mut query_out: Mat> = -//! Mat::new(MinMaxMeta::new(num_query_vectors, dim), Defaulted).unwrap(); +//! Mat::from_repr(MinMaxMeta::new(num_query_vectors, dim), Defaulted).unwrap(); //! let mut doc_out: Mat> = -//! Mat::new(MinMaxMeta::new(num_doc_vectors, dim), Defaulted).unwrap(); +//! Mat::from_repr(MinMaxMeta::new(num_doc_vectors, dim), Defaulted).unwrap(); //! //! // Quantize both multi-vectors //! quantizer.compress_into(query_input, query_out.reborrow_mut()).unwrap(); diff --git a/diskann-quantization/src/multi_vector/block_transposed.rs b/diskann-quantization/src/multi_vector/block_transposed.rs index 3efb5ddad..5e9ad9eaf 100644 --- a/diskann-quantization/src/multi_vector/block_transposed.rs +++ b/diskann-quantization/src/multi_vector/block_transposed.rs @@ -81,8 +81,8 @@ use std::{alloc::Layout, marker::PhantomData, ptr::NonNull}; use diskann_utils::{ Reborrow, ReborrowMut, + matrix::{MatrixView, MatrixViewMut}, strided::StridedView, - views::{MatrixView, MatrixViewMut}, }; use super::matrix::{ @@ -579,10 +579,8 @@ unsafe impl ReprOwned // SAFETY: The returned `Mat` contains a `Box` with exactly `self.storage_len()` elements. // -// Only `NewOwned` is provided (no generic `NewOwned` value-fill): `Defaulted` -// now lives in `diskann-utils`, so a value-fill impl would overlap with this one under the -// intercrate coherence rules (the compiler cannot prove `Defaulted: !Default` for a foreign -// type). Block-transposed matrices are only ever default-initialized. +// No generic `NewOwned` value-fill: `Defaulted` is foreign (diskann-utils), so a value-fill +// impl would overlap with this under intercrate coherence. These matrices are only default-init'd. unsafe impl NewOwned for BlockTransposedRepr { @@ -1112,7 +1110,7 @@ impl BlockTransposed::new(nrows, ncols) .expect("dimensions should not overflow"); Self { - data: Mat::new(repr, Defaulted).expect("infallible"), + data: Mat::from_repr(repr, Defaulted).expect("infallible"), } } @@ -1120,7 +1118,7 @@ impl BlockTransposed Result { let repr = BlockTransposedRepr::::new(nrows, ncols)?; Ok(Self { - data: Mat::new(repr, Defaulted).expect("infallible"), + data: Mat::from_repr(repr, Defaulted).expect("infallible"), }) } @@ -1230,7 +1228,7 @@ mod tests { //! parameters to `test_full_api` (`Send`/`Sync`, panic paths, //! non-unit strides, concurrent mutation, etc.). - use diskann_utils::{lazy_format, views::Matrix}; + use diskann_utils::{lazy_format, matrix::Matrix}; use super::*; use crate::utils::div_round_up; @@ -1282,7 +1280,7 @@ mod tests { // ── Construction ───────────────────────────────────────── - let mut data = Matrix::from_gen(T::default(), nrows, ncols); + let mut data = Matrix::new(T::default(), nrows, ncols); data.as_mut_slice() .iter_mut() .enumerate() @@ -1838,7 +1836,7 @@ mod tests { ncols: usize, gen_element: fn(usize) -> T, ) { - let mut data = Matrix::from_gen(T::default(), nrows, ncols); + let mut data = Matrix::new(T::default(), nrows, ncols); data.as_mut_slice() .iter_mut() .enumerate() diff --git a/diskann-quantization/src/multi_vector/distance/factory.rs b/diskann-quantization/src/multi_vector/distance/factory.rs index e05016b17..817d64a87 100644 --- a/diskann-quantization/src/multi_vector/distance/factory.rs +++ b/diskann-quantization/src/multi_vector/distance/factory.rs @@ -444,7 +444,7 @@ mod tests { } fn make_mat(data: &[T], nrows: usize, ncols: usize) -> MatRef<'_, RowMajor> { - MatRef::new(RowMajor::new(nrows, ncols).unwrap(), data).unwrap() + MatRef::from_repr(RowMajor::new(nrows, ncols).unwrap(), data).unwrap() } fn make_test_data(len: usize, ceil: usize, shift: usize) -> Vec { diff --git a/diskann-quantization/src/multi_vector/distance/fallback.rs b/diskann-quantization/src/multi_vector/distance/fallback.rs index 22fa460e4..86319a831 100644 --- a/diskann-quantization/src/multi_vector/distance/fallback.rs +++ b/diskann-quantization/src/multi_vector/distance/fallback.rs @@ -29,7 +29,7 @@ use crate::multi_vector::{MatRef, MaxSimError, Repr, RowMajor}; /// use diskann_quantization::multi_vector::distance::QueryMatRef; /// /// let data = [1.0f32, 2.0, 3.0, 4.0]; -/// let view = MatRef::new(RowMajor::new(2, 2).unwrap(), &data).unwrap(); +/// let view = MatRef::from_repr(RowMajor::new(2, 2).unwrap(), &data).unwrap(); /// let query: QueryMatRef<_> = view.into(); /// ``` #[derive(Debug, Clone, Copy)] @@ -231,14 +231,14 @@ mod tests { /// Helper to create a QueryMatRef from raw data fn make_query(data: &[f32], nrows: usize, ncols: usize) -> QueryMatRef<'_, RowMajor> { - MatRef::new(RowMajor::new(nrows, ncols).unwrap(), data) + MatRef::from_repr(RowMajor::new(nrows, ncols).unwrap(), data) .unwrap() .into() } /// Helper to create a MatRef from raw data fn make_doc(data: &[f32], nrows: usize, ncols: usize) -> MatRef<'_, RowMajor> { - MatRef::new(RowMajor::new(nrows, ncols).unwrap(), data).unwrap() + MatRef::from_repr(RowMajor::new(nrows, ncols).unwrap(), data).unwrap() } /// Naive implementation of max-sim for a single query vector against all doc vectors. @@ -273,7 +273,7 @@ mod tests { #[test] fn from_mat_ref_and_deref() { let data = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; - let view = MatRef::new(RowMajor::new(2, 3).unwrap(), &data).unwrap(); + let view = MatRef::from_repr(RowMajor::new(2, 3).unwrap(), &data).unwrap(); let query: QueryMatRef<_> = view.into(); // Deref access works diff --git a/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs b/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs index e7d3ebf07..5cd689d65 100644 --- a/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs +++ b/diskann-quantization/src/multi_vector/distance/kernels/tiled_reduce.rs @@ -521,9 +521,9 @@ mod tests { layouts::RowMajor: ConvertTo as Kernel>::Right> + Layout, { - let a_mat = MatRef::new(RowMajor::new(a_nrows, dim).unwrap(), a_data).unwrap(); + let a_mat = MatRef::from_repr(RowMajor::new(a_nrows, dim).unwrap(), a_data).unwrap(); let a_bt = BlockTransposed::::from_matrix_view(a_mat.as_matrix_view()); - let b_mat = MatRef::new(RowMajor::new(b_nrows, dim).unwrap(), b_data).unwrap(); + let b_mat = MatRef::from_repr(RowMajor::new(b_nrows, dim).unwrap(), b_data).unwrap(); let mut scratch = vec![f32::MIN; a_bt.padded_nrows()]; max_ip_kernel::( @@ -741,9 +741,9 @@ mod tests { let b_data = gen_data(b_nrows * dim, ceil); let expected = naive(&a_data, a_nrows, &b_data, b_nrows, dim); - let a_mat = MatRef::new(RowMajor::new(a_nrows, dim).unwrap(), &a_data).unwrap(); + let a_mat = MatRef::from_repr(RowMajor::new(a_nrows, dim).unwrap(), &a_data).unwrap(); let a_bt = BlockTransposed::::from_matrix_view(a_mat.as_matrix_view()); - let b_mat = MatRef::new(RowMajor::new(b_nrows, dim).unwrap(), &b_data).unwrap(); + let b_mat = MatRef::from_repr(RowMajor::new(b_nrows, dim).unwrap(), &b_data).unwrap(); let mut scratch = vec![f32::MIN; a_bt.padded_nrows()]; max_ip_kernel::(arch, a_bt.as_view(), b_mat, &mut scratch, budget); diff --git a/diskann-quantization/src/multi_vector/distance/mod.rs b/diskann-quantization/src/multi_vector/distance/mod.rs index af96642b3..9e94c81bc 100644 --- a/diskann-quantization/src/multi_vector/distance/mod.rs +++ b/diskann-quantization/src/multi_vector/distance/mod.rs @@ -18,14 +18,14 @@ //! //! // Query: 2 vectors of dim 3 (wrapped as QueryMatRef) //! let query_data = [1.0f32, 0.0, 0.0, 0.0, 1.0, 0.0]; -//! let query: QueryMatRef<_> = MatRef::new( +//! let query: QueryMatRef<_> = MatRef::from_repr( //! RowMajor::new(2, 3).unwrap(), //! &query_data, //! ).unwrap().into(); //! //! // Doc: 2 vectors of dim 3 //! let doc_data = [1.0f32, 0.0, 0.0, 0.0, 0.0, 1.0]; -//! let doc = MatRef::new( +//! let doc = MatRef::from_repr( //! RowMajor::new(2, 3).unwrap(), //! &doc_data, //! ).unwrap(); diff --git a/diskann-quantization/src/multi_vector/mod.rs b/diskann-quantization/src/multi_vector/mod.rs index 51f7a3049..668b75a4d 100644 --- a/diskann-quantization/src/multi_vector/mod.rs +++ b/diskann-quantization/src/multi_vector/mod.rs @@ -19,7 +19,7 @@ //! use diskann_vector::{DistanceFunctionMut, PureDistanceFunction}; //! //! // Create an owned matrix (2 vectors, dim 3, initialized to 0.0) -//! let mut owned = Mat::new(RowMajor::new(2, 3).unwrap(), 0.0f32).unwrap(); +//! let mut owned = Mat::from_repr(RowMajor::new(2, 3).unwrap(), 0.0f32).unwrap(); //! assert_eq!(owned.num_vectors(), 2); //! //! // Modify via mutable view @@ -33,11 +33,11 @@ //! let doc_data = [1.0f32, 0.0, 0.0, 1.0]; //! //! // Wrap query as QueryMatRef for type-safe asymmetric distance -//! let query: QueryMatRef<_> = MatRef::new( +//! let query: QueryMatRef<_> = MatRef::from_repr( //! RowMajor::new(2, 2).unwrap(), //! &query_data, //! ).unwrap().into(); -//! let doc = MatRef::new(RowMajor::new(2, 2).unwrap(), &doc_data).unwrap(); +//! let doc = MatRef::from_repr(RowMajor::new(2, 2).unwrap(), &doc_data).unwrap(); //! //! // Chamfer distance (sum of max similarities) //! let distance = Chamfer::evaluate(query, doc); @@ -56,11 +56,11 @@ pub mod distance; pub(crate) use diskann_utils::matrix; pub use block_transposed::{BlockTransposed, BlockTransposedMut, BlockTransposedRef}; +pub use diskann_utils::matrix::{ + Defaulted, LayoutError, Mat, MatMut, MatRef, NewCloned, NewMut, NewOwned, NewRef, Overflow, + Repr, ReprMut, ReprOwned, RowMajor, SliceError, +}; pub use distance::{ BoxErase, Chamfer, Erase, MaxSim, MaxSimElement, MaxSimError, MaxSimIsa, MaxSimKernel, NotSupported, ProjectedEigen, QueryMatRef, build_max_sim, }; -pub use diskann_utils::matrix::{ - Defaulted, LayoutError, Mat, MatMut, MatRef, NewCloned, NewMut, NewOwned, NewRef, Overflow, - Repr, ReprMut, ReprOwned, SliceError, RowMajor, -}; diff --git a/diskann-quantization/src/product/tables/basic.rs b/diskann-quantization/src/product/tables/basic.rs index e22ee04d8..c826af640 100644 --- a/diskann-quantization/src/product/tables/basic.rs +++ b/diskann-quantization/src/product/tables/basic.rs @@ -5,7 +5,7 @@ use crate::traits::CompressInto; use crate::views::{ChunkOffsetsBase, ChunkOffsetsView}; -use diskann_utils::views::{DenseData, Matrix, MatrixView}; +use diskann_utils::{DenseData, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use thiserror::Error; @@ -22,25 +22,40 @@ use thiserror::Error; /// /// # Invariants /// -/// * `offsets.dim() == pivots.nrows()`: The dimensionality of the two must agree. +/// * `offsets.dim() == pivots.ncols()`: The dimensionality of the two must agree. #[derive(Debug, Clone)] -pub struct BasicTableBase +pub struct BasicTableBase where - T: DenseData, U: DenseData, { - pivots: T, - num_pivots: usize, - pivot_dim: usize, + pivots: M, offsets: ChunkOffsetsBase, } /// A `BasicTableBase` that owns its contents. -pub type BasicTable = BasicTableBase, Box<[usize]>>; +pub type BasicTable = BasicTableBase, Box<[usize]>>; /// A `BasicTableBase` that references its contents. Construction of such a table will /// not result in a memory allocation. -pub type BasicTableView<'a> = BasicTableBase<&'a [f32], &'a [usize]>; +pub type BasicTableView<'a> = BasicTableBase, &'a [usize]>; + +/// Bridges owned ([`Matrix`]) and borrowed ([`MatrixView`]) pivot storage, exposing a +/// [`MatrixView`] so a [`BasicTableBase`] reads its dimensions and rows from one place. +pub trait PivotTable { + fn view(&self) -> MatrixView<'_, f32>; +} + +impl PivotTable for Matrix { + fn view(&self) -> MatrixView<'_, f32> { + self.as_matrix_view() + } +} + +impl PivotTable for MatrixView<'_, f32> { + fn view(&self) -> MatrixView<'_, f32> { + self.as_matrix_view() + } +} #[derive(Error, Debug)] #[non_exhaustive] @@ -54,9 +69,9 @@ pub enum BasicTableError { PivotsEmpty, } -impl BasicTableBase +impl BasicTableBase where - T: DenseData, + M: PivotTable, U: DenseData, { /// Construct a new `BasicTableBase` over the pivot table and offsets. @@ -64,12 +79,11 @@ where /// # Error /// /// Returns an error if `pivots.ncols() != offsets.dim()` or if `pivots.nrows() == 0`. - fn from_parts( - pivots: T, - num_pivots: usize, - pivot_dim: usize, - offsets: ChunkOffsetsBase, - ) -> Result { + pub fn new(pivots: M, offsets: ChunkOffsetsBase) -> Result { + let (num_pivots, pivot_dim) = { + let view = pivots.view(); + (view.nrows(), view.ncols()) + }; let offsets_dim = offsets.dim(); if pivot_dim != offsets_dim { @@ -80,20 +94,13 @@ where } else if num_pivots == 0 { Err(BasicTableError::PivotsEmpty) } else { - Ok(Self { - pivots, - num_pivots, - pivot_dim, - offsets, - }) + Ok(Self { pivots, offsets }) } } /// Return a view over the pivot table. - #[allow(clippy::expect_used)] pub fn view_pivots(&self) -> MatrixView<'_, f32> { - MatrixView::try_from(self.pivots.as_slice(), self.num_pivots, self.pivot_dim) - .expect("valid pivot dimensions") + self.pivots.view() } /// Return a view over the schema offsets. @@ -103,7 +110,7 @@ where /// Return the number of pivots in each PQ chunk. pub fn ncenters(&self) -> usize { - self.num_pivots + self.view_pivots().nrows() } /// Return the number of PQ chunks. @@ -113,29 +120,7 @@ where /// Return the dimensionality of the full-precision vectors associated with this table. pub fn dim(&self) -> usize { - self.pivot_dim - } -} - -impl BasicTable { - /// Construct an owned table over `pivots` and `offsets`. - pub fn new( - pivots: Matrix, - offsets: ChunkOffsetsBase>, - ) -> Result { - let (num_pivots, pivot_dim) = (pivots.nrows(), pivots.ncols()); - Self::from_parts(pivots.into_inner(), num_pivots, pivot_dim, offsets) - } -} - -impl<'a> BasicTableView<'a> { - /// Construct a borrowed table over `pivots` and `offsets`. - pub fn new( - pivots: MatrixView<'a, f32>, - offsets: ChunkOffsetsView<'a>, - ) -> Result { - let (num_pivots, pivot_dim) = (pivots.nrows(), pivots.ncols()); - Self::from_parts(pivots.as_slice(), num_pivots, pivot_dim, offsets) + self.view_pivots().ncols() } } @@ -152,9 +137,9 @@ pub enum TableCompressionError { InfinityOrNaN(usize), } -impl CompressInto<&[f32], &mut [u8]> for BasicTableBase +impl CompressInto<&[f32], &mut [u8]> for BasicTableBase where - T: DenseData, + M: PivotTable, U: DenseData, { type Error = TableCompressionError; @@ -233,7 +218,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::{lazy_format, views}; + use diskann_utils::{lazy_format, matrix}; use rand::{ SeedableRng, distr::{Distribution, StandardUniform}, @@ -252,7 +237,7 @@ mod tests { // disagree. #[test] fn error_on_mismatch_dim() { - let pivots = views::Matrix::from_gen(0.0, 3, 5); + let pivots = matrix::Matrix::new(0.0, 3, 5); let offsets = crate::views::ChunkOffsets::new(Box::new([0, 1, 6])).unwrap(); let result = BasicTable::new(pivots, offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -265,7 +250,7 @@ mod tests { // Test that the table constructor errors when there are no pivots. #[test] fn error_on_no_pivots() { - let pivots = views::Matrix::from_gen(0.0, 0, 5); + let pivots = matrix::Matrix::new(0.0, 0, 5); let offsets = crate::views::ChunkOffsets::new(Box::new([0, 1, 2, 5])).unwrap(); let result = BasicTable::new(pivots, offsets); assert!(result.is_err(), "pivots is empty"); @@ -277,8 +262,8 @@ mod tests { let mut rng = rand::rngs::StdRng::seed_from_u64(0xd96bac968083ec29); for dim in [5, 10, 12] { for total in [1, 2, 3] { - let pivots = views::Matrix::from_gen( - views::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), + let pivots = matrix::Matrix::new( + matrix::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), total, dim, ); @@ -355,7 +340,7 @@ mod tests { // Set up `ncenters > 256`. { - let pivots = views::Matrix::from_gen(0.0, 257, dim); + let pivots = matrix::Matrix::new(0.0, 257, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim]; @@ -374,7 +359,7 @@ mod tests { // Setup input dim not equal to expected. { - let pivots = views::Matrix::from_gen(0.0, 10, dim); + let pivots = matrix::Matrix::new(0.0, 10, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim - 1]; @@ -393,7 +378,7 @@ mod tests { // Setup output dim not equal to expected. { - let pivots = views::Matrix::from_gen(0.0, 10, dim); + let pivots = matrix::Matrix::new(0.0, 10, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim]; @@ -418,7 +403,7 @@ mod tests { #[test] fn test_table_single_compression_errors() { check_pqtable_single_compression_errors( - &|pivots: views::Matrix, offsets| BasicTable::new(pivots, offsets).unwrap(), + &|pivots: matrix::Matrix, offsets| BasicTable::new(pivots, offsets).unwrap(), &"BasicTable", ) } diff --git a/diskann-quantization/src/product/tables/test.rs b/diskann-quantization/src/product/tables/test.rs index feb6b3bd9..d8b21355a 100644 --- a/diskann-quantization/src/product/tables/test.rs +++ b/diskann-quantization/src/product/tables/test.rs @@ -4,9 +4,9 @@ */ // A collection of test helpers to ensure uniformity across tables. -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; #[cfg(not(miri))] -use diskann_utils::views::{MatrixView, MatrixViewMut}; +use diskann_utils::{MatrixView, MatrixViewMut}; #[cfg(not(miri))] use rand::seq::IndexedRandom; use rand::{ @@ -84,7 +84,7 @@ pub(super) fn create_pivot_tables( schema: ChunkOffsets, num_centers: usize, ) -> (Matrix, ChunkOffsets) { - let mut pivots = Matrix::::from_gen(0.0, num_centers, schema.dim()); + let mut pivots = Matrix::::new(0.0, num_centers, schema.dim()); (0..schema.len()).for_each(|chunk| { let range = schema.at(chunk); @@ -126,8 +126,8 @@ pub(super) fn create_dataset( num_data: usize, rng: &mut R, ) -> (Matrix, Matrix) { - let mut data = Matrix::::from_gen(0.0, num_data, schema.dim()); - let mut expected = Matrix::::from_gen(0, num_data, schema.len()); + let mut data = Matrix::::new(0.0, num_data, schema.dim()); + let mut expected = Matrix::::new(0, num_data, schema.len()); let dist = Uniform::new(0, num_centers).unwrap(); for row_index in 0..data.nrows() { @@ -171,7 +171,7 @@ pub(super) fn check_pqtable_single_compression_errors( // Set up `ncenters > 256`. { - let pivots = Matrix::from_gen(0.0, 257, dim); + let pivots = Matrix::new(0.0, 257, dim); let table = build(pivots, offsets.clone()); let input = vec![f32::default(); dim]; @@ -193,7 +193,7 @@ pub(super) fn check_pqtable_single_compression_errors( // Setup input dim not equal to expected. { - let pivots = Matrix::from_gen(0.0, 10, dim); + let pivots = Matrix::new(0.0, 10, dim); let table = build(pivots, offsets.clone()); let input = vec![f32::default(); dim - 1]; @@ -215,7 +215,7 @@ pub(super) fn check_pqtable_single_compression_errors( // Setup output dim not equal to expected. { - let pivots = Matrix::from_gen(0.0, 10, dim); + let pivots = Matrix::new(0.0, 10, dim); let table = build(pivots, offsets.clone()); let input = vec![f32::default(); dim]; @@ -308,11 +308,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Set up `ncenters > 256`. { - let pivots = Matrix::from_gen(0.0, 257, dim); + let pivots = Matrix::new(0.0, 257, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::from_gen(f32::default(), batchsize, dim); - let mut output = Matrix::from_gen(u8::MAX, batchsize, num_chunks); + let input = Matrix::new(f32::default(), batchsize, dim); + let mut output = Matrix::new(u8::MAX, batchsize, num_chunks); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); assert_eq!( @@ -330,11 +330,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Setup input dim not equal to expected. { - let pivots = Matrix::from_gen(0.0, 10, dim); + let pivots = Matrix::new(0.0, 10, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::from_gen(f32::default(), batchsize, dim - 1); - let mut output = Matrix::from_gen(u8::MAX, batchsize, num_chunks); + let input = Matrix::new(f32::default(), batchsize, dim - 1); + let mut output = Matrix::new(u8::MAX, batchsize, num_chunks); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); assert_eq!( @@ -352,11 +352,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Setup output dim not equal to expected. { - let pivots = Matrix::from_gen(0.0, 10, dim); + let pivots = Matrix::new(0.0, 10, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::from_gen(f32::default(), batchsize, dim); - let mut output = Matrix::from_gen(u8::MAX, batchsize, num_chunks - 1); + let input = Matrix::new(f32::default(), batchsize, dim); + let mut output = Matrix::new(u8::MAX, batchsize, num_chunks - 1); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); @@ -379,11 +379,11 @@ pub(super) fn check_pqtable_batch_compression_errors( // Num rows are different. { - let pivots = Matrix::from_gen(0.0, 10, dim); + let pivots = Matrix::new(0.0, 10, dim); let table = build(pivots, offsets.clone()); - let input = Matrix::from_gen(f32::default(), batchsize, dim); - let mut output = Matrix::from_gen(u8::MAX, batchsize - 1, num_chunks); + let input = Matrix::new(f32::default(), batchsize, dim); + let mut output = Matrix::new(u8::MAX, batchsize - 1, num_chunks); let result = table.compress_into(input.as_view(), output.as_mut_view()); assert!(result.is_err()); @@ -416,8 +416,8 @@ pub(super) fn check_pqtable_batch_compression_errors( let table = build(pivots, o); let num_points = 15; - let mut buf = Matrix::::from_gen(0.0, num_points, offsets.dim()); - let mut output = Matrix::::from_gen(0, num_points, offsets.len()); + let mut buf = Matrix::::new(0.0, num_points, offsets.dim()); + let mut output = Matrix::::new(0, num_points, offsets.len()); fn clear(mut x: MatrixViewMut) { x.as_mut_slice().iter_mut().for_each(|i| *i = T::default()); diff --git a/diskann-quantization/src/product/tables/transposed/pivots.rs b/diskann-quantization/src/product/tables/transposed/pivots.rs index c4b063a9d..07dc6e0bc 100644 --- a/diskann-quantization/src/product/tables/transposed/pivots.rs +++ b/diskann-quantization/src/product/tables/transposed/pivots.rs @@ -1061,7 +1061,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::{lazy_format, views}; + use diskann_utils::{lazy_format, matrix}; use diskann_vector::{PureDistanceFunction, distance}; use rand::{ SeedableRng, @@ -1520,7 +1520,7 @@ mod tests { #[test] #[should_panic(expected = "row 5 must be less than 5")] fn get_panics_on_row() { - let data = views::Matrix::from_gen(0.0, 5, 10); + let data = matrix::Matrix::new(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); chunk.get(5, 1); } @@ -1528,7 +1528,7 @@ mod tests { #[test] #[should_panic(expected = "col 5 must be less than 5")] fn get_panics_on_col() { - let data = views::Matrix::from_gen(0.0, 10, 5); + let data = matrix::Matrix::new(0.0, 10, 5); let chunk = Chunk::new(data.as_view().into()).unwrap(); chunk.get(1, 5); } @@ -1547,8 +1547,11 @@ mod tests { fn test_process_into_impl(dim: usize, total: usize, rng: &mut StdRng) { let distribution = Uniform::::new(-10, 10).unwrap(); - let base = - views::Matrix::::from_gen(views::Init(|| distribution.sample(rng) as f32), total, dim); + let base = matrix::Matrix::::new( + matrix::Init(|| distribution.sample(rng) as f32), + total, + dim, + ); let chunk = Chunk::new(base.as_view().into()).unwrap(); let mut input = vec![0.0; dim]; @@ -1597,7 +1600,7 @@ mod tests { #[test] #[should_panic] fn test_process_into_panics_on_from() { - let data = views::Matrix::::from_gen(0.0, 5, 10); + let data = matrix::Matrix::::new(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); assert_eq!(chunk.dimension(), 10); assert_eq!(chunk.num_centers(), 5); @@ -1611,7 +1614,7 @@ mod tests { #[test] #[should_panic] fn test_process_into_panics_on_into() { - let data = views::Matrix::::from_gen(0.0, 5, 10); + let data = matrix::Matrix::::new(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); assert_eq!(chunk.dimension(), 10); assert_eq!(chunk.num_centers(), 5); diff --git a/diskann-quantization/src/product/tables/transposed/table.rs b/diskann-quantization/src/product/tables/transposed/table.rs index 1a2bd34d6..2c49fbf1c 100644 --- a/diskann-quantization/src/product/tables/transposed/table.rs +++ b/diskann-quantization/src/product/tables/transposed/table.rs @@ -12,8 +12,8 @@ use crate::{ views::{ChunkOffsets, ChunkOffsetsView}, }; use diskann_utils::{ + matrix::{self, MatrixView, MatrixViewMut}, strided, - views::{self, MatrixView, MatrixViewMut}, }; use thiserror::Error; @@ -71,7 +71,7 @@ impl TransposedTable { /// * `pivots.nrows() == 0`: The pivot table cannot be empty. #[allow(clippy::expect_used)] pub fn from_parts( - pivots: views::MatrixView, + pivots: matrix::MatrixView, offsets: ChunkOffsets, ) -> Result { let pivot_dim = pivots.ncols(); @@ -154,7 +154,7 @@ impl TransposedTable { #[allow(clippy::expect_used)] pub fn compress_batch( &self, - data: views::MatrixView<'_, T>, + data: matrix::MatrixView<'_, T>, mut compression_delegate: F, ) -> Result<(), CompressError> where @@ -187,7 +187,7 @@ impl TransposedTable { let range = self.offsets.at(i); if let Some(chunk_dim) = NonZeroUsize::new(range.len()) { // Construct a view for the packing buffer for this chunk. - let mut packing_view = views::MatrixViewMut::try_from( + let mut packing_view = matrix::MatrixViewMut::try_from( &mut packing_buffer[..SUB_BATCH_SIZE * chunk_dim.get()], SUB_BATCH_SIZE, chunk_dim.get(), @@ -530,7 +530,7 @@ mod test_compression { // disagree. #[test] fn error_on_mismatch_dim() { - let pivots = views::Matrix::from_gen(0.0, 3, 5); + let pivots = matrix::Matrix::new(0.0, 3, 5); let offsets = ChunkOffsets::new(Box::new([0, 1, 6])).unwrap(); let result = TransposedTable::from_parts(pivots.as_view(), offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -544,7 +544,7 @@ mod test_compression { // disagree. #[test] fn error_on_empty() { - let pivots = views::Matrix::from_gen(0.0, 0, 5); + let pivots = matrix::Matrix::new(0.0, 0, 5); let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); let result = TransposedTable::from_parts(pivots.as_view(), offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -564,8 +564,8 @@ mod test_compression { for dim in [5, 10, 12] { // Sweep over enough totals to ensure the inner chunks have a non-trivial layout. for total in [1, 2, 3, 7, 8, 9, 10] { - let pivots = views::Matrix::from_gen( - views::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), + let pivots = matrix::Matrix::new( + matrix::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), total, dim, ); @@ -684,7 +684,7 @@ mod test_compression { assert_eq!(called.len(), num_data * schema.len()); // Trait Interface. - let mut output = views::Matrix::from_gen(0, num_data, schema.len()); + let mut output = matrix::Matrix::new(0, num_data, schema.len()); table .compress_into(data.as_view(), output.as_mut_view()) .unwrap(); @@ -741,7 +741,7 @@ mod test_compression { // should panic let _ = table.compress_batch( - views::MatrixView::try_from(data.as_slice(), 1, 5).unwrap(), + matrix::MatrixView::try_from(data.as_slice(), 1, 5).unwrap(), |_, _| -> Result<(), Infallible> { panic!("this shouldn't be called") }, ); } @@ -767,7 +767,7 @@ mod test_compression { let (data, _) = create_dataset(schema, num_centers, num_data, &mut rng); let data_view = - views::MatrixView::try_from(data.as_slice(), num_data, schema.dim()).unwrap(); + matrix::MatrixView::try_from(data.as_slice(), num_data, schema.dim()).unwrap(); let distribution = rand_distr::StandardUniform {}; for row in 0..data_view.nrows() { @@ -809,7 +809,7 @@ mod test_compression { #[cfg(not(miri))] fn test_table_single_compression_errors() { check_pqtable_single_compression_errors( - &|pivots: views::Matrix, offsets| { + &|pivots: matrix::Matrix, offsets| { TransposedTable::from_parts(pivots.as_view(), offsets).unwrap() }, &"TranposedTable", @@ -820,7 +820,7 @@ mod test_compression { #[cfg(not(miri))] fn test_table_batch_compression_errors() { check_pqtable_batch_compression_errors( - &|pivots: views::Matrix, offsets| { + &|pivots: matrix::Matrix, offsets| { TransposedTable::from_parts(pivots.as_view(), offsets).unwrap() }, &"TranposedTable", @@ -856,15 +856,15 @@ mod test_compression { let offsets = ChunkOffsets::new(offsets.into()).unwrap(); let dim = offsets.dim(); - let pivots = views::Matrix::::from_gen( - views::Init(|| value_distribution.sample(rng) as f32), + let pivots = matrix::Matrix::::new( + matrix::Init(|| value_distribution.sample(rng) as f32), num_centers, dim, ); let table = TransposedTable::from_parts(pivots.as_view(), offsets.clone()).unwrap(); - let mut output = views::Matrix::::from_gen(0.0, num_chunks, num_centers); + let mut output = matrix::Matrix::::new(0.0, num_chunks, num_centers); let query: Vec<_> = (0..dim) .map(|_| value_distribution.sample(rng) as f32) .collect(); @@ -936,13 +936,13 @@ mod test_compression { #[should_panic(expected = "query has the wrong number of dimensions")] fn test_process_into_panics_query() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = views::Matrix::::from_gen(0.0, 3, 5); + let data = matrix::Matrix::::new(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); // query has the wrong length. let query = vec![0.0; table.dim() - 1]; - let mut partials = views::Matrix::from_gen(0.0, table.nchunks(), table.ncenters()); + let mut partials = matrix::Matrix::new(0.0, table.nchunks(), table.ncenters()); table.process_into::(&query, partials.as_mut_view()); } @@ -950,13 +950,13 @@ mod test_compression { #[should_panic(expected = "output has the wrong number of rows")] fn test_process_into_panics_partials_rows() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = views::Matrix::::from_gen(0.0, 3, 5); + let data = matrix::Matrix::::new(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); let query = vec![0.0; table.dim()]; // partials has the wrong numbers of rows. - let mut partials = views::Matrix::from_gen(0.0, table.nchunks() - 1, table.ncenters()); + let mut partials = matrix::Matrix::new(0.0, table.nchunks() - 1, table.ncenters()); table.process_into::(&query, partials.as_mut_view()); } @@ -964,13 +964,13 @@ mod test_compression { #[should_panic(expected = "output has the wrong number of columns")] fn test_process_into_panics_partials_cols() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = views::Matrix::::from_gen(0.0, 3, 5); + let data = matrix::Matrix::::new(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); let query = vec![0.0; table.dim()]; // partials has the wrong numbers of rows. - let mut partials = views::Matrix::from_gen(0.0, table.nchunks(), table.ncenters() - 1); + let mut partials = matrix::Matrix::new(0.0, table.nchunks(), table.ncenters() - 1); table.process_into::(&query, partials.as_mut_view()); } } diff --git a/diskann-quantization/src/product/train.rs b/diskann-quantization/src/product/train.rs index c853f9e4a..96741f5d0 100644 --- a/diskann-quantization/src/product/train.rs +++ b/diskann-quantization/src/product/train.rs @@ -4,8 +4,8 @@ */ use diskann_utils::{ + matrix::{self, Matrix}, strided::StridedView, - views::{self, Matrix}, }; #[cfg(feature = "rayon")] use rayon::iter::{IntoParallelIterator, ParallelIterator}; @@ -44,7 +44,7 @@ pub struct SimplePivots { } fn flatten(pivots: &[Matrix], ncenters: usize, dim: usize) -> Matrix { - let mut flattened = Matrix::from_gen(T::default(), ncenters, dim); + let mut flattened = Matrix::new(T::default(), ncenters, dim); let mut col_start = 0; for matrix in pivots { assert_eq!(matrix.nrows(), flattened.nrows()); @@ -77,7 +77,7 @@ pub trait TrainQuantizer { fn train( &self, - data: views::MatrixView, + data: matrix::MatrixView, schema: crate::views::ChunkOffsetsView<'_>, parallelism: Parallelism, rng_builder: &R, @@ -108,7 +108,7 @@ impl TrainQuantizer for LightPQTrainingParameters { /// * `NaN` or infinities are observed during the training process. fn train( &self, - data: views::MatrixView, + data: matrix::MatrixView, schema: crate::views::ChunkOffsetsView<'_>, parallelism: Parallelism, rng_builder: &R, @@ -123,7 +123,7 @@ impl TrainQuantizer for LightPQTrainingParameters { #[inline(never)] fn train( trainer: &LightPQTrainingParameters, - data: views::MatrixView, + data: matrix::MatrixView, schema: crate::views::ChunkOffsetsView<'_>, parallelism: Parallelism, rng_builder: &(dyn BoxedRngBuilder + Sync), @@ -169,7 +169,7 @@ impl TrainQuantizer for LightPQTrainingParameters { // Allocate scratch data structures. let norms: Vec = view.row_iter().map(square_norm).collect(); let transpose = BlockTransposed::::from_strided(view); - let mut centers = Matrix::from_gen(0.0, trainer.ncenters, range.len()); + let mut centers = Matrix::new(0.0, trainer.ncenters, range.len()); // Construct the random number generator seeded by the PQ chunk. let mut rng = rng_builder.build_boxed_rng(i); @@ -302,7 +302,7 @@ mod tests { // Create the sub matrices. let matrices: Vec> = std::iter::zip(sub_dims.iter(), prefix_sum.iter()) .map(|(&this_dim, &offset)| { - let mut m = Matrix::from_gen(0, nrows, this_dim); + let mut m = Matrix::new(0, nrows, this_dim); for r in 0..nrows { for c in 0..this_dim { m[(r, c)] = dim * r + offset + c; @@ -358,8 +358,8 @@ mod tests { .map(|chunk| { let dim = schema.at(chunk).len(); - let mut initial = Matrix::from_gen(0.0, ndata, dim); - let mut centers = Matrix::from_gen(0.0, self.nclusters, 1); + let mut initial = Matrix::new(0.0, ndata, dim); + let mut centers = Matrix::new(0.0, self.nclusters, 1); // The starting offset for clusters. let offset = offsets_distribution.sample(rng); @@ -380,7 +380,7 @@ mod tests { // Shuffle the dataset. indices.shuffle(rng); - let mut piece = Matrix::from_gen(0.0, ndata, dim); + let mut piece = Matrix::new(0.0, ndata, dim); for (dst, src) in indices.iter().enumerate() { piece.row_mut(dst).copy_from_slice(initial.row(*src)); } @@ -579,7 +579,7 @@ mod tests { // pivots exceeds the number of dataset items. #[test] fn tests_succeeded_with_too_many_pivots() { - let data = Matrix::::from_gen(1.0, 10, 5); + let data = Matrix::::new(1.0, 10, 5); let offsets: Vec = vec![0, 1, 4, 5]; let trainer = LightPQTrainingParameters::new(2 * data.nrows(), 6); @@ -650,7 +650,7 @@ mod tests { assert!(format(&err).contains("infinity")); }; - let mut data = Matrix::::from_gen(1.0, nrows, ncols); + let mut data = Matrix::::new(1.0, nrows, ncols); // Positive Infinity data[(r, c)] = f32::INFINITY; diff --git a/diskann-quantization/src/scalar/mod.rs b/diskann-quantization/src/scalar/mod.rs index c9a3afe8a..b26ebb007 100644 --- a/diskann-quantization/src/scalar/mod.rs +++ b/diskann-quantization/src/scalar/mod.rs @@ -62,7 +62,7 @@ //! scalar::{self, train, CompensatedVector, CompensatedIP, CompensatedSquaredL2}, //! num::Positive, //! }; -//! use diskann_utils::{Reborrow, ReborrowMut, views::Matrix}; +//! use diskann_utils::{Reborrow, ReborrowMut, matrix::Matrix}; //! use rand::{rngs::StdRng, SeedableRng, distr::Distribution}; //! use rand_distr::StandardNormal; //! use diskann_vector::{PureDistanceFunction, DistanceFunction, distance}; @@ -74,7 +74,7 @@ //! // Construct a set of offsets for each dimension. //! let offset: Vec = (0..dim).map(|_| distribution.sample(&mut rng)).collect(); //! // The output dataset. -//! let mut data = Matrix::::from_gen(0.0, nvectors, dim); +//! let mut data = Matrix::::new(0.0, nvectors, dim); //! for row in data.row_iter_mut() { //! std::iter::zip(row.iter_mut(), offset.iter()).for_each(|(r, i)| { //! let v: f32 = distribution.sample(&mut rng); diff --git a/diskann-quantization/src/scalar/quantizer.rs b/diskann-quantization/src/scalar/quantizer.rs index 711fcceac..3b48513ea 100644 --- a/diskann-quantization/src/scalar/quantizer.rs +++ b/diskann-quantization/src/scalar/quantizer.rs @@ -38,11 +38,11 @@ use crate::{ /// CompensatedIP, CompensatedSquaredL2, /// } /// }; -/// use diskann_utils::{views::Matrix, Reborrow, ReborrowMut}; +/// use diskann_utils::{matrix::Matrix, Reborrow, ReborrowMut}; /// use diskann_vector::DistanceFunction; /// /// // A small training set consisting of two 5-dimensional vectors. -/// let mut data = Matrix::::from_gen(0.0, 2, 5); +/// let mut data = Matrix::::new(0.0, 2, 5); /// data.row_mut(0).copy_from_slice(&[-1.0, -1.0, -1.0, -1.0, -1.0]); /// data.row_mut(1).copy_from_slice(&[1.0, 1.0, 1.0, 1.0, 1.0]); /// @@ -459,7 +459,7 @@ pub enum SQComparisonError { mod tests { use std::collections::HashSet; - use diskann_utils::{ReborrowMut, views}; + use diskann_utils::{ReborrowMut, matrix}; use rand::{ SeedableRng, @@ -593,7 +593,7 @@ mod tests { // Create a shuffled matrix of offset values for each dimension. This ensure that // each dimension covers the target dynamic range, but in a different order so // we can rule out cross-coupling of dimensions. - let dim_offsets: views::Matrix = { + let dim_offsets: matrix::Matrix = { let range_min = -min_encodable - 3.0 * scale; let range_max = max_encodable + 3.0 * scale; let mut base: Vec = Vec::new(); @@ -607,7 +607,7 @@ mod tests { // Push one more to have one point above `range_max`. base.push(i); - let mut output = views::Matrix::from_gen(0.0, base.len(), dim); + let mut output = matrix::Matrix::new(0.0, base.len(), dim); (0..dim).for_each(|j| { base.shuffle(rng); for (i, b) in base.iter().enumerate() { diff --git a/diskann-quantization/src/scalar/train.rs b/diskann-quantization/src/scalar/train.rs index becf99fd5..01799606b 100644 --- a/diskann-quantization/src/scalar/train.rs +++ b/diskann-quantization/src/scalar/train.rs @@ -8,7 +8,7 @@ use crate::{ num::Positive, utils::{compute_means_and_average_norm, compute_variances}, }; -use diskann_utils::views; +use diskann_utils::matrix; /// Parameters controlling the generation of the scalar quantization Quantizer. /// @@ -71,7 +71,7 @@ impl ScalarQuantizationParameters { /// # Parallelism /// /// This function is single threaded. - pub fn train(&self, data: views::MatrixView) -> ScalarQuantizer + pub fn train(&self, data: matrix::MatrixView) -> ScalarQuantizer where T: Copy + Into + Into, { diff --git a/diskann-quantization/src/spherical/iface.rs b/diskann-quantization/src/spherical/iface.rs index 42822bf7a..13daa2445 100644 --- a/diskann-quantization/src/spherical/iface.rs +++ b/diskann-quantization/src/spherical/iface.rs @@ -40,10 +40,10 @@ //! spherical::{iface, SupportedMetric, SphericalQuantizer, PreScale}, //! num::PowerOfTwo, //! }; -//! use diskann_utils::views::Matrix; +//! use diskann_utils::Matrix; //! //! // For illustration purposes, the dataset consists of just a single vector. -//! let mut data = Matrix::from_gen(1.0, 1, 4); +//! let mut data = Matrix::new(1.0, 1, 4); //! let quantizer = SphericalQuantizer::train( //! data.as_view(), //! TransformKind::Null, @@ -2086,7 +2086,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::views::{Matrix, MatrixView}; + use diskann_utils::{Matrix, MatrixView}; use rand::{SeedableRng, rngs::StdRng}; use super::*; diff --git a/diskann-quantization/src/spherical/quantizer.rs b/diskann-quantization/src/spherical/quantizer.rs index 554b4432a..1ceeaa9b7 100644 --- a/diskann-quantization/src/spherical/quantizer.rs +++ b/diskann-quantization/src/spherical/quantizer.rs @@ -5,7 +5,7 @@ use std::num::NonZeroUsize; -use diskann_utils::{ReborrowMut, views::MatrixView}; +use diskann_utils::{ReborrowMut, matrix::MatrixView}; use diskann_vector::{ MathematicalValue, Norm, PureDistanceFunction, distance::InnerProduct, norm::FastL2Norm, }; @@ -1220,7 +1220,7 @@ mod tests { use diskann_utils::{ ReborrowMut, lazy_format, - views::{self, Matrix}, + matrix::{self, Matrix}, }; use diskann_vector::{PureDistanceFunction, norm::FastL2NormSquared}; use diskann_wide::ARCH; @@ -2273,7 +2273,7 @@ mod tests { #[test] fn err_dim_cannot_be_zero() { - let data = Matrix::from_gen(0.0f32, 10, 0); + let data = Matrix::new(0.0f32, 10, 0); let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); let err = SphericalQuantizer::train( data.as_view(), @@ -2291,7 +2291,7 @@ mod tests { #[test] fn err_norm_must_be_positive() { - let data = Matrix::from_gen(0.0f32, 10, 10); + let data = Matrix::new(0.0f32, 10, 10); let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); let err = SphericalQuantizer::train( data.as_view(), @@ -2309,7 +2309,7 @@ mod tests { #[test] fn err_norm_cannot_be_infinity() { - let mut data = Matrix::from_gen(0.0f32, 10, 10); + let mut data = Matrix::new(0.0f32, 10, 10); data[(2, 5)] = f32::INFINITY; let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); @@ -2329,7 +2329,7 @@ mod tests { #[test] fn err_reciprocal_norm_cannot_be_infinity() { - let mut data = Matrix::from_gen(0.0f32, 10, 10); + let mut data = Matrix::new(0.0f32, 10, 10); data[(2, 5)] = 2.93863e-39; let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); @@ -2388,7 +2388,7 @@ mod tests { #[test] fn compression_errors_data() { let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); - let data = Matrix::::from_gen(views::Init(|| StandardNormal {}.sample(&mut rng)), 16, 12); + let data = Matrix::::new(matrix::Init(|| StandardNormal {}.sample(&mut rng)), 16, 12); let quantizer = SphericalQuantizer::train( data.as_view(), diff --git a/diskann-quantization/src/test_util.rs b/diskann-quantization/src/test_util.rs index 3a0728c41..9ba19b476 100644 --- a/diskann-quantization/src/test_util.rs +++ b/diskann-quantization/src/test_util.rs @@ -9,7 +9,7 @@ use std::sync::{ atomic::{AtomicUsize, Ordering}, }; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; use rand::{ distr::{Distribution, Uniform}, rngs::StdRng, @@ -169,7 +169,7 @@ pub(crate) fn create_test_problem(nrows: usize, ncols: usize, rng: &mut StdRng) }) .collect(); - let mut data = Matrix::::from_gen(0.0, nrows, ncols); + let mut data = Matrix::::new(0.0, nrows, ncols); for col in 0..ncols { offsets.shuffle(rng); for row in 0..nrows { diff --git a/diskann-quantization/src/utils.rs b/diskann-quantization/src/utils.rs index fd9ee16f8..4b40f38e2 100644 --- a/diskann-quantization/src/utils.rs +++ b/diskann-quantization/src/utils.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use thiserror::Error; -use diskann_utils::views::MatrixView; +use diskann_utils::MatrixView; /// Specify featres and config flags that will be propagated to `docsrs` config. macro_rules! features { @@ -205,7 +205,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::views::Matrix; + use diskann_utils::Matrix; use diskann_vector::{Norm, norm::FastL2Norm}; use rand::{SeedableRng, rngs::StdRng}; @@ -317,12 +317,12 @@ mod tests { #[test] fn test_normalized_means_corner_cases() { // If the input data has no columns, the returned vector should be empty. - let data = Matrix::from_gen(1.0f32, 10, 0); + let data = Matrix::new(1.0f32, 10, 0); let means = compute_normalized_means(data.as_view()).unwrap(); assert!(means.is_empty()); // If the data has no rows, an error should be returned. - let data = Matrix::from_gen(1.0f32, 0, 10); + let data = Matrix::new(1.0f32, 0, 10); let _: CannotBeEmpty = compute_normalized_means(data.as_view()).unwrap_err(); } diff --git a/diskann-quantization/src/views.rs b/diskann-quantization/src/views.rs index 04c4a0953..3772b5087 100644 --- a/diskann-quantization/src/views.rs +++ b/diskann-quantization/src/views.rs @@ -5,7 +5,7 @@ use std::num::NonZeroUsize; -use diskann_utils::views::{DenseData, MutDenseData}; +use diskann_utils::{DenseData, MutDenseData}; use std::ops::{Index, IndexMut}; use thiserror::Error; diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs b/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs index 549859c76..0a96679ec 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `as_view` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the view is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.as_view(); // This should fail: we cannot mutably borrow `mat` while `view` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs index 32a39a38f..bc245355b 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `as_view_mut` on Mat correctly captures a mutable lifetime, // preventing the Mat from being used while the mutable view is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.as_view_mut(); // This should fail: we cannot use `mat` while `view` is still alive let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs b/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs index 2ca8cc4a1..e971c49de 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `get_row` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let row = mat.get_row(0).unwrap(); // This should fail: we cannot mutably borrow `mat` while `row` exists let _ = mat.get_row_mut(1); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs index 099a99b73..81324d52a 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `get_row_mut` on Mat correctly captures a mutable // lifetime, preventing the Mat from being used while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let row = mat.get_row_mut(0).unwrap(); // This should fail: we cannot use `mat` while `row` is still borrowed let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs b/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs index 6c3792c8b..3e06b4be2 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs @@ -18,6 +18,6 @@ where fn main() { let b = 0u8; - let m = Mat::new(RowMajor::new(4, 3).unwrap(), &b).unwrap(); + let m = Mat::from_repr(RowMajor::new(4, 3).unwrap(), &b).unwrap(); bad(m); } diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs b/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs index 806d9b7dd..000ea234a 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs @@ -9,7 +9,7 @@ use diskann_utils::Reborrow; // Test that `reborrow` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.reborrow(); // This should fail: we cannot mutably borrow `mat` while `view` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs index b4e1336c5..ca1bef597 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs @@ -9,7 +9,7 @@ use diskann_utils::ReborrowMut; // Test that `reborrow_mut` on Mat correctly captures a mutable borrow, // preventing use of the Mat while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view = mat.reborrow_mut(); // This should fail: we cannot use `mat` while `view` exists let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows.rs b/diskann-quantization/tests/compile-fail/multi/mat_rows.rs index a5f86bf48..5085022f6 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_rows.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that `rows` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let iter = mat.rows(); // This should fail: we cannot mutably borrow `mat` while `iter` exists let _ = mat.as_view_mut(); diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs b/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs index f06ebf4e4..80a786c18 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, RowMajor}; // Test that the `rows_mut` iterator correctly captures a mutable lifetime, // preventing the Mat from being used while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let iter = mat.rows_mut(); // This should fail: we cannot use `mat` while the mutable iterator is alive let _ = mat.num_vectors(); diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs b/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs index 77fbae2a2..101cd95b4 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `as_view` on MatMut correctly captures an immutable lifetime, // preventing mutating the MatMut while the immutable view is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let immut_view = view.as_view(); // This should fail: we cannot mutate `view` while `immut_view` exists diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs b/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs index bb28a6aaa..5220d97e4 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `get_row` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let row = view.get_row(0).unwrap(); // This should fail: we cannot mutably borrow `view` while `row` exists diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs b/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs index 43db3d592..3a6694f75 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `get_row_mut` on MatMut correctly captures a mutable lifetime, // preventing the MatMut from being used while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let row = view.get_row_mut(0).unwrap(); // This should fail: we cannot use `view` while `row` is still borrowed diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs b/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs index 52112d5a6..86890463e 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs @@ -18,6 +18,6 @@ where fn main() { let b = 0u8; - let mut m = Mat::new(RowMajor::new(4, 3).unwrap(), &b).unwrap(); + let mut m = Mat::from_repr(RowMajor::new(4, 3).unwrap(), &b).unwrap(); bad(m.as_view_mut()); } diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs index 892fe830d..afee970d7 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs @@ -9,7 +9,7 @@ use diskann_utils::Reborrow; // Test that `reborrow` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let immut_view = view.reborrow(); // This should fail: we cannot mutably borrow `view` while `immut_view` exists diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs index 0c5627b33..b53f631a8 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs @@ -9,7 +9,7 @@ use diskann_utils::ReborrowMut; // Test that `reborrow_mut` on MatMut correctly captures a mutable lifetime, // preventing the original MatMut from being used while the reborrow is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let reborrowed = view.reborrow_mut(); // This should fail: we cannot use `view` while `reborrowed` is still alive diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs b/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs index 43fa5534c..9c51c85f6 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that `rows` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let iter = view.rows(); // This should fail: we cannot mutably borrow `view` while `iter` exists diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs b/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs index 3144f15ad..871da0e40 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs +++ b/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; // Test that the `rows_mut` iterator on MatMut correctly captures a mutable lifetime, // preventing the MatMut from being used while the iterator is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let mut view: MatMut<'_, RowMajor> = mat.as_view_mut(); let iter = view.rows_mut(); // This should fail: we cannot use `view` while the mutable iterator is alive diff --git a/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs b/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs index e3d8cd98a..72ddc79de 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs +++ b/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatRef, RowMajor}; // Test that `get_row` on MatRef returns a row with the correct lifetime, // and that an immutable borrow is held while the row is in scope. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view: MatRef<'_, RowMajor> = mat.as_view(); let row = view.get_row(0).unwrap(); // This should fail: we cannot mutably borrow `mat` while `row` exists diff --git a/diskann-quantization/tests/compile-fail/multi/matref_rows.rs b/diskann-quantization/tests/compile-fail/multi/matref_rows.rs index 56ae5e940..3cfb8a8cc 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_rows.rs +++ b/diskann-quantization/tests/compile-fail/multi/matref_rows.rs @@ -8,7 +8,7 @@ use diskann_quantization::multi_vector::{Mat, MatRef, RowMajor}; // Test that `rows` on MatRef returns an iterator with the correct lifetime, // preventing mutation of the underlying Mat while iterating. fn main() { - let mut mat: Mat> = Mat::new(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); + let mut mat: Mat> = Mat::from_repr(RowMajor::new(4, 3).unwrap(), 0.0f32).unwrap(); let view: MatRef<'_, RowMajor> = mat.as_view(); let iter = view.rows(); // This should fail: we cannot mutably borrow `mat` while `iter` exists diff --git a/diskann-tools/src/utils/ground_truth.rs b/diskann-tools/src/utils/ground_truth.rs index 77c2f663c..47422454a 100644 --- a/diskann-tools/src/utils/ground_truth.rs +++ b/diskann-tools/src/utils/ground_truth.rs @@ -20,7 +20,7 @@ use diskann_providers::utils::{ }; use diskann_utils::{ io::{read_bin, Metadata}, - views::Matrix, + matrix::Matrix, }; use diskann_vector::{distance::Metric, DistanceFunction}; use itertools::Itertools; diff --git a/diskann-utils/src/io.rs b/diskann-utils/src/io.rs index b442b4bfe..d3508bc85 100644 --- a/diskann-utils/src/io.rs +++ b/diskann-utils/src/io.rs @@ -16,7 +16,7 @@ use std::io::{Read, Seek, Write}; use diskann_wide::{LoHi, SplitJoin}; use thiserror::Error; -use crate::views::{Matrix, MatrixView}; +use crate::matrix::{Matrix, MatrixView}; /// Read a matrix of `T` from the DiskANN binary format (see [module docs](self)). /// @@ -53,7 +53,7 @@ where }); } - let mut data = Matrix::from_gen(::zeroed(), npoints, ndims); + let mut data = Matrix::new(::zeroed(), npoints, ndims); reader.read_exact(bytemuck::must_cast_slice_mut::(data.as_mut_slice()))?; Ok(data) @@ -209,14 +209,14 @@ pub enum SaveBinError { mod tests { use std::io::Cursor; - use crate::views::Init; + use crate::matrix::Init; use super::*; #[test] fn round_trip_f32() { let mut counter = 1.0f32; - let matrix = Matrix::::from_gen( + let matrix = Matrix::::new( Init(|| { let v = counter; counter += 1.0; diff --git a/diskann-utils/src/lib.rs b/diskann-utils/src/lib.rs index 762a4b3a0..3fc7b8469 100644 --- a/diskann-utils/src/lib.rs +++ b/diskann-utils/src/lib.rs @@ -18,11 +18,10 @@ pub mod io; pub mod object_pool; pub mod sampling; -// Views pub mod strided; -pub mod views; pub mod matrix; +pub use matrix::{DenseData, Init, Matrix, MatrixView, MatrixViewMut, MutDenseData, TryFromError}; mod lazystring; pub use lazystring::LazyString; diff --git a/diskann-utils/src/matrix.rs b/diskann-utils/src/matrix.rs index bcda8c706..67f5422d3 100644 --- a/diskann-utils/src/matrix.rs +++ b/diskann-utils/src/matrix.rs @@ -253,7 +253,7 @@ pub unsafe trait NewOwned: ReprOwned { /// /// ```rust /// use diskann_utils::matrix::{Mat, RowMajor, Defaulted}; -/// let mat = Mat::new(RowMajor::::new(4, 3).unwrap(), Defaulted).unwrap(); +/// let mat = Mat::from_repr(RowMajor::::new(4, 3).unwrap(), Defaulted).unwrap(); /// for i in 0..4 { /// assert!(mat.get_row(i).unwrap().iter().all(|&x| x == 0.0f32)); /// } @@ -399,11 +399,7 @@ impl Overflow { /// /// On failure the error reports the original `(nrows, ncols)` dimensions rather /// than the padded capacity. - pub fn check_byte_budget( - capacity: usize, - nrows: usize, - ncols: usize, - ) -> Result<(), Self> { + pub fn check_byte_budget(capacity: usize, nrows: usize, ncols: usize) -> Result<(), Self> { let bytes = std::mem::size_of::().saturating_mul(capacity); if bytes <= isize::MAX as usize { Ok(()) @@ -621,7 +617,7 @@ unsafe impl Sync for Mat where T: ReprOwned + Sync {} impl Mat { /// Create a new matrix using `init` as the initializer. - pub fn new(repr: T, init: U) -> Result>::Error> + pub fn from_repr(repr: T, init: U) -> Result>::Error> where T: NewOwned, { @@ -752,7 +748,7 @@ impl Clone for Mat { impl Mat> { /// Construct a [`Mat`] by filling each element in row-major order from `gen`. - pub fn from_gen>(mut gen: U, nrows: usize, ncols: usize) -> Self { + pub fn new>(mut gen: U, nrows: usize, ncols: usize) -> Self { let repr = RowMajor::new(nrows, ncols).expect("dimension overflow"); let b: Box<[T]> = (0..repr.num_elements()).map(|_| gen.generate()).collect(); // SAFETY: `b` has length `repr.num_elements()` by construction. @@ -811,7 +807,7 @@ unsafe impl Sync for MatRef<'_, T> where T: Repr + Sync {} impl<'a, T: Repr> MatRef<'a, T> { /// Construct a new [`MatRef`] over `data`. - pub fn new(repr: T, data: &'a [U]) -> Result + pub fn from_repr(repr: T, data: &'a [U]) -> Result where T: NewRef, { @@ -978,7 +974,7 @@ unsafe impl Sync for MatMut<'_, T> where T: ReprMut + Sync {} impl<'a, T: ReprMut> MatMut<'a, T> { /// Construct a new [`MatMut`] over `data`. - pub fn new(repr: T, data: &'a mut [U]) -> Result + pub fn from_repr(repr: T, data: &'a mut [U]) -> Result where T: NewMut, { @@ -1014,9 +1010,6 @@ impl<'a, T: ReprMut> MatMut<'a, T> { /// /// `i` must be less than `self.num_vectors()`. #[inline] - /// # Safety - /// - /// `i` must be less than `self.num_vectors()`. pub unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { // SAFETY: Caller must ensure i < self.num_vectors(). unsafe { self.repr.get_row(self.ptr, i) } @@ -1146,7 +1139,7 @@ impl<'a, T> MatMut<'a, RowMajor> { // Dense (RowMajor) API + aliases ////////////////////////////// -/// A generator for initializing matrix entries via [`Matrix::from_gen`]. +/// A generator for initializing matrix entries via [`Matrix::new`]. pub trait Generator { fn generate(&mut self) -> T; } @@ -1193,9 +1186,13 @@ pub struct TryFromError { impl<'a, T> MatRef<'a, RowMajor> { /// View `data` as an `nrows x ncols` matrix. pub fn try_from(data: &'a [T], nrows: usize, ncols: usize) -> Result { - let err = || TryFromError { len: data.len(), nrows, ncols }; + let err = || TryFromError { + len: data.len(), + nrows, + ncols, + }; let repr = RowMajor::new(nrows, ncols).map_err(|_| err())?; - MatRef::new(repr, data).map_err(|_| err()) + MatRef::from_repr(repr, data).map_err(|_| err()) } /// View `data` as a single-row matrix. @@ -1311,15 +1308,11 @@ impl<'a, T> MatRef<'a, RowMajor> { impl<'a, T> MatMut<'a, RowMajor> { /// View `data` as an `nrows x ncols` mutable matrix. - pub fn try_from( - data: &'a mut [T], - nrows: usize, - ncols: usize, - ) -> Result { + pub fn try_from(data: &'a mut [T], nrows: usize, ncols: usize) -> Result { let len = data.len(); let err = || TryFromError { len, nrows, ncols }; let repr = RowMajor::new(nrows, ncols).map_err(|_| err())?; - MatMut::new(repr, data).map_err(|_| err()) + MatMut::from_repr(repr, data).map_err(|_| err()) } /// Number of rows. @@ -1367,9 +1360,7 @@ impl<'a, T> MatMut<'a, RowMajor> { /// Parallel iterator over mutable rows. #[cfg(feature = "rayon")] - pub fn par_row_iter_mut( - &mut self, - ) -> impl rayon::iter::IndexedParallelIterator + pub fn par_row_iter_mut(&mut self) -> impl rayon::iter::IndexedParallelIterator where T: Send, { @@ -1395,7 +1386,7 @@ impl Mat> { where T: Clone, { - Self::from_gen(value, nrows, ncols) + Self::new(value, nrows, ncols) } /// Take ownership of `data`, interpreting it as an `nrows x ncols` matrix. @@ -1531,7 +1522,10 @@ impl Mat> { T: Send, { use rayon::slice::ParallelSliceMut; - assert!(batchsize != 0, "par_window_iter_mut batchsize cannot be zero"); + assert!( + batchsize != 0, + "par_window_iter_mut batchsize cannot be zero" + ); let ncols = self.ncols(); self.as_mut_slice() .par_chunks_mut(ncols * batchsize) @@ -1679,7 +1673,10 @@ impl<'a, T> MatMut<'a, RowMajor> { T: Send, { use rayon::slice::ParallelSliceMut; - assert!(batchsize != 0, "par_window_iter_mut batchsize cannot be zero"); + assert!( + batchsize != 0, + "par_window_iter_mut batchsize cannot be zero" + ); let ncols = self.ncols(); self.as_mut_slice() .par_chunks_mut(ncols * batchsize) @@ -1835,6 +1832,71 @@ where impl<'a, T> ExactSizeIterator for RowsMut<'a, T> where T: ReprMut + 'a {} impl<'a, T> FusedIterator for RowsMut<'a, T> where T: ReprMut + 'a {} +/////////////// +// DenseData // +/////////////// + +/// Abstraction over a type that can yield a dense slice of its contents. +/// +/// # Safety +/// +/// `as_slice` must be idempotent: it must **always** return the same slice with the same +/// length (unsafe code relies on this). +pub unsafe trait DenseData { + type Elem; + + /// Return the underlying data as a slice. + fn as_slice(&self) -> &[Self::Elem]; +} + +/// A mutable companion to [`DenseData`]. +/// +/// # Safety +/// +/// `as_mut_slice` must be idempotent and must span the exact same memory as +/// [`DenseData::as_slice`]. +pub unsafe trait MutDenseData: DenseData { + fn as_mut_slice(&mut self) -> &mut [Self::Elem]; +} + +// SAFETY: fulfills the idempotency requirement. +unsafe impl DenseData for &[T] { + type Elem = T; + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +// SAFETY: fulfills the idempotency requirement. +unsafe impl DenseData for &mut [T] { + type Elem = T; + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +// SAFETY: fulfills the idempotency requirement and spans the same memory as `as_slice`. +unsafe impl MutDenseData for &mut [T] { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} + +// SAFETY: fulfills the idempotency requirement. +unsafe impl DenseData for Box<[T]> { + type Elem = T; + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +// SAFETY: fulfills the idempotency requirement and spans the same memory as `as_slice`. +unsafe impl MutDenseData for Box<[T]> { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} + /////////// // Tests // /////////// @@ -2159,7 +2221,7 @@ mod tests { #[test] fn mat_new_and_basic_accessors() { - let mat = Mat::new(RowMajor::::new(3, 4).unwrap(), 42usize).unwrap(); + let mat = Mat::from_repr(RowMajor::::new(3, 4).unwrap(), 42usize).unwrap(); let base: *const u8 = mat.as_raw_ptr(); assert_eq!(mat.num_vectors(), 3); @@ -2181,7 +2243,7 @@ mod tests { #[test] fn mat_new_with_default() { - let mat = Mat::new(RowMajor::::new(2, 3).unwrap(), Defaulted).unwrap(); + let mat = Mat::from_repr(RowMajor::::new(2, 3).unwrap(), Defaulted).unwrap(); let base: *const u8 = mat.as_raw_ptr(); assert_eq!(mat.num_vectors(), 2); @@ -2209,7 +2271,7 @@ mod tests { // Populate the matrix using `&mut Mat` { let ctx = &lazy_format!("{ctx} - direct"); - let mut mat = Mat::new(repr, Defaulted).unwrap(); + let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); assert_eq!(mat.num_vectors(), *nrows); assert_eq!(mat.vector_dim(), *ncols); @@ -2229,7 +2291,7 @@ mod tests { // Populate the matrix using `MatMut` { let ctx = &lazy_format!("{ctx} - matmut"); - let mut mat = Mat::new(repr, Defaulted).unwrap(); + let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); let matmut = mat.reborrow_mut(); assert_eq!(matmut.num_vectors(), *nrows); @@ -2246,7 +2308,7 @@ mod tests { // Populate the matrix using `RowsMut` { let ctx = &lazy_format!("{ctx} - rows_mut"); - let mut mat = Mat::new(repr, Defaulted).unwrap(); + let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); fill_rows_mut(mat.rows_mut(), repr); check_mat(&mat, repr, ctx); @@ -2265,7 +2327,7 @@ mod tests { let repr = RowMajor::::new(*nrows, *ncols).unwrap(); let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols); - let mut mat = Mat::new(repr, Defaulted).unwrap(); + let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); fill_mat(&mut mat, repr); // Clone via Mat::clone @@ -2329,7 +2391,7 @@ mod tests { let ctx = &lazy_format!("{ctx} - by matmut"); let mut b: Box<[_]> = (0..repr.num_elements()).map(|_| 0usize).collect(); let ptr = b.as_ptr().cast::(); - let mut matmut = MatMut::new(repr, &mut b).unwrap(); + let mut matmut = MatMut::from_repr(repr, &mut b).unwrap(); assert_eq!( ptr, @@ -2344,7 +2406,7 @@ mod tests { check_rows(matmut.rows(), repr, ctx); check_rows(matmut.reborrow().rows(), repr, ctx); - let matref = MatRef::new(repr, &b).unwrap(); + let matref = MatRef::from_repr(repr, &b).unwrap(); check_mat_ref(matref, repr, ctx); check_mat_ref(matref.reborrow(), repr, ctx); check_rows(matref.rows(), repr, ctx); @@ -2355,7 +2417,7 @@ mod tests { let ctx = &lazy_format!("{ctx} - by rows"); let mut b: Box<[_]> = (0..repr.num_elements()).map(|_| 0usize).collect(); let ptr = b.as_ptr().cast::(); - let mut matmut = MatMut::new(repr, &mut b).unwrap(); + let mut matmut = MatMut::from_repr(repr, &mut b).unwrap(); assert_eq!( ptr, @@ -2370,7 +2432,7 @@ mod tests { check_rows(matmut.rows(), repr, ctx); check_rows(matmut.reborrow().rows(), repr, ctx); - let matref = MatRef::new(repr, &b).unwrap(); + let matref = MatRef::from_repr(repr, &b).unwrap(); check_mat_ref(matref, repr, ctx); check_mat_ref(matref.reborrow(), repr, ctx); check_rows(matref.rows(), repr, ctx); @@ -2390,7 +2452,7 @@ mod tests { for nrows in rows { for ncols in cols { - let m = Mat::new(RowMajor::new(nrows, ncols).unwrap(), 1usize).unwrap(); + let m = Mat::from_repr(RowMajor::new(nrows, ncols).unwrap(), 1usize).unwrap(); let rows_iter = m.rows(); let len = <_ as ExactSizeIterator>::len(&rows_iter); assert_eq!(len, nrows); @@ -2410,11 +2472,15 @@ mod tests { for nrows in rows { for ncols in cols { let mut counter = 0u32; - let m = Mat::from_gen(Init(|| { - let v = counter; - counter += 1; - v - }), nrows, ncols); + let m = Mat::new( + Init(|| { + let v = counter; + counter += 1; + v + }), + nrows, + ncols, + ); assert_eq!(counter as usize, nrows * ncols); for (i, row) in m.rows().enumerate() { @@ -2433,12 +2499,12 @@ mod tests { // Correct length succeeds let data = vec![0u32; 12]; - assert!(MatRef::new(repr, &data).is_ok()); + assert!(MatRef::from_repr(repr, &data).is_ok()); // Too short fails let short = vec![0u32; 11]; assert!(matches!( - MatRef::new(repr, &short), + MatRef::from_repr(repr, &short), Err(SliceError::LengthMismatch { expected: 12, found: 11 @@ -2448,7 +2514,7 @@ mod tests { // Too long fails let long = vec![0u32; 13]; assert!(matches!( - MatRef::new(repr, &long), + MatRef::from_repr(repr, &long), Err(SliceError::LengthMismatch { expected: 12, found: 13 @@ -2462,12 +2528,12 @@ mod tests { // Correct length succeeds let mut data = vec![0u32; 12]; - assert!(MatMut::new(repr, &mut data).is_ok()); + assert!(MatMut::from_repr(repr, &mut data).is_ok()); // Too short fails let mut short = vec![0u32; 11]; assert!(matches!( - MatMut::new(repr, &mut short), + MatMut::from_repr(repr, &mut short), Err(SliceError::LengthMismatch { expected: 12, found: 11 @@ -2477,7 +2543,7 @@ mod tests { // Too long fails let mut long = vec![0u32; 13]; assert!(matches!( - MatMut::new(repr, &mut long), + MatMut::from_repr(repr, &mut long), Err(SliceError::LengthMismatch { expected: 12, found: 13 @@ -2490,7 +2556,7 @@ mod tests { let data = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; // MatRef - let matref = MatRef::new(RowMajor::new(2, 3).unwrap(), &data).unwrap(); + let matref = MatRef::from_repr(RowMajor::new(2, 3).unwrap(), &data).unwrap(); let view = matref.as_matrix_view(); assert_eq!(view.nrows(), 2); assert_eq!(view.ncols(), 3); @@ -2502,7 +2568,7 @@ mod tests { assert_eq!(matref.as_slice(), &data); // Mat - let mut mat = Mat::new(RowMajor::::new(2, 3).unwrap(), 0.0f32).unwrap(); + let mut mat = Mat::from_repr(RowMajor::::new(2, 3).unwrap(), 0.0f32).unwrap(); for i in 0..2 { let r = mat.get_row_mut(i).unwrap(); for j in 0..3 { @@ -2521,7 +2587,7 @@ mod tests { // MatMut let mut buf = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; - let matmut = MatMut::new(RowMajor::new(2, 3).unwrap(), &mut buf).unwrap(); + let matmut = MatMut::from_repr(RowMajor::new(2, 3).unwrap(), &mut buf).unwrap(); let view = matmut.as_matrix_view(); assert_eq!(view.nrows(), 2); assert_eq!(view.ncols(), 3); @@ -2538,21 +2604,25 @@ mod tests { let repr = RowMajor::::new(2, 3).unwrap(); // Owned fill via NewOwned (Clone). - let filled = Mat::new(repr, String::from("x")).unwrap(); + let filled = Mat::from_repr(repr, String::from("x")).unwrap(); assert_eq!(filled.num_vectors(), 2); assert!(filled.rows().flatten().all(|s| s == "x")); // NewOwned (Clone + Default). - let defaulted = Mat::new(repr, Defaulted).unwrap(); + let defaulted = Mat::from_repr(repr, Defaulted).unwrap(); assert!(defaulted.rows().flatten().all(String::is_empty)); // from_fn. let mut counter = 0usize; - let mut mat = Mat::from_gen(Init(|| { - let s = counter.to_string(); - counter += 1; - s - }), 2, 3); + let mut mat = Mat::new( + Init(|| { + let s = counter.to_string(); + counter += 1; + s + }), + 2, + 3, + ); assert_eq!(counter, 6); assert_eq!(mat.get_row(1).unwrap()[0], "3"); @@ -2567,12 +2637,12 @@ mod tests { // Immutable view over a non-Copy slice (NewRef). let data = [String::from("a"), String::from("b")]; - let view = MatRef::new(RowMajor::new(2, 1).unwrap(), &data).unwrap(); + let view = MatRef::from_repr(RowMajor::new(2, 1).unwrap(), &data).unwrap(); assert_eq!(view.get_row(1).unwrap()[0], "b"); // Mutable view over a non-Copy slice (NewMut). let mut data_mut = [String::from("a"), String::from("b")]; - let mut view_mut = MatMut::new(RowMajor::new(1, 2).unwrap(), &mut data_mut).unwrap(); + let mut view_mut = MatMut::from_repr(RowMajor::new(1, 2).unwrap(), &mut data_mut).unwrap(); view_mut.get_row_mut(0).unwrap()[1] = String::from("z"); assert_eq!(data_mut[1], "z"); } diff --git a/diskann-utils/src/sampling/latin_hypercube.rs b/diskann-utils/src/sampling/latin_hypercube.rs index ecb416e20..03d227471 100644 --- a/diskann-utils/src/sampling/latin_hypercube.rs +++ b/diskann-utils/src/sampling/latin_hypercube.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use crate::views::{Matrix, MatrixView}; +use crate::matrix::{Matrix, MatrixView}; use rand::{rngs::StdRng, Rng, SeedableRng}; /// Return multiple rows sampled using Latin Hypercube Sampling in `data` that aproximetely uniformly distributed. @@ -25,12 +25,12 @@ impl SampleLatinHyperCube for T { let nrows = data.nrows(); let ncols = data.ncols(); if ncols == 0 || nrows == 0 { - return Matrix::from_gen(T::default(), num_samples, ncols); + return Matrix::new(T::default(), num_samples, ncols); } let seed = seed.unwrap_or(0xaf2f5fa0b5161acf); let mut rng = StdRng::seed_from_u64(seed); - let mut result: Matrix = Matrix::from_gen(T::default(), num_samples, ncols); + let mut result: Matrix = Matrix::new(T::default(), num_samples, ncols); // sample a random partitions down the diagonal for (s, res) in result.row_iter_mut().enumerate() { @@ -67,7 +67,7 @@ impl SampleLatinHyperCube for T { mod tests { use std::fmt::Display; - use crate::views::{Init, Matrix}; + use crate::matrix::{Init, Matrix}; use diskann_vector::conversion::CastFromSlice; use half::f16; use rand::{ @@ -178,17 +178,17 @@ mod tests { StandardUniform: Distribution, { // No Rows - let x = Matrix::::from_gen(T::default(), 0, 10); + let x = Matrix::::new(T::default(), 0, 10); assert_eq!( T::sample_latin_hypercube(x.as_view(), 1, None), - Matrix::::from_gen(T::default(), 1, x.ncols()) + Matrix::::new(T::default(), 1, x.ncols()) ); // No Cols0 - let x = Matrix::::from_gen(T::default(), 1, 0); + let x = Matrix::::new(T::default(), 1, 0); assert_eq!( T::sample_latin_hypercube(x.as_view(), 1, None), - Matrix::::from_gen(T::default(), 1, x.ncols()) + Matrix::::new(T::default(), 1, x.ncols()) ); let mut rng: StdRng = StdRng::seed_from_u64(0xaf2f5fa0b5161acf); @@ -196,7 +196,7 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!( T::sample_latin_hypercube(x.as_view(), 1, None), Matrix::::try_from(x.row(0).to_vec().into_boxed_slice(), 1, dim).unwrap() @@ -234,7 +234,7 @@ mod tests { #[test] fn test_f16() { let data = example_dataset(); - let mut data_f16 = Matrix::::from_gen(f16::default(), data.nrows(), data.ncols()); + let mut data_f16 = Matrix::::new(f16::default(), data.nrows(), data.ncols()); data_f16.as_mut_slice().cast_from_slice(data.as_slice()); test_for_type(data_f16); } diff --git a/diskann-utils/src/sampling/medoid.rs b/diskann-utils/src/sampling/medoid.rs index 69d176550..9b98a8f6e 100644 --- a/diskann-utils/src/sampling/medoid.rs +++ b/diskann-utils/src/sampling/medoid.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use crate::views::MatrixView; +use crate::matrix::MatrixView; use diskann_vector::{conversion::CastFromSlice, distance::SquaredL2, PureDistanceFunction}; use half::f16; @@ -161,7 +161,7 @@ impl ComputeMedoid for i8 { #[cfg(test)] mod tests { - use crate::views::{Init, Matrix}; + use crate::matrix::{Init, Matrix}; use rand::{ distr::{Distribution, StandardUniform}, rngs::StdRng, @@ -242,11 +242,11 @@ mod tests { #[test] fn test_f32() { // No Rows - let x = Matrix::::from_gen(0.0f32, 0, 10); + let x = Matrix::::new(0.0f32, 0, 10); assert_eq!(f32::compute_medoid(x.as_view()), vec![0.0; x.ncols()]); // No Cols - let x = Matrix::::from_gen(0.0f32, 10, 0); + let x = Matrix::::new(0.0f32, 10, 0); assert_eq!(f32::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0xaf2f5fa0b5161acf); @@ -254,7 +254,7 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!(&*f32::compute_medoid(x.as_view()), x.row(0)); } @@ -267,14 +267,14 @@ mod tests { #[test] fn test_f16() { // No Rows - let x = Matrix::::from_gen(f16::default(), 0, 10); + let x = Matrix::::new(f16::default(), 0, 10); assert_eq!( f16::compute_medoid(x.as_view()), vec![f16::default(); x.ncols()] ); // No Cols - let x = Matrix::::from_gen(f16::default(), 10, 0); + let x = Matrix::::new(f16::default(), 10, 0); assert_eq!(f16::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0x88e2f7096fc9b90e); @@ -282,13 +282,13 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::from_gen(Init(|| f16::from_f32(dist.sample(&mut rng))), 1, dim); + let x = Matrix::::new(Init(|| f16::from_f32(dist.sample(&mut rng))), 1, dim); assert_eq!(&*f16::compute_medoid(x.as_view()), x.row(0)); } // Example dataset let (data, expected) = example_dataset(); - let mut data_f16 = Matrix::::from_gen(f16::default(), data.nrows(), data.ncols()); + let mut data_f16 = Matrix::::new(f16::default(), data.nrows(), data.ncols()); data_f16.as_mut_slice().cast_from_slice(data.as_slice()); let mut expected_f16 = vec![f16::default(); expected.len()]; @@ -316,18 +316,18 @@ mod tests { #[test] fn test_u8() { // No Rows - let x = Matrix::::from_gen(0u8, 0, 10); + let x = Matrix::::new(0u8, 0, 10); assert_eq!(u8::compute_medoid(x.as_view()), vec![0u8; x.ncols()]); // No Cols - let x = Matrix::::from_gen(0u8, 10, 0); + let x = Matrix::::new(0u8, 10, 0); assert_eq!(u8::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0x8f2f5fa0b5161acf); // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!(&*u8::compute_medoid(x.as_view()), x.row(0)); } @@ -356,11 +356,11 @@ mod tests { #[test] fn test_i8() { // No Rows - let x = Matrix::::from_gen(0i8, 0, 10); + let x = Matrix::::new(0i8, 0, 10); assert_eq!(i8::compute_medoid(x.as_view()), vec![0i8; x.ncols()]); // No Cols - let x = Matrix::::from_gen(0i8, 10, 0); + let x = Matrix::::new(0i8, 10, 0); assert_eq!(i8::compute_medoid(x.as_view()), Vec::::new()); let mut rng = StdRng::seed_from_u64(0x8f2f5fa0b5161acf); @@ -368,7 +368,7 @@ mod tests { // One row let dist = StandardUniform; for dim in 1..20 { - let x = Matrix::::from_gen(Init(|| dist.sample(&mut rng)), 1, dim); + let x = Matrix::::new(Init(|| dist.sample(&mut rng)), 1, dim); assert_eq!(&*i8::compute_medoid(x.as_view()), x.row(0)); } diff --git a/diskann-utils/src/strided.rs b/diskann-utils/src/strided.rs index ced09bece..8d83a58f0 100644 --- a/diskann-utils/src/strided.rs +++ b/diskann-utils/src/strided.rs @@ -9,11 +9,11 @@ use std::{ }; use thiserror::Error; -use crate::views::{DenseData, MutDenseData}; +use crate::matrix::{DenseData, MutDenseData}; /// A row-major strided matrix. /// -/// This is a generalization of the dense [`Matrix`](crate::views::Matrix) type as it does not mandate a dense +/// This is a generalization of the dense [`Matrix`](crate::matrix::Matrix) type as it does not mandate a dense /// layout in memory. /// /// ```text @@ -497,7 +497,6 @@ where } } -// Dense (row-major) views convert to strided views with `cstride == ncols`. impl<'a, T> From>> for StridedBase<&'a [T]> { fn from(m: crate::matrix::MatRef<'a, crate::matrix::RowMajor>) -> Self { let (nrows, ncols) = (m.nrows(), m.ncols()); @@ -531,7 +530,7 @@ impl<'a, T> From>> #[cfg(test)] mod tests { use super::*; - use crate::views; + use crate::matrix; #[test] fn test_linear_length() { @@ -602,7 +601,7 @@ mod tests { } // Test that the contents of `dut` match those in the dense 2d matrix. - fn test_indexing(dut: StridedView<'_, usize>, expected: views::MatrixView<'_, usize>) { + fn test_indexing(dut: StridedView<'_, usize>, expected: matrix::MatrixView<'_, usize>) { assert_eq!(dut.nrows(), expected.nrows()); assert_eq!(dut.ncols(), expected.ncols()); @@ -642,10 +641,10 @@ mod tests { // 2*ncols 2*ncols+1 2*ncols+2 ... 3*ncols-1 // ... // ``` - fn create_test_matrix(nrows: usize, ncols: usize) -> views::Matrix { + fn create_test_matrix(nrows: usize, ncols: usize) -> matrix::Matrix { let mut i = 0; - views::Matrix::from_gen( - views::Init(|| { + matrix::Matrix::new( + matrix::Init(|| { let v = i; i += 1; v @@ -680,7 +679,7 @@ mod tests { assert_eq!(v.as_ptr(), ptr, "base pointer was not preserved"); // Create the expected matrix. - let mut expected = views::Matrix::from_gen(0, 5, 2); + let mut expected = matrix::Matrix::new(0, 5, 2); for row in 0..expected.nrows() { for col in 0..expected.ncols() { expected[(row, col)] = m[(row, col)]; @@ -690,7 +689,7 @@ mod tests { // Create a strided view over the last two columns. let v = StridedView::try_from(&(m.as_slice()[1..]), m.nrows(), 2, m.ncols()).unwrap(); - let mut expected = views::Matrix::from_gen(0, 5, 2); + let mut expected = matrix::Matrix::new(0, 5, 2); for row in 0..expected.nrows() { for col in 0..expected.ncols() { expected[(row, col)] = m[(row, col + 1)]; @@ -706,7 +705,7 @@ mod tests { // Initialize using 2d indexing. { - let mut dst = views::Matrix::::from_gen(0, 5, 10); + let mut dst = matrix::Matrix::::new(0, 5, 10); let ptr = dst.as_ptr(); @@ -736,7 +735,7 @@ mod tests { // Initialize using row-wise indexing. { - let mut dst = views::Matrix::::from_gen(0, 5, 10); + let mut dst = matrix::Matrix::::new(0, 5, 10); let ptr = dst.as_ptr(); @@ -764,7 +763,7 @@ mod tests { // Initialize using row-iterator indexing. { - let mut dst = views::Matrix::::from_gen(0, 5, 10); + let mut dst = matrix::Matrix::::new(0, 5, 10); let offset = 2; // SAFETY: The underlying allocation is valid for much more than 2 elements. @@ -845,7 +844,7 @@ mod tests { #[test] fn test_try_shrink_from() { // Exact is okay. - let m = views::Matrix::::from_gen(0, 10, 10); + let m = matrix::Matrix::::new(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); let s = StridedView::try_shrink_from(m.as_slice(), nrows, ncols, ncols).unwrap(); @@ -869,14 +868,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_shink_from_panics() { - let m = views::Matrix::::from_gen(0, 4, 4); + let m = matrix::Matrix::::new(0, 4, 4); let _ = StridedView::try_shrink_from(m.as_slice(), 2, 2, 1); } #[test] fn test_try_shrink_from_mut() { // Exact is okay. - let mut m = views::Matrix::::from_gen(0, 10, 10); + let mut m = matrix::Matrix::::new(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); @@ -904,14 +903,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_shink_from_mut_panics() { - let mut m = views::Matrix::::from_gen(0, 4, 4); + let mut m = matrix::Matrix::::new(0, 4, 4); let _ = MutStridedView::try_shrink_from_mut(m.as_mut_slice(), 2, 2, 1); } #[test] fn test_try_from() { // Exact is okay. - let m = views::Matrix::::from_gen(0, 10, 10); + let m = matrix::Matrix::::new(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); let s = StridedView::try_from(m.as_slice(), nrows, ncols, ncols).unwrap(); @@ -940,14 +939,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_frompanics() { - let mut m = views::Matrix::::from_gen(0, 4, 4); + let mut m = matrix::Matrix::::new(0, 4, 4); let _ = MutStridedView::try_from(m.as_mut_slice(), 2, 2, 1); } #[test] #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] fn test_get_row_panics() { - let m = views::Matrix::::from_gen(0, 3, 7); + let m = matrix::Matrix::::new(0, 3, 7); let v: StridedView<_> = m.as_view().into(); v.row(3); } @@ -955,7 +954,7 @@ mod tests { #[test] #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] fn test_get_row_mut_panics() { - let mut m = views::Matrix::::from_gen(0, 3, 7); + let mut m = matrix::Matrix::::new(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v.row_mut(3); } @@ -963,7 +962,7 @@ mod tests { #[test] #[should_panic(expected = "row 3 is out of bounds (max: 3)")] fn test_index_panics_row() { - let m = views::Matrix::::from_gen(0, 3, 7); + let m = matrix::Matrix::::new(0, 3, 7); let v: StridedView<_> = m.as_view().into(); let _ = v[(3, 2)]; } @@ -971,7 +970,7 @@ mod tests { #[test] #[should_panic(expected = "col 7 is out of bounds (max: 7)")] fn test_index_panics_col() { - let m = views::Matrix::::from_gen(0, 3, 7); + let m = matrix::Matrix::::new(0, 3, 7); let v: StridedView<_> = m.as_view().into(); let _ = v[(2, 7)]; } @@ -979,7 +978,7 @@ mod tests { #[test] #[should_panic(expected = "row 3 is out of bounds (max: 3)")] fn test_index_mut_panics_row() { - let mut m = views::Matrix::::from_gen(0, 3, 7); + let mut m = matrix::Matrix::::new(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v[(3, 2)] = 1; } @@ -987,7 +986,7 @@ mod tests { #[test] #[should_panic(expected = "col 7 is out of bounds (max: 7)")] fn test_index_mut_panics_col() { - let mut m = views::Matrix::::from_gen(0, 3, 7); + let mut m = matrix::Matrix::::new(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v[(2, 7)] = 1; } diff --git a/diskann-utils/src/views.rs b/diskann-utils/src/views.rs deleted file mode 100644 index 7a899c1e0..000000000 --- a/diskann-utils/src/views.rs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT license. - */ - -//! Dense matrix types and the `DenseData` container abstraction. -//! -//! The [`Matrix`], [`MatrixView`], and [`MatrixViewMut`] types are re-exported from -//! [`crate::matrix`]. [`DenseData`]/[`MutDenseData`] abstract over owned and borrowed -//! contiguous storage and are used by [`crate::strided`]. - -pub use crate::matrix::{Generator, Init, Matrix, MatrixView, MatrixViewMut, TryFromError}; - -/// Abstraction over a type that can yield a dense slice of its contents. -/// -/// # Safety -/// -/// `as_slice` must be idempotent: it must **always** return the same slice with the same -/// length (unsafe code relies on this). -pub unsafe trait DenseData { - type Elem; - - /// Return the underlying data as a slice. - fn as_slice(&self) -> &[Self::Elem]; -} - -/// A mutable companion to [`DenseData`]. -/// -/// # Safety -/// -/// `as_mut_slice` must be idempotent and must span the exact same memory as -/// [`DenseData::as_slice`]. -pub unsafe trait MutDenseData: DenseData { - fn as_mut_slice(&mut self) -> &mut [Self::Elem]; -} - -// SAFETY: fulfills the idempotency requirement. -unsafe impl DenseData for &[T] { - type Elem = T; - fn as_slice(&self) -> &[Self::Elem] { - self - } -} - -// SAFETY: fulfills the idempotency requirement. -unsafe impl DenseData for &mut [T] { - type Elem = T; - fn as_slice(&self) -> &[Self::Elem] { - self - } -} - -// SAFETY: fulfills the idempotency requirement and spans the same memory as `as_slice`. -unsafe impl MutDenseData for &mut [T] { - fn as_mut_slice(&mut self) -> &mut [Self::Elem] { - self - } -} - -// SAFETY: fulfills the idempotency requirement. -unsafe impl DenseData for Box<[T]> { - type Elem = T; - fn as_slice(&self) -> &[Self::Elem] { - self - } -} - -// SAFETY: fulfills the idempotency requirement and spans the same memory as `as_slice`. -unsafe impl MutDenseData for Box<[T]> { - fn as_mut_slice(&mut self) -> &mut [Self::Elem] { - self - } -} diff --git a/diskann/src/error/ann_error.rs b/diskann/src/error/ann_error.rs index afb5ca098..795cf7e6d 100644 --- a/diskann/src/error/ann_error.rs +++ b/diskann/src/error/ann_error.rs @@ -588,9 +588,9 @@ where } } -impl From for ANNError { +impl From for ANNError { #[track_caller] - fn from(err: diskann_utils::views::TryFromError) -> Self { + fn from(err: diskann_utils::TryFromError) -> Self { ANNError::new(ANNErrorKind::DimensionMismatchError, err) } } @@ -1534,7 +1534,7 @@ Caused by: #[test] fn from_try_from_error() { let data: &[f32] = &[1.0, 2.0, 3.0]; - let err = diskann_utils::views::MatrixView::try_from(data, 2, 2).unwrap_err(); + let err = diskann_utils::MatrixView::try_from(data, 2, 2).unwrap_err(); let ann_err = ANNError::from(err); assert_eq!(ann_err.kind(), ANNErrorKind::DimensionMismatchError); } diff --git a/diskann/src/flat/test/provider.rs b/diskann/src/flat/test/provider.rs index 6f8a14136..7f28afc73 100644 --- a/diskann/src/flat/test/provider.rs +++ b/diskann/src/flat/test/provider.rs @@ -13,7 +13,7 @@ use std::{ sync::Arc, }; -use diskann_utils::{future::SendFuture, views::Matrix}; +use diskann_utils::{future::SendFuture, matrix::Matrix}; use diskann_vector::{PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; diff --git a/diskann/src/graph/glue.rs b/diskann/src/graph/glue.rs index 91cd7643d..548f8a304 100644 --- a/diskann/src/graph/glue.rs +++ b/diskann/src/graph/glue.rs @@ -1030,7 +1030,7 @@ where /// [`Overlay`](crate::graph::workingset::map::Overlay) for a working set seed compatible /// with [`Batch`]. /// -/// The primary implementation of this trait is [`Matrix`](diskann_utils::views::Matrix). +/// The primary implementation of this trait is [`Matrix`](diskann_utils::Matrix). pub trait Batch: Send + Sync + 'static { /// The element type of the batch. type Element<'a>: Copy; @@ -1047,7 +1047,7 @@ pub trait Batch: Send + Sync + 'static { } } -impl Batch for diskann_utils::views::Matrix { +impl Batch for diskann_utils::Matrix { type Element<'a> = &'a [T]; fn len(&self) -> usize { diff --git a/diskann/src/graph/start_point.rs b/diskann/src/graph/start_point.rs index 37d197915..4c7841d77 100644 --- a/diskann/src/graph/start_point.rs +++ b/diskann/src/graph/start_point.rs @@ -8,8 +8,8 @@ use std::{fmt::Display, num::NonZeroUsize}; use thiserror::Error; use diskann_utils::{ + matrix::{Matrix, MatrixView}, sampling::WithApproximateNorm, - views::{Matrix, MatrixView}, }; /// 'StartPointStrategy' is an enum that represents the different strategies to select @@ -98,7 +98,7 @@ impl StartPointStrategy { let indices = rand::seq::index::sample(&mut rng, train_data.nrows(), nsamples.get()); - let mut points = Matrix::from_gen(T::default(), nsamples.get(), train_data.ncols()); + let mut points = Matrix::new(T::default(), nsamples.get(), train_data.ncols()); std::iter::zip(points.row_iter_mut(), indices).for_each(|(dst, src)| { dst.copy_from_slice(train_data.row(src)); }); @@ -115,7 +115,7 @@ impl StartPointStrategy { } => { let mut rng = StdRng::seed_from_u64(*seed); let dim = train_data.ncols(); - let mut points = Matrix::from_gen(T::default(), nsamples.get(), dim); + let mut points = Matrix::new(T::default(), nsamples.get(), dim); points.row_iter_mut().for_each(|row| { row.copy_from_slice(&WithApproximateNorm::with_approximate_norm( dim, *norm, &mut rng, diff --git a/diskann/src/graph/test/cases/grid_insert.rs b/diskann/src/graph/test/cases/grid_insert.rs index 0c0e24724..b48f3a21e 100644 --- a/diskann/src/graph/test/cases/grid_insert.rs +++ b/diskann/src/graph/test/cases/grid_insert.rs @@ -18,7 +18,7 @@ use std::{num::NonZeroUsize, sync::Arc}; -use diskann_utils::views::MatrixView; +use diskann_utils::MatrixView; use diskann_vector::distance::Metric; use crate::{ diff --git a/diskann/src/graph/test/provider.rs b/diskann/src/graph/test/provider.rs index 56f1c23aa..f77659206 100644 --- a/diskann/src/graph/test/provider.rs +++ b/diskann/src/graph/test/provider.rs @@ -13,7 +13,7 @@ use std::{ }; use dashmap::{DashMap, mapref::entry::Entry}; -use diskann_utils::views::Matrix; +use diskann_utils::Matrix; use diskann_vector::{PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; diff --git a/diskann/src/graph/test/synthetic.rs b/diskann/src/graph/test/synthetic.rs index 1d2851c90..658ee11bf 100644 --- a/diskann/src/graph/test/synthetic.rs +++ b/diskann/src/graph/test/synthetic.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_utils::views::{Init, Matrix}; +use diskann_utils::{Init, Matrix}; use crate::graph::AdjacencyList; @@ -111,7 +111,7 @@ impl Grid { i += 1; this }); - Matrix::from_gen(init, size, 1) + Matrix::new(init, size, 1) } Self::Two => { let mut v = [0; 2]; @@ -126,7 +126,7 @@ impl Grid { value }); - Matrix::from_gen(init, size.pow(self.dim().into()), 2) + Matrix::new(init, size.pow(self.dim().into()), 2) } Self::Three => { // The whole we do with the array here is to avoid a `Default` bound on `R` @@ -145,7 +145,7 @@ impl Grid { value }); - Matrix::from_gen(init, size.pow(self.dim().into()), 3) + Matrix::new(init, size.pow(self.dim().into()), 3) } Self::Four => { let mut v = [0; 4]; @@ -160,7 +160,7 @@ impl Grid { value }); - Matrix::from_gen(init, size.pow(self.dim().into()), 4) + Matrix::new(init, size.pow(self.dim().into()), 4) } } } diff --git a/diskann/src/graph/workingset/map.rs b/diskann/src/graph/workingset/map.rs index e24b927ca..0f31e3cc1 100644 --- a/diskann/src/graph/workingset/map.rs +++ b/diskann/src/graph/workingset/map.rs @@ -101,7 +101,7 @@ //! //! ``` //! use std::sync::Arc; -//! use diskann_utils::views::Matrix; +//! use diskann_utils::Matrix; //! //! use diskann::graph::workingset::{Map, View, map::{Overlay, Ref, Builder, Capacity}}; //! @@ -646,7 +646,7 @@ where /// /// ``` /// use std::sync::Arc; -/// use diskann_utils::views::Matrix; +/// use diskann_utils::Matrix; /// /// use diskann::graph::workingset::map::{Overlay, Ref}; /// @@ -923,7 +923,7 @@ mod tests { use std::sync::Arc; - use diskann_utils::views::Matrix; + use diskann_utils::Matrix; use crate::graph::workingset::View as WorkingSetView; From 0d769cf296c2d5db68d1e3be5f7e6b0220f35e7c Mon Sep 17 00:00:00 2001 From: Suryansh Gupta Date: Wed, 22 Jul 2026 03:33:14 +0530 Subject: [PATCH 4/6] Remove overly re-exports --- diskann-benchmark-core/src/recall.rs | 2 +- diskann-benchmark-core/src/search/ids.rs | 2 +- .../streaming/executors/bigann/withdata.rs | 2 +- diskann-benchmark-simd/src/lib.rs | 4 ++-- diskann-benchmark/src/disk_index/search.rs | 2 +- diskann-benchmark/src/exhaustive/algos.rs | 6 +++--- diskann-benchmark/src/exhaustive/minmax.rs | 6 +++--- diskann-benchmark/src/exhaustive/product.rs | 7 ++++--- diskann-benchmark/src/exhaustive/spherical.rs | 6 +++--- .../index/bftree/full_precision_streaming.rs | 2 +- .../src/index/bftree/spherical.rs | 2 +- .../src/index/bftree/spherical_streaming.rs | 2 +- diskann-benchmark/src/index/inmem/product.rs | 2 +- diskann-benchmark/src/index/inmem/scalar.rs | 2 +- .../src/index/inmem/spherical.rs | 2 +- .../src/index/streaming/managed.rs | 2 +- diskann-benchmark/src/utils/datafiles.rs | 4 ++-- diskann-bftree/src/provider.rs | 6 +++--- diskann-bftree/src/quant.rs | 4 ++-- diskann-disk/src/build/builder/quantizer.rs | 2 +- .../src/search/pq/quantizer_preprocess.rs | 2 +- diskann-disk/src/storage/quant/compressor.rs | 2 +- .../src/storage/quant/pq/pq_dataset.rs | 2 +- .../src/storage/quant/pq/pq_generation.rs | 4 ++-- diskann-garnet/src/provider.rs | 2 +- diskann-garnet/src/quantization.rs | 4 ++-- diskann-providers/src/index/diskann_async.rs | 20 ++++++++++--------- .../provider/async_/inmem/full_precision.rs | 2 +- .../graph/provider/async_/inmem/scalar.rs | 2 +- .../graph/provider/async_/inmem/spherical.rs | 4 ++-- .../graph/provider/determinant_diversity.rs | 4 ++-- .../src/model/pq/fixed_chunk_pq_table.rs | 2 +- diskann-providers/src/storage/pq_storage.rs | 2 +- .../src/test_utils/search_utils.rs | 2 +- .../src/algorithms/hadamard.rs | 2 +- .../src/algorithms/kmeans/lloyds.rs | 2 +- .../algorithms/transforms/random_rotation.rs | 10 +++++----- .../src/product/tables/basic.rs | 2 +- .../src/product/tables/test.rs | 4 ++-- diskann-quantization/src/spherical/iface.rs | 4 ++-- diskann-quantization/src/test_util.rs | 2 +- diskann-quantization/src/utils.rs | 4 ++-- diskann-quantization/src/views.rs | 2 +- diskann-utils/src/lib.rs | 1 - diskann/src/error/ann_error.rs | 6 +++--- diskann/src/graph/glue.rs | 4 ++-- diskann/src/graph/test/cases/grid_insert.rs | 2 +- diskann/src/graph/test/provider.rs | 2 +- diskann/src/graph/test/synthetic.rs | 2 +- diskann/src/graph/workingset/map.rs | 6 +++--- 50 files changed, 89 insertions(+), 87 deletions(-) diff --git a/diskann-benchmark-core/src/recall.rs b/diskann-benchmark-core/src/recall.rs index f284100d3..a17780e3a 100644 --- a/diskann-benchmark-core/src/recall.rs +++ b/diskann-benchmark-core/src/recall.rs @@ -364,7 +364,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::{Matrix, matrix}; + use diskann_utils::matrix::{self, Matrix}; use super::*; diff --git a/diskann-benchmark-core/src/search/ids.rs b/diskann-benchmark-core/src/search/ids.rs index 7a24f37b7..0227f3468 100644 --- a/diskann-benchmark-core/src/search/ids.rs +++ b/diskann-benchmark-core/src/search/ids.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_utils::{Matrix, matrix}; +use diskann_utils::matrix::{self, Matrix}; use crate::recall; diff --git a/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs b/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs index cf76affd0..dbb7b43b0 100644 --- a/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs +++ b/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs @@ -5,7 +5,7 @@ use std::{ops::Range, path::Path, sync::Arc}; -use diskann_utils::{Matrix, MatrixView}; +use diskann_utils::matrix::{Matrix, MatrixView}; use crate::{recall, streaming}; diff --git a/diskann-benchmark-simd/src/lib.rs b/diskann-benchmark-simd/src/lib.rs index 0e2928304..824874f3a 100644 --- a/diskann-benchmark-simd/src/lib.rs +++ b/diskann-benchmark-simd/src/lib.rs @@ -7,7 +7,7 @@ use std::{io::Write, num::NonZeroUsize}; -use diskann_utils::{Matrix, MatrixView}; +use diskann_utils::matrix::{Matrix, MatrixView}; use diskann_vector::distance::simd; use diskann_wide::Architecture; use half::f16; @@ -755,7 +755,7 @@ impl Data { .map(|_| StandardUniform.sample(&mut rng)) .collect(); let data = Matrix::::new( - diskann_utils::Init(|| StandardUniform.sample(&mut rng)), + diskann_utils::matrix::Init(|| StandardUniform.sample(&mut rng)), run.num_points.get(), run.dim.get(), ); diff --git a/diskann-benchmark/src/disk_index/search.rs b/diskann-benchmark/src/disk_index/search.rs index c907875c2..0500ae3ac 100644 --- a/diskann-benchmark/src/disk_index/search.rs +++ b/diskann-benchmark/src/disk_index/search.rs @@ -31,7 +31,7 @@ use diskann_providers::{ utils::{create_thread_pool, ParallelIteratorInPool}, }; use diskann_tools::utils::{search_index_utils, KRecallAtN}; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; use serde::{Deserialize, Serialize}; use crate::{ diff --git a/diskann-benchmark/src/exhaustive/algos.rs b/diskann-benchmark/src/exhaustive/algos.rs index 36f8d35b2..8f28641a5 100644 --- a/diskann-benchmark/src/exhaustive/algos.rs +++ b/diskann-benchmark/src/exhaustive/algos.rs @@ -33,7 +33,7 @@ where #[derive(Debug, Clone)] pub(super) struct LinearSearch { - pub(super) ids: diskann_utils::Matrix, + pub(super) ids: diskann_utils::matrix::Matrix, pub(super) preprocess: Vec, pub(super) search: Vec, pub(super) total: MicroSeconds, @@ -41,7 +41,7 @@ pub(super) struct LinearSearch { pub(super) fn linear_search( store: &Q, - queries: diskann_utils::MatrixView, + queries: diskann_utils::matrix::MatrixView, builder: &C, results_per_query: usize, progress: &indicatif::ProgressBar, @@ -51,7 +51,7 @@ where C: CreateQuantComputer + Sync, { let mut output = - diskann_utils::Matrix::::new(u32::MAX, queries.nrows(), results_per_query); + diskann_utils::matrix::Matrix::::new(u32::MAX, queries.nrows(), results_per_query); struct Times { preprocess: MicroSeconds, diff --git a/diskann-benchmark/src/exhaustive/minmax.rs b/diskann-benchmark/src/exhaustive/minmax.rs index a5f392401..4ea3ea630 100644 --- a/diskann-benchmark/src/exhaustive/minmax.rs +++ b/diskann-benchmark/src/exhaustive/minmax.rs @@ -370,7 +370,7 @@ mod imp { pub(super) struct Store { // The number of bytes to take from each row. bytes: usize, - data: diskann_utils::Matrix, + data: diskann_utils::matrix::Matrix, quantizer: diskann_quantization::minmax::MinMaxQuantizer, } @@ -379,7 +379,7 @@ mod imp { Unsigned: Representation, { fn new( - input: diskann_utils::MatrixView, + input: diskann_utils::matrix::MatrixView, quantizer: diskann_quantization::minmax::MinMaxQuantizer, progress: &ProgressBar, ) -> anyhow::Result { @@ -389,7 +389,7 @@ mod imp { // The APIs below should correctly handle these variables. let output_dim = quantizer.output_dim(); let bytes = Data::::canonical_bytes(output_dim); - let mut data = diskann_utils::Matrix::new(0, input.nrows(), bytes); + let mut data = diskann_utils::matrix::Matrix::new(0, input.nrows(), bytes); // Compress the data. // diff --git a/diskann-benchmark/src/exhaustive/product.rs b/diskann-benchmark/src/exhaustive/product.rs index 59ef2cc9f..5e56d40fb 100644 --- a/diskann-benchmark/src/exhaustive/product.rs +++ b/diskann-benchmark/src/exhaustive/product.rs @@ -322,17 +322,18 @@ mod imp { /// A store for quantized data. pub(super) struct Store { - data: diskann_utils::Matrix, + data: diskann_utils::matrix::Matrix, quantizer: diskann_providers::model::pq::FixedChunkPQTable, } impl Store { fn new( - input: diskann_utils::MatrixView, + input: diskann_utils::matrix::MatrixView, quantizer: diskann_providers::model::pq::FixedChunkPQTable, progress: &ProgressBar, ) -> anyhow::Result { - let mut data = diskann_utils::Matrix::new(0, input.nrows(), quantizer.get_num_chunks()); + let mut data = + diskann_utils::matrix::Matrix::new(0, input.nrows(), quantizer.get_num_chunks()); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/exhaustive/spherical.rs b/diskann-benchmark/src/exhaustive/spherical.rs index 1a7d4f4cf..ef487b6ec 100644 --- a/diskann-benchmark/src/exhaustive/spherical.rs +++ b/diskann-benchmark/src/exhaustive/spherical.rs @@ -394,7 +394,7 @@ mod imp { pub(super) struct Store { // The number of bytes to take from each row. bytes: usize, - data: diskann_utils::Matrix, + data: diskann_utils::matrix::Matrix, plan: diskann_quantization::spherical::iface::Impl, } @@ -405,7 +405,7 @@ mod imp { for<'a> CompressIntoWith<&'a [f32], DataMut<'a, NBITS>, ScopedAllocator<'a>>, { fn new( - input: diskann_utils::MatrixView, + input: diskann_utils::matrix::MatrixView, plan: diskann_quantization::spherical::iface::Impl, progress: &ProgressBar, ) -> anyhow::Result { @@ -416,7 +416,7 @@ mod imp { let output_dim = plan.quantizer().output_dim(); let bytes = diskann_quantization::spherical::DataRef::::canonical_bytes(output_dim); - let mut data = diskann_utils::Matrix::new(0, input.nrows(), bytes); + let mut data = diskann_utils::matrix::Matrix::new(0, input.nrows(), bytes); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/index/bftree/full_precision_streaming.rs b/diskann-benchmark/src/index/bftree/full_precision_streaming.rs index 5d1605beb..d1fb12b4d 100644 --- a/diskann-benchmark/src/index/bftree/full_precision_streaming.rs +++ b/diskann-benchmark/src/index/bftree/full_precision_streaming.rs @@ -24,7 +24,7 @@ use diskann_providers::{ model::graph::provider::async_::common::FullPrecision, storage::{FileStorageProvider, SaveWith}, }; -use diskann_utils::{Matrix, MatrixView}; +use diskann_utils::matrix::{Matrix, MatrixView}; use crate::{ index::{ diff --git a/diskann-benchmark/src/index/bftree/spherical.rs b/diskann-benchmark/src/index/bftree/spherical.rs index 7cf0d076d..badf7f565 100644 --- a/diskann-benchmark/src/index/bftree/spherical.rs +++ b/diskann-benchmark/src/index/bftree/spherical.rs @@ -23,7 +23,7 @@ use diskann_quantization::{ SphericalQuantizer, }, }; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; use rand::SeedableRng; use crate::{ diff --git a/diskann-benchmark/src/index/bftree/spherical_streaming.rs b/diskann-benchmark/src/index/bftree/spherical_streaming.rs index e15c3dde8..f74706f80 100644 --- a/diskann-benchmark/src/index/bftree/spherical_streaming.rs +++ b/diskann-benchmark/src/index/bftree/spherical_streaming.rs @@ -30,7 +30,7 @@ use diskann_quantization::spherical::{ iface::{self as spherical_iface, Quantizer}, SphericalQuantizer, }; -use diskann_utils::{Matrix, MatrixView}; +use diskann_utils::matrix::{Matrix, MatrixView}; use rand::SeedableRng; use crate::{ diff --git a/diskann-benchmark/src/index/inmem/product.rs b/diskann-benchmark/src/index/inmem/product.rs index b727b42bf..1fb9a09f8 100644 --- a/diskann-benchmark/src/index/inmem/product.rs +++ b/diskann-benchmark/src/index/inmem/product.rs @@ -49,7 +49,7 @@ mod imp { IndexConfiguration, }, }; - use diskann_utils::{Matrix, MatrixView}; + use diskann_utils::matrix::{Matrix, MatrixView}; use diskann_benchmark_runner::{ benchmark::{MatchContext, Score}, diff --git a/diskann-benchmark/src/index/inmem/scalar.rs b/diskann-benchmark/src/index/inmem/scalar.rs index 390a5722c..866b580fa 100644 --- a/diskann-benchmark/src/index/inmem/scalar.rs +++ b/diskann-benchmark/src/index/inmem/scalar.rs @@ -69,7 +69,7 @@ mod imp { graph::provider::async_::{common, inmem}, }, }; - use diskann_utils::{Matrix, MatrixView}; + use diskann_utils::matrix::{Matrix, MatrixView}; use crate::{ index::{ diff --git a/diskann-benchmark/src/index/inmem/spherical.rs b/diskann-benchmark/src/index/inmem/spherical.rs index f926d9746..54ed19509 100644 --- a/diskann-benchmark/src/index/inmem/spherical.rs +++ b/diskann-benchmark/src/index/inmem/spherical.rs @@ -75,7 +75,7 @@ mod imp { model::graph::provider::async_::{common, inmem}, }; use diskann_quantization::alloc::GlobalAllocator; - use diskann_utils::Matrix; + use diskann_utils::matrix::Matrix; use rand::SeedableRng; use serde::Serialize; use std::{io::Write, sync::Arc}; diff --git a/diskann-benchmark/src/index/streaming/managed.rs b/diskann-benchmark/src/index/streaming/managed.rs index 515ccaff2..6527de951 100644 --- a/diskann-benchmark/src/index/streaming/managed.rs +++ b/diskann-benchmark/src/index/streaming/managed.rs @@ -11,7 +11,7 @@ use diskann_benchmark_core::{ streaming::{self, executors}, }; use diskann_benchmark_runner::{timed, utils::MicroSeconds}; -use diskann_utils::{Matrix, MatrixView}; +use diskann_utils::matrix::{Matrix, MatrixView}; use crate::utils::streaming::TagSlotManager; diff --git a/diskann-benchmark/src/utils/datafiles.rs b/diskann-benchmark/src/utils/datafiles.rs index db252801d..620faddfc 100644 --- a/diskann-benchmark/src/utils/datafiles.rs +++ b/diskann-benchmark/src/utils/datafiles.rs @@ -10,7 +10,7 @@ use bit_set::BitSet; use diskann::utils::IntoUsize; use diskann_benchmark_runner::utils::datatype::DataType; use diskann_providers::storage::StorageReadProvider; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; use serde::{Deserialize, Serialize}; pub(crate) struct BinFile<'a>(pub(crate) &'a Path); @@ -71,7 +71,7 @@ impl ConvertingLoad for f32 { ))] fn converting_load(path: BinFile<'_>, data_type: DataType) -> anyhow::Result> { #[inline(never)] - fn convert(from: diskann_utils::MatrixView) -> Matrix + fn convert(from: diskann_utils::matrix::MatrixView) -> Matrix where U: Default + Clone + From, T: Copy, diff --git a/diskann-bftree/src/provider.rs b/diskann-bftree/src/provider.rs index 612f81def..f6dec1fb5 100644 --- a/diskann-bftree/src/provider.rs +++ b/diskann-bftree/src/provider.rs @@ -97,7 +97,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// use diskann_bftree::NoStore; /// use diskann_vector::distance::Metric; -/// use diskann_utils::{Init, Matrix}; +/// use diskann_utils::matrix::{Init, Matrix}; /// use bf_tree::Config; /// use std::num::NonZeroUsize; /// @@ -134,7 +134,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// algorithms::TransformKind, /// spherical::{iface, SphericalQuantizer, SupportedMetric, PreScale}, /// }; -/// use diskann_utils::{Init, Matrix}; +/// use diskann_utils::matrix::{Init, Matrix}; /// use diskann_bftree::provider::{ /// BfTreeProvider, BfTreeProviderParameters /// }; @@ -2020,7 +2020,7 @@ mod tests { neighbor::BackInserter, }; use diskann_providers::storage::FileStorageProvider; - use diskann_utils::{Init, Matrix}; + use diskann_utils::matrix::{Init, Matrix}; fn create_quant_index() -> Arc>> { let start_point = Matrix::new(Init(|| 0.0f32), 1, 5); diff --git a/diskann-bftree/src/quant.rs b/diskann-bftree/src/quant.rs index 4926358bf..88de8e679 100644 --- a/diskann-bftree/src/quant.rs +++ b/diskann-bftree/src/quant.rs @@ -236,8 +236,8 @@ pub(crate) fn create_test_quantizer(dim: usize) -> Poly { alloc::poly, spherical::{iface, PreScale, SphericalQuantizer, SupportedMetric}, }; - use diskann_utils::Init; - use diskann_utils::Matrix; + use diskann_utils::matrix::Init; + use diskann_utils::matrix::Matrix; use rand::{rngs::StdRng, SeedableRng}; // Create training data with spread-out values. diff --git a/diskann-disk/src/build/builder/quantizer.rs b/diskann-disk/src/build/builder/quantizer.rs index 68fa659a0..1d35e5f9c 100644 --- a/diskann-disk/src/build/builder/quantizer.rs +++ b/diskann-disk/src/build/builder/quantizer.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{create_thread_pool, BridgeErr, PQPathNames}, }; use diskann_quantization::scalar::train::ScalarQuantizationParameters; -use diskann_utils::MatrixView; +use diskann_utils::matrix::MatrixView; use tracing::info; use crate::QuantizationType; diff --git a/diskann-disk/src/search/pq/quantizer_preprocess.rs b/diskann-disk/src/search/pq/quantizer_preprocess.rs index 1c7d96dd8..86e706b93 100644 --- a/diskann-disk/src/search/pq/quantizer_preprocess.rs +++ b/diskann-disk/src/search/pq/quantizer_preprocess.rs @@ -22,7 +22,7 @@ pub fn quantizer_preprocess( ) -> ANNResult<()> { let table = pq_data.pq_table(); let expected_len = table.ncenters() * table.nchunks(); - let dst = diskann_utils::MatrixViewMut::try_from( + let dst = diskann_utils::matrix::MatrixViewMut::try_from( &mut (*pq_scratch.aligned_pqtable_dist_scratch)[..expected_len], table.nchunks(), table.ncenters(), diff --git a/diskann-disk/src/storage/quant/compressor.rs b/diskann-disk/src/storage/quant/compressor.rs index 0d5ea9dac..2d20501a4 100644 --- a/diskann-disk/src/storage/quant/compressor.rs +++ b/diskann-disk/src/storage/quant/compressor.rs @@ -4,7 +4,7 @@ */ use diskann::{utils::VectorRepr, ANNResult}; -use diskann_utils::{MatrixView, MatrixViewMut}; +use diskann_utils::matrix::{MatrixView, MatrixViewMut}; /// [`QuantCompressor`] defines the interface for quantizer with [`QuantDataGenerator`] /// diff --git a/diskann-disk/src/storage/quant/pq/pq_dataset.rs b/diskann-disk/src/storage/quant/pq/pq_dataset.rs index fb451292c..529706b28 100644 --- a/diskann-disk/src/storage/quant/pq/pq_dataset.rs +++ b/diskann-disk/src/storage/quant/pq/pq_dataset.rs @@ -8,7 +8,7 @@ use core::fmt::Debug; use diskann::{ANNError, ANNResult}; use diskann_providers::model::FixedChunkPQTable; use diskann_quantization::product::TransposedTable; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; #[derive(Debug)] pub struct PQData { diff --git a/diskann-disk/src/storage/quant/pq/pq_generation.rs b/diskann-disk/src/storage/quant/pq/pq_generation.rs index d3f76e0ae..4530cef09 100644 --- a/diskann-disk/src/storage/quant/pq/pq_generation.rs +++ b/diskann-disk/src/storage/quant/pq/pq_generation.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{BridgeErr, RayonThreadPoolRef}, }; use diskann_quantization::{product::TransposedTable, CompressInto}; -use diskann_utils::{MatrixView, MatrixViewMut}; +use diskann_utils::matrix::{MatrixView, MatrixViewMut}; use diskann_vector::distance::Metric; use tracing::info; @@ -119,7 +119,7 @@ where context.storage_provider, )?; - let mut full_pivot_data_mat = diskann_utils::MatrixViewMut::try_from( + let mut full_pivot_data_mat = diskann_utils::matrix::MatrixViewMut::try_from( full_pivot_data.as_mut_slice(), context.num_centers, full_dim, diff --git a/diskann-garnet/src/provider.rs b/diskann-garnet/src/provider.rs index aeae077e8..5cf55be02 100644 --- a/diskann-garnet/src/provider.rs +++ b/diskann-garnet/src/provider.rs @@ -24,7 +24,7 @@ use diskann::{ utils::VectorRepr, }; use diskann_quantization::alloc::{AllocatorError, Poly}; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; use diskann_utils::{ matrix::MatrixView, object_pool::{AsPooled, ObjectPool, PooledRef, Undef}, diff --git a/diskann-garnet/src/quantization.rs b/diskann-garnet/src/quantization.rs index c9716992f..288579717 100644 --- a/diskann-garnet/src/quantization.rs +++ b/diskann-garnet/src/quantization.rs @@ -12,7 +12,7 @@ use diskann_quantization::{ iface::{self, Opaque, OpaqueMut, Quantizer}, }, }; -use diskann_utils::MatrixView; +use diskann_utils::matrix::MatrixView; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; @@ -357,7 +357,7 @@ impl DynQueryComputer for MinMax8BitQueryComputer { #[cfg(test)] mod tests { - use diskann_utils::Matrix; + use diskann_utils::matrix::Matrix; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use crate::quantization::{GarnetQuantizer, GarnetQuantizerError, MinMax8Bit, Spherical1Bit}; diff --git a/diskann-providers/src/index/diskann_async.rs b/diskann-providers/src/index/diskann_async.rs index 79b95b0d8..20470ddb8 100644 --- a/diskann-providers/src/index/diskann_async.rs +++ b/diskann-providers/src/index/diskann_async.rs @@ -59,7 +59,7 @@ pub(crate) fn simplified_builder( } pub fn train_pq( - data: diskann_utils::MatrixView, + data: diskann_utils::matrix::MatrixView, num_pq_chunks: usize, rng: &mut dyn rand::RngCore, pool: crate::utils::RayonThreadPoolRef<'_>, @@ -213,7 +213,7 @@ pub(crate) mod tests { /// Convert an iterator of vectors into a single Matrix. All elements in `data` must /// have the same length, otherwise this function panics. - pub(crate) fn squish<'a, To, T, Itr>(data: Itr, dim: usize) -> diskann_utils::Matrix + pub(crate) fn squish<'a, To, T, Itr>(data: Itr, dim: usize) -> diskann_utils::matrix::Matrix where To: Clone + Default, T: Clone + Into + 'a, @@ -221,7 +221,7 @@ pub(crate) mod tests { { // Assume that all the vectors in `data` have the same length. // If they don't, `copy_from_slice` will panic, so we're double checking. - let mut mat = diskann_utils::Matrix::new(To::default(), data.len(), dim); + let mut mat = diskann_utils::matrix::Matrix::new(To::default(), data.len(), dim); std::iter::zip(mat.row_iter_mut(), data).for_each(|(output, input)| { assert_eq!( input.len(), @@ -621,7 +621,8 @@ pub(crate) mod tests { // // So, when we compute the corpus used during groundtruth generation, we take all // but this last point. - let corpus: diskann_utils::Matrix = squish(vectors.iter().take(num_points), dim); + let corpus: diskann_utils::matrix::Matrix = + squish(vectors.iter().take(num_points), dim); let mut paged_tests = Vec::new(); @@ -874,7 +875,7 @@ pub(crate) mod tests { let data = T::generate_spherical(num, dim, radius, rng); let table = { - let train_data: diskann_utils::Matrix = squish(data.iter(), dim); + let train_data: diskann_utils::matrix::Matrix = squish(data.iter(), dim); train_pq( train_data.as_view(), 2.min(dim), @@ -1065,7 +1066,8 @@ pub(crate) mod tests { let beta = 0.5; - let corpus: diskann_utils::Matrix = squish(vectors.iter().take(num_points), dim); + let corpus: diskann_utils::matrix::Matrix = + squish(vectors.iter().take(num_points), dim); let query = vec![grid_size as f32; dim]; // The strategy we use here for checking is that we pull in a lot of neighbors and @@ -2202,7 +2204,7 @@ pub(crate) mod tests { parameters: InitParams, file: &str, start_strategy: StartPointStrategy, - train_data: diskann_utils::MatrixView<'_, f32>, + train_data: diskann_utils::matrix::MatrixView<'_, f32>, ) where DefaultProvider: DataProvider + for<'a> SetElement<&'a [f32]> @@ -2258,7 +2260,7 @@ pub(crate) mod tests { file: &str, num_pq_chunks: usize, startpoint: StartPointStrategy, - ) -> (Arc, diskann_utils::Matrix) + ) -> (Arc, diskann_utils::matrix::Matrix) where S: for<'a> InsertStrategy<'a, TestProvider, &'a [f32]> + MultiInsertStrategy> @@ -2656,7 +2658,7 @@ pub(crate) mod tests { // Randomize the vectors let rng = &mut create_rnd_from_seed_in_tests(0x7dc205fcda38d3a3); indices.shuffle(rng); - let mut queries = diskann_utils::Matrix::new(0.0, data.nrows(), data.ncols()); + let mut queries = diskann_utils::matrix::Matrix::new(0.0, data.nrows(), data.ncols()); std::iter::zip(queries.row_iter_mut(), indices.iter()).for_each(|(row, i)| { row.copy_from_slice(data.row(*i)); }); diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs index acb729e93..e061d2554 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs @@ -22,8 +22,8 @@ use diskann::{ utils::{IntoUsize, VectorRepr}, }; -use diskann_utils::Matrix; use diskann_utils::future::AsyncFriendly; +use diskann_utils::matrix::Matrix; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use crate::model::graph::provider::async_::{ diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs index ccbf94108..c7aad4e82 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs @@ -892,7 +892,7 @@ mod tests { use crate::storage::VirtualStorageProvider; use diskann::utils::ONE; use diskann_quantization::scalar::train::ScalarQuantizationParameters; - use diskann_utils::MatrixView; + use diskann_utils::matrix::MatrixView; use diskann_vector::distance::Metric; use rstest::rstest; diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs index b50f0053a..cc1b9efa0 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs @@ -725,7 +725,7 @@ mod tests { alloc::GlobalAllocator, spherical::{SphericalQuantizer, SupportedMetric}, }; - use diskann_utils::{Matrix, MatrixView}; + use diskann_utils::matrix::{Matrix, MatrixView}; use diskann_vector::{ DistanceFunction, PreprocessedDistanceFunction, PureDistanceFunction, distance::{InnerProduct, Metric, SquaredL2}, @@ -769,7 +769,7 @@ mod tests { fn dataset(nrows: usize, ncols: usize, rng: &mut StdRng) -> Matrix { Matrix::new( - diskann_utils::Init(|| StandardNormal {}.sample(rng)), + diskann_utils::matrix::Init(|| StandardNormal {}.sample(rng)), nrows, ncols, ) diff --git a/diskann-providers/src/model/graph/provider/determinant_diversity.rs b/diskann-providers/src/model/graph/provider/determinant_diversity.rs index de776caab..62eac126a 100644 --- a/diskann-providers/src/model/graph/provider/determinant_diversity.rs +++ b/diskann-providers/src/model/graph/provider/determinant_diversity.rs @@ -53,7 +53,7 @@ use std::fmt; -use diskann_utils::MatrixViewMut; +use diskann_utils::matrix::MatrixViewMut; use diskann_vector::{MathematicalValue, PureDistanceFunction, distance::InnerProduct}; /// Parameters for Determinant-Diversity post-processor with validation. @@ -481,7 +481,7 @@ fn dot_product(a: &[f32], b: &[f32]) -> f32 { mod tests { use super::*; use diskann_quantization::num::Positive; - use diskann_utils::Matrix; + use diskann_utils::matrix::Matrix; #[test] fn test_valid_params() { diff --git a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs index 5bf363aed..8e0ef403e 100644 --- a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs +++ b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs @@ -9,7 +9,7 @@ use diskann_quantization::{ product::{self, BasicTable}, views::ChunkOffsetsBase, }; -use diskann_utils::{Matrix, MatrixView, matrix}; +use diskann_utils::matrix::{self, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance}; use diskann_wide::ARCH; diff --git a/diskann-providers/src/storage/pq_storage.rs b/diskann-providers/src/storage/pq_storage.rs index 46fa8ace7..bf859e633 100644 --- a/diskann-providers/src/storage/pq_storage.rs +++ b/diskann-providers/src/storage/pq_storage.rs @@ -523,7 +523,7 @@ mod pq_storage_tests { #[test] fn write_read_roundtrip_with_legacy_centroid() { use crate::model::pq::accum_row_inplace; - use diskann_utils::MatrixViewMut; + use diskann_utils::matrix::MatrixViewMut; let storage_provider = VirtualStorageProvider::new_memory(); let pivot_path = "/roundtrip_legacy_centroid_pivots.bin"; diff --git a/diskann-providers/src/test_utils/search_utils.rs b/diskann-providers/src/test_utils/search_utils.rs index 5f1700514..59303d51d 100644 --- a/diskann-providers/src/test_utils/search_utils.rs +++ b/diskann-providers/src/test_utils/search_utils.rs @@ -4,7 +4,7 @@ */ use diskann::neighbor::Neighbor; -use diskann_utils::MatrixView; +use diskann_utils::matrix::MatrixView; /// Compute the ground truth for a small dataset. /// diff --git a/diskann-quantization/src/algorithms/hadamard.rs b/diskann-quantization/src/algorithms/hadamard.rs index d057973de..321bffc4e 100644 --- a/diskann-quantization/src/algorithms/hadamard.rs +++ b/diskann-quantization/src/algorithms/hadamard.rs @@ -383,7 +383,7 @@ mod tests { }; use super::*; - use diskann_utils::{Matrix, MatrixView, matrix}; + use diskann_utils::matrix::{self, Matrix, MatrixView}; /// Retrieve the 8x8 hadamard matrix as a `Matrix`. fn get_hadamard_8() -> Matrix { diff --git a/diskann-quantization/src/algorithms/kmeans/lloyds.rs b/diskann-quantization/src/algorithms/kmeans/lloyds.rs index 9ff1ad9c8..2fad1e917 100644 --- a/diskann-quantization/src/algorithms/kmeans/lloyds.rs +++ b/diskann-quantization/src/algorithms/kmeans/lloyds.rs @@ -462,9 +462,9 @@ pub fn lloyds( #[cfg(test)] mod tests { - use diskann_utils::Matrix; #[cfg(not(miri))] use diskann_utils::lazy_format; + use diskann_utils::matrix::Matrix; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom}; #[cfg(not(miri))] diff --git a/diskann-quantization/src/algorithms/transforms/random_rotation.rs b/diskann-quantization/src/algorithms/transforms/random_rotation.rs index 16265d0c9..562e043c0 100644 --- a/diskann-quantization/src/algorithms/transforms/random_rotation.rs +++ b/diskann-quantization/src/algorithms/transforms/random_rotation.rs @@ -31,7 +31,7 @@ use crate::flatbuffers as fb; #[cfg_attr(test, derive(PartialEq))] pub struct RandomRotation { /// This data structure maintains the invariant that this **must** be a square matrix. - transform: diskann_utils::Matrix, + transform: diskann_utils::matrix::Matrix, } impl RandomRotation { @@ -88,7 +88,7 @@ impl RandomRotation { // Lint: By construction, the matrix returned from // `diskann_linalg::random_distance_preserving_matrix` will by `matrix_dim x matrix_dim`. #[allow(clippy::unwrap_used)] - let initial = diskann_utils::Matrix::try_from( + let initial = diskann_utils::matrix::Matrix::try_from( diskann_linalg::random_distance_preserving_matrix(matrix_dim, rng).into(), matrix_dim, matrix_dim, @@ -102,7 +102,7 @@ impl RandomRotation { let indices = rand::seq::index::sample(rng, dim, target_dim); let scaling = (dim as f32 / target_dim as f32).sqrt(); - let mut transform = diskann_utils::Matrix::new(0.0f32, target_dim, dim); + let mut transform = diskann_utils::matrix::Matrix::new(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), indices.iter()).for_each(|(ro, ri)| { std::iter::zip(ro.iter_mut(), initial.row(ri).iter()).for_each(|(o, i)| { *o = scaling * (*i); @@ -111,7 +111,7 @@ impl RandomRotation { transform } std::cmp::Ordering::Greater => { - let mut transform = diskann_utils::Matrix::new(0.0f32, target_dim, dim); + let mut transform = diskann_utils::matrix::Matrix::new(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), initial.row_iter()) .for_each(|(o, i)| o.copy_from_slice(&i[..dim])); transform @@ -220,7 +220,7 @@ impl RandomRotation { let data = proto.data().into_iter().collect(); let transform = - diskann_utils::Matrix::try_from(data, nrows as usize, ncols as usize) + diskann_utils::matrix::Matrix::try_from(data, nrows as usize, ncols as usize) .map_err(|_| RandomRotationError::IncorrectDim)?; Ok(Self { transform }) diff --git a/diskann-quantization/src/product/tables/basic.rs b/diskann-quantization/src/product/tables/basic.rs index c826af640..ee43ba08c 100644 --- a/diskann-quantization/src/product/tables/basic.rs +++ b/diskann-quantization/src/product/tables/basic.rs @@ -5,7 +5,7 @@ use crate::traits::CompressInto; use crate::views::{ChunkOffsetsBase, ChunkOffsetsView}; -use diskann_utils::{DenseData, Matrix, MatrixView}; +use diskann_utils::matrix::{DenseData, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use thiserror::Error; diff --git a/diskann-quantization/src/product/tables/test.rs b/diskann-quantization/src/product/tables/test.rs index d8b21355a..8a48ebd0a 100644 --- a/diskann-quantization/src/product/tables/test.rs +++ b/diskann-quantization/src/product/tables/test.rs @@ -4,9 +4,9 @@ */ // A collection of test helpers to ensure uniformity across tables. -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; #[cfg(not(miri))] -use diskann_utils::{MatrixView, MatrixViewMut}; +use diskann_utils::matrix::{MatrixView, MatrixViewMut}; #[cfg(not(miri))] use rand::seq::IndexedRandom; use rand::{ diff --git a/diskann-quantization/src/spherical/iface.rs b/diskann-quantization/src/spherical/iface.rs index 13daa2445..3775f4a4b 100644 --- a/diskann-quantization/src/spherical/iface.rs +++ b/diskann-quantization/src/spherical/iface.rs @@ -40,7 +40,7 @@ //! spherical::{iface, SupportedMetric, SphericalQuantizer, PreScale}, //! num::PowerOfTwo, //! }; -//! use diskann_utils::Matrix; +//! use diskann_utils::matrix::Matrix; //! //! // For illustration purposes, the dataset consists of just a single vector. //! let mut data = Matrix::new(1.0, 1, 4); @@ -2086,7 +2086,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::{Matrix, MatrixView}; + use diskann_utils::matrix::{Matrix, MatrixView}; use rand::{SeedableRng, rngs::StdRng}; use super::*; diff --git a/diskann-quantization/src/test_util.rs b/diskann-quantization/src/test_util.rs index 9ba19b476..f887a822e 100644 --- a/diskann-quantization/src/test_util.rs +++ b/diskann-quantization/src/test_util.rs @@ -9,7 +9,7 @@ use std::sync::{ atomic::{AtomicUsize, Ordering}, }; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; use rand::{ distr::{Distribution, Uniform}, rngs::StdRng, diff --git a/diskann-quantization/src/utils.rs b/diskann-quantization/src/utils.rs index 4b40f38e2..1d5df3a61 100644 --- a/diskann-quantization/src/utils.rs +++ b/diskann-quantization/src/utils.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use thiserror::Error; -use diskann_utils::MatrixView; +use diskann_utils::matrix::MatrixView; /// Specify featres and config flags that will be propagated to `docsrs` config. macro_rules! features { @@ -205,7 +205,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::Matrix; + use diskann_utils::matrix::Matrix; use diskann_vector::{Norm, norm::FastL2Norm}; use rand::{SeedableRng, rngs::StdRng}; diff --git a/diskann-quantization/src/views.rs b/diskann-quantization/src/views.rs index 3772b5087..864b775da 100644 --- a/diskann-quantization/src/views.rs +++ b/diskann-quantization/src/views.rs @@ -5,7 +5,7 @@ use std::num::NonZeroUsize; -use diskann_utils::{DenseData, MutDenseData}; +use diskann_utils::matrix::{DenseData, MutDenseData}; use std::ops::{Index, IndexMut}; use thiserror::Error; diff --git a/diskann-utils/src/lib.rs b/diskann-utils/src/lib.rs index 3fc7b8469..450211e29 100644 --- a/diskann-utils/src/lib.rs +++ b/diskann-utils/src/lib.rs @@ -21,7 +21,6 @@ pub mod sampling; pub mod strided; pub mod matrix; -pub use matrix::{DenseData, Init, Matrix, MatrixView, MatrixViewMut, MutDenseData, TryFromError}; mod lazystring; pub use lazystring::LazyString; diff --git a/diskann/src/error/ann_error.rs b/diskann/src/error/ann_error.rs index 795cf7e6d..36733ed56 100644 --- a/diskann/src/error/ann_error.rs +++ b/diskann/src/error/ann_error.rs @@ -588,9 +588,9 @@ where } } -impl From for ANNError { +impl From for ANNError { #[track_caller] - fn from(err: diskann_utils::TryFromError) -> Self { + fn from(err: diskann_utils::matrix::TryFromError) -> Self { ANNError::new(ANNErrorKind::DimensionMismatchError, err) } } @@ -1534,7 +1534,7 @@ Caused by: #[test] fn from_try_from_error() { let data: &[f32] = &[1.0, 2.0, 3.0]; - let err = diskann_utils::MatrixView::try_from(data, 2, 2).unwrap_err(); + let err = diskann_utils::matrix::MatrixView::try_from(data, 2, 2).unwrap_err(); let ann_err = ANNError::from(err); assert_eq!(ann_err.kind(), ANNErrorKind::DimensionMismatchError); } diff --git a/diskann/src/graph/glue.rs b/diskann/src/graph/glue.rs index 548f8a304..60e244f92 100644 --- a/diskann/src/graph/glue.rs +++ b/diskann/src/graph/glue.rs @@ -1030,7 +1030,7 @@ where /// [`Overlay`](crate::graph::workingset::map::Overlay) for a working set seed compatible /// with [`Batch`]. /// -/// The primary implementation of this trait is [`Matrix`](diskann_utils::Matrix). +/// The primary implementation of this trait is [`Matrix`](diskann_utils::matrix::Matrix). pub trait Batch: Send + Sync + 'static { /// The element type of the batch. type Element<'a>: Copy; @@ -1047,7 +1047,7 @@ pub trait Batch: Send + Sync + 'static { } } -impl Batch for diskann_utils::Matrix { +impl Batch for diskann_utils::matrix::Matrix { type Element<'a> = &'a [T]; fn len(&self) -> usize { diff --git a/diskann/src/graph/test/cases/grid_insert.rs b/diskann/src/graph/test/cases/grid_insert.rs index b48f3a21e..3471e248b 100644 --- a/diskann/src/graph/test/cases/grid_insert.rs +++ b/diskann/src/graph/test/cases/grid_insert.rs @@ -18,7 +18,7 @@ use std::{num::NonZeroUsize, sync::Arc}; -use diskann_utils::MatrixView; +use diskann_utils::matrix::MatrixView; use diskann_vector::distance::Metric; use crate::{ diff --git a/diskann/src/graph/test/provider.rs b/diskann/src/graph/test/provider.rs index f77659206..3ae7abeac 100644 --- a/diskann/src/graph/test/provider.rs +++ b/diskann/src/graph/test/provider.rs @@ -13,7 +13,7 @@ use std::{ }; use dashmap::{DashMap, mapref::entry::Entry}; -use diskann_utils::Matrix; +use diskann_utils::matrix::Matrix; use diskann_vector::{PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; diff --git a/diskann/src/graph/test/synthetic.rs b/diskann/src/graph/test/synthetic.rs index 658ee11bf..87450f591 100644 --- a/diskann/src/graph/test/synthetic.rs +++ b/diskann/src/graph/test/synthetic.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_utils::{Init, Matrix}; +use diskann_utils::matrix::{Init, Matrix}; use crate::graph::AdjacencyList; diff --git a/diskann/src/graph/workingset/map.rs b/diskann/src/graph/workingset/map.rs index 0f31e3cc1..607ea70c0 100644 --- a/diskann/src/graph/workingset/map.rs +++ b/diskann/src/graph/workingset/map.rs @@ -101,7 +101,7 @@ //! //! ``` //! use std::sync::Arc; -//! use diskann_utils::Matrix; +//! use diskann_utils::matrix::Matrix; //! //! use diskann::graph::workingset::{Map, View, map::{Overlay, Ref, Builder, Capacity}}; //! @@ -646,7 +646,7 @@ where /// /// ``` /// use std::sync::Arc; -/// use diskann_utils::Matrix; +/// use diskann_utils::matrix::Matrix; /// /// use diskann::graph::workingset::map::{Overlay, Ref}; /// @@ -923,7 +923,7 @@ mod tests { use std::sync::Arc; - use diskann_utils::Matrix; + use diskann_utils::matrix::Matrix; use crate::graph::workingset::View as WorkingSetView; From 051ce9840b30f0a8716709bbff1be6585b3b4d0c Mon Sep 17 00:00:00 2001 From: Suryansh Gupta Date: Thu, 23 Jul 2026 04:29:43 +0530 Subject: [PATCH 5/6] Address review comments --- Cargo.lock | 1 + .../src/build/graph/multi.rs | 2 +- .../src/build/graph/single.rs | 2 +- diskann-benchmark-core/src/recall.rs | 6 +- diskann-benchmark-core/src/search/api.rs | 4 +- .../src/search/graph/inline.rs | 2 +- .../src/search/graph/knn.rs | 2 +- .../src/search/graph/multihop.rs | 2 +- .../src/search/graph/range.rs | 2 +- diskann-benchmark-core/src/search/ids.rs | 4 +- .../streaming/executors/bigann/withdata.rs | 2 +- diskann-benchmark-simd/src/lib.rs | 4 +- diskann-benchmark/src/disk_index/search.rs | 2 +- diskann-benchmark/src/exhaustive/algos.rs | 6 +- diskann-benchmark/src/exhaustive/minmax.rs | 6 +- diskann-benchmark/src/exhaustive/product.rs | 6 +- diskann-benchmark/src/exhaustive/spherical.rs | 6 +- diskann-benchmark/src/flat/search.rs | 2 +- diskann-benchmark/src/index/benchmarks.rs | 2 +- .../index/bftree/full_precision_streaming.rs | 2 +- .../src/index/bftree/spherical.rs | 2 +- .../src/index/bftree/spherical_streaming.rs | 2 +- diskann-benchmark/src/index/build.rs | 2 +- diskann-benchmark/src/index/inmem/product.rs | 2 +- diskann-benchmark/src/index/inmem/scalar.rs | 2 +- .../src/index/inmem/spherical.rs | 2 +- .../src/index/streaming/full_precision.rs | 2 +- .../src/index/streaming/managed.rs | 2 +- diskann-benchmark/src/utils/datafiles.rs | 4 +- diskann-bftree/src/provider.rs | 8 +- diskann-bftree/src/quant.rs | 4 +- diskann-disk/src/build/builder/quantizer.rs | 2 +- .../src/search/pq/quantizer_preprocess.rs | 2 +- .../src/search/provider/disk_provider.rs | 2 +- diskann-disk/src/storage/quant/compressor.rs | 2 +- diskann-disk/src/storage/quant/generator.rs | 12 +- .../src/storage/quant/pq/pq_dataset.rs | 2 +- .../src/storage/quant/pq/pq_generation.rs | 6 +- diskann-garnet/src/provider.rs | 4 +- diskann-garnet/src/quantization.rs | 4 +- diskann-providers/src/index/diskann_async.rs | 20 +- .../provider/async_/inmem/full_precision.rs | 2 +- .../graph/provider/async_/inmem/scalar.rs | 2 +- .../graph/provider/async_/inmem/spherical.rs | 4 +- .../graph/provider/determinant_diversity.rs | 4 +- diskann-providers/src/model/pq/debug.rs | 10 +- .../src/model/pq/fixed_chunk_pq_table.rs | 4 +- .../src/model/pq/pq_construction.rs | 2 +- diskann-providers/src/model/pq/strided.rs | 4 +- diskann-providers/src/model/pq/views.rs | 8 +- .../src/storage/index_storage.rs | 2 +- diskann-providers/src/storage/pq_storage.rs | 4 +- .../src/test_utils/search_utils.rs | 2 +- diskann-providers/src/utils/file_util.rs | 2 +- diskann-providers/src/utils/storage_utils.rs | 2 +- .../src/algorithms/hadamard.rs | 6 +- .../src/algorithms/kmeans/lloyds.rs | 4 +- .../src/algorithms/kmeans/plusplus.rs | 4 +- .../algorithms/transforms/random_rotation.rs | 10 +- diskann-quantization/src/binary/quantizer.rs | 2 +- diskann-quantization/src/lib.rs | 1 - .../src/minmax/multi/max_sim.rs | 4 +- diskann-quantization/src/minmax/multi/meta.rs | 20 +- diskann-quantization/src/minmax/multi/mod.rs | 6 +- .../src/multi_vector/block_transposed.rs | 35 +- diskann-quantization/src/multi_vector/mod.rs | 6 +- .../src/product/tables/basic.rs | 20 +- .../src/product/tables/test.rs | 4 +- .../src/product/tables/transposed/pivots.rs | 17 +- .../src/product/tables/transposed/table.rs | 44 +- diskann-quantization/src/product/train.rs | 8 +- diskann-quantization/src/scalar/mod.rs | 2 +- diskann-quantization/src/scalar/quantizer.rs | 8 +- diskann-quantization/src/scalar/train.rs | 4 +- diskann-quantization/src/spherical/iface.rs | 4 +- .../src/spherical/quantizer.rs | 6 +- diskann-quantization/src/test_util.rs | 2 +- diskann-quantization/src/utils.rs | 6 +- diskann-quantization/src/views.rs | 2 +- diskann-tools/src/utils/ground_truth.rs | 2 +- diskann-utils/Cargo.toml | 1 + diskann-utils/src/io.rs | 4 +- diskann-utils/src/lib.rs | 2 +- diskann-utils/src/sampling/latin_hypercube.rs | 4 +- diskann-utils/src/sampling/medoid.rs | 4 +- diskann-utils/src/strided.rs | 66 +- diskann-utils/src/{matrix.rs => views.rs} | 647 ++++++++++++------ .../tests/compile-fail}/mat_as_view.rs | 2 +- .../tests/compile-fail}/mat_as_view.stderr | 2 +- .../tests/compile-fail}/mat_as_view_mut.rs | 2 +- .../compile-fail}/mat_as_view_mut.stderr | 2 +- .../tests/compile-fail}/mat_get_row.rs | 2 +- .../tests/compile-fail}/mat_get_row.stderr | 2 +- .../tests/compile-fail}/mat_get_row_mut.rs | 2 +- .../compile-fail}/mat_get_row_mut.stderr | 2 +- .../tests/compile-fail}/mat_invariant.rs | 2 +- .../tests/compile-fail}/mat_invariant.stderr | 2 +- .../tests/compile-fail}/mat_reborrow.rs | 2 +- .../tests/compile-fail}/mat_reborrow.stderr | 2 +- .../tests/compile-fail}/mat_reborrow_mut.rs | 2 +- .../compile-fail}/mat_reborrow_mut.stderr | 2 +- .../tests/compile-fail}/mat_rows.rs | 2 +- .../tests/compile-fail}/mat_rows.stderr | 2 +- .../tests/compile-fail}/mat_rows_mut.rs | 2 +- .../tests/compile-fail}/mat_rows_mut.stderr | 2 +- .../compile-fail}/matmut_as_view_borrows.rs | 2 +- .../matmut_as_view_borrows.stderr | 2 +- .../tests/compile-fail}/matmut_get_row.rs | 2 +- .../tests/compile-fail}/matmut_get_row.stderr | 2 +- .../tests/compile-fail}/matmut_get_row_mut.rs | 2 +- .../compile-fail}/matmut_get_row_mut.stderr | 2 +- .../tests/compile-fail}/matmut_invariant.rs | 2 +- .../compile-fail}/matmut_invariant.stderr | 2 +- .../tests/compile-fail}/matmut_reborrow.rs | 2 +- .../compile-fail}/matmut_reborrow.stderr | 2 +- .../compile-fail}/matmut_reborrow_mut.rs | 2 +- .../compile-fail}/matmut_reborrow_mut.stderr | 2 +- .../tests/compile-fail}/matmut_rows.rs | 2 +- .../tests/compile-fail}/matmut_rows.stderr | 2 +- .../tests/compile-fail}/matmut_rows_mut.rs | 2 +- .../compile-fail}/matmut_rows_mut.stderr | 2 +- .../tests/compile-fail}/matref_get_row.rs | 2 +- .../tests/compile-fail}/matref_get_row.stderr | 2 +- .../tests/compile-fail}/matref_rows.rs | 2 +- .../tests/compile-fail}/matref_rows.stderr | 2 +- diskann-utils/tests/compile_fail.rs | 14 + diskann/src/error/ann_error.rs | 13 +- diskann/src/flat/test/provider.rs | 2 +- diskann/src/graph/glue.rs | 4 +- diskann/src/graph/start_point.rs | 2 +- diskann/src/graph/test/cases/grid_insert.rs | 2 +- diskann/src/graph/test/provider.rs | 2 +- diskann/src/graph/test/synthetic.rs | 2 +- diskann/src/graph/workingset/map.rs | 6 +- 134 files changed, 765 insertions(+), 518 deletions(-) rename diskann-utils/src/{matrix.rs => views.rs} (82%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_as_view.rs (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_as_view.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_as_view_mut.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_as_view_mut.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_get_row.rs (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_get_row.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_get_row_mut.rs (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_get_row_mut.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_invariant.rs (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_invariant.stderr (93%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_reborrow.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_reborrow.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_reborrow_mut.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_reborrow_mut.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_rows.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_rows.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_rows_mut.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/mat_rows_mut.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_as_view_borrows.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_as_view_borrows.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_get_row.rs (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_get_row.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_get_row_mut.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_get_row_mut.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_invariant.rs (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_invariant.stderr (93%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_reborrow.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_reborrow.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_reborrow_mut.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_reborrow_mut.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_rows.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_rows.stderr (89%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_rows_mut.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matmut_rows_mut.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matref_get_row.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matref_get_row.stderr (88%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matref_rows.rs (90%) rename {diskann-quantization/tests/compile-fail/multi => diskann-utils/tests/compile-fail}/matref_rows.stderr (88%) create mode 100644 diskann-utils/tests/compile_fail.rs diff --git a/Cargo.lock b/Cargo.lock index b518311a4..e4a4d949c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -953,6 +953,7 @@ dependencies = [ "rayon", "rstest", "thiserror 2.0.17", + "trybuild", ] [[package]] diff --git a/diskann-benchmark-core/src/build/graph/multi.rs b/diskann-benchmark-core/src/build/graph/multi.rs index 62153b067..f5eed11bc 100644 --- a/diskann-benchmark-core/src/build/graph/multi.rs +++ b/diskann-benchmark-core/src/build/graph/multi.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, glue}, provider, }; -use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; +use diskann_utils::{future::AsyncFriendly, views::Matrix}; use crate::build::{Build, ids::ToId}; diff --git a/diskann-benchmark-core/src/build/graph/single.rs b/diskann-benchmark-core/src/build/graph/single.rs index 906b0cf2f..96a367b6a 100644 --- a/diskann-benchmark-core/src/build/graph/single.rs +++ b/diskann-benchmark-core/src/build/graph/single.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, glue}, provider, }; -use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; +use diskann_utils::{future::AsyncFriendly, views::Matrix}; use crate::build::{Build, ids::ToId}; diff --git a/diskann-benchmark-core/src/recall.rs b/diskann-benchmark-core/src/recall.rs index a17780e3a..12c9f11ba 100644 --- a/diskann-benchmark-core/src/recall.rs +++ b/diskann-benchmark-core/src/recall.rs @@ -9,8 +9,8 @@ use std::{ }; use diskann_utils::{ - matrix::{Matrix, MatrixView}, strided::StridedView, + views::{Matrix, MatrixView}, }; use thiserror::Error; @@ -364,7 +364,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::matrix::{self, Matrix}; + use diskann_utils::views::{self, Matrix}; use super::*; @@ -380,7 +380,7 @@ mod tests { fn test_rows() { let mut i = 0usize; let mat = Matrix::new( - matrix::Init(|| { + views::Init(|| { let v = i; i += 1; v diff --git a/diskann-benchmark-core/src/search/api.rs b/diskann-benchmark-core/src/search/api.rs index 1888eacf2..636a9ab19 100644 --- a/diskann-benchmark-core/src/search/api.rs +++ b/diskann-benchmark-core/src/search/api.rs @@ -9,7 +9,7 @@ use diskann::{ANNResult, graph, utils::async_tools}; use diskann_benchmark_runner::utils::MicroSeconds; use diskann_utils::{ future::{AsyncFriendly, boxit}, - matrix::{self, Matrix}, + views::{self, Matrix}, }; use crate::{ @@ -517,7 +517,7 @@ where T: Search, { let mut lengths = Vec::with_capacity(range.len()); - let mut ids = Matrix::new(matrix::Init(T::Id::default), range.len(), num_ids.into()); + let mut ids = Matrix::new(views::Init(T::Id::default), range.len(), num_ids.into()); let mut latencies = Vec::::with_capacity(range.len()); let mut outputs = Vec::::with_capacity(range.len()); diff --git a/diskann-benchmark-core/src/search/graph/inline.rs b/diskann-benchmark-core/src/search/graph/inline.rs index 838fb44a8..5e32e187d 100644 --- a/diskann-benchmark-core/src/search/graph/inline.rs +++ b/diskann-benchmark-core/src/search/graph/inline.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, ext::labeled, glue, search::AdaptiveL}, provider, }; -use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; +use diskann_utils::{future::AsyncFriendly, views::Matrix}; use crate::search::{self, Search, graph::Strategy}; diff --git a/diskann-benchmark-core/src/search/graph/knn.rs b/diskann-benchmark-core/src/search/graph/knn.rs index 936f6ae96..f1c074d04 100644 --- a/diskann-benchmark-core/src/search/graph/knn.rs +++ b/diskann-benchmark-core/src/search/graph/knn.rs @@ -13,7 +13,7 @@ use diskann::{ provider, }; use diskann_benchmark_runner::utils::{MicroSeconds, percentiles}; -use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; +use diskann_utils::{future::AsyncFriendly, views::Matrix}; use crate::{ recall, diff --git a/diskann-benchmark-core/src/search/graph/multihop.rs b/diskann-benchmark-core/src/search/graph/multihop.rs index 09323651d..dba7c9925 100644 --- a/diskann-benchmark-core/src/search/graph/multihop.rs +++ b/diskann-benchmark-core/src/search/graph/multihop.rs @@ -10,7 +10,7 @@ use diskann::{ graph::{self, ext::labeled, glue}, provider, }; -use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; +use diskann_utils::{future::AsyncFriendly, views::Matrix}; use crate::search::{self, Search, graph::Strategy}; diff --git a/diskann-benchmark-core/src/search/graph/range.rs b/diskann-benchmark-core/src/search/graph/range.rs index dab8d799a..edf95e29a 100644 --- a/diskann-benchmark-core/src/search/graph/range.rs +++ b/diskann-benchmark-core/src/search/graph/range.rs @@ -11,7 +11,7 @@ use diskann::{ provider, }; use diskann_benchmark_runner::utils::{MicroSeconds, percentiles}; -use diskann_utils::{future::AsyncFriendly, matrix::Matrix}; +use diskann_utils::{future::AsyncFriendly, views::Matrix}; use crate::{ recall, diff --git a/diskann-benchmark-core/src/search/ids.rs b/diskann-benchmark-core/src/search/ids.rs index 0227f3468..28eabe1e3 100644 --- a/diskann-benchmark-core/src/search/ids.rs +++ b/diskann-benchmark-core/src/search/ids.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_utils::matrix::{self, Matrix}; +use diskann_utils::views::{self, Matrix}; use crate::recall; @@ -231,7 +231,7 @@ where len, num_ids, } => { - let mut dst = Matrix::new(matrix::Init(|| I::default()), len, num_ids); + let mut dst = Matrix::new(views::Init(|| I::default()), len, num_ids); let mut lengths = Vec::with_capacity(len); let mut output_row = 0; diff --git a/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs b/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs index dbb7b43b0..b30229362 100644 --- a/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs +++ b/diskann-benchmark-core/src/streaming/executors/bigann/withdata.rs @@ -5,7 +5,7 @@ use std::{ops::Range, path::Path, sync::Arc}; -use diskann_utils::matrix::{Matrix, MatrixView}; +use diskann_utils::views::{Matrix, MatrixView}; use crate::{recall, streaming}; diff --git a/diskann-benchmark-simd/src/lib.rs b/diskann-benchmark-simd/src/lib.rs index 824874f3a..25b021d8a 100644 --- a/diskann-benchmark-simd/src/lib.rs +++ b/diskann-benchmark-simd/src/lib.rs @@ -7,7 +7,7 @@ use std::{io::Write, num::NonZeroUsize}; -use diskann_utils::matrix::{Matrix, MatrixView}; +use diskann_utils::views::{Matrix, MatrixView}; use diskann_vector::distance::simd; use diskann_wide::Architecture; use half::f16; @@ -755,7 +755,7 @@ impl Data { .map(|_| StandardUniform.sample(&mut rng)) .collect(); let data = Matrix::::new( - diskann_utils::matrix::Init(|| StandardUniform.sample(&mut rng)), + diskann_utils::views::Init(|| StandardUniform.sample(&mut rng)), run.num_points.get(), run.dim.get(), ); diff --git a/diskann-benchmark/src/disk_index/search.rs b/diskann-benchmark/src/disk_index/search.rs index 0500ae3ac..8cd0f5e60 100644 --- a/diskann-benchmark/src/disk_index/search.rs +++ b/diskann-benchmark/src/disk_index/search.rs @@ -31,7 +31,7 @@ use diskann_providers::{ utils::{create_thread_pool, ParallelIteratorInPool}, }; use diskann_tools::utils::{search_index_utils, KRecallAtN}; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use serde::{Deserialize, Serialize}; use crate::{ diff --git a/diskann-benchmark/src/exhaustive/algos.rs b/diskann-benchmark/src/exhaustive/algos.rs index 8f28641a5..1d7d56989 100644 --- a/diskann-benchmark/src/exhaustive/algos.rs +++ b/diskann-benchmark/src/exhaustive/algos.rs @@ -33,7 +33,7 @@ where #[derive(Debug, Clone)] pub(super) struct LinearSearch { - pub(super) ids: diskann_utils::matrix::Matrix, + pub(super) ids: diskann_utils::views::Matrix, pub(super) preprocess: Vec, pub(super) search: Vec, pub(super) total: MicroSeconds, @@ -41,7 +41,7 @@ pub(super) struct LinearSearch { pub(super) fn linear_search( store: &Q, - queries: diskann_utils::matrix::MatrixView, + queries: diskann_utils::views::MatrixView, builder: &C, results_per_query: usize, progress: &indicatif::ProgressBar, @@ -51,7 +51,7 @@ where C: CreateQuantComputer + Sync, { let mut output = - diskann_utils::matrix::Matrix::::new(u32::MAX, queries.nrows(), results_per_query); + diskann_utils::views::Matrix::::new(u32::MAX, queries.nrows(), results_per_query); struct Times { preprocess: MicroSeconds, diff --git a/diskann-benchmark/src/exhaustive/minmax.rs b/diskann-benchmark/src/exhaustive/minmax.rs index 4ea3ea630..444d4d6be 100644 --- a/diskann-benchmark/src/exhaustive/minmax.rs +++ b/diskann-benchmark/src/exhaustive/minmax.rs @@ -370,7 +370,7 @@ mod imp { pub(super) struct Store { // The number of bytes to take from each row. bytes: usize, - data: diskann_utils::matrix::Matrix, + data: diskann_utils::views::Matrix, quantizer: diskann_quantization::minmax::MinMaxQuantizer, } @@ -379,7 +379,7 @@ mod imp { Unsigned: Representation, { fn new( - input: diskann_utils::matrix::MatrixView, + input: diskann_utils::views::MatrixView, quantizer: diskann_quantization::minmax::MinMaxQuantizer, progress: &ProgressBar, ) -> anyhow::Result { @@ -389,7 +389,7 @@ mod imp { // The APIs below should correctly handle these variables. let output_dim = quantizer.output_dim(); let bytes = Data::::canonical_bytes(output_dim); - let mut data = diskann_utils::matrix::Matrix::new(0, input.nrows(), bytes); + let mut data = diskann_utils::views::Matrix::new(0, input.nrows(), bytes); // Compress the data. // diff --git a/diskann-benchmark/src/exhaustive/product.rs b/diskann-benchmark/src/exhaustive/product.rs index 5e56d40fb..d05145e39 100644 --- a/diskann-benchmark/src/exhaustive/product.rs +++ b/diskann-benchmark/src/exhaustive/product.rs @@ -322,18 +322,18 @@ mod imp { /// A store for quantized data. pub(super) struct Store { - data: diskann_utils::matrix::Matrix, + data: diskann_utils::views::Matrix, quantizer: diskann_providers::model::pq::FixedChunkPQTable, } impl Store { fn new( - input: diskann_utils::matrix::MatrixView, + input: diskann_utils::views::MatrixView, quantizer: diskann_providers::model::pq::FixedChunkPQTable, progress: &ProgressBar, ) -> anyhow::Result { let mut data = - diskann_utils::matrix::Matrix::new(0, input.nrows(), quantizer.get_num_chunks()); + diskann_utils::views::Matrix::new(0, input.nrows(), quantizer.get_num_chunks()); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/exhaustive/spherical.rs b/diskann-benchmark/src/exhaustive/spherical.rs index ef487b6ec..5e009c231 100644 --- a/diskann-benchmark/src/exhaustive/spherical.rs +++ b/diskann-benchmark/src/exhaustive/spherical.rs @@ -394,7 +394,7 @@ mod imp { pub(super) struct Store { // The number of bytes to take from each row. bytes: usize, - data: diskann_utils::matrix::Matrix, + data: diskann_utils::views::Matrix, plan: diskann_quantization::spherical::iface::Impl, } @@ -405,7 +405,7 @@ mod imp { for<'a> CompressIntoWith<&'a [f32], DataMut<'a, NBITS>, ScopedAllocator<'a>>, { fn new( - input: diskann_utils::matrix::MatrixView, + input: diskann_utils::views::MatrixView, plan: diskann_quantization::spherical::iface::Impl, progress: &ProgressBar, ) -> anyhow::Result { @@ -416,7 +416,7 @@ mod imp { let output_dim = plan.quantizer().output_dim(); let bytes = diskann_quantization::spherical::DataRef::::canonical_bytes(output_dim); - let mut data = diskann_utils::matrix::Matrix::new(0, input.nrows(), bytes); + let mut data = diskann_utils::views::Matrix::new(0, input.nrows(), bytes); // Compress the data. #[allow(clippy::disallowed_methods)] diff --git a/diskann-benchmark/src/flat/search.rs b/diskann-benchmark/src/flat/search.rs index 1730af248..a670d0df4 100644 --- a/diskann-benchmark/src/flat/search.rs +++ b/diskann-benchmark/src/flat/search.rs @@ -24,7 +24,7 @@ use diskann_benchmark_runner::{ utils::{datatype::AsDataType, percentiles, MicroSeconds}, Benchmark, Checkpoint, Registry, }; -use diskann_utils::{future::SendFuture, matrix::Matrix}; +use diskann_utils::{future::SendFuture, views::Matrix}; use diskann_vector::{distance::Metric, PreprocessedDistanceFunction}; use half::f16; use serde::Serialize; diff --git a/diskann-benchmark/src/index/benchmarks.rs b/diskann-benchmark/src/index/benchmarks.rs index 63457b6eb..4307f2e5b 100644 --- a/diskann-benchmark/src/index/benchmarks.rs +++ b/diskann-benchmark/src/index/benchmarks.rs @@ -31,7 +31,7 @@ use diskann_providers::{ }; use diskann_utils::{ future::AsyncFriendly, - matrix::{Matrix, MatrixView}, + views::{Matrix, MatrixView}, }; use half::f16; diff --git a/diskann-benchmark/src/index/bftree/full_precision_streaming.rs b/diskann-benchmark/src/index/bftree/full_precision_streaming.rs index d1fb12b4d..1d39e59cb 100644 --- a/diskann-benchmark/src/index/bftree/full_precision_streaming.rs +++ b/diskann-benchmark/src/index/bftree/full_precision_streaming.rs @@ -24,7 +24,7 @@ use diskann_providers::{ model::graph::provider::async_::common::FullPrecision, storage::{FileStorageProvider, SaveWith}, }; -use diskann_utils::matrix::{Matrix, MatrixView}; +use diskann_utils::views::{Matrix, MatrixView}; use crate::{ index::{ diff --git a/diskann-benchmark/src/index/bftree/spherical.rs b/diskann-benchmark/src/index/bftree/spherical.rs index badf7f565..54bee04af 100644 --- a/diskann-benchmark/src/index/bftree/spherical.rs +++ b/diskann-benchmark/src/index/bftree/spherical.rs @@ -23,7 +23,7 @@ use diskann_quantization::{ SphericalQuantizer, }, }; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use rand::SeedableRng; use crate::{ diff --git a/diskann-benchmark/src/index/bftree/spherical_streaming.rs b/diskann-benchmark/src/index/bftree/spherical_streaming.rs index f74706f80..d676b9994 100644 --- a/diskann-benchmark/src/index/bftree/spherical_streaming.rs +++ b/diskann-benchmark/src/index/bftree/spherical_streaming.rs @@ -30,7 +30,7 @@ use diskann_quantization::spherical::{ iface::{self as spherical_iface, Quantizer}, SphericalQuantizer, }; -use diskann_utils::matrix::{Matrix, MatrixView}; +use diskann_utils::views::{Matrix, MatrixView}; use rand::SeedableRng; use crate::{ diff --git a/diskann-benchmark/src/index/build.rs b/diskann-benchmark/src/index/build.rs index 1a3b9a141..8625f4975 100644 --- a/diskann-benchmark/src/index/build.rs +++ b/diskann-benchmark/src/index/build.rs @@ -23,7 +23,7 @@ use diskann_providers::{ }; use diskann_utils::{ future::AsyncFriendly, - matrix::{Matrix, MatrixView}, + views::{Matrix, MatrixView}, }; use indicatif::{ProgressBar, ProgressStyle}; use serde::Serialize; diff --git a/diskann-benchmark/src/index/inmem/product.rs b/diskann-benchmark/src/index/inmem/product.rs index 1fb9a09f8..931ca725c 100644 --- a/diskann-benchmark/src/index/inmem/product.rs +++ b/diskann-benchmark/src/index/inmem/product.rs @@ -49,7 +49,7 @@ mod imp { IndexConfiguration, }, }; - use diskann_utils::matrix::{Matrix, MatrixView}; + use diskann_utils::views::{Matrix, MatrixView}; use diskann_benchmark_runner::{ benchmark::{MatchContext, Score}, diff --git a/diskann-benchmark/src/index/inmem/scalar.rs b/diskann-benchmark/src/index/inmem/scalar.rs index 866b580fa..b10fd874b 100644 --- a/diskann-benchmark/src/index/inmem/scalar.rs +++ b/diskann-benchmark/src/index/inmem/scalar.rs @@ -69,7 +69,7 @@ mod imp { graph::provider::async_::{common, inmem}, }, }; - use diskann_utils::matrix::{Matrix, MatrixView}; + use diskann_utils::views::{Matrix, MatrixView}; use crate::{ index::{ diff --git a/diskann-benchmark/src/index/inmem/spherical.rs b/diskann-benchmark/src/index/inmem/spherical.rs index 54ed19509..e69025f8c 100644 --- a/diskann-benchmark/src/index/inmem/spherical.rs +++ b/diskann-benchmark/src/index/inmem/spherical.rs @@ -75,7 +75,7 @@ mod imp { model::graph::provider::async_::{common, inmem}, }; use diskann_quantization::alloc::GlobalAllocator; - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Matrix; use rand::SeedableRng; use serde::Serialize; use std::{io::Write, sync::Arc}; diff --git a/diskann-benchmark/src/index/streaming/full_precision.rs b/diskann-benchmark/src/index/streaming/full_precision.rs index 3ff75f603..4e3d62a25 100644 --- a/diskann-benchmark/src/index/streaming/full_precision.rs +++ b/diskann-benchmark/src/index/streaming/full_precision.rs @@ -19,7 +19,7 @@ use diskann_providers::model::graph::provider::async_::{ }; use diskann_utils::{ future::AsyncFriendly, - matrix::{Matrix, MatrixView}, + views::{Matrix, MatrixView}, }; use super::{ diff --git a/diskann-benchmark/src/index/streaming/managed.rs b/diskann-benchmark/src/index/streaming/managed.rs index 6527de951..cbe7188d9 100644 --- a/diskann-benchmark/src/index/streaming/managed.rs +++ b/diskann-benchmark/src/index/streaming/managed.rs @@ -11,7 +11,7 @@ use diskann_benchmark_core::{ streaming::{self, executors}, }; use diskann_benchmark_runner::{timed, utils::MicroSeconds}; -use diskann_utils::matrix::{Matrix, MatrixView}; +use diskann_utils::views::{Matrix, MatrixView}; use crate::utils::streaming::TagSlotManager; diff --git a/diskann-benchmark/src/utils/datafiles.rs b/diskann-benchmark/src/utils/datafiles.rs index 620faddfc..abfe06a7d 100644 --- a/diskann-benchmark/src/utils/datafiles.rs +++ b/diskann-benchmark/src/utils/datafiles.rs @@ -10,7 +10,7 @@ use bit_set::BitSet; use diskann::utils::IntoUsize; use diskann_benchmark_runner::utils::datatype::DataType; use diskann_providers::storage::StorageReadProvider; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use serde::{Deserialize, Serialize}; pub(crate) struct BinFile<'a>(pub(crate) &'a Path); @@ -71,7 +71,7 @@ impl ConvertingLoad for f32 { ))] fn converting_load(path: BinFile<'_>, data_type: DataType) -> anyhow::Result> { #[inline(never)] - fn convert(from: diskann_utils::matrix::MatrixView) -> Matrix + fn convert(from: diskann_utils::views::MatrixView) -> Matrix where U: Default + Clone + From, T: Copy, diff --git a/diskann-bftree/src/provider.rs b/diskann-bftree/src/provider.rs index f6dec1fb5..1a9f773ca 100644 --- a/diskann-bftree/src/provider.rs +++ b/diskann-bftree/src/provider.rs @@ -37,7 +37,7 @@ use diskann::{ }; use diskann_utils::{ future::{AsyncFriendly, SendFuture}, - matrix::MatrixView, + views::MatrixView, }; use diskann_vector::{distance::Metric, DistanceFunction, PreprocessedDistanceFunction}; @@ -97,7 +97,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// }; /// use diskann_bftree::NoStore; /// use diskann_vector::distance::Metric; -/// use diskann_utils::matrix::{Init, Matrix}; +/// use diskann_utils::views::{Init, Matrix}; /// use bf_tree::Config; /// use std::num::NonZeroUsize; /// @@ -134,7 +134,7 @@ use diskann_providers::storage::{LoadWith, SaveWith, StorageReadProvider, Storag /// algorithms::TransformKind, /// spherical::{iface, SphericalQuantizer, SupportedMetric, PreScale}, /// }; -/// use diskann_utils::matrix::{Init, Matrix}; +/// use diskann_utils::views::{Init, Matrix}; /// use diskann_bftree::provider::{ /// BfTreeProvider, BfTreeProviderParameters /// }; @@ -2020,7 +2020,7 @@ mod tests { neighbor::BackInserter, }; use diskann_providers::storage::FileStorageProvider; - use diskann_utils::matrix::{Init, Matrix}; + use diskann_utils::views::{Init, Matrix}; fn create_quant_index() -> Arc>> { let start_point = Matrix::new(Init(|| 0.0f32), 1, 5); diff --git a/diskann-bftree/src/quant.rs b/diskann-bftree/src/quant.rs index 88de8e679..8a37ffd19 100644 --- a/diskann-bftree/src/quant.rs +++ b/diskann-bftree/src/quant.rs @@ -236,8 +236,8 @@ pub(crate) fn create_test_quantizer(dim: usize) -> Poly { alloc::poly, spherical::{iface, PreScale, SphericalQuantizer, SupportedMetric}, }; - use diskann_utils::matrix::Init; - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Init; + use diskann_utils::views::Matrix; use rand::{rngs::StdRng, SeedableRng}; // Create training data with spread-out values. diff --git a/diskann-disk/src/build/builder/quantizer.rs b/diskann-disk/src/build/builder/quantizer.rs index 1d35e5f9c..7bbfacf3c 100644 --- a/diskann-disk/src/build/builder/quantizer.rs +++ b/diskann-disk/src/build/builder/quantizer.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{create_thread_pool, BridgeErr, PQPathNames}, }; use diskann_quantization::scalar::train::ScalarQuantizationParameters; -use diskann_utils::matrix::MatrixView; +use diskann_utils::views::MatrixView; use tracing::info; use crate::QuantizationType; diff --git a/diskann-disk/src/search/pq/quantizer_preprocess.rs b/diskann-disk/src/search/pq/quantizer_preprocess.rs index 86e706b93..344570ba5 100644 --- a/diskann-disk/src/search/pq/quantizer_preprocess.rs +++ b/diskann-disk/src/search/pq/quantizer_preprocess.rs @@ -22,7 +22,7 @@ pub fn quantizer_preprocess( ) -> ANNResult<()> { let table = pq_data.pq_table(); let expected_len = table.ncenters() * table.nchunks(); - let dst = diskann_utils::matrix::MatrixViewMut::try_from( + let dst = diskann_utils::views::MatrixViewMut::try_from( &mut (*pq_scratch.aligned_pqtable_dist_scratch)[..expected_len], table.nchunks(), table.ncenters(), diff --git a/diskann-disk/src/search/provider/disk_provider.rs b/diskann-disk/src/search/provider/disk_provider.rs index bde832489..c497414a6 100644 --- a/diskann-disk/src/search/provider/disk_provider.rs +++ b/diskann-disk/src/search/provider/disk_provider.rs @@ -37,8 +37,8 @@ use diskann_providers::{ storage::{get_compressed_pq_file, get_disk_index_file, get_pq_pivot_file, LoadWith}, }; use diskann_utils::{ - matrix::Matrix, object_pool::{ObjectPool, PoolOption, TryAsPooled}, + views::Matrix, }; use crate::search::pq::{quantizer_preprocess, PQData, PQScratch}; diff --git a/diskann-disk/src/storage/quant/compressor.rs b/diskann-disk/src/storage/quant/compressor.rs index 2d20501a4..dfd82b3a3 100644 --- a/diskann-disk/src/storage/quant/compressor.rs +++ b/diskann-disk/src/storage/quant/compressor.rs @@ -4,7 +4,7 @@ */ use diskann::{utils::VectorRepr, ANNResult}; -use diskann_utils::matrix::{MatrixView, MatrixViewMut}; +use diskann_utils::views::{MatrixView, MatrixViewMut}; /// [`QuantCompressor`] defines the interface for quantizer with [`QuantDataGenerator`] /// diff --git a/diskann-disk/src/storage/quant/generator.rs b/diskann-disk/src/storage/quant/generator.rs index 796aa93a0..45ed4f6bb 100644 --- a/diskann-disk/src/storage/quant/generator.rs +++ b/diskann-disk/src/storage/quant/generator.rs @@ -14,7 +14,7 @@ use diskann_providers::{ storage::{StorageReadProvider, StorageWriteProvider}, utils::{load_metadata_from_file, BridgeErr, ParallelIteratorInPool, RayonThreadPoolRef}, }; -use diskann_utils::{io::Metadata, matrix}; +use diskann_utils::{io::Metadata, views}; use rayon::iter::IndexedParallelIterator; use tracing::info; @@ -147,14 +147,14 @@ where // Wrap the data in `MatrixViews` so we do not need to manually construct view // in the compression loop. - let mut compressed_block = matrix::MatrixViewMut::try_from( + let mut compressed_block = views::MatrixViewMut::try_from( block_compressed_base, cur_block_size, compressed_size, ) .bridge_err()?; let base_block = - matrix::MatrixView::try_from(&block_data, cur_block_size, full_dim).bridge_err()?; + views::MatrixView::try_from(&block_data, cur_block_size, full_dim).bridge_err()?; base_block .par_window_iter(BATCH_SIZE) .zip_eq(compressed_block.par_window_iter_mut(BATCH_SIZE)) @@ -193,7 +193,7 @@ mod generator_tests { use diskann_providers::utils::create_thread_pool_for_test; use diskann_utils::{ io::{write_bin, Metadata}, - matrix::MatrixView, + views::MatrixView, }; use rstest::rstest; use vfs::{FileSystem, MemoryFS}; @@ -220,8 +220,8 @@ mod generator_tests { fn compress( &self, - _vector: matrix::MatrixView, - mut output: matrix::MatrixViewMut, + _vector: views::MatrixView, + mut output: views::MatrixViewMut, ) -> ANNResult<()> { output .row_iter_mut() diff --git a/diskann-disk/src/storage/quant/pq/pq_dataset.rs b/diskann-disk/src/storage/quant/pq/pq_dataset.rs index 529706b28..5dc31e3b3 100644 --- a/diskann-disk/src/storage/quant/pq/pq_dataset.rs +++ b/diskann-disk/src/storage/quant/pq/pq_dataset.rs @@ -8,7 +8,7 @@ use core::fmt::Debug; use diskann::{ANNError, ANNResult}; use diskann_providers::model::FixedChunkPQTable; use diskann_quantization::product::TransposedTable; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; #[derive(Debug)] pub struct PQData { diff --git a/diskann-disk/src/storage/quant/pq/pq_generation.rs b/diskann-disk/src/storage/quant/pq/pq_generation.rs index 4530cef09..e317d8e3c 100644 --- a/diskann-disk/src/storage/quant/pq/pq_generation.rs +++ b/diskann-disk/src/storage/quant/pq/pq_generation.rs @@ -16,7 +16,7 @@ use diskann_providers::{ utils::{BridgeErr, RayonThreadPoolRef}, }; use diskann_quantization::{product::TransposedTable, CompressInto}; -use diskann_utils::matrix::{MatrixView, MatrixViewMut}; +use diskann_utils::views::{MatrixView, MatrixViewMut}; use diskann_vector::distance::Metric; use tracing::info; @@ -119,7 +119,7 @@ where context.storage_provider, )?; - let mut full_pivot_data_mat = diskann_utils::matrix::MatrixViewMut::try_from( + let mut full_pivot_data_mat = diskann_utils::views::MatrixViewMut::try_from( full_pivot_data.as_mut_slice(), context.num_centers, full_dim, @@ -174,8 +174,8 @@ mod pq_generation_tests { use diskann_providers::utils::{create_thread_pool_for_test, RayonThreadPoolRef}; use diskann_utils::{ io::{read_bin, write_bin}, - matrix::{MatrixView, MatrixViewMut}, test_data_root, + views::{MatrixView, MatrixViewMut}, }; use diskann_vector::distance::Metric; use rstest::rstest; diff --git a/diskann-garnet/src/provider.rs b/diskann-garnet/src/provider.rs index 5cf55be02..b4c608334 100644 --- a/diskann-garnet/src/provider.rs +++ b/diskann-garnet/src/provider.rs @@ -24,10 +24,10 @@ use diskann::{ utils::VectorRepr, }; use diskann_quantization::alloc::{AllocatorError, Poly}; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use diskann_utils::{ - matrix::MatrixView, object_pool::{AsPooled, ObjectPool, PooledRef, Undef}, + views::MatrixView, }; use diskann_vector::{ DistanceFunction, PreprocessedDistanceFunction, contains::ContainsSimd, distance::Metric, diff --git a/diskann-garnet/src/quantization.rs b/diskann-garnet/src/quantization.rs index 288579717..8faa876c1 100644 --- a/diskann-garnet/src/quantization.rs +++ b/diskann-garnet/src/quantization.rs @@ -12,7 +12,7 @@ use diskann_quantization::{ iface::{self, Opaque, OpaqueMut, Quantizer}, }, }; -use diskann_utils::matrix::MatrixView; +use diskann_utils::views::MatrixView; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; @@ -357,7 +357,7 @@ impl DynQueryComputer for MinMax8BitQueryComputer { #[cfg(test)] mod tests { - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Matrix; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use crate::quantization::{GarnetQuantizer, GarnetQuantizerError, MinMax8Bit, Spherical1Bit}; diff --git a/diskann-providers/src/index/diskann_async.rs b/diskann-providers/src/index/diskann_async.rs index 20470ddb8..41389910e 100644 --- a/diskann-providers/src/index/diskann_async.rs +++ b/diskann-providers/src/index/diskann_async.rs @@ -59,7 +59,7 @@ pub(crate) fn simplified_builder( } pub fn train_pq( - data: diskann_utils::matrix::MatrixView, + data: diskann_utils::views::MatrixView, num_pq_chunks: usize, rng: &mut dyn rand::RngCore, pool: crate::utils::RayonThreadPoolRef<'_>, @@ -179,7 +179,7 @@ pub(crate) mod tests { utils::{IntoUsize, ONE}, }; use diskann_quantization::scalar::train::ScalarQuantizationParameters; - use diskann_utils::{matrix::Matrix, test_data_root}; + use diskann_utils::{test_data_root, views::Matrix}; use diskann_vector::{ DistanceFunction, PureDistanceFunction, distance::{Metric, SquaredL2}, @@ -213,7 +213,7 @@ pub(crate) mod tests { /// Convert an iterator of vectors into a single Matrix. All elements in `data` must /// have the same length, otherwise this function panics. - pub(crate) fn squish<'a, To, T, Itr>(data: Itr, dim: usize) -> diskann_utils::matrix::Matrix + pub(crate) fn squish<'a, To, T, Itr>(data: Itr, dim: usize) -> diskann_utils::views::Matrix where To: Clone + Default, T: Clone + Into + 'a, @@ -221,7 +221,7 @@ pub(crate) mod tests { { // Assume that all the vectors in `data` have the same length. // If they don't, `copy_from_slice` will panic, so we're double checking. - let mut mat = diskann_utils::matrix::Matrix::new(To::default(), data.len(), dim); + let mut mat = diskann_utils::views::Matrix::new(To::default(), data.len(), dim); std::iter::zip(mat.row_iter_mut(), data).for_each(|(output, input)| { assert_eq!( input.len(), @@ -621,7 +621,7 @@ pub(crate) mod tests { // // So, when we compute the corpus used during groundtruth generation, we take all // but this last point. - let corpus: diskann_utils::matrix::Matrix = + let corpus: diskann_utils::views::Matrix = squish(vectors.iter().take(num_points), dim); let mut paged_tests = Vec::new(); @@ -875,7 +875,7 @@ pub(crate) mod tests { let data = T::generate_spherical(num, dim, radius, rng); let table = { - let train_data: diskann_utils::matrix::Matrix = squish(data.iter(), dim); + let train_data: diskann_utils::views::Matrix = squish(data.iter(), dim); train_pq( train_data.as_view(), 2.min(dim), @@ -1066,7 +1066,7 @@ pub(crate) mod tests { let beta = 0.5; - let corpus: diskann_utils::matrix::Matrix = + let corpus: diskann_utils::views::Matrix = squish(vectors.iter().take(num_points), dim); let query = vec![grid_size as f32; dim]; @@ -2204,7 +2204,7 @@ pub(crate) mod tests { parameters: InitParams, file: &str, start_strategy: StartPointStrategy, - train_data: diskann_utils::matrix::MatrixView<'_, f32>, + train_data: diskann_utils::views::MatrixView<'_, f32>, ) where DefaultProvider: DataProvider + for<'a> SetElement<&'a [f32]> @@ -2260,7 +2260,7 @@ pub(crate) mod tests { file: &str, num_pq_chunks: usize, startpoint: StartPointStrategy, - ) -> (Arc, diskann_utils::matrix::Matrix) + ) -> (Arc, diskann_utils::views::Matrix) where S: for<'a> InsertStrategy<'a, TestProvider, &'a [f32]> + MultiInsertStrategy> @@ -2658,7 +2658,7 @@ pub(crate) mod tests { // Randomize the vectors let rng = &mut create_rnd_from_seed_in_tests(0x7dc205fcda38d3a3); indices.shuffle(rng); - let mut queries = diskann_utils::matrix::Matrix::new(0.0, data.nrows(), data.ncols()); + let mut queries = diskann_utils::views::Matrix::new(0.0, data.nrows(), data.ncols()); std::iter::zip(queries.row_iter_mut(), indices.iter()).for_each(|(row, i)| { row.copy_from_slice(data.row(*i)); }); diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs index e061d2554..15c2d6af1 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/full_precision.rs @@ -23,7 +23,7 @@ use diskann::{ }; use diskann_utils::future::AsyncFriendly; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use diskann_vector::{DistanceFunction, PreprocessedDistanceFunction, distance::Metric}; use crate::model::graph::provider::async_::{ diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs index c7aad4e82..561eaaec5 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/scalar.rs @@ -892,7 +892,7 @@ mod tests { use crate::storage::VirtualStorageProvider; use diskann::utils::ONE; use diskann_quantization::scalar::train::ScalarQuantizationParameters; - use diskann_utils::matrix::MatrixView; + use diskann_utils::views::MatrixView; use diskann_vector::distance::Metric; use rstest::rstest; diff --git a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs index cc1b9efa0..10f174a87 100644 --- a/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs +++ b/diskann-providers/src/model/graph/provider/async_/inmem/spherical.rs @@ -725,7 +725,7 @@ mod tests { alloc::GlobalAllocator, spherical::{SphericalQuantizer, SupportedMetric}, }; - use diskann_utils::matrix::{Matrix, MatrixView}; + use diskann_utils::views::{Matrix, MatrixView}; use diskann_vector::{ DistanceFunction, PreprocessedDistanceFunction, PureDistanceFunction, distance::{InnerProduct, Metric, SquaredL2}, @@ -769,7 +769,7 @@ mod tests { fn dataset(nrows: usize, ncols: usize, rng: &mut StdRng) -> Matrix { Matrix::new( - diskann_utils::matrix::Init(|| StandardNormal {}.sample(rng)), + diskann_utils::views::Init(|| StandardNormal {}.sample(rng)), nrows, ncols, ) diff --git a/diskann-providers/src/model/graph/provider/determinant_diversity.rs b/diskann-providers/src/model/graph/provider/determinant_diversity.rs index 62eac126a..a553a5cb6 100644 --- a/diskann-providers/src/model/graph/provider/determinant_diversity.rs +++ b/diskann-providers/src/model/graph/provider/determinant_diversity.rs @@ -53,7 +53,7 @@ use std::fmt; -use diskann_utils::matrix::MatrixViewMut; +use diskann_utils::views::MatrixViewMut; use diskann_vector::{MathematicalValue, PureDistanceFunction, distance::InnerProduct}; /// Parameters for Determinant-Diversity post-processor with validation. @@ -481,7 +481,7 @@ fn dot_product(a: &[f32], b: &[f32]) -> f32 { mod tests { use super::*; use diskann_quantization::num::Positive; - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Matrix; #[test] fn test_valid_params() { diff --git a/diskann-providers/src/model/pq/debug.rs b/diskann-providers/src/model/pq/debug.rs index b033b4155..5ecbe8c80 100644 --- a/diskann-providers/src/model/pq/debug.rs +++ b/diskann-providers/src/model/pq/debug.rs @@ -4,7 +4,7 @@ */ use diskann::utils::IntoUsize; -use diskann_utils::matrix; +use diskann_utils::views; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; pub struct MismatchRecord { @@ -48,12 +48,12 @@ impl std::fmt::Display for MismatchRecord { /// on the sizes of the provided arguments, but can be helpful for writing test routines /// and as such is still marked as public. pub fn compare_pq( - data: matrix::MatrixView<'_, T>, + data: views::MatrixView<'_, T>, schema: diskann_quantization::views::ChunkOffsetsView<'_>, - pivots: matrix::MatrixView<'_, f32>, + pivots: views::MatrixView<'_, f32>, center: &[f32], - a: matrix::MatrixView<'_, U>, - b: matrix::MatrixView<'_, U>, + a: views::MatrixView<'_, U>, + b: views::MatrixView<'_, U>, ) -> Vec where T: Copy + Into, diff --git a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs index 8e0ef403e..2ef019f73 100644 --- a/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs +++ b/diskann-providers/src/model/pq/fixed_chunk_pq_table.rs @@ -9,7 +9,7 @@ use diskann_quantization::{ product::{self, BasicTable}, views::ChunkOffsetsBase, }; -use diskann_utils::matrix::{self, Matrix, MatrixView}; +use diskann_utils::views::{self, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance}; use diskann_wide::ARCH; @@ -417,7 +417,7 @@ impl FixedChunkPQTable { } /// Return the pivots as a `MatrixView`. - pub fn view_pivots(&self) -> matrix::MatrixView<'_, f32> { + pub fn view_pivots(&self) -> views::MatrixView<'_, f32> { self.table.view_pivots() } diff --git a/diskann-providers/src/model/pq/pq_construction.rs b/diskann-providers/src/model/pq/pq_construction.rs index 28beff8f9..91fa6ca5e 100644 --- a/diskann-providers/src/model/pq/pq_construction.rs +++ b/diskann-providers/src/model/pq/pq_construction.rs @@ -25,7 +25,7 @@ use diskann_quantization::{ }; use diskann_utils::{ io::Metadata, - matrix::{MatrixView, MatrixViewMut}, + views::{MatrixView, MatrixViewMut}, }; use rand::{Rng, distr::Distribution}; use rayon::prelude::*; diff --git a/diskann-providers/src/model/pq/strided.rs b/diskann-providers/src/model/pq/strided.rs index cea96d69f..4930e6b79 100644 --- a/diskann-providers/src/model/pq/strided.rs +++ b/diskann-providers/src/model/pq/strided.rs @@ -4,12 +4,12 @@ */ use diskann::ANNError; -use diskann_utils::{matrix, strided}; +use diskann_utils::{strided, views}; use crate::utils::Bridge; // Compatibility with ANNError. -impl From>> for ANNError { +impl From>> for ANNError { #[track_caller] fn from(value: Bridge>) -> Self { ANNError::log_pq_error(value.into_inner()) diff --git a/diskann-providers/src/model/pq/views.rs b/diskann-providers/src/model/pq/views.rs index 76fd222d8..b6dc8652b 100644 --- a/diskann-providers/src/model/pq/views.rs +++ b/diskann-providers/src/model/pq/views.rs @@ -4,7 +4,7 @@ */ use diskann::ANNError; -use diskann_utils::matrix; +use diskann_utils::views; use crate::utils::Bridge; @@ -41,9 +41,9 @@ impl From> for ANNError { } // Compatibility with ANNError. -impl From> for ANNError { +impl From>> for ANNError { #[track_caller] - fn from(value: Bridge) -> Self { + fn from(value: Bridge>) -> Self { ANNError::log_pq_error(value.into_inner()) } } @@ -106,7 +106,7 @@ mod tests { let data = vec![0; ncols * nrows]; test_error(|| { - matrix::MatrixView::try_from(&data, nrows, ncols + 1) + views::MatrixView::try_from(&data, nrows, ncols + 1) .bridge_err() .unwrap_err() }); diff --git a/diskann-providers/src/storage/index_storage.rs b/diskann-providers/src/storage/index_storage.rs index 8f01023f9..fc526aa1f 100644 --- a/diskann-providers/src/storage/index_storage.rs +++ b/diskann-providers/src/storage/index_storage.rs @@ -222,7 +222,7 @@ mod tests { provider::SetElement, utils::{IntoUsize, ONE}, }; - use diskann_utils::{matrix::MatrixView, test_data_root}; + use diskann_utils::{test_data_root, views::MatrixView}; use diskann_vector::distance::Metric; use super::*; diff --git a/diskann-providers/src/storage/pq_storage.rs b/diskann-providers/src/storage/pq_storage.rs index bf859e633..fcae33c24 100644 --- a/diskann-providers/src/storage/pq_storage.rs +++ b/diskann-providers/src/storage/pq_storage.rs @@ -11,7 +11,7 @@ use diskann::{ }; use diskann_utils::{ io::{Metadata, read_bin, write_bin}, - matrix::{Matrix, MatrixView}, + views::{Matrix, MatrixView}, }; use rand::Rng; use tracing::info; @@ -523,7 +523,7 @@ mod pq_storage_tests { #[test] fn write_read_roundtrip_with_legacy_centroid() { use crate::model::pq::accum_row_inplace; - use diskann_utils::matrix::MatrixViewMut; + use diskann_utils::views::MatrixViewMut; let storage_provider = VirtualStorageProvider::new_memory(); let pivot_path = "/roundtrip_legacy_centroid_pivots.bin"; diff --git a/diskann-providers/src/test_utils/search_utils.rs b/diskann-providers/src/test_utils/search_utils.rs index 59303d51d..1cf74fd22 100644 --- a/diskann-providers/src/test_utils/search_utils.rs +++ b/diskann-providers/src/test_utils/search_utils.rs @@ -4,7 +4,7 @@ */ use diskann::neighbor::Neighbor; -use diskann_utils::matrix::MatrixView; +use diskann_utils::views::MatrixView; /// Compute the ground truth for a small dataset. /// diff --git a/diskann-providers/src/utils/file_util.rs b/diskann-providers/src/utils/file_util.rs index 105c52cb4..f5ebdadc6 100644 --- a/diskann-providers/src/utils/file_util.rs +++ b/diskann-providers/src/utils/file_util.rs @@ -10,7 +10,7 @@ use std::io::Read; use crate::storage::StorageReadProvider; use diskann::{ANNError, ANNResult, utils::IntoUsize}; -use diskann_utils::{io::Metadata, matrix::Matrix}; +use diskann_utils::{io::Metadata, views::Matrix}; /// Read metadata of data file. pub fn load_metadata_from_file( diff --git a/diskann-providers/src/utils/storage_utils.rs b/diskann-providers/src/utils/storage_utils.rs index 58521d1c3..40064368a 100644 --- a/diskann-providers/src/utils/storage_utils.rs +++ b/diskann-providers/src/utils/storage_utils.rs @@ -13,7 +13,7 @@ use byteorder::{LittleEndian, ReadBytesExt}; use diskann::ANNResult; use diskann_utils::{ io::{Metadata, ReadBinError, SaveBinError, read_bin, write_bin}, - matrix::{Matrix, MatrixView}, + views::{Matrix, MatrixView}, }; /// Load a list of vector ids from the stream. diff --git a/diskann-quantization/src/algorithms/hadamard.rs b/diskann-quantization/src/algorithms/hadamard.rs index 321bffc4e..5be88d473 100644 --- a/diskann-quantization/src/algorithms/hadamard.rs +++ b/diskann-quantization/src/algorithms/hadamard.rs @@ -383,7 +383,7 @@ mod tests { }; use super::*; - use diskann_utils::matrix::{self, Matrix, MatrixView}; + use diskann_utils::views::{self, Matrix, MatrixView}; /// Retrieve the 8x8 hadamard matrix as a `Matrix`. fn get_hadamard_8() -> Matrix { @@ -443,7 +443,7 @@ mod tests { fn test_micro_kernel_64() { let mut src = { let mut rng = StdRng::seed_from_u64(0xde1936d651285fc8); - let init = matrix::Init(|| StandardUniform {}.sample(&mut rng)); + let init = views::Init(|| StandardUniform {}.sample(&mut rng)); Matrix::new(init, 64, 1) }; @@ -476,7 +476,7 @@ mod tests { fn test_hadamard_transform(dim: usize, seed: u64) { let src = { let mut rng = StdRng::seed_from_u64(seed); - let init = matrix::Init(|| StandardUniform {}.sample(&mut rng)); + let init = views::Init(|| StandardUniform {}.sample(&mut rng)); Matrix::new(init, dim, 1) }; diff --git a/diskann-quantization/src/algorithms/kmeans/lloyds.rs b/diskann-quantization/src/algorithms/kmeans/lloyds.rs index 2fad1e917..5681b48f1 100644 --- a/diskann-quantization/src/algorithms/kmeans/lloyds.rs +++ b/diskann-quantization/src/algorithms/kmeans/lloyds.rs @@ -8,8 +8,8 @@ use diskann_wide::{SIMDMask, SIMDMulAdd, SIMDPartialOrd, SIMDSelect, SIMDSumTree use super::common::square_norm; use crate::multi_vector::{BlockTransposed, BlockTransposedRef}; use diskann_utils::{ - matrix::{Matrix, MatrixView, MatrixViewMut}, strided::StridedView, + views::{Matrix, MatrixView, MatrixViewMut}, }; //////////////////////////////// @@ -464,7 +464,7 @@ pub fn lloyds( mod tests { #[cfg(not(miri))] use diskann_utils::lazy_format; - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Matrix; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom}; #[cfg(not(miri))] diff --git a/diskann-quantization/src/algorithms/kmeans/plusplus.rs b/diskann-quantization/src/algorithms/kmeans/plusplus.rs index bb399237c..652139335 100644 --- a/diskann-quantization/src/algorithms/kmeans/plusplus.rs +++ b/diskann-quantization/src/algorithms/kmeans/plusplus.rs @@ -6,8 +6,8 @@ use std::{collections::HashSet, fmt}; use diskann_utils::{ - matrix::{MatrixView, MatrixViewMut}, strided::StridedView, + views::{MatrixView, MatrixViewMut}, }; use diskann_wide::{SIMDMulAdd, SIMDPartialOrd, SIMDSelect, SIMDVector}; use rand::{ @@ -521,7 +521,7 @@ pub fn kmeans_plusplus_into( #[cfg(test)] mod tests { - use diskann_utils::{lazy_format, matrix::Matrix}; + use diskann_utils::{lazy_format, views::Matrix}; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom}; diff --git a/diskann-quantization/src/algorithms/transforms/random_rotation.rs b/diskann-quantization/src/algorithms/transforms/random_rotation.rs index 562e043c0..dc7794151 100644 --- a/diskann-quantization/src/algorithms/transforms/random_rotation.rs +++ b/diskann-quantization/src/algorithms/transforms/random_rotation.rs @@ -31,7 +31,7 @@ use crate::flatbuffers as fb; #[cfg_attr(test, derive(PartialEq))] pub struct RandomRotation { /// This data structure maintains the invariant that this **must** be a square matrix. - transform: diskann_utils::matrix::Matrix, + transform: diskann_utils::views::Matrix, } impl RandomRotation { @@ -88,7 +88,7 @@ impl RandomRotation { // Lint: By construction, the matrix returned from // `diskann_linalg::random_distance_preserving_matrix` will by `matrix_dim x matrix_dim`. #[allow(clippy::unwrap_used)] - let initial = diskann_utils::matrix::Matrix::try_from( + let initial = diskann_utils::views::Matrix::try_from( diskann_linalg::random_distance_preserving_matrix(matrix_dim, rng).into(), matrix_dim, matrix_dim, @@ -102,7 +102,7 @@ impl RandomRotation { let indices = rand::seq::index::sample(rng, dim, target_dim); let scaling = (dim as f32 / target_dim as f32).sqrt(); - let mut transform = diskann_utils::matrix::Matrix::new(0.0f32, target_dim, dim); + let mut transform = diskann_utils::views::Matrix::new(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), indices.iter()).for_each(|(ro, ri)| { std::iter::zip(ro.iter_mut(), initial.row(ri).iter()).for_each(|(o, i)| { *o = scaling * (*i); @@ -111,7 +111,7 @@ impl RandomRotation { transform } std::cmp::Ordering::Greater => { - let mut transform = diskann_utils::matrix::Matrix::new(0.0f32, target_dim, dim); + let mut transform = diskann_utils::views::Matrix::new(0.0f32, target_dim, dim); std::iter::zip(transform.row_iter_mut(), initial.row_iter()) .for_each(|(o, i)| o.copy_from_slice(&i[..dim])); transform @@ -220,7 +220,7 @@ impl RandomRotation { let data = proto.data().into_iter().collect(); let transform = - diskann_utils::matrix::Matrix::try_from(data, nrows as usize, ncols as usize) + diskann_utils::views::Matrix::try_from(data, nrows as usize, ncols as usize) .map_err(|_| RandomRotationError::IncorrectDim)?; Ok(Self { transform }) diff --git a/diskann-quantization/src/binary/quantizer.rs b/diskann-quantization/src/binary/quantizer.rs index a059543d1..566c0f282 100644 --- a/diskann-quantization/src/binary/quantizer.rs +++ b/diskann-quantization/src/binary/quantizer.rs @@ -129,7 +129,7 @@ impl AsFunctor for BinaryQuantizer { #[cfg(test)] mod tests { - use diskann_utils::{ReborrowMut, matrix::Matrix}; + use diskann_utils::{ReborrowMut, views::Matrix}; use rand::{SeedableRng, rngs::StdRng, seq::SliceRandom}; use super::*; diff --git a/diskann-quantization/src/lib.rs b/diskann-quantization/src/lib.rs index 248d02f23..5446f9773 100644 --- a/diskann-quantization/src/lib.rs +++ b/diskann-quantization/src/lib.rs @@ -216,7 +216,6 @@ mod tests { t.pass("tests/compile-fail/bootstrap/bootstrap.rs"); t.compile_fail("tests/compile-fail/*.rs"); t.compile_fail("tests/compile-fail/error/*.rs"); - t.compile_fail("tests/compile-fail/multi/*.rs"); } } diff --git a/diskann-quantization/src/minmax/multi/max_sim.rs b/diskann-quantization/src/minmax/multi/max_sim.rs index 44382f00b..247add67a 100644 --- a/diskann-quantization/src/minmax/multi/max_sim.rs +++ b/diskann-quantization/src/minmax/multi/max_sim.rs @@ -144,7 +144,7 @@ mod tests { use crate::algorithms::transforms::NullTransform; use crate::bits::{Representation, Unsigned}; use crate::minmax::{Data, MinMaxQuantizer}; - use crate::multi_vector::{Defaulted, Mat, RowMajor}; + use crate::multi_vector::{Mat, RowMajor}; use crate::num::Positive; use diskann_utils::ReborrowMut; use std::num::NonZeroUsize; @@ -204,7 +204,7 @@ mod tests { { let input_mat = MatRef::from_repr(RowMajor::::new(n, dim).unwrap(), input).unwrap(); let mut output: Mat> = - Mat::from_repr(MinMaxMeta::new(n, dim), Defaulted).unwrap(); + Mat::from_default(MinMaxMeta::new(n, dim)).unwrap(); quantizer .compress_into(input_mat, output.reborrow_mut()) .unwrap(); diff --git a/diskann-quantization/src/minmax/multi/meta.rs b/diskann-quantization/src/minmax/multi/meta.rs index d0dd693b7..cf136c594 100644 --- a/diskann-quantization/src/minmax/multi/meta.rs +++ b/diskann-quantization/src/minmax/multi/meta.rs @@ -10,8 +10,8 @@ use super::super::vectors::DataMutRef; use crate::CompressInto; use crate::bits::{Representation, Unsigned}; use crate::minmax::{self, Data}; -use crate::multi_vector::matrix::{ - Defaulted, NewMut, NewOwned, NewRef, Repr, ReprMut, ReprOwned, SliceError, +use crate::multi_vector::views::{ + NewDefault, NewMut, NewRef, Repr, ReprMut, ReprOwned, SliceError, }; use crate::multi_vector::{LayoutError, Mat, MatMut, MatRef, RowMajor}; use crate::scalar::InputContainsNaN; @@ -165,12 +165,12 @@ where // SAFETY: `ptr` points to a properly sized slice that is compatible with the drop // logic in `Self as ReprOwned`. Box guarantees that the initial construction // will be non-null. -unsafe impl NewOwned for MinMaxMeta +unsafe impl NewDefault for MinMaxMeta where Unsigned: Representation, { type Error = crate::error::Infallible; - fn new_owned(self, _: Defaulted) -> Result, Self::Error> { + fn new_default(self) -> Result, Self::Error> { let b: Box<[u8]> = vec![0u8; self.bytes()].into_boxed_slice(); let ptr = utils::box_into_nonnull(b).cast::(); @@ -372,7 +372,7 @@ mod tests { mod construction { use super::*; - /// Tests NewOwned (Mat::from_repr with Defaulted) for various dimensions and sizes. + /// Tests NewDefault (Mat::from_default) for various dimensions and sizes. fn test_new_owned() where Unsigned: Representation, @@ -381,7 +381,7 @@ mod tests { for &num_vectors in TEST_NVECS { let meta = MinMaxMeta::::new(num_vectors, dim); let mat: Mat> = - Mat::from_repr(meta, Defaulted).expect("NewOwned should succeed"); + Mat::from_default(meta).expect("NewOwned should succeed"); // Verify num_vectors and intrinsic_dim assert_eq!(mat.num_vectors(), num_vectors); @@ -536,7 +536,7 @@ mod tests { .expect("input view creation"); let mut multi_mat: Mat> = - Mat::from_repr(MinMaxMeta::new(num_vectors, dim), Defaulted) + Mat::from_default(MinMaxMeta::new(num_vectors, dim)) .expect("output mat creation"); quantizer @@ -592,7 +592,7 @@ mod tests { .expect("input view"); let mut mat: Mat> = - Mat::from_repr(MinMaxMeta::new(num_vectors, dim), Defaulted).expect("mat creation"); + Mat::from_default(MinMaxMeta::new(num_vectors, dim)).expect("mat creation"); quantizer .compress_into(input_view, mat.reborrow_mut()) @@ -632,7 +632,7 @@ mod tests { // Output has 2 vectors (mismatch) let mut mat: Mat> = - Mat::from_repr(MinMaxMeta::new(2, dim), Defaulted).expect("mat creation"); + Mat::from_default(MinMaxMeta::new(2, dim)).expect("mat creation"); let _ = quantizer.compress_into(input_view, mat.reborrow_mut()); } @@ -650,7 +650,7 @@ mod tests { // Output correctly has dim=4 let mut mat: Mat> = - Mat::from_repr(MinMaxMeta::new(2, 4), Defaulted).expect("mat creation"); + Mat::from_default(MinMaxMeta::new(2, 4)).expect("mat creation"); let _ = quantizer.compress_into(input_view, mat.reborrow_mut()); } diff --git a/diskann-quantization/src/minmax/multi/mod.rs b/diskann-quantization/src/minmax/multi/mod.rs index 793d8316e..2c43dbbcf 100644 --- a/diskann-quantization/src/minmax/multi/mod.rs +++ b/diskann-quantization/src/minmax/multi/mod.rs @@ -20,7 +20,7 @@ //! minmax::{MinMaxMeta, MinMaxQuantizer}, //! multi_vector::{ //! distance::{Chamfer, MaxSim, QueryMatRef}, -//! Defaulted, Mat, MatRef, RowMajor, +//! Mat, MatRef, RowMajor, //! }, //! num::Positive, //! CompressInto, @@ -60,9 +60,9 @@ //! //! // Create owned matrices for quantized output using Mat::from_repr //! let mut query_out: Mat> = -//! Mat::from_repr(MinMaxMeta::new(num_query_vectors, dim), Defaulted).unwrap(); +//! Mat::from_default(MinMaxMeta::new(num_query_vectors, dim)).unwrap(); //! let mut doc_out: Mat> = -//! Mat::from_repr(MinMaxMeta::new(num_doc_vectors, dim), Defaulted).unwrap(); +//! Mat::from_default(MinMaxMeta::new(num_doc_vectors, dim)).unwrap(); //! //! // Quantize both multi-vectors //! quantizer.compress_into(query_input, query_out.reborrow_mut()).unwrap(); diff --git a/diskann-quantization/src/multi_vector/block_transposed.rs b/diskann-quantization/src/multi_vector/block_transposed.rs index 5e9ad9eaf..acc56f739 100644 --- a/diskann-quantization/src/multi_vector/block_transposed.rs +++ b/diskann-quantization/src/multi_vector/block_transposed.rs @@ -81,13 +81,13 @@ use std::{alloc::Layout, marker::PhantomData, ptr::NonNull}; use diskann_utils::{ Reborrow, ReborrowMut, - matrix::{MatrixView, MatrixViewMut}, strided::StridedView, + views::{MatrixView, MatrixViewMut}, }; -use super::matrix::{ - Defaulted, LayoutError, Mat, MatMut, MatRef, NewMut, NewOwned, NewRef, Overflow, Repr, ReprMut, - ReprOwned, SliceError, +use super::views::{ + LayoutError, Mat, MatMut, MatRef, NewDefault, NewMut, NewOwned, NewRef, Overflow, Repr, + ReprMut, ReprOwned, SliceError, }; use crate::bits::{AsMutPtr, AsPtr, MutSlicePtr, SlicePtr}; use crate::utils; @@ -578,15 +578,26 @@ unsafe impl ReprOwned // ════════════════════════════════════════════════════════════════════ // SAFETY: The returned `Mat` contains a `Box` with exactly `self.storage_len()` elements. -// -// No generic `NewOwned` value-fill: `Defaulted` is foreign (diskann-utils), so a value-fill -// impl would overlap with this under intercrate coherence. These matrices are only default-init'd. -unsafe impl NewOwned +unsafe impl NewOwned for BlockTransposedRepr { type Error = crate::error::Infallible; - fn new_owned(self, _: Defaulted) -> Result, Self::Error> { + fn new_owned(self, value: T) -> Result, Self::Error> { + let b: Box<[T]> = vec![value; self.storage_len()].into_boxed_slice(); + + // SAFETY: By construction, `b.len() == self.storage_len()`. + Ok(unsafe { self.box_to_mat(b) }) + } +} + +// SAFETY: The returned `Mat` contains a `Box` with exactly `self.storage_len()` elements. +unsafe impl NewDefault + for BlockTransposedRepr +{ + type Error = crate::error::Infallible; + + fn new_default(self) -> Result, Self::Error> { let b: Box<[T]> = vec![T::default(); self.storage_len()].into_boxed_slice(); // SAFETY: By construction, `b.len() == self.storage_len()`. @@ -1110,7 +1121,7 @@ impl BlockTransposed::new(nrows, ncols) .expect("dimensions should not overflow"); Self { - data: Mat::from_repr(repr, Defaulted).expect("infallible"), + data: Mat::from_default(repr).expect("infallible"), } } @@ -1118,7 +1129,7 @@ impl BlockTransposed Result { let repr = BlockTransposedRepr::::new(nrows, ncols)?; Ok(Self { - data: Mat::from_repr(repr, Defaulted).expect("infallible"), + data: Mat::from_default(repr).expect("infallible"), }) } @@ -1228,7 +1239,7 @@ mod tests { //! parameters to `test_full_api` (`Send`/`Sync`, panic paths, //! non-unit strides, concurrent mutation, etc.). - use diskann_utils::{lazy_format, matrix::Matrix}; + use diskann_utils::{lazy_format, views::Matrix}; use super::*; use crate::utils::div_round_up; diff --git a/diskann-quantization/src/multi_vector/mod.rs b/diskann-quantization/src/multi_vector/mod.rs index 668b75a4d..7c0b8989f 100644 --- a/diskann-quantization/src/multi_vector/mod.rs +++ b/diskann-quantization/src/multi_vector/mod.rs @@ -53,11 +53,11 @@ pub mod block_transposed; pub mod distance; -pub(crate) use diskann_utils::matrix; +pub(crate) use diskann_utils::views; pub use block_transposed::{BlockTransposed, BlockTransposedMut, BlockTransposedRef}; -pub use diskann_utils::matrix::{ - Defaulted, LayoutError, Mat, MatMut, MatRef, NewCloned, NewMut, NewOwned, NewRef, Overflow, +pub use diskann_utils::views::{ + LayoutError, Mat, MatMut, MatRef, NewCloned, NewDefault, NewMut, NewOwned, NewRef, Overflow, Repr, ReprMut, ReprOwned, RowMajor, SliceError, }; pub use distance::{ diff --git a/diskann-quantization/src/product/tables/basic.rs b/diskann-quantization/src/product/tables/basic.rs index ee43ba08c..69d53a81b 100644 --- a/diskann-quantization/src/product/tables/basic.rs +++ b/diskann-quantization/src/product/tables/basic.rs @@ -5,7 +5,7 @@ use crate::traits::CompressInto; use crate::views::{ChunkOffsetsBase, ChunkOffsetsView}; -use diskann_utils::matrix::{DenseData, Matrix, MatrixView}; +use diskann_utils::views::{DenseData, Matrix, MatrixView}; use diskann_vector::{PureDistanceFunction, distance::SquaredL2}; use thiserror::Error; @@ -218,7 +218,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::{lazy_format, matrix}; + use diskann_utils::{lazy_format, views}; use rand::{ SeedableRng, distr::{Distribution, StandardUniform}, @@ -237,7 +237,7 @@ mod tests { // disagree. #[test] fn error_on_mismatch_dim() { - let pivots = matrix::Matrix::new(0.0, 3, 5); + let pivots = views::Matrix::new(0.0, 3, 5); let offsets = crate::views::ChunkOffsets::new(Box::new([0, 1, 6])).unwrap(); let result = BasicTable::new(pivots, offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -250,7 +250,7 @@ mod tests { // Test that the table constructor errors when there are no pivots. #[test] fn error_on_no_pivots() { - let pivots = matrix::Matrix::new(0.0, 0, 5); + let pivots = views::Matrix::new(0.0, 0, 5); let offsets = crate::views::ChunkOffsets::new(Box::new([0, 1, 2, 5])).unwrap(); let result = BasicTable::new(pivots, offsets); assert!(result.is_err(), "pivots is empty"); @@ -262,8 +262,8 @@ mod tests { let mut rng = rand::rngs::StdRng::seed_from_u64(0xd96bac968083ec29); for dim in [5, 10, 12] { for total in [1, 2, 3] { - let pivots = matrix::Matrix::new( - matrix::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), + let pivots = views::Matrix::new( + views::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), total, dim, ); @@ -340,7 +340,7 @@ mod tests { // Set up `ncenters > 256`. { - let pivots = matrix::Matrix::new(0.0, 257, dim); + let pivots = views::Matrix::new(0.0, 257, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim]; @@ -359,7 +359,7 @@ mod tests { // Setup input dim not equal to expected. { - let pivots = matrix::Matrix::new(0.0, 10, dim); + let pivots = views::Matrix::new(0.0, 10, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim - 1]; @@ -378,7 +378,7 @@ mod tests { // Setup output dim not equal to expected. { - let pivots = matrix::Matrix::new(0.0, 10, dim); + let pivots = views::Matrix::new(0.0, 10, dim); let table = BasicTable::new(pivots, offsets.clone()).unwrap(); let input = vec![f32::default(); dim]; @@ -403,7 +403,7 @@ mod tests { #[test] fn test_table_single_compression_errors() { check_pqtable_single_compression_errors( - &|pivots: matrix::Matrix, offsets| BasicTable::new(pivots, offsets).unwrap(), + &|pivots: views::Matrix, offsets| BasicTable::new(pivots, offsets).unwrap(), &"BasicTable", ) } diff --git a/diskann-quantization/src/product/tables/test.rs b/diskann-quantization/src/product/tables/test.rs index 8a48ebd0a..32261c2dc 100644 --- a/diskann-quantization/src/product/tables/test.rs +++ b/diskann-quantization/src/product/tables/test.rs @@ -4,9 +4,9 @@ */ // A collection of test helpers to ensure uniformity across tables. -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; #[cfg(not(miri))] -use diskann_utils::matrix::{MatrixView, MatrixViewMut}; +use diskann_utils::views::{MatrixView, MatrixViewMut}; #[cfg(not(miri))] use rand::seq::IndexedRandom; use rand::{ diff --git a/diskann-quantization/src/product/tables/transposed/pivots.rs b/diskann-quantization/src/product/tables/transposed/pivots.rs index 07dc6e0bc..c76c5c519 100644 --- a/diskann-quantization/src/product/tables/transposed/pivots.rs +++ b/diskann-quantization/src/product/tables/transposed/pivots.rs @@ -1061,7 +1061,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::{lazy_format, matrix}; + use diskann_utils::{lazy_format, views}; use diskann_vector::{PureDistanceFunction, distance}; use rand::{ SeedableRng, @@ -1520,7 +1520,7 @@ mod tests { #[test] #[should_panic(expected = "row 5 must be less than 5")] fn get_panics_on_row() { - let data = matrix::Matrix::new(0.0, 5, 10); + let data = views::Matrix::new(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); chunk.get(5, 1); } @@ -1528,7 +1528,7 @@ mod tests { #[test] #[should_panic(expected = "col 5 must be less than 5")] fn get_panics_on_col() { - let data = matrix::Matrix::new(0.0, 10, 5); + let data = views::Matrix::new(0.0, 10, 5); let chunk = Chunk::new(data.as_view().into()).unwrap(); chunk.get(1, 5); } @@ -1547,11 +1547,8 @@ mod tests { fn test_process_into_impl(dim: usize, total: usize, rng: &mut StdRng) { let distribution = Uniform::::new(-10, 10).unwrap(); - let base = matrix::Matrix::::new( - matrix::Init(|| distribution.sample(rng) as f32), - total, - dim, - ); + let base = + views::Matrix::::new(views::Init(|| distribution.sample(rng) as f32), total, dim); let chunk = Chunk::new(base.as_view().into()).unwrap(); let mut input = vec![0.0; dim]; @@ -1600,7 +1597,7 @@ mod tests { #[test] #[should_panic] fn test_process_into_panics_on_from() { - let data = matrix::Matrix::::new(0.0, 5, 10); + let data = views::Matrix::::new(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); assert_eq!(chunk.dimension(), 10); assert_eq!(chunk.num_centers(), 5); @@ -1614,7 +1611,7 @@ mod tests { #[test] #[should_panic] fn test_process_into_panics_on_into() { - let data = matrix::Matrix::::new(0.0, 5, 10); + let data = views::Matrix::::new(0.0, 5, 10); let chunk = Chunk::new(data.as_view().into()).unwrap(); assert_eq!(chunk.dimension(), 10); assert_eq!(chunk.num_centers(), 5); diff --git a/diskann-quantization/src/product/tables/transposed/table.rs b/diskann-quantization/src/product/tables/transposed/table.rs index 2c49fbf1c..ea5567b82 100644 --- a/diskann-quantization/src/product/tables/transposed/table.rs +++ b/diskann-quantization/src/product/tables/transposed/table.rs @@ -12,8 +12,8 @@ use crate::{ views::{ChunkOffsets, ChunkOffsetsView}, }; use diskann_utils::{ - matrix::{self, MatrixView, MatrixViewMut}, strided, + views::{self, MatrixView, MatrixViewMut}, }; use thiserror::Error; @@ -71,7 +71,7 @@ impl TransposedTable { /// * `pivots.nrows() == 0`: The pivot table cannot be empty. #[allow(clippy::expect_used)] pub fn from_parts( - pivots: matrix::MatrixView, + pivots: views::MatrixView, offsets: ChunkOffsets, ) -> Result { let pivot_dim = pivots.ncols(); @@ -154,7 +154,7 @@ impl TransposedTable { #[allow(clippy::expect_used)] pub fn compress_batch( &self, - data: matrix::MatrixView<'_, T>, + data: views::MatrixView<'_, T>, mut compression_delegate: F, ) -> Result<(), CompressError> where @@ -187,7 +187,7 @@ impl TransposedTable { let range = self.offsets.at(i); if let Some(chunk_dim) = NonZeroUsize::new(range.len()) { // Construct a view for the packing buffer for this chunk. - let mut packing_view = matrix::MatrixViewMut::try_from( + let mut packing_view = views::MatrixViewMut::try_from( &mut packing_buffer[..SUB_BATCH_SIZE * chunk_dim.get()], SUB_BATCH_SIZE, chunk_dim.get(), @@ -530,7 +530,7 @@ mod test_compression { // disagree. #[test] fn error_on_mismatch_dim() { - let pivots = matrix::Matrix::new(0.0, 3, 5); + let pivots = views::Matrix::new(0.0, 3, 5); let offsets = ChunkOffsets::new(Box::new([0, 1, 6])).unwrap(); let result = TransposedTable::from_parts(pivots.as_view(), offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -544,7 +544,7 @@ mod test_compression { // disagree. #[test] fn error_on_empty() { - let pivots = matrix::Matrix::new(0.0, 0, 5); + let pivots = views::Matrix::new(0.0, 0, 5); let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); let result = TransposedTable::from_parts(pivots.as_view(), offsets); assert!(result.is_err(), "dimensions are not equal"); @@ -564,8 +564,8 @@ mod test_compression { for dim in [5, 10, 12] { // Sweep over enough totals to ensure the inner chunks have a non-trivial layout. for total in [1, 2, 3, 7, 8, 9, 10] { - let pivots = matrix::Matrix::new( - matrix::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), + let pivots = views::Matrix::new( + views::Init(|| -> f32 { StandardUniform {}.sample(&mut rng) }), total, dim, ); @@ -684,7 +684,7 @@ mod test_compression { assert_eq!(called.len(), num_data * schema.len()); // Trait Interface. - let mut output = matrix::Matrix::new(0, num_data, schema.len()); + let mut output = views::Matrix::new(0, num_data, schema.len()); table .compress_into(data.as_view(), output.as_mut_view()) .unwrap(); @@ -741,7 +741,7 @@ mod test_compression { // should panic let _ = table.compress_batch( - matrix::MatrixView::try_from(data.as_slice(), 1, 5).unwrap(), + views::MatrixView::try_from(data.as_slice(), 1, 5).unwrap(), |_, _| -> Result<(), Infallible> { panic!("this shouldn't be called") }, ); } @@ -767,7 +767,7 @@ mod test_compression { let (data, _) = create_dataset(schema, num_centers, num_data, &mut rng); let data_view = - matrix::MatrixView::try_from(data.as_slice(), num_data, schema.dim()).unwrap(); + views::MatrixView::try_from(data.as_slice(), num_data, schema.dim()).unwrap(); let distribution = rand_distr::StandardUniform {}; for row in 0..data_view.nrows() { @@ -809,7 +809,7 @@ mod test_compression { #[cfg(not(miri))] fn test_table_single_compression_errors() { check_pqtable_single_compression_errors( - &|pivots: matrix::Matrix, offsets| { + &|pivots: views::Matrix, offsets| { TransposedTable::from_parts(pivots.as_view(), offsets).unwrap() }, &"TranposedTable", @@ -820,7 +820,7 @@ mod test_compression { #[cfg(not(miri))] fn test_table_batch_compression_errors() { check_pqtable_batch_compression_errors( - &|pivots: matrix::Matrix, offsets| { + &|pivots: views::Matrix, offsets| { TransposedTable::from_parts(pivots.as_view(), offsets).unwrap() }, &"TranposedTable", @@ -856,15 +856,15 @@ mod test_compression { let offsets = ChunkOffsets::new(offsets.into()).unwrap(); let dim = offsets.dim(); - let pivots = matrix::Matrix::::new( - matrix::Init(|| value_distribution.sample(rng) as f32), + let pivots = views::Matrix::::new( + views::Init(|| value_distribution.sample(rng) as f32), num_centers, dim, ); let table = TransposedTable::from_parts(pivots.as_view(), offsets.clone()).unwrap(); - let mut output = matrix::Matrix::::new(0.0, num_chunks, num_centers); + let mut output = views::Matrix::::new(0.0, num_chunks, num_centers); let query: Vec<_> = (0..dim) .map(|_| value_distribution.sample(rng) as f32) .collect(); @@ -936,13 +936,13 @@ mod test_compression { #[should_panic(expected = "query has the wrong number of dimensions")] fn test_process_into_panics_query() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = matrix::Matrix::::new(0.0, 3, 5); + let data = views::Matrix::::new(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); // query has the wrong length. let query = vec![0.0; table.dim() - 1]; - let mut partials = matrix::Matrix::new(0.0, table.nchunks(), table.ncenters()); + let mut partials = views::Matrix::new(0.0, table.nchunks(), table.ncenters()); table.process_into::(&query, partials.as_mut_view()); } @@ -950,13 +950,13 @@ mod test_compression { #[should_panic(expected = "output has the wrong number of rows")] fn test_process_into_panics_partials_rows() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = matrix::Matrix::::new(0.0, 3, 5); + let data = views::Matrix::::new(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); let query = vec![0.0; table.dim()]; // partials has the wrong numbers of rows. - let mut partials = matrix::Matrix::new(0.0, table.nchunks() - 1, table.ncenters()); + let mut partials = views::Matrix::new(0.0, table.nchunks() - 1, table.ncenters()); table.process_into::(&query, partials.as_mut_view()); } @@ -964,13 +964,13 @@ mod test_compression { #[should_panic(expected = "output has the wrong number of columns")] fn test_process_into_panics_partials_cols() { let offsets = ChunkOffsets::new(Box::new([0, 1, 5])).unwrap(); - let data = matrix::Matrix::::new(0.0, 3, 5); + let data = views::Matrix::::new(0.0, 3, 5); let table = TransposedTable::from_parts(data.as_view(), offsets).unwrap(); assert_eq!(table.dim(), 5); let query = vec![0.0; table.dim()]; // partials has the wrong numbers of rows. - let mut partials = matrix::Matrix::new(0.0, table.nchunks(), table.ncenters() - 1); + let mut partials = views::Matrix::new(0.0, table.nchunks(), table.ncenters() - 1); table.process_into::(&query, partials.as_mut_view()); } } diff --git a/diskann-quantization/src/product/train.rs b/diskann-quantization/src/product/train.rs index 96741f5d0..3d9a1a47d 100644 --- a/diskann-quantization/src/product/train.rs +++ b/diskann-quantization/src/product/train.rs @@ -4,8 +4,8 @@ */ use diskann_utils::{ - matrix::{self, Matrix}, strided::StridedView, + views::{self, Matrix}, }; #[cfg(feature = "rayon")] use rayon::iter::{IntoParallelIterator, ParallelIterator}; @@ -77,7 +77,7 @@ pub trait TrainQuantizer { fn train( &self, - data: matrix::MatrixView, + data: views::MatrixView, schema: crate::views::ChunkOffsetsView<'_>, parallelism: Parallelism, rng_builder: &R, @@ -108,7 +108,7 @@ impl TrainQuantizer for LightPQTrainingParameters { /// * `NaN` or infinities are observed during the training process. fn train( &self, - data: matrix::MatrixView, + data: views::MatrixView, schema: crate::views::ChunkOffsetsView<'_>, parallelism: Parallelism, rng_builder: &R, @@ -123,7 +123,7 @@ impl TrainQuantizer for LightPQTrainingParameters { #[inline(never)] fn train( trainer: &LightPQTrainingParameters, - data: matrix::MatrixView, + data: views::MatrixView, schema: crate::views::ChunkOffsetsView<'_>, parallelism: Parallelism, rng_builder: &(dyn BoxedRngBuilder + Sync), diff --git a/diskann-quantization/src/scalar/mod.rs b/diskann-quantization/src/scalar/mod.rs index b26ebb007..284a285be 100644 --- a/diskann-quantization/src/scalar/mod.rs +++ b/diskann-quantization/src/scalar/mod.rs @@ -62,7 +62,7 @@ //! scalar::{self, train, CompensatedVector, CompensatedIP, CompensatedSquaredL2}, //! num::Positive, //! }; -//! use diskann_utils::{Reborrow, ReborrowMut, matrix::Matrix}; +//! use diskann_utils::{Reborrow, ReborrowMut, views::Matrix}; //! use rand::{rngs::StdRng, SeedableRng, distr::Distribution}; //! use rand_distr::StandardNormal; //! use diskann_vector::{PureDistanceFunction, DistanceFunction, distance}; diff --git a/diskann-quantization/src/scalar/quantizer.rs b/diskann-quantization/src/scalar/quantizer.rs index 3b48513ea..6c86fc228 100644 --- a/diskann-quantization/src/scalar/quantizer.rs +++ b/diskann-quantization/src/scalar/quantizer.rs @@ -38,7 +38,7 @@ use crate::{ /// CompensatedIP, CompensatedSquaredL2, /// } /// }; -/// use diskann_utils::{matrix::Matrix, Reborrow, ReborrowMut}; +/// use diskann_utils::{views::Matrix, Reborrow, ReborrowMut}; /// use diskann_vector::DistanceFunction; /// /// // A small training set consisting of two 5-dimensional vectors. @@ -459,7 +459,7 @@ pub enum SQComparisonError { mod tests { use std::collections::HashSet; - use diskann_utils::{ReborrowMut, matrix}; + use diskann_utils::{ReborrowMut, views}; use rand::{ SeedableRng, @@ -593,7 +593,7 @@ mod tests { // Create a shuffled matrix of offset values for each dimension. This ensure that // each dimension covers the target dynamic range, but in a different order so // we can rule out cross-coupling of dimensions. - let dim_offsets: matrix::Matrix = { + let dim_offsets: views::Matrix = { let range_min = -min_encodable - 3.0 * scale; let range_max = max_encodable + 3.0 * scale; let mut base: Vec = Vec::new(); @@ -607,7 +607,7 @@ mod tests { // Push one more to have one point above `range_max`. base.push(i); - let mut output = matrix::Matrix::new(0.0, base.len(), dim); + let mut output = views::Matrix::new(0.0, base.len(), dim); (0..dim).for_each(|j| { base.shuffle(rng); for (i, b) in base.iter().enumerate() { diff --git a/diskann-quantization/src/scalar/train.rs b/diskann-quantization/src/scalar/train.rs index 01799606b..becf99fd5 100644 --- a/diskann-quantization/src/scalar/train.rs +++ b/diskann-quantization/src/scalar/train.rs @@ -8,7 +8,7 @@ use crate::{ num::Positive, utils::{compute_means_and_average_norm, compute_variances}, }; -use diskann_utils::matrix; +use diskann_utils::views; /// Parameters controlling the generation of the scalar quantization Quantizer. /// @@ -71,7 +71,7 @@ impl ScalarQuantizationParameters { /// # Parallelism /// /// This function is single threaded. - pub fn train(&self, data: matrix::MatrixView) -> ScalarQuantizer + pub fn train(&self, data: views::MatrixView) -> ScalarQuantizer where T: Copy + Into + Into, { diff --git a/diskann-quantization/src/spherical/iface.rs b/diskann-quantization/src/spherical/iface.rs index 3775f4a4b..2662f84bf 100644 --- a/diskann-quantization/src/spherical/iface.rs +++ b/diskann-quantization/src/spherical/iface.rs @@ -40,7 +40,7 @@ //! spherical::{iface, SupportedMetric, SphericalQuantizer, PreScale}, //! num::PowerOfTwo, //! }; -//! use diskann_utils::matrix::Matrix; +//! use diskann_utils::views::Matrix; //! //! // For illustration purposes, the dataset consists of just a single vector. //! let mut data = Matrix::new(1.0, 1, 4); @@ -2086,7 +2086,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::matrix::{Matrix, MatrixView}; + use diskann_utils::views::{Matrix, MatrixView}; use rand::{SeedableRng, rngs::StdRng}; use super::*; diff --git a/diskann-quantization/src/spherical/quantizer.rs b/diskann-quantization/src/spherical/quantizer.rs index 1ceeaa9b7..ec82b48ce 100644 --- a/diskann-quantization/src/spherical/quantizer.rs +++ b/diskann-quantization/src/spherical/quantizer.rs @@ -5,7 +5,7 @@ use std::num::NonZeroUsize; -use diskann_utils::{ReborrowMut, matrix::MatrixView}; +use diskann_utils::{ReborrowMut, views::MatrixView}; use diskann_vector::{ MathematicalValue, Norm, PureDistanceFunction, distance::InnerProduct, norm::FastL2Norm, }; @@ -1220,7 +1220,7 @@ mod tests { use diskann_utils::{ ReborrowMut, lazy_format, - matrix::{self, Matrix}, + views::{self, Matrix}, }; use diskann_vector::{PureDistanceFunction, norm::FastL2NormSquared}; use diskann_wide::ARCH; @@ -2388,7 +2388,7 @@ mod tests { #[test] fn compression_errors_data() { let mut rng = StdRng::seed_from_u64(0xe3e9f42ed9f15883); - let data = Matrix::::new(matrix::Init(|| StandardNormal {}.sample(&mut rng)), 16, 12); + let data = Matrix::::new(views::Init(|| StandardNormal {}.sample(&mut rng)), 16, 12); let quantizer = SphericalQuantizer::train( data.as_view(), diff --git a/diskann-quantization/src/test_util.rs b/diskann-quantization/src/test_util.rs index f887a822e..6cde8e6d6 100644 --- a/diskann-quantization/src/test_util.rs +++ b/diskann-quantization/src/test_util.rs @@ -9,7 +9,7 @@ use std::sync::{ atomic::{AtomicUsize, Ordering}, }; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use rand::{ distr::{Distribution, Uniform}, rngs::StdRng, diff --git a/diskann-quantization/src/utils.rs b/diskann-quantization/src/utils.rs index 1d5df3a61..baf5286a3 100644 --- a/diskann-quantization/src/utils.rs +++ b/diskann-quantization/src/utils.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use thiserror::Error; -use diskann_utils::matrix::MatrixView; +use diskann_utils::views::MatrixView; /// Specify featres and config flags that will be propagated to `docsrs` config. macro_rules! features { @@ -41,7 +41,7 @@ pub(crate) fn as_nonnull_mut(slice: &mut [T]) -> NonNull { /// /// This is the owned-allocation counterpart of [`as_nonnull`]: it consumes the /// box, preventing its destructor from running, and hands back a non-null -/// pointer suitable for storing inside a [`Mat`](super::multi_vector::matrix::Mat). +/// pointer suitable for storing inside a [`Mat`](super::multi_vector::views::Mat). /// /// To reclaim the memory later, reconstruct the `Box` via /// `Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr.as_ptr(), len))`. @@ -205,7 +205,7 @@ where #[cfg(test)] mod tests { - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Matrix; use diskann_vector::{Norm, norm::FastL2Norm}; use rand::{SeedableRng, rngs::StdRng}; diff --git a/diskann-quantization/src/views.rs b/diskann-quantization/src/views.rs index 864b775da..04c4a0953 100644 --- a/diskann-quantization/src/views.rs +++ b/diskann-quantization/src/views.rs @@ -5,7 +5,7 @@ use std::num::NonZeroUsize; -use diskann_utils::matrix::{DenseData, MutDenseData}; +use diskann_utils::views::{DenseData, MutDenseData}; use std::ops::{Index, IndexMut}; use thiserror::Error; diff --git a/diskann-tools/src/utils/ground_truth.rs b/diskann-tools/src/utils/ground_truth.rs index 47422454a..77c2f663c 100644 --- a/diskann-tools/src/utils/ground_truth.rs +++ b/diskann-tools/src/utils/ground_truth.rs @@ -20,7 +20,7 @@ use diskann_providers::utils::{ }; use diskann_utils::{ io::{read_bin, Metadata}, - matrix::Matrix, + views::Matrix, }; use diskann_vector::{distance::Metric, DistanceFunction}; use itertools::Itertools; diff --git a/diskann-utils/Cargo.toml b/diskann-utils/Cargo.toml index ea358601e..283849c2a 100644 --- a/diskann-utils/Cargo.toml +++ b/diskann-utils/Cargo.toml @@ -32,6 +32,7 @@ workspace = true cfg-if.workspace = true rand.workspace = true rstest.workspace = true +trybuild = "1.0.101" [features] diff --git a/diskann-utils/src/io.rs b/diskann-utils/src/io.rs index d3508bc85..0ac45b03f 100644 --- a/diskann-utils/src/io.rs +++ b/diskann-utils/src/io.rs @@ -16,7 +16,7 @@ use std::io::{Read, Seek, Write}; use diskann_wide::{LoHi, SplitJoin}; use thiserror::Error; -use crate::matrix::{Matrix, MatrixView}; +use crate::views::{Matrix, MatrixView}; /// Read a matrix of `T` from the DiskANN binary format (see [module docs](self)). /// @@ -209,7 +209,7 @@ pub enum SaveBinError { mod tests { use std::io::Cursor; - use crate::matrix::Init; + use crate::views::Init; use super::*; diff --git a/diskann-utils/src/lib.rs b/diskann-utils/src/lib.rs index 450211e29..1f94e7adb 100644 --- a/diskann-utils/src/lib.rs +++ b/diskann-utils/src/lib.rs @@ -20,7 +20,7 @@ pub mod sampling; pub mod strided; -pub mod matrix; +pub mod views; mod lazystring; pub use lazystring::LazyString; diff --git a/diskann-utils/src/sampling/latin_hypercube.rs b/diskann-utils/src/sampling/latin_hypercube.rs index 03d227471..3318d3b7f 100644 --- a/diskann-utils/src/sampling/latin_hypercube.rs +++ b/diskann-utils/src/sampling/latin_hypercube.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use crate::matrix::{Matrix, MatrixView}; +use crate::views::{Matrix, MatrixView}; use rand::{rngs::StdRng, Rng, SeedableRng}; /// Return multiple rows sampled using Latin Hypercube Sampling in `data` that aproximetely uniformly distributed. @@ -67,7 +67,7 @@ impl SampleLatinHyperCube for T { mod tests { use std::fmt::Display; - use crate::matrix::{Init, Matrix}; + use crate::views::{Init, Matrix}; use diskann_vector::conversion::CastFromSlice; use half::f16; use rand::{ diff --git a/diskann-utils/src/sampling/medoid.rs b/diskann-utils/src/sampling/medoid.rs index 9b98a8f6e..a4a537fe9 100644 --- a/diskann-utils/src/sampling/medoid.rs +++ b/diskann-utils/src/sampling/medoid.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use crate::matrix::MatrixView; +use crate::views::MatrixView; use diskann_vector::{conversion::CastFromSlice, distance::SquaredL2, PureDistanceFunction}; use half::f16; @@ -161,7 +161,7 @@ impl ComputeMedoid for i8 { #[cfg(test)] mod tests { - use crate::matrix::{Init, Matrix}; + use crate::views::{Init, Matrix}; use rand::{ distr::{Distribution, StandardUniform}, rngs::StdRng, diff --git a/diskann-utils/src/strided.rs b/diskann-utils/src/strided.rs index 8d83a58f0..30a9f89ab 100644 --- a/diskann-utils/src/strided.rs +++ b/diskann-utils/src/strided.rs @@ -9,11 +9,11 @@ use std::{ }; use thiserror::Error; -use crate::matrix::{DenseData, MutDenseData}; +use crate::views::{DenseData, MatMut, MatRef, MutDenseData, RowMajor}; /// A row-major strided matrix. /// -/// This is a generalization of the dense [`Matrix`](crate::matrix::Matrix) type as it does not mandate a dense +/// This is a generalization of the dense [`Matrix`](crate::views::Matrix) type as it does not mandate a dense /// layout in memory. /// /// ```text @@ -497,11 +497,11 @@ where } } -impl<'a, T> From>> for StridedBase<&'a [T]> { - fn from(m: crate::matrix::MatRef<'a, crate::matrix::RowMajor>) -> Self { +impl<'a, T> From>> for StridedBase<&'a [T]> { + fn from(m: MatRef<'a, RowMajor>) -> Self { let (nrows, ncols) = (m.nrows(), m.ncols()); Self { - data: m.as_slice(), + data: m.into(), nrows, ncols, cstride: ncols, @@ -509,17 +509,11 @@ impl<'a, T> From>> for Stri } } -impl<'a, T> From>> - for StridedBase<&'a mut [T]> -{ - fn from(mut m: crate::matrix::MatMut<'a, crate::matrix::RowMajor>) -> Self { +impl<'a, T> From>> for StridedBase<&'a mut [T]> { + fn from(m: MatMut<'a, RowMajor>) -> Self { let (nrows, ncols) = (m.nrows(), m.ncols()); - let ptr = m.as_mut_slice().as_mut_ptr(); - // SAFETY: `m` owns an exclusive `&'a mut` borrow of `nrows * ncols` contiguous `T`; - // consuming `m` (a non-owning view with no `Drop`) transfers that borrow here. - let data: &'a mut [T] = unsafe { std::slice::from_raw_parts_mut(ptr, nrows * ncols) }; Self { - data, + data: m.into(), nrows, ncols, cstride: ncols, @@ -530,7 +524,7 @@ impl<'a, T> From>> #[cfg(test)] mod tests { use super::*; - use crate::matrix; + use crate::views; #[test] fn test_linear_length() { @@ -601,7 +595,7 @@ mod tests { } // Test that the contents of `dut` match those in the dense 2d matrix. - fn test_indexing(dut: StridedView<'_, usize>, expected: matrix::MatrixView<'_, usize>) { + fn test_indexing(dut: StridedView<'_, usize>, expected: views::MatrixView<'_, usize>) { assert_eq!(dut.nrows(), expected.nrows()); assert_eq!(dut.ncols(), expected.ncols()); @@ -641,10 +635,10 @@ mod tests { // 2*ncols 2*ncols+1 2*ncols+2 ... 3*ncols-1 // ... // ``` - fn create_test_matrix(nrows: usize, ncols: usize) -> matrix::Matrix { + fn create_test_matrix(nrows: usize, ncols: usize) -> views::Matrix { let mut i = 0; - matrix::Matrix::new( - matrix::Init(|| { + views::Matrix::new( + views::Init(|| { let v = i; i += 1; v @@ -679,7 +673,7 @@ mod tests { assert_eq!(v.as_ptr(), ptr, "base pointer was not preserved"); // Create the expected matrix. - let mut expected = matrix::Matrix::new(0, 5, 2); + let mut expected = views::Matrix::new(0, 5, 2); for row in 0..expected.nrows() { for col in 0..expected.ncols() { expected[(row, col)] = m[(row, col)]; @@ -689,7 +683,7 @@ mod tests { // Create a strided view over the last two columns. let v = StridedView::try_from(&(m.as_slice()[1..]), m.nrows(), 2, m.ncols()).unwrap(); - let mut expected = matrix::Matrix::new(0, 5, 2); + let mut expected = views::Matrix::new(0, 5, 2); for row in 0..expected.nrows() { for col in 0..expected.ncols() { expected[(row, col)] = m[(row, col + 1)]; @@ -705,7 +699,7 @@ mod tests { // Initialize using 2d indexing. { - let mut dst = matrix::Matrix::::new(0, 5, 10); + let mut dst = views::Matrix::::new(0, 5, 10); let ptr = dst.as_ptr(); @@ -735,7 +729,7 @@ mod tests { // Initialize using row-wise indexing. { - let mut dst = matrix::Matrix::::new(0, 5, 10); + let mut dst = views::Matrix::::new(0, 5, 10); let ptr = dst.as_ptr(); @@ -763,7 +757,7 @@ mod tests { // Initialize using row-iterator indexing. { - let mut dst = matrix::Matrix::::new(0, 5, 10); + let mut dst = views::Matrix::::new(0, 5, 10); let offset = 2; // SAFETY: The underlying allocation is valid for much more than 2 elements. @@ -844,7 +838,7 @@ mod tests { #[test] fn test_try_shrink_from() { // Exact is okay. - let m = matrix::Matrix::::new(0, 10, 10); + let m = views::Matrix::::new(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); let s = StridedView::try_shrink_from(m.as_slice(), nrows, ncols, ncols).unwrap(); @@ -868,14 +862,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_shink_from_panics() { - let m = matrix::Matrix::::new(0, 4, 4); + let m = views::Matrix::::new(0, 4, 4); let _ = StridedView::try_shrink_from(m.as_slice(), 2, 2, 1); } #[test] fn test_try_shrink_from_mut() { // Exact is okay. - let mut m = matrix::Matrix::::new(0, 10, 10); + let mut m = views::Matrix::::new(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); @@ -903,14 +897,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_shink_from_mut_panics() { - let mut m = matrix::Matrix::::new(0, 4, 4); + let mut m = views::Matrix::::new(0, 4, 4); let _ = MutStridedView::try_shrink_from_mut(m.as_mut_slice(), 2, 2, 1); } #[test] fn test_try_from() { // Exact is okay. - let m = matrix::Matrix::::new(0, 10, 10); + let m = views::Matrix::::new(0, 10, 10); let nrows = m.nrows(); let ncols = m.ncols(); let s = StridedView::try_from(m.as_slice(), nrows, ncols, ncols).unwrap(); @@ -939,14 +933,14 @@ mod tests { #[test] #[should_panic(expected = "cstride must be greater than or equal to ncols")] fn test_try_frompanics() { - let mut m = matrix::Matrix::::new(0, 4, 4); + let mut m = views::Matrix::::new(0, 4, 4); let _ = MutStridedView::try_from(m.as_mut_slice(), 2, 2, 1); } #[test] #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] fn test_get_row_panics() { - let m = matrix::Matrix::::new(0, 3, 7); + let m = views::Matrix::::new(0, 3, 7); let v: StridedView<_> = m.as_view().into(); v.row(3); } @@ -954,7 +948,7 @@ mod tests { #[test] #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")] fn test_get_row_mut_panics() { - let mut m = matrix::Matrix::::new(0, 3, 7); + let mut m = views::Matrix::::new(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v.row_mut(3); } @@ -962,7 +956,7 @@ mod tests { #[test] #[should_panic(expected = "row 3 is out of bounds (max: 3)")] fn test_index_panics_row() { - let m = matrix::Matrix::::new(0, 3, 7); + let m = views::Matrix::::new(0, 3, 7); let v: StridedView<_> = m.as_view().into(); let _ = v[(3, 2)]; } @@ -970,7 +964,7 @@ mod tests { #[test] #[should_panic(expected = "col 7 is out of bounds (max: 7)")] fn test_index_panics_col() { - let m = matrix::Matrix::::new(0, 3, 7); + let m = views::Matrix::::new(0, 3, 7); let v: StridedView<_> = m.as_view().into(); let _ = v[(2, 7)]; } @@ -978,7 +972,7 @@ mod tests { #[test] #[should_panic(expected = "row 3 is out of bounds (max: 3)")] fn test_index_mut_panics_row() { - let mut m = matrix::Matrix::::new(0, 3, 7); + let mut m = views::Matrix::::new(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v[(3, 2)] = 1; } @@ -986,7 +980,7 @@ mod tests { #[test] #[should_panic(expected = "col 7 is out of bounds (max: 7)")] fn test_index_mut_panics_col() { - let mut m = matrix::Matrix::::new(0, 3, 7); + let mut m = views::Matrix::::new(0, 3, 7); let mut v: MutStridedView<_> = m.as_mut_view().into(); v[(2, 7)] = 1; } diff --git a/diskann-utils/src/matrix.rs b/diskann-utils/src/views.rs similarity index 82% rename from diskann-utils/src/matrix.rs rename to diskann-utils/src/views.rs index 67f5422d3..b1f76d36a 100644 --- a/diskann-utils/src/matrix.rs +++ b/diskann-utils/src/views.rs @@ -248,18 +248,23 @@ pub unsafe trait NewOwned: ReprOwned { fn new_owned(self, init: T) -> Result, Self::Error>; } -/// An initializer argument to [`NewOwned`] that uses a type's [`Default`] implementation -/// to initialize a matrix. +/// Create a new [`Mat`] with every element default-initialized. /// -/// ```rust -/// use diskann_utils::matrix::{Mat, RowMajor, Defaulted}; -/// let mat = Mat::from_repr(RowMajor::::new(4, 3).unwrap(), Defaulted).unwrap(); -/// for i in 0..4 { -/// assert!(mat.get_row(i).unwrap().iter().all(|&x| x == 0.0f32)); -/// } -/// ``` -#[derive(Debug, Clone, Copy)] -pub struct Defaulted; +/// This is a distinct trait from [`NewOwned`] (rather than a `NewOwned`) so that a repr +/// can offer both a value-fill and a default-fill constructor without the two impls overlapping +/// under coherence. +/// +/// # Safety +/// +/// Implementations must ensure that the returned [`Mat`] is compatible with +/// `Self`'s implementation of [`ReprOwned`]. +pub unsafe trait NewDefault: ReprOwned { + /// Errors that can occur when initializing. + type Error; + + /// Create a new [`Mat`] with each element set to its [`Default`]. + fn new_default(self) -> Result, Self::Error>; +} /// Create a new [`Mat`] cloned from a view. pub trait NewCloned: ReprOwned { @@ -537,12 +542,12 @@ where // SAFETY: The implementation uses guarantees from `Box` to ensure that the pointer // initialized by it is non-null and properly aligned to the underlying type. -unsafe impl NewOwned for RowMajor +unsafe impl NewDefault for RowMajor where T: Default, { type Error = std::convert::Infallible; - fn new_owned(self, _: Defaulted) -> Result, Self::Error> { + fn new_default(self) -> Result, Self::Error> { let b: Box<[T]> = std::iter::repeat_with(T::default) .take(self.num_elements()) .collect(); @@ -624,6 +629,22 @@ impl Mat { repr.new_owned(init) } + /// Create a new matrix with every element default-initialized. + /// + /// ```rust + /// use diskann_utils::views::{Mat, RowMajor}; + /// let mat = Mat::from_default(RowMajor::::new(4, 3).unwrap()).unwrap(); + /// for i in 0..4 { + /// assert!(mat.get_row(i).unwrap().iter().all(|&x| x == 0.0f32)); + /// } + /// ``` + pub fn from_default(repr: T) -> Result::Error> + where + T: NewDefault, + { + repr.new_default() + } + /// Returns the number of rows (vectors) in the matrix. #[inline] pub fn num_vectors(&self) -> usize { @@ -648,6 +669,8 @@ impl Mat { } } + /// Returns the `i`th row without bounds checking. + /// /// # Safety /// /// `i` must be less than `self.num_vectors()`. @@ -746,6 +769,31 @@ impl Clone for Mat { } } +// Delegation macro for the dense (`RowMajor`) read API. The canonical read +// implementations live once on `MatRef<'_, RowMajor>` (`MatrixView`); the +// owning `Mat` and the mutable view forward to them through `self.as_view()`, so +// each method has a single body. Mirrors the `delegate_to_ref!` pattern used by +// `diskann-quantization`'s block-transposed layout. +macro_rules! delegate_read { + ($(#[$m:meta])* $vis:vis fn $name:ident(&self $(, $a:ident: $t:ty)*) $(-> $r:ty)?) => { + #[doc = "Delegates to the canonical immutable-view implementation."] + $(#[$m])* + #[inline] + $vis fn $name(&self $(, $a: $t)*) $(-> $r)? { + self.as_view().$name($($a),*) + } + }; + ($(#[$m:meta])* unsafe $vis:vis fn $name:ident(&self $(, $a:ident: $t:ty)*) $(-> $r:ty)?) => { + #[doc = "Delegates to the canonical immutable-view implementation."] + $(#[$m])* + #[inline] + $vis unsafe fn $name(&self $(, $a: $t)*) $(-> $r)? { + // SAFETY: the caller upholds the delegated method's safety contract. + unsafe { self.as_view().$name($($a),*) } + } + }; +} + impl Mat> { /// Construct a [`Mat`] by filling each element in row-major order from `gen`. pub fn new>(mut gen: U, nrows: usize, ncols: usize) -> Self { @@ -761,19 +809,8 @@ impl Mat> { self.repr.ncols() } - /// Return the backing data as a contiguous slice of `T`. - /// - /// The returned slice has `num_vectors() * vector_dim()` elements in row-major order. - #[inline] - pub fn as_slice(&self) -> &[T] { - self.as_view().as_slice() - } - - /// Return a [`MatrixView`] over the backing data. - #[inline] - pub fn as_matrix_view(&self) -> MatrixView<'_, T> { - self.as_view().as_matrix_view() - } + delegate_read!(pub fn as_slice(&self) -> &[T]); + delegate_read!(pub fn as_matrix_view(&self) -> MatrixView<'_, T>); } //////////// @@ -838,15 +875,12 @@ impl<'a, T: Repr> MatRef<'a, T> { } } - /// Returns the i-th row without bounds checking. + /// Returns the `i`th row without bounds checking. /// /// # Safety /// /// `i` must be less than `self.num_vectors()`. #[inline] - /// # Safety - /// - /// `i` must be less than `self.num_vectors()`. pub unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> { // SAFETY: Caller must ensure i < self.num_vectors(). unsafe { self.repr.get_row(self.ptr, i) } @@ -899,8 +933,8 @@ impl<'a, T> MatRef<'a, RowMajor> { #[inline] pub fn as_slice(&self) -> &'a [T] { let len = self.repr.num_elements(); - // SAFETY: `RowMajor` guarantees `nrows * ncols` contiguous `T` elements - // starting at `self.ptr`. The lifetime `'a` is tied to the original data. + // SAFETY: `RowMajor` guarantees `nrows * ncols` contiguous `T` elements starting + // at `self.ptr`, valid for the view's lifetime `'a`. unsafe { std::slice::from_raw_parts(self.ptr.as_ptr().cast::(), len) } } @@ -1120,19 +1154,8 @@ impl<'a, T> MatMut<'a, RowMajor> { self.repr.ncols() } - /// Return the backing data as a contiguous slice of `T`. - /// - /// The returned slice has `num_vectors() * vector_dim()` elements in row-major order. - #[inline] - pub fn as_slice(&self) -> &[T] { - self.as_view().as_slice() - } - - /// Return a [`MatrixView`] over the backing data. - #[inline] - pub fn as_matrix_view(&self) -> MatrixView<'_, T> { - self.as_view().as_matrix_view() - } + delegate_read!(pub fn as_slice(&self) -> &[T]); + delegate_read!(pub fn as_matrix_view(&self) -> MatrixView<'_, T>); } ////////////////////////////// @@ -1174,37 +1197,91 @@ pub type MatrixView<'a, T> = MatRef<'a, RowMajor>; /// Mutable dense row-major view. pub type MatrixViewMut<'a, T> = MatMut<'a, RowMajor>; -/// Error returned when a slice length is incompatible with the requested dimensions. +/// A lightweight, `'static` version of [`TryFromError`] that drops the offending data. #[derive(Debug, Error)] +#[non_exhaustive] #[error("cannot view a slice of length {len} as a {nrows}x{ncols} matrix")] -pub struct TryFromError { +pub struct TryFromErrorLight { pub len: usize, pub nrows: usize, pub ncols: usize, } +/// Error returned when a slice length is incompatible with the requested dimensions. +/// +/// Carries the original `data` so a failed construction does not deallocate it; recover it +/// with [`TryFromError::into_inner`]. +#[derive(Error)] +#[non_exhaustive] +#[error("cannot view a slice of length {} as a {nrows}x{ncols} matrix", data.as_slice().len())] +pub struct TryFromError { + data: T, + nrows: usize, + ncols: usize, +} + +// Hand-written so `TryFromError` does not require `T: Debug`. +impl std::fmt::Debug for TryFromError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TryFromError") + .field("data_len", &self.data.as_slice().len()) + .field("nrows", &self.nrows) + .field("ncols", &self.ncols) + .finish() + } +} + +impl TryFromError { + /// Consume the error and return the original data, without deallocating it. + pub fn into_inner(self) -> T { + self.data + } + + /// Return a `'static` copy of this error that drops the offending data. + pub fn as_static(&self) -> TryFromErrorLight { + TryFromErrorLight { + len: self.data.as_slice().len(), + nrows: self.nrows, + ncols: self.ncols, + } + } +} + impl<'a, T> MatRef<'a, RowMajor> { /// View `data` as an `nrows x ncols` matrix. - pub fn try_from(data: &'a [T], nrows: usize, ncols: usize) -> Result { - let err = || TryFromError { - len: data.len(), - nrows, - ncols, + pub fn try_from( + data: &'a [T], + nrows: usize, + ncols: usize, + ) -> Result> { + let repr = match RowMajor::new(nrows, ncols) { + Ok(repr) if repr.num_elements() == data.len() => repr, + _ => return Err(TryFromError { data, nrows, ncols }), }; - let repr = RowMajor::new(nrows, ncols).map_err(|_| err())?; - MatRef::from_repr(repr, data).map_err(|_| err()) + // SAFETY: `data.len()` was checked to equal `repr.num_elements()`. + Ok(unsafe { MatRef::from_raw_parts(repr, as_nonnull(data).cast::()) }) } /// View `data` as a single-row matrix. pub fn row_vector(data: &'a [T]) -> Self { - let ncols = data.len(); - Self::try_from(data, 1, ncols).expect("row vector length") + let repr = RowMajor { + nrows: 1, + ncols: data.len(), + _elem: PhantomData, + }; + // SAFETY: `data` is exactly `1 * data.len()` contiguous `T`, matching `repr`. + unsafe { MatRef::from_raw_parts(repr, as_nonnull(data).cast::()) } } /// View `data` as a single-column matrix. pub fn column_vector(data: &'a [T]) -> Self { - let nrows = data.len(); - Self::try_from(data, nrows, 1).expect("column vector length") + let repr = RowMajor { + nrows: data.len(), + ncols: 1, + _elem: PhantomData, + }; + // SAFETY: `data` is exactly `data.len() * 1` contiguous `T`, matching `repr`. + unsafe { MatRef::from_raw_parts(repr, as_nonnull(data).cast::()) } } /// Number of rows. @@ -1221,8 +1298,16 @@ impl<'a, T> MatRef<'a, RowMajor> { /// Row `i`. Panics if `i >= self.nrows()`. pub fn row(&self, i: usize) -> &'a [T] { + assert!( + i < self.nrows(), + "tried to access row {i} of a matrix with {} rows", + self.nrows() + ); let ncols = self.ncols(); - &self.as_slice()[i * ncols..i * ncols + ncols] + let start = i * ncols; + // SAFETY: `i < self.nrows()` was asserted, and the backing slice holds + // `nrows * ncols` elements, so `start..start + ncols` is in bounds. + unsafe { self.as_slice().get_unchecked(start..start + ncols) } } /// Iterator over rows. @@ -1278,7 +1363,13 @@ impl<'a, T> MatRef<'a, RowMajor> { let lo = rows.start.checked_mul(ncols)?; let hi = rows.end.checked_mul(ncols)?; let data = self.as_slice().get(lo..hi)?; - Some(MatrixView::try_from(data, rows.len(), ncols).expect("exact subview")) + let repr = RowMajor { + nrows: rows.len(), + ncols, + _elem: PhantomData, + }; + // SAFETY: `data` is exactly `rows.len() * ncols` contiguous `T`, matching `repr`. + Some(unsafe { MatRef::from_raw_parts(repr, as_nonnull(data).cast::()) }) } /// Element at `(row, col)`, or `None` if out of bounds. @@ -1286,8 +1377,8 @@ impl<'a, T> MatRef<'a, RowMajor> { if row >= self.nrows() || col >= self.ncols() { None } else { - let ncols = self.ncols(); - self.as_slice().get(row * ncols + col) + // SAFETY: `row` and `col` were just verified in-bounds. + Some(unsafe { self.get_unchecked(row, col) }) } } @@ -1302,17 +1393,29 @@ impl<'a, T> MatRef<'a, RowMajor> { F: FnMut(&T) -> R, { let data: Box<[R]> = self.as_slice().iter().map(f).collect(); - Matrix::try_from(data, self.nrows(), self.ncols()).expect("same shape") + let repr = RowMajor { + nrows: self.nrows(), + ncols: self.ncols(), + _elem: PhantomData, + }; + // SAFETY: `data` has exactly `nrows * ncols` elements (one per source element). + unsafe { repr.box_to_mat(data) } } } impl<'a, T> MatMut<'a, RowMajor> { /// View `data` as an `nrows x ncols` mutable matrix. - pub fn try_from(data: &'a mut [T], nrows: usize, ncols: usize) -> Result { - let len = data.len(); - let err = || TryFromError { len, nrows, ncols }; - let repr = RowMajor::new(nrows, ncols).map_err(|_| err())?; - MatMut::from_repr(repr, data).map_err(|_| err()) + pub fn try_from( + data: &'a mut [T], + nrows: usize, + ncols: usize, + ) -> Result> { + let repr = match RowMajor::new(nrows, ncols) { + Ok(repr) if repr.num_elements() == data.len() => repr, + _ => return Err(TryFromError { data, nrows, ncols }), + }; + // SAFETY: `data.len()` was checked to equal `repr.num_elements()`. + Ok(unsafe { MatMut::from_raw_parts(repr, as_nonnull_mut(data).cast::()) }) } /// Number of rows. @@ -1327,29 +1430,63 @@ impl<'a, T> MatMut<'a, RowMajor> { self.vector_dim() } + // Reads delegate to the canonical `MatrixView` implementation. + delegate_read!(pub fn row(&self, i: usize) -> &[T]); + delegate_read!(pub fn row_iter(&self) -> impl ExactSizeIterator); + delegate_read!(pub fn window_iter(&self, batchsize: usize) -> impl Iterator>); + delegate_read!(pub fn subview(&self, rows: std::ops::Range) -> Option>); + delegate_read!(pub fn try_get(&self, row: usize, col: usize) -> Option<&T>); + delegate_read!(pub fn as_ptr(&self) -> *const T); + + /// Parallel iterator over rows. + #[cfg(feature = "rayon")] + pub fn par_row_iter(&self) -> impl rayon::iter::IndexedParallelIterator + where + T: Sync, + { + self.as_view().par_row_iter() + } + + /// Parallel iterator over sub-matrices of up to `batchsize` rows. + #[cfg(feature = "rayon")] + pub fn par_window_iter( + &self, + batchsize: usize, + ) -> impl rayon::iter::IndexedParallelIterator> + where + T: Send + Sync, + { + self.as_view().par_window_iter(batchsize) + } + + /// Apply `f` to every element, producing a new owned matrix of the same shape. + pub fn map(&self, f: F) -> Matrix + where + F: FnMut(&T) -> R, + { + self.as_view().map(f) + } + /// Backing data as a mutable slice. pub fn as_mut_slice(&mut self) -> &mut [T] { - let len = self.nrows() * self.ncols(); + let len = self.repr.num_elements(); // SAFETY: the backing allocation holds `len` contiguous `T`, and `&mut self` grants // exclusive access for the returned slice's lifetime. unsafe { std::slice::from_raw_parts_mut(self.as_raw_mut_ptr().cast::(), len) } } - /// Row `i`. Panics if `i >= self.nrows()`. - pub fn row(&self, i: usize) -> &[T] { - self.as_view().row(i) - } - - /// Iterator over rows. - pub fn row_iter(&self) -> impl ExactSizeIterator { - let ncols = self.ncols(); - self.as_slice().chunks_exact(ncols) - } - /// Mutable row `i`. Panics if `i >= self.nrows()`. pub fn row_mut(&mut self, i: usize) -> &mut [T] { + assert!( + i < self.nrows(), + "tried to access row {i} of a matrix with {} rows", + self.nrows() + ); let ncols = self.ncols(); - &mut self.as_mut_slice()[i * ncols..i * ncols + ncols] + let start = i * ncols; + // SAFETY: `i < self.nrows()` was asserted, and the backing slice holds + // `nrows * ncols` elements, so `start..start + ncols` is in bounds. + unsafe { self.as_mut_slice().get_unchecked_mut(start..start + ncols) } } /// Iterator over mutable rows. @@ -1369,11 +1506,6 @@ impl<'a, T> MatMut<'a, RowMajor> { self.as_mut_slice().par_chunks_exact_mut(ncols) } - /// Element at `(row, col)`, or `None` if out of bounds. - pub fn try_get(&self, row: usize, col: usize) -> Option<&T> { - self.as_view().try_get(row, col) - } - /// Base pointer of the backing data. pub fn as_mut_ptr(&mut self) -> *mut T { self.as_mut_slice().as_mut_ptr() @@ -1381,24 +1513,15 @@ impl<'a, T> MatMut<'a, RowMajor> { } impl Mat> { - /// Fill a new `nrows x ncols` matrix with clones of `value`. - pub fn filled(value: T, nrows: usize, ncols: usize) -> Self - where - T: Clone, - { - Self::new(value, nrows, ncols) - } - /// Take ownership of `data`, interpreting it as an `nrows x ncols` matrix. - pub fn try_from(data: Box<[T]>, nrows: usize, ncols: usize) -> Result { - let err = TryFromError { - len: data.len(), - nrows, - ncols, - }; + pub fn try_from( + data: Box<[T]>, + nrows: usize, + ncols: usize, + ) -> Result>> { let repr = match RowMajor::new(nrows, ncols) { Ok(repr) if repr.num_elements() == data.len() => repr, - _ => return Err(err), + _ => return Err(TryFromError { data, nrows, ncols }), }; // SAFETY: `data.len()` was checked to equal `repr.num_elements()`. Ok(unsafe { repr.box_to_mat(data) }) @@ -1406,14 +1529,24 @@ impl Mat> { /// Take ownership of `data` as a single-row matrix. pub fn row_vector(data: Box<[T]>) -> Self { - let ncols = data.len(); - Self::try_from(data, 1, ncols).expect("row vector length") + let repr = RowMajor { + nrows: 1, + ncols: data.len(), + _elem: PhantomData, + }; + // SAFETY: `data` has exactly `1 * data.len()` elements matching `repr`. + unsafe { repr.box_to_mat(data) } } /// Take ownership of `data` as a single-column matrix. pub fn column_vector(data: Box<[T]>) -> Self { - let nrows = data.len(); - Self::try_from(data, nrows, 1).expect("column vector length") + let repr = RowMajor { + nrows: data.len(), + ncols: 1, + _elem: PhantomData, + }; + // SAFETY: `data` has exactly `data.len() * 1` elements matching `repr`. + unsafe { repr.box_to_mat(data) } } /// Number of rows. @@ -1428,9 +1561,46 @@ impl Mat> { self.vector_dim() } + // Reads delegate to the canonical `MatrixView` implementation. + delegate_read!(pub fn row(&self, i: usize) -> &[T]); + delegate_read!(pub fn row_iter(&self) -> impl ExactSizeIterator); + delegate_read!(pub fn window_iter(&self, batchsize: usize) -> impl Iterator>); + delegate_read!(pub fn subview(&self, rows: std::ops::Range) -> Option>); + delegate_read!(pub fn try_get(&self, row: usize, col: usize) -> Option<&T>); + delegate_read!(pub fn as_ptr(&self) -> *const T); + + /// Parallel iterator over rows. + #[cfg(feature = "rayon")] + pub fn par_row_iter(&self) -> impl rayon::iter::IndexedParallelIterator + where + T: Sync, + { + self.as_view().par_row_iter() + } + + /// Parallel iterator over sub-matrices of up to `batchsize` rows. + #[cfg(feature = "rayon")] + pub fn par_window_iter( + &self, + batchsize: usize, + ) -> impl rayon::iter::IndexedParallelIterator> + where + T: Send + Sync, + { + self.as_view().par_window_iter(batchsize) + } + + /// Apply `f` to every element, producing a new owned matrix of the same shape. + pub fn map(&self, f: F) -> Matrix + where + F: FnMut(&T) -> R, + { + self.as_view().map(f) + } + /// Backing data as a mutable slice. pub fn as_mut_slice(&mut self) -> &mut [T] { - let len = self.nrows() * self.ncols(); + let len = self.repr.num_elements(); // SAFETY: the backing allocation holds `len` contiguous `T`, and `&mut self` grants // exclusive access for the returned slice's lifetime. unsafe { std::slice::from_raw_parts_mut(self.as_raw_mut_ptr().cast::(), len) } @@ -1441,21 +1611,18 @@ impl Mat> { self.as_view_mut() } - /// Row `i`. Panics if `i >= self.nrows()`. - pub fn row(&self, i: usize) -> &[T] { - self.as_view().row(i) - } - - /// Iterator over rows. - pub fn row_iter(&self) -> impl ExactSizeIterator { - let ncols = self.ncols(); - self.as_slice().chunks_exact(ncols) - } - /// Mutable row `i`. Panics if `i >= self.nrows()`. pub fn row_mut(&mut self, i: usize) -> &mut [T] { + assert!( + i < self.nrows(), + "tried to access row {i} of a matrix with {} rows", + self.nrows() + ); let ncols = self.ncols(); - &mut self.as_mut_slice()[i * ncols..i * ncols + ncols] + let start = i * ncols; + // SAFETY: `i < self.nrows()` was asserted, and the backing slice holds + // `nrows * ncols` elements, so `start..start + ncols` is in bounds. + unsafe { self.as_mut_slice().get_unchecked_mut(start..start + ncols) } } /// Iterator over mutable rows. @@ -1464,26 +1631,6 @@ impl Mat> { self.as_mut_slice().chunks_exact_mut(ncols) } - /// Iterator over sub-matrices of up to `batchsize` rows. - pub fn window_iter(&self, batchsize: usize) -> impl Iterator> { - assert!(batchsize != 0, "window_iter batchsize cannot be zero"); - let ncols = self.ncols(); - self.as_slice() - .chunks(ncols * batchsize) - .map(move |d| MatrixView::try_from(d, d.len() / ncols, ncols).expect("exact chunk")) - } - - /// Parallel iterator over rows. - #[cfg(feature = "rayon")] - pub fn par_row_iter(&self) -> impl rayon::iter::IndexedParallelIterator - where - T: Sync, - { - use rayon::slice::ParallelSlice; - let ncols = self.ncols(); - self.as_slice().par_chunks_exact(ncols) - } - /// Parallel iterator over mutable rows. #[cfg(feature = "rayon")] pub fn par_row_iter_mut(&mut self) -> impl rayon::iter::IndexedParallelIterator @@ -1495,23 +1642,6 @@ impl Mat> { self.as_mut_slice().par_chunks_exact_mut(ncols) } - /// Parallel iterator over sub-matrices of up to `batchsize` rows. - #[cfg(feature = "rayon")] - pub fn par_window_iter( - &self, - batchsize: usize, - ) -> impl rayon::iter::IndexedParallelIterator> - where - T: Send + Sync, - { - use rayon::slice::ParallelSlice; - assert!(batchsize != 0, "par_window_iter batchsize cannot be zero"); - let ncols = self.ncols(); - self.as_slice() - .par_chunks(ncols * batchsize) - .map(move |d| MatrixView::try_from(d, d.len() / ncols, ncols).expect("exact chunk")) - } - /// Parallel iterator over mutable sub-matrices of up to `batchsize` rows. #[cfg(feature = "rayon")] pub fn par_window_iter_mut( @@ -1535,33 +1665,10 @@ impl Mat> { }) } - /// View of the rows in `rows`, or `None` if out of bounds. - pub fn subview(&self, rows: std::ops::Range) -> Option> { - self.as_view().subview(rows) - } - - /// Element at `(row, col)`, or `None` if out of bounds. - pub fn try_get(&self, row: usize, col: usize) -> Option<&T> { - self.as_view().try_get(row, col) - } - - /// Base pointer of the backing data. - pub fn as_ptr(&self) -> *const T { - self.as_slice().as_ptr() - } - /// Mutable base pointer of the backing data. pub fn as_mut_ptr(&mut self) -> *mut T { self.as_mut_slice().as_mut_ptr() } - - /// Apply `f` to every element, producing a new owned matrix of the same shape. - pub fn map(&self, f: F) -> Matrix - where - F: FnMut(&T) -> R, - { - self.as_view().map(f) - } } // Indexing by `(row, col)`. @@ -1574,9 +1681,12 @@ impl std::ops::Index<(usize, usize)> for Mat> { impl std::ops::IndexMut<(usize, usize)> for Mat> { fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T { - let ncols = self.ncols(); - assert!(row < self.nrows() && col < ncols, "index out of bounds"); - &mut self.as_mut_slice()[row * ncols + col] + assert!( + row < self.nrows() && col < self.ncols(), + "index out of bounds" + ); + // SAFETY: `row` and `col` were checked in-bounds above. + unsafe { self.get_unchecked_mut(row, col) } } } @@ -1596,28 +1706,37 @@ impl std::ops::Index<(usize, usize)> for MatMut<'_, RowMajor> { impl std::ops::IndexMut<(usize, usize)> for MatMut<'_, RowMajor> { fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T { - let ncols = self.ncols(); - assert!(row < self.nrows() && col < ncols, "index out of bounds"); - &mut self.as_mut_slice()[row * ncols + col] + assert!( + row < self.nrows() && col < self.ncols(), + "index out of bounds" + ); + // SAFETY: `row` and `col` were checked in-bounds above. + unsafe { self.get_unchecked_mut(row, col) } } } // Equality compares shape and contents. impl PartialEq for Mat> { fn eq(&self, other: &Self) -> bool { - self.ncols() == other.ncols() && self.as_slice() == other.as_slice() + self.nrows() == other.nrows() + && self.ncols() == other.ncols() + && self.as_slice() == other.as_slice() } } impl PartialEq for MatRef<'_, RowMajor> { fn eq(&self, other: &Self) -> bool { - self.ncols() == other.ncols() && self.as_slice() == other.as_slice() + self.nrows() == other.nrows() + && self.ncols() == other.ncols() + && self.as_slice() == other.as_slice() } } impl PartialEq for MatMut<'_, RowMajor> { fn eq(&self, other: &Self) -> bool { - self.ncols() == other.ncols() && self.as_slice() == other.as_slice() + self.nrows() == other.nrows() + && self.ncols() == other.ncols() + && self.as_slice() == other.as_slice() } } @@ -1632,6 +1751,8 @@ impl<'a, T> MatRef<'a, RowMajor> { /// # Safety /// `row < self.nrows()` and `col < self.ncols()`. pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &'a T { + debug_assert!(row < self.nrows()); + debug_assert!(col < self.ncols()); let ncols = self.ncols(); // SAFETY: guaranteed in-bounds by the caller. unsafe { self.as_slice().get_unchecked(row * ncols + col) } @@ -1644,14 +1765,13 @@ impl<'a, T> MatMut<'a, RowMajor> { self.reborrow_mut() } - /// Element at `(row, col)` without bounds checking. - /// - /// # Safety - /// `row < self.nrows()` and `col < self.ncols()`. - pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T { - // SAFETY: guaranteed in-bounds by the caller. - unsafe { self.as_view().get_unchecked(row, col) } - } + delegate_read!( + /// Element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + unsafe pub fn get_unchecked(&self, row: usize, col: usize) -> &T + ); /// Mutable element at `(row, col)` without bounds checking. /// @@ -1688,14 +1808,13 @@ impl<'a, T> MatMut<'a, RowMajor> { } impl Mat> { - /// Element at `(row, col)` without bounds checking. - /// - /// # Safety - /// `row < self.nrows()` and `col < self.ncols()`. - pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T { - // SAFETY: guaranteed in-bounds by the caller. - unsafe { self.as_view().get_unchecked(row, col) } - } + delegate_read!( + /// Element at `(row, col)` without bounds checking. + /// + /// # Safety + /// `row < self.nrows()` and `col < self.ncols()`. + unsafe pub fn get_unchecked(&self, row: usize, col: usize) -> &T + ); /// Mutable element at `(row, col)` without bounds checking. /// @@ -1709,9 +1828,9 @@ impl Mat> { /// Consume the matrix, returning its backing storage as a `Box<[T]>`. pub fn into_inner(self) -> Box<[T]> { - let len = self.nrows() * self.ncols(); let this = core::mem::ManuallyDrop::new(self); - let ptr = this.as_raw_ptr().cast::().cast_mut(); + let slice = this.as_slice(); + let (ptr, len) = (slice.as_ptr().cast_mut(), slice.len()); // SAFETY: the matrix is backed by a `Box<[T]>` of `len` elements (see // `RowMajor::box_to_mat`); `ManuallyDrop` prevents a double free via `Mat`'s `Drop`. unsafe { Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr, len)) } @@ -1725,6 +1844,15 @@ impl<'a, T> From>> for &'a [T] { } } +// A dense mutable view converts directly to its backing slice. +impl<'a, T> From>> for &'a mut [T] { + fn from(m: MatMut<'a, RowMajor>) -> Self { + let len = m.repr.num_elements(); + // SAFETY: `m: MatMut<'a, RowMajor>` exclusively views `len` contiguous `T` valid for `'a`. + unsafe { std::slice::from_raw_parts_mut(m.ptr.as_ptr().cast::(), len) } + } +} + ////////// // Rows // ////////// @@ -2215,6 +2343,24 @@ mod tests { assert!(zst_msg.contains("usize::MAX"), "{zst_msg}"); } + #[test] + fn try_from_error_recovers_owned_data() { + // A failed owned `try_from` must hand the `Box` back, not deallocate it. + let data: Box<[i32]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); + let err = Mat::try_from(data, 4, 4).unwrap_err(); + assert_eq!(&*err.into_inner(), &[1, 2, 3, 4, 5, 6]); + } + + #[test] + fn eq_distinguishes_row_count_for_zero_columns() { + // With zero columns the backing slice is empty for any row count, so equality + // must compare the row count too: a 5x0 and a 3x0 matrix are not equal. + let a = Mat::from_repr(RowMajor::::new(5, 0).unwrap(), 0).unwrap(); + let b = Mat::from_repr(RowMajor::::new(3, 0).unwrap(), 0).unwrap(); + assert!(a != b); + assert!(a == Mat::from_repr(RowMajor::::new(5, 0).unwrap(), 0).unwrap()); + } + ///////// // Mat // ///////// @@ -2243,7 +2389,7 @@ mod tests { #[test] fn mat_new_with_default() { - let mat = Mat::from_repr(RowMajor::::new(2, 3).unwrap(), Defaulted).unwrap(); + let mat = Mat::from_default(RowMajor::::new(2, 3).unwrap()).unwrap(); let base: *const u8 = mat.as_raw_ptr(); assert_eq!(mat.num_vectors(), 2); @@ -2271,7 +2417,7 @@ mod tests { // Populate the matrix using `&mut Mat` { let ctx = &lazy_format!("{ctx} - direct"); - let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); + let mut mat = Mat::from_default(repr).unwrap(); assert_eq!(mat.num_vectors(), *nrows); assert_eq!(mat.vector_dim(), *ncols); @@ -2291,7 +2437,7 @@ mod tests { // Populate the matrix using `MatMut` { let ctx = &lazy_format!("{ctx} - matmut"); - let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); + let mut mat = Mat::from_default(repr).unwrap(); let matmut = mat.reborrow_mut(); assert_eq!(matmut.num_vectors(), *nrows); @@ -2308,7 +2454,7 @@ mod tests { // Populate the matrix using `RowsMut` { let ctx = &lazy_format!("{ctx} - rows_mut"); - let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); + let mut mat = Mat::from_default(repr).unwrap(); fill_rows_mut(mat.rows_mut(), repr); check_mat(&mat, repr, ctx); @@ -2327,7 +2473,7 @@ mod tests { let repr = RowMajor::::new(*nrows, *ncols).unwrap(); let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols); - let mut mat = Mat::from_repr(repr, Defaulted).unwrap(); + let mut mat = Mat::from_default(repr).unwrap(); fill_mat(&mut mat, repr); // Clone via Mat::clone @@ -2608,8 +2754,8 @@ mod tests { assert_eq!(filled.num_vectors(), 2); assert!(filled.rows().flatten().all(|s| s == "x")); - // NewOwned (Clone + Default). - let defaulted = Mat::from_repr(repr, Defaulted).unwrap(); + // NewDefault (Default). + let defaulted = Mat::from_default(repr).unwrap(); assert!(defaulted.rows().flatten().all(String::is_empty)); // from_fn. @@ -2646,4 +2792,81 @@ mod tests { view_mut.get_row_mut(0).unwrap()[1] = String::from("z"); assert_eq!(data_mut[1], "z"); } + + // ── Dense read API (canonical on `MatrixView`, delegated by `Matrix`/`MatrixViewMut`) ── + + #[test] + fn dense_subview_and_try_get() { + let m: Matrix = + Matrix::try_from(vec![1, 2, 3, 4, 5, 6].into_boxed_slice(), 3, 2).unwrap(); + let sv = m.subview(1..3).unwrap(); + assert_eq!((sv.nrows(), sv.ncols()), (2, 2)); + assert_eq!(sv.row(0), &[3, 4]); + assert_eq!(sv.row(1), &[5, 6]); + assert!(m.subview(2..4).is_none()); + assert_eq!(m.try_get(2, 1), Some(&6)); + assert!(m.try_get(3, 0).is_none()); + assert!(m.try_get(0, 2).is_none()); + } + + #[test] + fn dense_map_and_vectors() { + let m: Matrix = Matrix::try_from(vec![1, 2, 3, 4].into_boxed_slice(), 2, 2).unwrap(); + let doubled = m.map(|&x| x * 2); + assert_eq!(doubled.as_slice(), &[2, 4, 6, 8]); + assert_eq!((doubled.nrows(), doubled.ncols()), (2, 2)); + + let rv = Matrix::row_vector(vec![7, 8, 9].into_boxed_slice()); + assert_eq!((rv.nrows(), rv.ncols()), (1, 3)); + let cv = Matrix::column_vector(vec![7, 8, 9].into_boxed_slice()); + assert_eq!((cv.nrows(), cv.ncols()), (3, 1)); + } + + #[test] + fn dense_window_iter_batches_and_remainder() { + let m: Matrix = + Matrix::try_from((0..9).collect::>().into_boxed_slice(), 3, 3).unwrap(); + let rows: Vec<_> = m.window_iter(2).map(|w| w.nrows()).collect(); + assert_eq!(rows, vec![2, 1]); + } + + #[test] + #[should_panic(expected = "window_iter batchsize cannot be zero")] + fn dense_window_iter_zero_panics() { + let m: Matrix = Matrix::try_from(vec![1, 2].into_boxed_slice(), 1, 2).unwrap(); + let _ = m.window_iter(0).count(); + } + + #[test] + #[should_panic(expected = "tried to access row 5 of a matrix with 1 rows")] + fn dense_row_out_of_bounds_panics() { + let m: Matrix = Matrix::try_from(vec![1, 2].into_boxed_slice(), 1, 2).unwrap(); + let _ = m.row(5); + } + + #[test] + fn dense_get_unchecked_reads_and_writes() { + let mut m: Matrix = + Matrix::try_from(vec![1, 2, 3, 4].into_boxed_slice(), 2, 2).unwrap(); + // SAFETY: `(1, 1)` is in bounds for a 2x2 matrix. + assert_eq!(unsafe { *m.get_unchecked(1, 1) }, 4); + // SAFETY: `(0, 0)` is in bounds. + unsafe { *m.get_unchecked_mut(0, 0) = 9 }; + assert_eq!(m.as_slice(), &[9, 2, 3, 4]); + } + + #[test] + fn dense_reads_delegate_consistently() { + let mut m: Matrix = + Matrix::try_from(vec![1, 2, 3, 4, 5, 6].into_boxed_slice(), 3, 2).unwrap(); + let owned = m.row(1).to_vec(); + let via_view = m.as_view().row(1).to_vec(); + let via_mut_view = m.as_mut_view().row(1).to_vec(); + assert_eq!(owned, &[3, 4]); + assert_eq!(owned, via_view); + assert_eq!(owned, via_mut_view); + // The mutable view exposes the full read set (subview/window_iter/as_ptr/...). + assert!(m.as_mut_view().subview(0..1).is_some()); + assert_eq!(m.as_mut_view().window_iter(2).count(), 2); + } } diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs b/diskann-utils/tests/compile-fail/mat_as_view.rs similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_as_view.rs rename to diskann-utils/tests/compile-fail/mat_as_view.rs index 0a96679ec..58fa66291 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view.rs +++ b/diskann-utils/tests/compile-fail/mat_as_view.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Test that `as_view` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the view is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view.stderr b/diskann-utils/tests/compile-fail/mat_as_view.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_as_view.stderr rename to diskann-utils/tests/compile-fail/mat_as_view.stderr index d63e03325..84deb9546 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view.stderr +++ b/diskann-utils/tests/compile-fail/mat_as_view.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/mat_as_view.rs:14:13 + --> tests/compile-fail/mat_as_view.rs:14:13 | 12 | let view = mat.as_view(); | --- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs b/diskann-utils/tests/compile-fail/mat_as_view_mut.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs rename to diskann-utils/tests/compile-fail/mat_as_view_mut.rs index bc245355b..4858d17ea 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.rs +++ b/diskann-utils/tests/compile-fail/mat_as_view_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Test that `as_view_mut` on Mat correctly captures a mutable lifetime, // preventing the Mat from being used while the mutable view is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.stderr b/diskann-utils/tests/compile-fail/mat_as_view_mut.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.stderr rename to diskann-utils/tests/compile-fail/mat_as_view_mut.stderr index cf5432eed..7d1a37d8a 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_as_view_mut.stderr +++ b/diskann-utils/tests/compile-fail/mat_as_view_mut.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as immutable because it is also borrowed as mutable - --> tests/compile-fail/multi/mat_as_view_mut.rs:14:13 + --> tests/compile-fail/mat_as_view_mut.rs:14:13 | 12 | let view = mat.as_view_mut(); | --- mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs b/diskann-utils/tests/compile-fail/mat_get_row.rs similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_get_row.rs rename to diskann-utils/tests/compile-fail/mat_get_row.rs index e971c49de..e37a7d058 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row.rs +++ b/diskann-utils/tests/compile-fail/mat_get_row.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Test that `get_row` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the row is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row.stderr b/diskann-utils/tests/compile-fail/mat_get_row.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_get_row.stderr rename to diskann-utils/tests/compile-fail/mat_get_row.stderr index 005e16421..d3e944b9b 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row.stderr +++ b/diskann-utils/tests/compile-fail/mat_get_row.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/mat_get_row.rs:14:13 + --> tests/compile-fail/mat_get_row.rs:14:13 | 12 | let row = mat.get_row(0).unwrap(); | --- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs b/diskann-utils/tests/compile-fail/mat_get_row_mut.rs similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs rename to diskann-utils/tests/compile-fail/mat_get_row_mut.rs index 81324d52a..9f1a1f5aa 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.rs +++ b/diskann-utils/tests/compile-fail/mat_get_row_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Test that `get_row_mut` on Mat correctly captures a mutable // lifetime, preventing the Mat from being used while the row is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.stderr b/diskann-utils/tests/compile-fail/mat_get_row_mut.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.stderr rename to diskann-utils/tests/compile-fail/mat_get_row_mut.stderr index 48640670e..0b8aa65e9 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_get_row_mut.stderr +++ b/diskann-utils/tests/compile-fail/mat_get_row_mut.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as immutable because it is also borrowed as mutable - --> tests/compile-fail/multi/mat_get_row_mut.rs:14:13 + --> tests/compile-fail/mat_get_row_mut.rs:14:13 | 12 | let row = mat.get_row_mut(0).unwrap(); | --- mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs b/diskann-utils/tests/compile-fail/mat_invariant.rs similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_invariant.rs rename to diskann-utils/tests/compile-fail/mat_invariant.rs index 3e06b4be2..bdc7e1c4c 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_invariant.rs +++ b/diskann-utils/tests/compile-fail/mat_invariant.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Verify that `Mat` is invariant in any generic parameters. // diff --git a/diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr b/diskann-utils/tests/compile-fail/mat_invariant.stderr similarity index 93% rename from diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr rename to diskann-utils/tests/compile-fail/mat_invariant.stderr index 69edbb050..d3531694e 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_invariant.stderr +++ b/diskann-utils/tests/compile-fail/mat_invariant.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> tests/compile-fail/multi/mat_invariant.rs:16:5 + --> tests/compile-fail/mat_invariant.rs:16:5 | 12 | fn bad<'long, 'short>(v: Mat>) -> Mat> | ----- ------ lifetime `'short` defined here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs b/diskann-utils/tests/compile-fail/mat_reborrow.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs rename to diskann-utils/tests/compile-fail/mat_reborrow.rs index 000ea234a..55fe80a39 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.rs +++ b/diskann-utils/tests/compile-fail/mat_reborrow.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; use diskann_utils::Reborrow; // Test that `reborrow` on Mat correctly captures an immutable borrow, diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.stderr b/diskann-utils/tests/compile-fail/mat_reborrow.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_reborrow.stderr rename to diskann-utils/tests/compile-fail/mat_reborrow.stderr index 602a8412f..3c7058031 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow.stderr +++ b/diskann-utils/tests/compile-fail/mat_reborrow.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/mat_reborrow.rs:15:13 + --> tests/compile-fail/mat_reborrow.rs:15:13 | 13 | let view = mat.reborrow(); | --- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs b/diskann-utils/tests/compile-fail/mat_reborrow_mut.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs rename to diskann-utils/tests/compile-fail/mat_reborrow_mut.rs index ca1bef597..c734dd32c 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.rs +++ b/diskann-utils/tests/compile-fail/mat_reborrow_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; use diskann_utils::ReborrowMut; // Test that `reborrow_mut` on Mat correctly captures a mutable borrow, diff --git a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.stderr b/diskann-utils/tests/compile-fail/mat_reborrow_mut.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.stderr rename to diskann-utils/tests/compile-fail/mat_reborrow_mut.stderr index 14f5e1cf6..f1f3a95ec 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_reborrow_mut.stderr +++ b/diskann-utils/tests/compile-fail/mat_reborrow_mut.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as immutable because it is also borrowed as mutable - --> tests/compile-fail/multi/mat_reborrow_mut.rs:15:13 + --> tests/compile-fail/mat_reborrow_mut.rs:15:13 | 13 | let view = mat.reborrow_mut(); | --- mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows.rs b/diskann-utils/tests/compile-fail/mat_rows.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/mat_rows.rs rename to diskann-utils/tests/compile-fail/mat_rows.rs index 5085022f6..c968bb37d 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows.rs +++ b/diskann-utils/tests/compile-fail/mat_rows.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Test that `rows` on Mat correctly captures an immutable borrow, // preventing mutation of the Mat while the iterator is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows.stderr b/diskann-utils/tests/compile-fail/mat_rows.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_rows.stderr rename to diskann-utils/tests/compile-fail/mat_rows.stderr index 6f6e1420d..422a6683c 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows.stderr +++ b/diskann-utils/tests/compile-fail/mat_rows.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/mat_rows.rs:14:13 + --> tests/compile-fail/mat_rows.rs:14:13 | 12 | let iter = mat.rows(); | --- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs b/diskann-utils/tests/compile-fail/mat_rows_mut.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs rename to diskann-utils/tests/compile-fail/mat_rows_mut.rs index 80a786c18..09ea4eb73 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.rs +++ b/diskann-utils/tests/compile-fail/mat_rows_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, RowMajor}; +use diskann_utils::views::{Mat, RowMajor}; // Test that the `rows_mut` iterator correctly captures a mutable lifetime, // preventing the Mat from being used while the iterator is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.stderr b/diskann-utils/tests/compile-fail/mat_rows_mut.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/mat_rows_mut.stderr rename to diskann-utils/tests/compile-fail/mat_rows_mut.stderr index 30e04d6b5..bc2e12fc6 100644 --- a/diskann-quantization/tests/compile-fail/multi/mat_rows_mut.stderr +++ b/diskann-utils/tests/compile-fail/mat_rows_mut.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as immutable because it is also borrowed as mutable - --> tests/compile-fail/multi/mat_rows_mut.rs:14:13 + --> tests/compile-fail/mat_rows_mut.rs:14:13 | 12 | let iter = mat.rows_mut(); | --- mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs b/diskann-utils/tests/compile-fail/matmut_as_view_borrows.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs rename to diskann-utils/tests/compile-fail/matmut_as_view_borrows.rs index 101cd95b4..f1cac56f5 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.rs +++ b/diskann-utils/tests/compile-fail/matmut_as_view_borrows.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; // Test that `as_view` on MatMut correctly captures an immutable lifetime, // preventing mutating the MatMut while the immutable view is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.stderr b/diskann-utils/tests/compile-fail/matmut_as_view_borrows.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.stderr rename to diskann-utils/tests/compile-fail/matmut_as_view_borrows.stderr index 3a6a2933b..3c49c90b5 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_as_view_borrows.stderr +++ b/diskann-utils/tests/compile-fail/matmut_as_view_borrows.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `view` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/matmut_as_view_borrows.rs:15:13 + --> tests/compile-fail/matmut_as_view_borrows.rs:15:13 | 13 | let immut_view = view.as_view(); | ---- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs b/diskann-utils/tests/compile-fail/matmut_get_row.rs similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs rename to diskann-utils/tests/compile-fail/matmut_get_row.rs index 5220d97e4..c62e43391 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.rs +++ b/diskann-utils/tests/compile-fail/matmut_get_row.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; // Test that `get_row` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the row is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.stderr b/diskann-utils/tests/compile-fail/matmut_get_row.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/matmut_get_row.stderr rename to diskann-utils/tests/compile-fail/matmut_get_row.stderr index 618b5e97f..bba5f4c7f 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row.stderr +++ b/diskann-utils/tests/compile-fail/matmut_get_row.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `view` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/matmut_get_row.rs:15:13 + --> tests/compile-fail/matmut_get_row.rs:15:13 | 13 | let row = view.get_row(0).unwrap(); | ---- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs b/diskann-utils/tests/compile-fail/matmut_get_row_mut.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs rename to diskann-utils/tests/compile-fail/matmut_get_row_mut.rs index 3a6694f75..c4b157c82 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.rs +++ b/diskann-utils/tests/compile-fail/matmut_get_row_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; // Test that `get_row_mut` on MatMut correctly captures a mutable lifetime, // preventing the MatMut from being used while the row is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.stderr b/diskann-utils/tests/compile-fail/matmut_get_row_mut.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.stderr rename to diskann-utils/tests/compile-fail/matmut_get_row_mut.stderr index 2d6974b26..831e433ad 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_get_row_mut.stderr +++ b/diskann-utils/tests/compile-fail/matmut_get_row_mut.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `view` as mutable more than once at a time - --> tests/compile-fail/multi/matmut_get_row_mut.rs:15:13 + --> tests/compile-fail/matmut_get_row_mut.rs:15:13 | 13 | let row = view.get_row_mut(0).unwrap(); | ---- first mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs b/diskann-utils/tests/compile-fail/matmut_invariant.rs similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs rename to diskann-utils/tests/compile-fail/matmut_invariant.rs index 86890463e..8caf3bde6 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.rs +++ b/diskann-utils/tests/compile-fail/matmut_invariant.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; // Verify that `MatMut` is invariant in any generic parameters. // diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr b/diskann-utils/tests/compile-fail/matmut_invariant.stderr similarity index 93% rename from diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr rename to diskann-utils/tests/compile-fail/matmut_invariant.stderr index 6bbea4f59..831826fd2 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_invariant.stderr +++ b/diskann-utils/tests/compile-fail/matmut_invariant.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> tests/compile-fail/multi/matmut_invariant.rs:16:5 + --> tests/compile-fail/matmut_invariant.rs:16:5 | 12 | fn bad<'long, 'short, 'a>(v: MatMut<'a, RowMajor<&'long u8>>) -> MatMut<'a, RowMajor<&'short u8>> | ----- ------ lifetime `'short` defined here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs b/diskann-utils/tests/compile-fail/matmut_reborrow.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs rename to diskann-utils/tests/compile-fail/matmut_reborrow.rs index afee970d7..4bec9e756 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.rs +++ b/diskann-utils/tests/compile-fail/matmut_reborrow.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; use diskann_utils::Reborrow; // Test that `reborrow` on MatMut correctly captures an immutable borrow, diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.stderr b/diskann-utils/tests/compile-fail/matmut_reborrow.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/matmut_reborrow.stderr rename to diskann-utils/tests/compile-fail/matmut_reborrow.stderr index e95118902..f7b5c850c 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow.stderr +++ b/diskann-utils/tests/compile-fail/matmut_reborrow.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `view` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/matmut_reborrow.rs:16:13 + --> tests/compile-fail/matmut_reborrow.rs:16:13 | 14 | let immut_view = view.reborrow(); | ---- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs b/diskann-utils/tests/compile-fail/matmut_reborrow_mut.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs rename to diskann-utils/tests/compile-fail/matmut_reborrow_mut.rs index b53f631a8..d47829abc 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.rs +++ b/diskann-utils/tests/compile-fail/matmut_reborrow_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; use diskann_utils::ReborrowMut; // Test that `reborrow_mut` on MatMut correctly captures a mutable lifetime, diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.stderr b/diskann-utils/tests/compile-fail/matmut_reborrow_mut.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.stderr rename to diskann-utils/tests/compile-fail/matmut_reborrow_mut.stderr index 4429ae199..c6bd91776 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_reborrow_mut.stderr +++ b/diskann-utils/tests/compile-fail/matmut_reborrow_mut.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `view` as immutable because it is also borrowed as mutable - --> tests/compile-fail/multi/matmut_reborrow_mut.rs:16:13 + --> tests/compile-fail/matmut_reborrow_mut.rs:16:13 | 14 | let reborrowed = view.reborrow_mut(); | ---- mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs b/diskann-utils/tests/compile-fail/matmut_rows.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matmut_rows.rs rename to diskann-utils/tests/compile-fail/matmut_rows.rs index 9c51c85f6..6a097f5e1 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows.rs +++ b/diskann-utils/tests/compile-fail/matmut_rows.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; // Test that `rows` on MatMut correctly captures an immutable borrow, // preventing mutation of the MatMut while the iterator is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows.stderr b/diskann-utils/tests/compile-fail/matmut_rows.stderr similarity index 89% rename from diskann-quantization/tests/compile-fail/multi/matmut_rows.stderr rename to diskann-utils/tests/compile-fail/matmut_rows.stderr index 4b19eea9e..c27b14164 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows.stderr +++ b/diskann-utils/tests/compile-fail/matmut_rows.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `view` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/matmut_rows.rs:15:13 + --> tests/compile-fail/matmut_rows.rs:15:13 | 13 | let iter = view.rows(); | ---- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs b/diskann-utils/tests/compile-fail/matmut_rows_mut.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs rename to diskann-utils/tests/compile-fail/matmut_rows_mut.rs index 871da0e40..b5261b62f 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.rs +++ b/diskann-utils/tests/compile-fail/matmut_rows_mut.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatMut, RowMajor}; +use diskann_utils::views::{Mat, MatMut, RowMajor}; // Test that the `rows_mut` iterator on MatMut correctly captures a mutable lifetime, // preventing the MatMut from being used while the iterator is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.stderr b/diskann-utils/tests/compile-fail/matmut_rows_mut.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.stderr rename to diskann-utils/tests/compile-fail/matmut_rows_mut.stderr index 2fa4d882c..d7e6771e1 100644 --- a/diskann-quantization/tests/compile-fail/multi/matmut_rows_mut.stderr +++ b/diskann-utils/tests/compile-fail/matmut_rows_mut.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `view` as immutable because it is also borrowed as mutable - --> tests/compile-fail/multi/matmut_rows_mut.rs:15:13 + --> tests/compile-fail/matmut_rows_mut.rs:15:13 | 13 | let iter = view.rows_mut(); | ---- mutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs b/diskann-utils/tests/compile-fail/matref_get_row.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matref_get_row.rs rename to diskann-utils/tests/compile-fail/matref_get_row.rs index 72ddc79de..430f0daae 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_get_row.rs +++ b/diskann-utils/tests/compile-fail/matref_get_row.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatRef, RowMajor}; +use diskann_utils::views::{Mat, MatRef, RowMajor}; // Test that `get_row` on MatRef returns a row with the correct lifetime, // and that an immutable borrow is held while the row is in scope. diff --git a/diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr b/diskann-utils/tests/compile-fail/matref_get_row.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr rename to diskann-utils/tests/compile-fail/matref_get_row.stderr index 13c0fa549..997928827 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_get_row.stderr +++ b/diskann-utils/tests/compile-fail/matref_get_row.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/matref_get_row.rs:16:13 + --> tests/compile-fail/matref_get_row.rs:16:13 | 12 | let view: MatRef<'_, RowMajor> = mat.as_view(); | --- immutable borrow occurs here diff --git a/diskann-quantization/tests/compile-fail/multi/matref_rows.rs b/diskann-utils/tests/compile-fail/matref_rows.rs similarity index 90% rename from diskann-quantization/tests/compile-fail/multi/matref_rows.rs rename to diskann-utils/tests/compile-fail/matref_rows.rs index 3cfb8a8cc..0a9fa150e 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_rows.rs +++ b/diskann-utils/tests/compile-fail/matref_rows.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_quantization::multi_vector::{Mat, MatRef, RowMajor}; +use diskann_utils::views::{Mat, MatRef, RowMajor}; // Test that `rows` on MatRef returns an iterator with the correct lifetime, // preventing mutation of the underlying Mat while iterating. diff --git a/diskann-quantization/tests/compile-fail/multi/matref_rows.stderr b/diskann-utils/tests/compile-fail/matref_rows.stderr similarity index 88% rename from diskann-quantization/tests/compile-fail/multi/matref_rows.stderr rename to diskann-utils/tests/compile-fail/matref_rows.stderr index c4b10f866..0c6980b9e 100644 --- a/diskann-quantization/tests/compile-fail/multi/matref_rows.stderr +++ b/diskann-utils/tests/compile-fail/matref_rows.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `mat` as mutable because it is also borrowed as immutable - --> tests/compile-fail/multi/matref_rows.rs:15:13 + --> tests/compile-fail/matref_rows.rs:15:13 | 12 | let view: MatRef<'_, RowMajor> = mat.as_view(); | --- immutable borrow occurs here diff --git a/diskann-utils/tests/compile_fail.rs b/diskann-utils/tests/compile_fail.rs new file mode 100644 index 000000000..7f7885a34 --- /dev/null +++ b/diskann-utils/tests/compile_fail.rs @@ -0,0 +1,14 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +// Borrow/lifetime/variance guarantees of the `Mat`/`MatRef`/`MatMut` matrix framework. +// These are check-time errors, so no `pass` bootstrap is needed to force monomorphization. +#![cfg(not(miri))] + +#[test] +fn compile_fail() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compile-fail/*.rs"); +} diff --git a/diskann/src/error/ann_error.rs b/diskann/src/error/ann_error.rs index 36733ed56..401c5d77d 100644 --- a/diskann/src/error/ann_error.rs +++ b/diskann/src/error/ann_error.rs @@ -588,13 +588,20 @@ where } } -impl From for ANNError { +impl From for ANNError { #[track_caller] - fn from(err: diskann_utils::matrix::TryFromError) -> Self { + fn from(err: diskann_utils::views::TryFromErrorLight) -> Self { ANNError::new(ANNErrorKind::DimensionMismatchError, err) } } +impl From> for ANNError { + #[track_caller] + fn from(err: diskann_utils::views::TryFromError) -> Self { + Self::from(err.as_static()) + } +} + /// An internal wrapper for error types that also tracks the file and line information /// for where the error was first converted and where context was propagated. #[derive(Debug)] @@ -1534,7 +1541,7 @@ Caused by: #[test] fn from_try_from_error() { let data: &[f32] = &[1.0, 2.0, 3.0]; - let err = diskann_utils::matrix::MatrixView::try_from(data, 2, 2).unwrap_err(); + let err = diskann_utils::views::MatrixView::try_from(data, 2, 2).unwrap_err(); let ann_err = ANNError::from(err); assert_eq!(ann_err.kind(), ANNErrorKind::DimensionMismatchError); } diff --git a/diskann/src/flat/test/provider.rs b/diskann/src/flat/test/provider.rs index 7f28afc73..6f8a14136 100644 --- a/diskann/src/flat/test/provider.rs +++ b/diskann/src/flat/test/provider.rs @@ -13,7 +13,7 @@ use std::{ sync::Arc, }; -use diskann_utils::{future::SendFuture, matrix::Matrix}; +use diskann_utils::{future::SendFuture, views::Matrix}; use diskann_vector::{PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; diff --git a/diskann/src/graph/glue.rs b/diskann/src/graph/glue.rs index 60e244f92..91cd7643d 100644 --- a/diskann/src/graph/glue.rs +++ b/diskann/src/graph/glue.rs @@ -1030,7 +1030,7 @@ where /// [`Overlay`](crate::graph::workingset::map::Overlay) for a working set seed compatible /// with [`Batch`]. /// -/// The primary implementation of this trait is [`Matrix`](diskann_utils::matrix::Matrix). +/// The primary implementation of this trait is [`Matrix`](diskann_utils::views::Matrix). pub trait Batch: Send + Sync + 'static { /// The element type of the batch. type Element<'a>: Copy; @@ -1047,7 +1047,7 @@ pub trait Batch: Send + Sync + 'static { } } -impl Batch for diskann_utils::matrix::Matrix { +impl Batch for diskann_utils::views::Matrix { type Element<'a> = &'a [T]; fn len(&self) -> usize { diff --git a/diskann/src/graph/start_point.rs b/diskann/src/graph/start_point.rs index 4c7841d77..c829b9dcf 100644 --- a/diskann/src/graph/start_point.rs +++ b/diskann/src/graph/start_point.rs @@ -8,8 +8,8 @@ use std::{fmt::Display, num::NonZeroUsize}; use thiserror::Error; use diskann_utils::{ - matrix::{Matrix, MatrixView}, sampling::WithApproximateNorm, + views::{Matrix, MatrixView}, }; /// 'StartPointStrategy' is an enum that represents the different strategies to select diff --git a/diskann/src/graph/test/cases/grid_insert.rs b/diskann/src/graph/test/cases/grid_insert.rs index 3471e248b..0c0e24724 100644 --- a/diskann/src/graph/test/cases/grid_insert.rs +++ b/diskann/src/graph/test/cases/grid_insert.rs @@ -18,7 +18,7 @@ use std::{num::NonZeroUsize, sync::Arc}; -use diskann_utils::matrix::MatrixView; +use diskann_utils::views::MatrixView; use diskann_vector::distance::Metric; use crate::{ diff --git a/diskann/src/graph/test/provider.rs b/diskann/src/graph/test/provider.rs index 3ae7abeac..56f1c23aa 100644 --- a/diskann/src/graph/test/provider.rs +++ b/diskann/src/graph/test/provider.rs @@ -13,7 +13,7 @@ use std::{ }; use dashmap::{DashMap, mapref::entry::Entry}; -use diskann_utils::matrix::Matrix; +use diskann_utils::views::Matrix; use diskann_vector::{PreprocessedDistanceFunction, distance::Metric}; use thiserror::Error; diff --git a/diskann/src/graph/test/synthetic.rs b/diskann/src/graph/test/synthetic.rs index 87450f591..d3c822b09 100644 --- a/diskann/src/graph/test/synthetic.rs +++ b/diskann/src/graph/test/synthetic.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use diskann_utils::matrix::{Init, Matrix}; +use diskann_utils::views::{Init, Matrix}; use crate::graph::AdjacencyList; diff --git a/diskann/src/graph/workingset/map.rs b/diskann/src/graph/workingset/map.rs index 607ea70c0..e24b927ca 100644 --- a/diskann/src/graph/workingset/map.rs +++ b/diskann/src/graph/workingset/map.rs @@ -101,7 +101,7 @@ //! //! ``` //! use std::sync::Arc; -//! use diskann_utils::matrix::Matrix; +//! use diskann_utils::views::Matrix; //! //! use diskann::graph::workingset::{Map, View, map::{Overlay, Ref, Builder, Capacity}}; //! @@ -646,7 +646,7 @@ where /// /// ``` /// use std::sync::Arc; -/// use diskann_utils::matrix::Matrix; +/// use diskann_utils::views::Matrix; /// /// use diskann::graph::workingset::map::{Overlay, Ref}; /// @@ -923,7 +923,7 @@ mod tests { use std::sync::Arc; - use diskann_utils::matrix::Matrix; + use diskann_utils::views::Matrix; use crate::graph::workingset::View as WorkingSetView; From 16a45ef101c01714fab278fa63a773c2bc7c2f57 Mon Sep 17 00:00:00 2001 From: Suryansh Gupta Date: Sat, 25 Jul 2026 04:45:21 +0530 Subject: [PATCH 6/6] Minor review comments fix --- diskann-benchmark/src/multi_vector/driver.rs | 21 +++++++++++-------- diskann-benchmark/src/multi_vector/kernels.rs | 2 +- diskann-quantization/src/minmax/multi/mod.rs | 2 +- diskann-utils/src/views.rs | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/diskann-benchmark/src/multi_vector/driver.rs b/diskann-benchmark/src/multi_vector/driver.rs index 29cb5fc15..e91d23b18 100644 --- a/diskann-benchmark/src/multi_vector/driver.rs +++ b/diskann-benchmark/src/multi_vector/driver.rs @@ -14,7 +14,8 @@ use diskann_benchmark_runner::{ }, Checker, Input, }; -use diskann_quantization::multi_vector::{Mat, MatRef, MaxSimKernel, Overflow, RowMajor}; +use diskann_quantization::multi_vector::{Mat, MatRef, MaxSimKernel, RowMajor}; +use diskann_utils::views::Init; use rand::{ distr::{Distribution, StandardUniform}, rngs::StdRng, @@ -76,17 +77,19 @@ impl Data where StandardUniform: Distribution, { - pub(super) fn new(run: &Run) -> Result { + pub(super) fn new(run: &Run) -> Self { let mut rng = StdRng::seed_from_u64(0x12345); - let queries = Mat::from_fn( - RowMajor::new(run.num_query_vectors.get(), run.dim.get())?, - || StandardUniform.sample(&mut rng), + let queries = Mat::new( + Init(|| StandardUniform.sample(&mut rng)), + run.num_query_vectors.get(), + run.dim.get(), ); - let docs = Mat::from_fn( - RowMajor::new(run.num_doc_vectors.get(), run.dim.get())?, - || StandardUniform.sample(&mut rng), + let docs = Mat::new( + Init(|| StandardUniform.sample(&mut rng)), + run.num_doc_vectors.get(), + run.dim.get(), ); - Ok(Self { queries, docs }) + Self { queries, docs } } } diff --git a/diskann-benchmark/src/multi_vector/kernels.rs b/diskann-benchmark/src/multi_vector/kernels.rs index d45ac646b..12759ea11 100644 --- a/diskann-benchmark/src/multi_vector/kernels.rs +++ b/diskann-benchmark/src/multi_vector/kernels.rs @@ -66,7 +66,7 @@ where writeln!(output, "{}", input)?; let mut results = Vec::with_capacity(input.runs.len()); for run in input.runs.iter() { - let data = Data::::new(run)?; + let data = Data::::new(run); let kernel = build_max_sim::(input.isa.into(), data.queries.as_view(), BoxErase)?; results.push(run_with_kernel(run, data.docs.as_view(), &*kernel)); } diff --git a/diskann-quantization/src/minmax/multi/mod.rs b/diskann-quantization/src/minmax/multi/mod.rs index 2c43dbbcf..b1d61bbcf 100644 --- a/diskann-quantization/src/minmax/multi/mod.rs +++ b/diskann-quantization/src/minmax/multi/mod.rs @@ -58,7 +58,7 @@ //! RowMajor::new(num_doc_vectors, dim).unwrap(), &doc_data //! ).unwrap(); //! -//! // Create owned matrices for quantized output using Mat::from_repr +//! // Create owned matrices for the quantized output //! let mut query_out: Mat> = //! Mat::from_default(MinMaxMeta::new(num_query_vectors, dim)).unwrap(); //! let mut doc_out: Mat> = diff --git a/diskann-utils/src/views.rs b/diskann-utils/src/views.rs index b1f76d36a..3ab1b47aa 100644 --- a/diskann-utils/src/views.rs +++ b/diskann-utils/src/views.rs @@ -797,7 +797,7 @@ macro_rules! delegate_read { impl Mat> { /// Construct a [`Mat`] by filling each element in row-major order from `gen`. pub fn new>(mut gen: U, nrows: usize, ncols: usize) -> Self { - let repr = RowMajor::new(nrows, ncols).expect("dimension overflow"); + let repr = RowMajor::new(nrows, ncols).unwrap_or_else(|e| panic!("{e}")); let b: Box<[T]> = (0..repr.num_elements()).map(|_| gen.generate()).collect(); // SAFETY: `b` has length `repr.num_elements()` by construction. unsafe { repr.box_to_mat(b) }