diff --git a/crates/ruvector-rabitq/src/lib.rs b/crates/ruvector-rabitq/src/lib.rs index ecfa2744..986b400b 100644 --- a/crates/ruvector-rabitq/src/lib.rs +++ b/crates/ruvector-rabitq/src/lib.rs @@ -56,4 +56,4 @@ pub use index::{ }; pub use kernel::{CpuKernel, KernelCaps, ScanRequest, ScanResponse, VectorKernel}; pub use quantize::{pack_bits, unpack_bits, BinaryCode}; -pub use rotation::RandomRotation; +pub use rotation::{RandomRotation, RandomRotationKind}; diff --git a/crates/ruvector-rulake/src/bin/rulake-demo.rs b/crates/ruvector-rulake/src/bin/rulake-demo.rs index 8d98cfc6..f503a202 100644 --- a/crates/ruvector-rulake/src/bin/rulake-demo.rs +++ b/crates/ruvector-rulake/src/bin/rulake-demo.rs @@ -18,7 +18,7 @@ use std::time::Instant; use rand::SeedableRng; use rand_distr::{Distribution, Normal, Uniform}; -use ruvector_rabitq::{AnnIndex, RabitqPlusIndex}; +use ruvector_rabitq::{AnnIndex, RabitqPlusIndex, RandomRotationKind}; use ruvector_rulake::{cache::Consistency, LocalBackend, RuLake, SearchResult}; fn clustered(n: usize, d: usize, n_clusters: usize, seed: u64) -> Vec> { @@ -62,6 +62,31 @@ fn measure_direct( (build_ms, qps) } +/// Same shape as [`measure_direct`] but uses a randomised-Hadamard +/// rotation instead of the default Haar matrix (ADR-158 feature). +fn measure_direct_hadamard( + d: usize, + rerank: usize, + seed: u64, + data: &[Vec], + queries: &[Vec], +) -> (f64, f64) { + let t = Instant::now(); + let mut idx = + RabitqPlusIndex::new_with_rotation(d, seed, rerank, RandomRotationKind::HadamardSigned); + for (i, v) in data.iter().enumerate() { + idx.add(i, v.clone()).unwrap(); + } + let build_ms = t.elapsed().as_secs_f64() * 1000.0; + + let t = Instant::now(); + for q in queries { + let _ = idx.search(q, 10).unwrap(); + } + let qps = queries.len() as f64 / t.elapsed().as_secs_f64(); + (build_ms, qps) +} + fn measure_rulake_single( d: usize, rerank: usize, @@ -241,10 +266,18 @@ fn main() { let (direct_build, direct_qps) = measure_direct(d, rerank, seed, &data, &queries); println!( - " direct RaBitQ+ build={:>8.1} ms qps={:>8.0}", + " direct RaBitQ+ (Haar) build={:>8.1} ms qps={:>8.0}", direct_build, direct_qps ); + let (hada_build, hada_qps) = measure_direct_hadamard(d, rerank, seed, &data, &queries); + println!( + " direct RaBitQ+ (Hadamard) build={:>8.1} ms qps={:>8.0} build_speedup={:.2}×", + hada_build, + hada_qps, + direct_build / hada_build.max(0.001) + ); + let (lake_prime, lake_qps) = measure_rulake_single(d, rerank, seed, &data, &queries, Consistency::Fresh); println!(