PiPNN 1/6: extract shared RobustPrune - #1315
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extracts Vamana’s reusable RobustPrune alpha-round occlusion state machine into a new allocation-free kernel (graph/internal/robust_prune.rs) while keeping Vamana-specific scratch space, provider error handling, and adapter logic in graph/internal/vamana_prune.rs. The DiskANNIndex::occlude_list path is updated to prepare “available-only” candidates for the shared kernel, then translate selected positions back to IDs and apply optional saturation.
Changes:
- Introduces
internal::robust_pruneas a provider-independent RobustPrune kernel over prepared candidates + reusable per-candidate state. - Moves Vamana-owned scratch/context and ranked provider error types into
internal::vamana_prunewith co-located tests. - Refactors
graph/index.rs::occlude_listto: validate bounds → prepare available candidates → call shared kernel → write adjacency → saturate from available-only candidates.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| diskann/src/graph/internal/vamana_prune.rs | Adds Vamana-owned scratch/context + provider error ranking and Vamana integration tests. |
| diskann/src/graph/internal/robust_prune.rs | Adds allocation-free RobustPrune kernel + pure state-machine tests. |
| diskann/src/graph/internal/prune.rs | Removes the previous combined prune implementation/state. |
| diskann/src/graph/internal/mod.rs | Rewires internal modules to expose robust_prune and vamana_prune. |
| diskann/src/graph/index.rs | Switches pruning implementation to prepare candidates and call the shared robust_prune kernel; updates saturation behavior to be available-only. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1315 +/- ##
==========================================
+ Coverage 91.26% 92.55% +1.28%
==========================================
Files 517 522 +5
Lines 98511 99556 +1045
==========================================
+ Hits 89910 92142 +2232
+ Misses 8601 7414 -1187
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
25066a6 to
748d38f
Compare
There was a problem hiding this comment.
This PR would have been easy to review, but at nontrivially regresses internal documentation and comments. For such important internal algorithms, please avoid changing comments unnecessarily, particularly when unsafe is involved.
Please restore the deleted or altered comments, making only the necessary updates for the new location. Also, please avoid renaming variables when just moving code around. A simpler diff stands on its own.
Keep the prune module, comments, names, preparation, output, and saturation in place; expose only the selection loop and require the existing SortedNeighbors witness.
748d38f to
c2e6be6
Compare
|
Addressed review in
Validation: 311 |
|
Local IAI-Callgrind check against
Measured under WSL2 with the archived local regression fixture; no submitted benchmark target. Full record: |
|
All review threads now point to superseded lines. The final extraction keeps the helper in |
Wei Wu (wuw92)
left a comment
There was a problem hiding this comment.
LGTM. Since it is intended to be a focused extraction, I would keep the implementation as close to the original as possible and simplify the PR description.
| break; | ||
| } | ||
|
|
||
| let neighbor_distance = pool[i].distance(); |
There was a problem hiding this comment.
Could we keep this extraction identical to the old implementation by destructuring (neighbor_distance, neighbor) from cache, as the original loop did?
Once the distance comes from cache, pool has no remaining use inside robust_prune, so it can also be removed from the function signature. This avoids having two sources for the same candidate distance that could disagree.
There was a problem hiding this comment.
+1 to this. Drop the pool argument in favor of a documented, sorted cache.
There was a problem hiding this comment.
Updated robust_prune to read the source distance from cache and removed the pool parameter. This restores the pre-extraction distance source.
There was a problem hiding this comment.
Follow-up: cache is now the only distance source. I retained SortedNeighbors as the sortedness witness required by this private API and added an alignment assertion between the sorted pool and cache. RobustPrune does not read a distance from the pool.
There was a problem hiding this comment.
Since pool is only used for a debug-only length check, it does not actually establish that the separately supplied cache has the same ordering. Could we drop pool, document that cache must be sorted by source distance, and add a debug assertion using the canonical distance ordering? This keeps the helper’s contract attached to the data it actually consumes.
There was a problem hiding this comment.
Fixed in c3fd818. robust_prune now accepts only the nearest-first cache. The caller retains pool for cache construction and ID mapping. A debug assertion checks adjacent cache distances with the same canonical ordering used by SortedNeighbors.
4721ec5 to
149417b
Compare
149417b to
c3fd818
Compare
Purpose
This PR extracts the private Vamana RobustPrune selection loop. PiPNN can reuse this loop in a later PR.
The change adds no public API. It does not change Vamana pruning behavior.
Main changes
graph::internal::prune::robust_prunenow owns the alpha-round selection loop.DiskANNIndex::occlude_liststill sorts candidates, loads vectors, maps IDs, and applies saturation.Preserved behavior
Noneentries.occlude_list.Review order
diskann/src/graph/internal/prune.rs.index.rs.DiskANNIndex::occlude_list.Validation
diskannlibrary tests pass.-Dwarnings.Stack
Stack 1/6. #1287 adds PiPNN numerical kernels.