use std::fmt;
use diskann_utils::views::MutMatrixView;
use diskann_vector::{MathematicalValue, PureDistanceFunction, distance::InnerProduct};
#[derive(Debug, Clone, Copy)]
pub struct DeterminantDiversityParams {
power: f32,
eta: f32,
}
impl DeterminantDiversityParams {
pub fn new(power: f32, eta: f32) -> Result<Self, DeterminantDiversityError> {
if !power.is_finite() || power <= 0.0 {
return Err(DeterminantDiversityError::InvalidPower(power));
}
if !eta.is_finite() || eta < 0.0 {
return Err(DeterminantDiversityError::InvalidEta(eta));
}
Ok(Self { power, eta })
}
#[inline]
pub fn power(&self) -> f32 {
self.power
}
#[inline]
pub fn eta(&self) -> f32 {
self.eta
}
}
impl fmt::Display for DeterminantDiversityParams {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"DeterminantDiversity(power={}, eta={})",
self.power, self.eta
)
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum DeterminantDiversityError {
#[error("determinant-diversity power must be > 0.0, got: {0}")]
InvalidPower(f32),
#[error("determinant-diversity eta must be >= 0.0, got: {0}")]
InvalidEta(f32),
#[error(
"determinant-diversity candidate matrix has {candidate} columns but query dimension is {query}"
)]
QueryDimensionMismatch {
query: usize,
candidate: usize,
},
#[error("determinant-diversity received {distances} distances for {candidates} candidate rows")]
DistanceCountMismatch {
distances: usize,
candidates: usize,
},
}
impl From<DeterminantDiversityError> for diskann::ANNError {
#[track_caller]
fn from(err: DeterminantDiversityError) -> Self {
use diskann::ANNErrorKind;
let kind = match err {
DeterminantDiversityError::InvalidPower(_)
| DeterminantDiversityError::InvalidEta(_) => ANNErrorKind::IndexConfigError,
DeterminantDiversityError::QueryDimensionMismatch { .. }
| DeterminantDiversityError::DistanceCountMismatch { .. } => {
ANNErrorKind::DimensionMismatchError
}
};
diskann::ANNError::new(kind, err)
}
}
#[derive(Clone, Copy)]
struct DistanceRange {
min: f32,
max: f32,
}
pub fn determinant_diversity(
candidates: MutMatrixView<'_, f32>,
distances: &[f32],
query: &[f32],
k: usize,
params: &DeterminantDiversityParams,
) -> Result<Vec<usize>, DeterminantDiversityError> {
if candidates.ncols() != query.len() {
return Err(DeterminantDiversityError::QueryDimensionMismatch {
query: query.len(),
candidate: candidates.ncols(),
});
}
if distances.len() != candidates.nrows() {
return Err(DeterminantDiversityError::DistanceCountMismatch {
distances: distances.len(),
candidates: candidates.nrows(),
});
}
let k = k.min(candidates.nrows());
if k == 0 || candidates.ncols() == 0 {
return Ok(Vec::new());
}
let distance_range = {
let mut min_distance = f32::INFINITY;
let mut max_distance = f32::NEG_INFINITY;
for distance in distances {
min_distance = min_distance.min(*distance);
max_distance = max_distance.max(*distance);
}
DistanceRange {
min: min_distance,
max: max_distance,
}
};
let inv_sqrt_eta = if params.eta() > 0.0 {
1.0 / params.eta().sqrt()
} else {
1.0
};
Ok(greedy_orthogonal_select(
candidates,
distances,
k,
params.power(),
inv_sqrt_eta,
distance_range,
))
}
fn greedy_orthogonal_select(
mut candidates: MutMatrixView<'_, f32>,
distances: &[f32],
k: usize,
power: f32,
inv_sqrt_eta: f32,
distance_range: DistanceRange,
) -> Vec<usize> {
let n = candidates.nrows();
let k = k.min(n);
if k == 0 {
return Vec::new();
}
let mut norms_sq = Vec::with_capacity(n);
for (i, distance_to_query) in distances.iter().enumerate() {
let scale =
distance_to_similarity(*distance_to_query, distance_range).powf(power) * inv_sqrt_eta;
for value in candidates.row_mut(i) {
*value *= scale;
}
let norm_sq = dot_product(candidates.row(i), candidates.row(i));
norms_sq.push(norm_sq);
}
let mut available = vec![true; n];
let mut selected = Vec::with_capacity(k);
let mut projections = vec![0.0f32; n];
for _ in 0..k {
let best_idx = available
.iter()
.enumerate()
.filter(|&(_, &avail)| avail)
.max_by(|(i, _), (j, _)| {
norms_sq[*i]
.partial_cmp(&norms_sq[*j])
.unwrap_or(std::cmp::Ordering::Equal)
})
.map(|(i, _)| i);
let Some(selected_index) = best_idx else {
break;
};
selected.push(selected_index);
available[selected_index] = false;
if selected.len() == k {
break;
}
let best_norm_sq = norms_sq[selected_index];
if best_norm_sq <= 0.0 {
continue;
}
let inv_norm_sq = 1.0 / best_norm_sq;
let r_star_copy: Vec<f32> = candidates.row(selected_index).to_vec();
for i in 0..n {
if !available[i] {
projections[i] = 0.0;
} else {
projections[i] = dot_product(candidates.row(i), &r_star_copy) * inv_norm_sq;
}
}
for i in 0..n {
if !available[i] {
continue;
}
let projection = projections[i];
for (residual, &star) in candidates.row_mut(i).iter_mut().zip(r_star_copy.iter()) {
*residual -= projection * star;
}
norms_sq[i] = (norms_sq[i] - projection * projection * best_norm_sq).max(0.0);
}
}
selected
}
#[inline(always)]
fn distance_to_similarity(distance: f32, distance_range: DistanceRange) -> f32 {
let span = (distance_range.max - distance_range.min).max(f32::EPSILON);
((distance_range.max - distance) / span).max(0.0) + f32::EPSILON
}
#[inline]
fn dot_product(a: &[f32], b: &[f32]) -> f32 {
<InnerProduct as PureDistanceFunction<&[f32], &[f32], MathematicalValue<f32>>>::evaluate(a, b)
.into_inner()
}
#[cfg(test)]
mod tests {
use super::*;
use diskann_quantization::num::Positive;
use diskann_utils::views::Matrix;
#[test]
fn test_valid_params() {
assert!(DeterminantDiversityParams::new(1.0, 0.0).is_ok());
assert!(DeterminantDiversityParams::new(0.5, 1.5).is_ok());
assert!(DeterminantDiversityParams::new(2.0, 0.1).is_ok());
}
#[test]
fn test_invalid_power() {
assert!(DeterminantDiversityParams::new(0.0, 1.0).is_err());
assert!(DeterminantDiversityParams::new(-1.0, 1.0).is_err());
}
#[test]
fn test_invalid_eta() {
assert!(DeterminantDiversityParams::new(1.0, -0.1).is_err());
}
#[test]
fn test_invalid_non_finite_values() {
assert!(DeterminantDiversityParams::new(f32::NAN, 0.1).is_err());
assert!(DeterminantDiversityParams::new(f32::INFINITY, 0.1).is_err());
assert!(DeterminantDiversityParams::new(1.0, f32::NAN).is_err());
assert!(DeterminantDiversityParams::new(1.0, f32::INFINITY).is_err());
}
#[test]
fn test_display() {
let params = DeterminantDiversityParams::new(1.5, 0.5).unwrap();
assert_eq!(
params.to_string(),
"DeterminantDiversity(power=1.5, eta=0.5)"
);
}
fn run_with_ids(
candidates: Vec<(u32, f32, Vec<f32>)>,
query: &[f32],
k: usize,
eta: f32,
power: Positive<f32>,
) -> Vec<(u32, f32)> {
if candidates.is_empty() {
return Vec::new();
}
let dim = candidates[0].2.len();
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());
for (i, (id, distance, vector)) in candidates.into_iter().enumerate() {
ids.push(id);
distances.push(distance);
matrix.row_mut(i).copy_from_slice(&vector);
}
let params = DeterminantDiversityParams::new(power.into_inner(), eta).unwrap();
determinant_diversity(matrix.as_mut_view(), &distances, query, k, ¶ms)
.expect("valid determinant-diversity inputs")
.into_iter()
.map(|idx| (ids[idx], distances[idx]))
.collect()
}
fn p(value: f32) -> Positive<f32> {
Positive::new(value).unwrap()
}
#[test]
fn test_empty_candidates() {
let result = run_with_ids(Vec::new(), &[1.0, 2.0], 5, 0.5, p(1.0));
assert_eq!(result.len(), 0);
}
#[test]
fn test_empty_query_is_dimension_mismatch() {
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();
let result = determinant_diversity(matrix.as_mut_view(), &[0.5], &[], 5, ¶ms);
assert!(matches!(
result,
Err(DeterminantDiversityError::QueryDimensionMismatch {
query: 0,
candidate: 2,
})
));
}
#[test]
fn test_mismatched_dimensions_errors() {
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();
let result =
determinant_diversity(matrix.as_mut_view(), &[0.5], &[1.0, 2.0, 3.0], 5, ¶ms);
assert!(matches!(
result,
Err(DeterminantDiversityError::QueryDimensionMismatch {
query: 3,
candidate: 2,
})
));
}
#[test]
fn test_mismatched_distances_errors() {
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();
let result = determinant_diversity(matrix.as_mut_view(), &[0.5], &[1.0, 1.0], 2, ¶ms);
assert!(matches!(
result,
Err(DeterminantDiversityError::DistanceCountMismatch {
distances: 1,
candidates: 2,
})
));
}
#[test]
fn test_single_candidate() {
let candidates = vec![(0u32, 0.5, vec![1.0, 2.0])];
let query = &[1.0, 2.0];
let result = run_with_ids(candidates, query, 5, 0.5, p(1.0));
assert_eq!(result.len(), 1);
assert_eq!(result[0].0, 0);
}
#[test]
fn test_k_larger_than_candidates() {
let candidates = vec![(0u32, 0.5, vec![1.0, 0.0]), (1u32, 0.3, vec![0.0, 1.0])];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 10, 0.5, p(1.0));
assert_eq!(result.len(), 2); }
#[test]
fn test_with_eta_diversity() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0]),
(1u32, 0.2, vec![0.9, 0.1]),
(2u32, 0.3, vec![0.8, 0.2]),
];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 1.0, p(1.0));
assert_eq!(result.len(), 2);
assert!(result.iter().all(|(id, _)| *id < 3));
}
#[test]
fn test_without_eta_greedy() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0]),
(1u32, 0.2, vec![0.9, 0.1]),
(2u32, 0.3, vec![0.8, 0.2]),
];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert_eq!(result.len(), 2);
assert!(result.iter().all(|(id, _)| *id < 3));
}
#[test]
fn test_power_parameter() {
let candidates = vec![(0u32, 0.1, vec![1.0, 0.0]), (1u32, 0.2, vec![0.0, 1.0])];
let query = &[1.0, 1.0];
let result1 = run_with_ids(candidates.clone(), query, 2, 0.0, p(1.0));
let result2 = run_with_ids(candidates, query, 2, 0.0, p(2.0));
assert_eq!(result1.len(), 2);
assert_eq!(result2.len(), 2);
}
#[test]
fn test_distances_preserved() {
let candidates = vec![(0u32, 0.5, vec![1.0, 0.0]), (1u32, 0.3, vec![0.0, 1.0])];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert!(result.iter().all(|(_, dist)| *dist == 0.5 || *dist == 0.3));
}
#[test]
fn test_diversity_selects_orthogonal_candidates() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0, 0.0]), (1u32, 0.1, vec![0.0, 1.0, 0.0]), (2u32, 0.1, vec![0.99, 0.01, 0.0]), ];
let query = &[1.0, 1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert_eq!(result.len(), 2);
let ids: Vec<u32> = result.iter().map(|(id, _)| *id).collect();
assert!(ids.contains(&0), "Expected candidate 0 to be selected");
assert!(
ids.contains(&1),
"Expected candidate 1 (orthogonal) to be selected, not redundant candidate 2"
);
}
#[test]
fn test_diversity_selects_orthogonal_candidates_with_eta() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0, 0.0]),
(1u32, 0.1, vec![0.0, 1.0, 0.0]),
(2u32, 0.1, vec![0.99, 0.01, 0.0]),
];
let query = &[1.0, 1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 0.5, p(1.0));
assert_eq!(result.len(), 2);
let ids: Vec<u32> = result.iter().map(|(id, _)| *id).collect();
assert!(ids.contains(&0), "Expected candidate 0 to be selected");
assert!(
ids.contains(&1),
"Expected candidate 1 (orthogonal) to be selected"
);
}
#[test]
fn test_high_power_prefers_closer_candidates() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0]), (1u32, 0.9, vec![0.0, 1.0]), ];
let query = &[1.0, 0.0];
let result = run_with_ids(candidates.clone(), query, 1, 0.0, p(10.0));
assert_eq!(result.len(), 1);
assert_eq!(
result[0].0, 0,
"Closest candidate should be selected with high power"
);
}
#[test]
fn test_equal_distances() {
let candidates = vec![
(0u32, 0.5, vec![1.0, 0.0]),
(1u32, 0.5, vec![0.0, 1.0]), ];
let query = &[1.0, 0.0];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert_eq!(result.len(), 2);
}
#[test]
fn test_eta_zero_is_greedy_path() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0]),
(1u32, 0.2, vec![0.0, 1.0]),
(2u32, 0.3, vec![0.5, 0.5]),
];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert_eq!(result.len(), 2);
}
#[test]
fn test_k_zero_returns_empty() {
let candidates = vec![(0u32, 0.1, vec![1.0, 0.0]), (1u32, 0.2, vec![0.0, 1.0])];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 0, 0.5, p(1.0));
assert_eq!(result.len(), 0);
}
#[test]
fn test_zero_dimensional_candidates() {
let candidates = vec![(0u32, 0.1, Vec::<f32>::new()), (1u32, 0.2, Vec::new())];
let query: &[f32] = &[];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert_eq!(result.len(), 0);
}
#[test]
fn test_k_equals_candidates_returns_all() {
let candidates = vec![
(10u32, 0.1, vec![1.0, 0.0]),
(20u32, 0.2, vec![0.0, 1.0]),
(30u32, 0.3, vec![1.0, 1.0]),
];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 3, 0.0, p(1.0));
assert_eq!(result.len(), 3);
let mut ids: Vec<u32> = result.iter().map(|(id, _)| *id).collect();
ids.sort_unstable();
assert_eq!(ids, vec![10, 20, 30]);
}
#[test]
fn test_collinear_candidates_no_division_by_zero() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0]),
(1u32, 0.1, vec![2.0, 0.0]),
(2u32, 0.1, vec![3.0, 0.0]),
];
let query = &[1.0, 0.0];
let result = run_with_ids(candidates, query, 3, 0.0, p(1.0));
assert_eq!(result.len(), 3);
let mut ids: Vec<u32> = result.iter().map(|(id, _)| *id).collect();
ids.sort_unstable();
assert_eq!(ids, vec![0, 1, 2]);
}
#[test]
fn test_first_pivot_is_most_relevant_at_equal_norms() {
let candidates = vec![
(0u32, 0.1, vec![1.0, 0.0, 0.0]),
(1u32, 0.5, vec![0.0, 1.0, 0.0]),
(2u32, 0.9, vec![0.0, 0.0, 1.0]),
];
let query = &[1.0, 1.0, 1.0];
let result = run_with_ids(candidates, query, 3, 0.0, p(2.0));
assert_eq!(result.len(), 3);
assert_eq!(result[0].0, 0, "Most relevant candidate must be first");
}
#[test]
fn test_ids_pair_with_their_input_distance() {
let candidates = vec![(7u32, 1.5, vec![1.0, 0.0]), (9u32, 0.25, vec![0.0, 1.0])];
let query = &[1.0, 1.0];
let result = run_with_ids(candidates, query, 2, 0.0, p(1.0));
assert_eq!(result.len(), 2);
for (id, dist) in &result {
match *id {
7 => assert_eq!(*dist, 1.5),
9 => assert_eq!(*dist, 0.25),
other => panic!("unexpected id {other}"),
}
}
}
#[test]
fn test_distance_to_similarity_extremes() {
let range = DistanceRange { min: 0.5, max: 2.0 };
let s_min = distance_to_similarity(0.5, range);
let s_max = distance_to_similarity(2.0, range);
let s_below = distance_to_similarity(-1.0, range);
let s_above = distance_to_similarity(10.0, range);
for s in [s_min, s_max, s_below, s_above] {
assert!(s.is_finite());
assert!(s > 0.0);
}
assert!(s_min >= s_max);
assert!(s_below >= s_min - f32::EPSILON);
assert!(s_above <= s_max + f32::EPSILON);
}
#[test]
fn test_distance_to_similarity_degenerate_range() {
let range = DistanceRange { min: 0.7, max: 0.7 };
let a = distance_to_similarity(0.7, range);
let b = distance_to_similarity(0.7, range);
assert!(a.is_finite() && b.is_finite());
assert_eq!(a, b);
}
}