Reduce unnecessary work to enforce invariants

This commit is contained in:
Dirkjan Ochtman 2021-01-20 16:29:33 +01:00
parent ecdce08196
commit 5cf83543db
1 changed files with 8 additions and 11 deletions

View File

@ -509,7 +509,6 @@ trait Layer {
} }
} }
search.nearest.sort_unstable();
search.nearest.truncate(search.ef); search.nearest.truncate(search.ef);
} }
@ -526,6 +525,8 @@ pub struct Search {
/// Candidates for further inspection (`C` in the paper) /// Candidates for further inspection (`C` in the paper)
candidates: BinaryHeap<Reverse<Candidate>>, candidates: BinaryHeap<Reverse<Candidate>>,
/// Nearest neighbors found so far (`W` in the paper) /// Nearest neighbors found so far (`W` in the paper)
///
/// This must always be in sorted (nearest first) order.
nearest: Vec<Candidate>, nearest: Vec<Candidate>,
/// Working set for heuristic selection /// Working set for heuristic selection
working: Vec<Candidate>, working: Vec<Candidate>,
@ -562,7 +563,6 @@ impl Search {
/// Selection of neighbors for insertion (algorithm 3 from the paper) /// Selection of neighbors for insertion (algorithm 3 from the paper)
fn select_simple(&mut self) -> &[Candidate] { fn select_simple(&mut self) -> &[Candidate] {
self.nearest.sort_unstable();
&self.nearest &self.nearest
} }
@ -593,7 +593,10 @@ impl Search {
} }
} }
if params.extend_candidates {
self.working.sort_unstable(); self.working.sort_unstable();
}
self.nearest.clear(); self.nearest.clear();
self.discarded.clear(); self.discarded.clear();
for candidate in self.working.drain(..) { for candidate in self.working.drain(..) {
@ -625,7 +628,6 @@ impl Search {
} }
} }
self.nearest.sort_unstable();
&self.nearest &self.nearest
} }
@ -649,9 +651,6 @@ impl Search {
self.nearest.insert(idx, new); self.nearest.insert(idx, new);
self.candidates.push(Reverse(new)); self.candidates.push(Reverse(new));
if self.nearest.len() > self.ef {
self.nearest.truncate(self.ef);
}
} }
/// Lower the search to the next lower level /// Lower the search to the next lower level
@ -659,11 +658,9 @@ impl Search {
/// Re-initialize the `Search`: `nearest`, the output `W` from the last round, now becomes /// Re-initialize the `Search`: `nearest`, the output `W` from the last round, now becomes
/// the set of enter points, which we use to initialize both `candidates` and `visited`. /// the set of enter points, which we use to initialize both `candidates` and `visited`.
/// ///
/// Invariant: `nearest` should be sorted before this is called. This is generally the case /// Invariant: `nearest` should be sorted and truncated before this is called. This is generally
/// because `Layer::search()` is always called right before calling `cull()`. /// the case because `Layer::search()` is always called right before calling `cull()`.
fn cull(&mut self) { fn cull(&mut self) {
self.nearest.truncate(self.ef); // Limit size of the set of nearest neighbors
self.candidates.clear(); self.candidates.clear();
for &candidate in self.nearest.iter() { for &candidate in self.nearest.iter() {
self.candidates.push(Reverse(candidate)); self.candidates.push(Reverse(candidate));