use super::{rescore_euclidean_batch, PQVector, ProductQuantizer};
use crate::scored_result::ScoredResult;
use std::collections::HashMap;
fn small_trained_pq() -> ProductQuantizer {
let vectors = vec![
vec![1.0, 2.0, 3.0, 4.0],
vec![5.0, 6.0, 7.0, 8.0],
vec![-1.0, -2.0, 9.0, 10.0],
];
ProductQuantizer::train(&vectors, 2, 2).expect("train small PQ")
}
#[test]
fn invalid_pq_code_in_search_path_skips_candidate_without_panic() {
let quantizer = small_trained_pq();
let bad = PQVector { codes: vec![0, 99] };
let mut pq_cache: HashMap<u64, PQVector> = HashMap::new();
pq_cache.insert(7, bad);
let index_results = vec![ScoredResult::new(7, 0.42)];
let query = vec![1.0, 2.0, 3.0, 4.0];
let scored = rescore_euclidean_batch(&query, &quantizer, &pq_cache, &index_results);
assert_eq!(scored.len(), 1);
assert_eq!(scored[0].id, 7);
assert!(
(scored[0].score - 0.42).abs() < 1e-6,
"rejected candidate must keep its HNSW score, got {}",
scored[0].score
);
}
#[test]
fn an_index_search_error_is_returned_not_read_as_no_match() {
let dir = tempfile::tempdir().expect("test: temp dir");
let collection = crate::collection::types::Collection::create(
dir.path().to_path_buf(),
4,
crate::DistanceMetric::Cosine,
)
.expect("test: create collection");
collection
.upsert(vec![crate::Point::without_payload(
1,
vec![1.0, 0.0, 0.0, 0.0],
)])
.expect("test: upsert");
let control = collection
.search_ids_with_adc_if_pq(&[1.0, 0.0, 0.0, 0.0], 1, crate::SearchQuality::Balanced)
.expect("CONTROL: a well-formed query succeeds");
assert_eq!(control.len(), 1, "CONTROL: the fixture's point is found");
let outcome =
collection.search_ids_with_adc_if_pq(&[1.0, 0.0], 1, crate::SearchQuality::Balanced);
assert!(
outcome.is_err(),
"a query the index refuses must be an error, got {outcome:?}"
);
}