chore(gnn-rerank): cargo fmt — fix pre-existing rustfmt CI blocker

This formatting diff has blocked every PR's rustfmt check for weeks.
Formatting only (no logic changes).

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
ruvnet 2026-06-22 09:50:36 -04:00
parent aa17345a9c
commit c8af857714
5 changed files with 109 additions and 30 deletions

View file

@ -35,8 +35,7 @@ impl CandidateGraph {
// Cosine similarity is symmetric: sim(i,j) == sim(j,i). Compute each
// pair once (upper triangle) and push it into both neighbour lists,
// halving the dot-product work vs. the naive O(n²) double computation.
let mut sims: Vec<Vec<(usize, f32)>> =
vec![Vec::with_capacity(n.saturating_sub(1)); n];
let mut sims: Vec<Vec<(usize, f32)>> = vec![Vec::with_capacity(n.saturating_sub(1)); n];
for i in 0..n {
let (vi, ni) = (&candidates[i].vector, norms[i]);
for j in (i + 1)..n {

View file

@ -71,10 +71,14 @@ fn validate(candidates: &[Candidate], k: usize) -> Result<(), RerankerError> {
});
}
if !c.noisy_score.is_finite() {
return Err(RerankerError::NonFinite { what: "candidate score" });
return Err(RerankerError::NonFinite {
what: "candidate score",
});
}
if c.vector.iter().any(|x| !x.is_finite()) {
return Err(RerankerError::NonFinite { what: "candidate vector" });
return Err(RerankerError::NonFinite {
what: "candidate vector",
});
}
}
Ok(())

View file

@ -32,7 +32,9 @@ fn build_candidate_sets() -> (Vec<Vec<f32>>, Vec<Vec<Candidate>>) {
let queries: Vec<Vec<f32>> = (0..N_SETS)
.map(|_| {
let base = &corpus[rng.gen_range(0..CORPUS)];
base.iter().map(|&x| x + rng.gen_range(-0.1_f32..0.1)).collect()
base.iter()
.map(|&x| x + rng.gen_range(-0.1_f32..0.1))
.collect()
})
.collect();
let noise = Normal::new(0.0_f32, 0.40).unwrap();
@ -51,14 +53,22 @@ fn build_candidate_sets() -> (Vec<Vec<f32>>, Vec<Vec<Candidate>>) {
scored
.into_iter()
.take(RETRIEVAL_K)
.map(|(id, s)| Candidate { id: id as u32, vector: corpus[id].clone(), noisy_score: s })
.map(|(id, s)| Candidate {
id: id as u32,
vector: corpus[id].clone(),
noisy_score: s,
})
.collect::<Vec<_>>()
})
.collect();
(queries, sets)
}
fn time_reranker<R: CandidateReranker>(r: &R, queries: &[Vec<f32>], sets: &[Vec<Candidate>]) -> f64 {
fn time_reranker<R: CandidateReranker>(
r: &R,
queries: &[Vec<f32>],
sets: &[Vec<Candidate>],
) -> f64 {
// warm up
for (q, c) in queries.iter().zip(sets).take(16) {
let _ = r.rerank(q, c, K).unwrap();
@ -83,9 +93,18 @@ fn rerank_latency_throughput() {
let gnn_us = time_reranker(&GnnDiffusionReranker::default(), &queries, &sets);
eprintln!("rerank latency (DIM={DIM}, candidates={RETRIEVAL_K}, k={K}, n={N_SETS}):");
eprintln!(" NoisyScore {noisy_us:8.2} µs/q {:.2} M QPS", 1.0 / noisy_us);
eprintln!(" GnnDiffusion {gnn_us:8.2} µs/q {:.2} M QPS", 1.0 / gnn_us);
eprintln!(" diffusion overhead: {:.1}× baseline", gnn_us / noisy_us.max(1e-6));
eprintln!(
" NoisyScore {noisy_us:8.2} µs/q {:.2} M QPS",
1.0 / noisy_us
);
eprintln!(
" GnnDiffusion {gnn_us:8.2} µs/q {:.2} M QPS",
1.0 / gnn_us
);
eprintln!(
" diffusion overhead: {:.1}× baseline",
gnn_us / noisy_us.max(1e-6)
);
assert!(
gnn_us < BUDGET_US,

View file

@ -10,9 +10,7 @@ use std::collections::HashSet;
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Normal};
use ruvector_gnn_rerank::{
Candidate, CandidateReranker, GnnDiffusionReranker, NoisyScoreReranker,
};
use ruvector_gnn_rerank::{Candidate, CandidateReranker, GnnDiffusionReranker, NoisyScoreReranker};
const N: usize = 5_000;
const DIM: usize = 128;
@ -44,7 +42,9 @@ fn gen_queries(corpus: &[Vec<f32>], n_queries: usize, seed: u64) -> Vec<Vec<f32>
(0..n_queries)
.map(|_| {
let base = &corpus[rng.gen_range(0..corpus.len())];
base.iter().map(|&x| x + rng.gen_range(-0.1_f32..0.1)).collect()
base.iter()
.map(|&x| x + rng.gen_range(-0.1_f32..0.1))
.collect()
})
.collect()
}
@ -79,12 +79,24 @@ fn noisy_retrieve(
scored
.into_iter()
.take(retrieval_k)
.map(|(id, noisy_score)| Candidate { id: id as u32, vector: corpus[id].clone(), noisy_score })
.map(|(id, noisy_score)| Candidate {
id: id as u32,
vector: corpus[id].clone(),
noisy_score,
})
.collect()
}
fn recall_at_k(results: &[ruvector_gnn_rerank::RankedResult], gt: &HashSet<usize>, k: usize) -> f64 {
let hits = results.iter().take(k).filter(|r| gt.contains(&(r.id as usize))).count();
fn recall_at_k(
results: &[ruvector_gnn_rerank::RankedResult],
gt: &HashSet<usize>,
k: usize,
) -> f64 {
let hits = results
.iter()
.take(k)
.filter(|r| gt.contains(&(r.id as usize)))
.count();
hits as f64 / gt.len().min(k) as f64
}

View file

@ -11,7 +11,11 @@ use ruvector_gnn_rerank::{
};
fn cand(id: u32, vector: Vec<f32>, noisy_score: f32) -> Candidate {
Candidate { id, vector, noisy_score }
Candidate {
id,
vector,
noisy_score,
}
}
/// Run an input through every variant; return whether ALL returned Ok.
@ -28,15 +32,24 @@ fn all_variants(query: &[f32], cands: &[Candidate], k: usize) -> Vec<Result<(),
#[test]
fn rejects_nan_score() {
let cands = vec![cand(0, vec![1.0, 0.0], f32::NAN), cand(1, vec![0.0, 1.0], 0.5)];
let cands = vec![
cand(0, vec![1.0, 0.0], f32::NAN),
cand(1, vec![0.0, 1.0], 0.5),
];
for r in all_variants(&[1.0, 0.0], &cands, 1) {
assert!(matches!(r, Err(RerankerError::NonFinite { .. })), "NaN score must be rejected, got {r:?}");
assert!(
matches!(r, Err(RerankerError::NonFinite { .. })),
"NaN score must be rejected, got {r:?}"
);
}
}
#[test]
fn rejects_inf_score() {
let cands = vec![cand(0, vec![1.0, 0.0], f32::INFINITY), cand(1, vec![0.0, 1.0], 0.5)];
let cands = vec![
cand(0, vec![1.0, 0.0], f32::INFINITY),
cand(1, vec![0.0, 1.0], 0.5),
];
assert!(matches!(
GnnDiffusionReranker::default().rerank(&[1.0, 0.0], &cands, 1),
Err(RerankerError::NonFinite { .. })
@ -45,7 +58,10 @@ fn rejects_inf_score() {
#[test]
fn rejects_nan_in_vector() {
let cands = vec![cand(0, vec![f32::NAN, 0.0], 0.9), cand(1, vec![0.0, 1.0], 0.5)];
let cands = vec![
cand(0, vec![f32::NAN, 0.0], 0.9),
cand(1, vec![0.0, 1.0], 0.5),
];
assert!(matches!(
GnnDiffusionReranker::default().rerank(&[1.0, 0.0], &cands, 1),
Err(RerankerError::NonFinite { .. })
@ -54,17 +70,29 @@ fn rejects_nan_in_vector() {
#[test]
fn rejects_candidate_dimension_mismatch() {
let cands = vec![cand(0, vec![1.0, 0.0, 0.0], 0.9), cand(1, vec![0.0, 1.0], 0.5)];
let cands = vec![
cand(0, vec![1.0, 0.0, 0.0], 0.9),
cand(1, vec![0.0, 1.0], 0.5),
];
for r in all_variants(&[1.0, 0.0, 0.0], &cands, 1) {
assert!(matches!(r, Err(RerankerError::DimMismatch { .. })), "dim mismatch must be rejected, got {r:?}");
assert!(
matches!(r, Err(RerankerError::DimMismatch { .. })),
"dim mismatch must be rejected, got {r:?}"
);
}
}
#[test]
fn rejects_empty_and_k_too_large() {
assert!(matches!(GnnDiffusionReranker::default().rerank(&[1.0], &[], 1), Err(RerankerError::Empty)));
assert!(matches!(
GnnDiffusionReranker::default().rerank(&[1.0], &[], 1),
Err(RerankerError::Empty)
));
let cands = vec![cand(0, vec![1.0], 0.5)];
assert!(matches!(GnnDiffusionReranker::default().rerank(&[1.0], &cands, 5), Err(RerankerError::KTooLarge { .. })));
assert!(matches!(
GnnDiffusionReranker::default().rerank(&[1.0], &cands, 5),
Err(RerankerError::KTooLarge { .. })
));
}
#[test]
@ -72,11 +100,28 @@ fn degenerate_inputs_do_not_panic() {
// k=0 → empty result; single candidate; all-identical vectors (zero/degenerate
// cosine); k == n. None of these may panic.
let one = vec![cand(0, vec![1.0, 2.0], 0.5)];
assert_eq!(GnnDiffusionReranker::default().rerank(&[1.0, 2.0], &one, 0).unwrap().len(), 0);
assert_eq!(GnnDiffusionReranker::default().rerank(&[1.0, 2.0], &one, 1).unwrap().len(), 1);
assert_eq!(
GnnDiffusionReranker::default()
.rerank(&[1.0, 2.0], &one, 0)
.unwrap()
.len(),
0
);
assert_eq!(
GnnDiffusionReranker::default()
.rerank(&[1.0, 2.0], &one, 1)
.unwrap()
.len(),
1
);
let identical: Vec<Candidate> = (0..5).map(|i| cand(i, vec![0.0, 0.0, 0.0], 0.1 * i as f32)).collect();
let identical: Vec<Candidate> = (0..5)
.map(|i| cand(i, vec![0.0, 0.0, 0.0], 0.1 * i as f32))
.collect();
for r in all_variants(&[0.0, 0.0, 0.0], &identical, 5) {
assert!(r.is_ok(), "all-identical/zero vectors must not error or panic, got {r:?}");
assert!(
r.is_ok(),
"all-identical/zero vectors must not error or panic, got {r:?}"
);
}
}