You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The change implements the radius argument for search across the C++ core and Python wrapper, allowing users to exclude results beyond a maximum distance threshold.
Adds float radius to index_search_config_t, threaded through index_dense_gt::search() and filtered_search() overloads, with post-sort filtering in index_gt::search().
Wires the existing-but-unused radius parameter in Python Index.search() through _search_in_compiled(), and adds it to Indexes.search() and the module-level search().
Results with distance > radius are excluded; distance == radius is included. Default is infinity (no filtering, fully backward-compatible).
Changed files
File
What
include/usearch/index.hpp
radius field in index_search_config_t + filtering after sort_ascending()/shrink()
include/usearch/index_dense.hpp
radius param on all 12 search()/filtered_search() overloads + search_()
python/usearch/index.py
radius wired through _search_in_compiled(), Index.search(), Indexes.search(), search()
cpp/test.cpp
test_radius_search() -- default, tight, zero, and infinite radius with L2sq
C++ filtering happens after HNSW traversal completes (post-filter on sorted results), not during traversal;
Python filtering uses np.searchsorted on the ascending-sorted distance arrays in _search_in_compiled(). This handles both the HNSW and brute-force exact search paths without changing lib.cpp;
lib.cpp (pybind11 bindings) is intentionally not changed -- the module-level search(exact=True) path forwards **kwargs to _exact_search, which doesn't accept radius. Extracting radius as a named parameter in _search_in_compiled() avoids this cleanly.
Tests
C++ test_radius_search() passes (default, tight, zero, infinite radius)
C++ full test suite passes (build_debug/test_cpp)
Python radius tests pass (11/11 cases)
Python full test suite passes (593 passed, 6 skipped -- skips are pre-existing)
C++ filtering happens after HNSW traversal completes (post-filter on sorted results), not during traversal;
Would it mean that callers will have to experiment or pass a very high nn value to be sure that they retrieved all the nieghbours within a specific distance bound?
C++ filtering happens after HNSW traversal completes (post-filter on sorted results), not during traversal;
Would it mean that callers will have to experiment or pass a very high nn value to be sure that they retrieved all the nieghbours within a specific distance bound?
Yes. At the moment, this is by design.
The current flow is:
HNSW traversal runs to find wanted neighbors
Results are sorted ascending by distance
Then results beyond radius are filtered out
If we don't want this, we could let radius drive the HNSW traversal termination (stopping expansion when the nearest unvisited candidate exceeds radius) rather than acting as a post-filter.
This is more of a design constraint more than other.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
radiusargument for search across the C++ core and Python wrapper, allowing users to exclude results beyond a maximum distance threshold.float radiustoindex_search_config_t, threaded throughindex_dense_gt::search()andfiltered_search()overloads, with post-sort filtering inindex_gt::search().radiusparameter in PythonIndex.search()through_search_in_compiled(), and adds it toIndexes.search()and the module-levelsearch().distance > radiusare excluded;distance == radiusis included. Default is infinity (no filtering, fully backward-compatible).Changed files
include/usearch/index.hppradiusfield inindex_search_config_t+ filtering aftersort_ascending()/shrink()include/usearch/index_dense.hppradiusparam on all 12search()/filtered_search()overloads +search_()python/usearch/index.pyradiuswired through_search_in_compiled(),Index.search(),Indexes.search(),search()cpp/test.cpptest_radius_search()-- default, tight, zero, and infinite radius with L2sqpython/scripts/test_index.pyDesign notes
np.searchsortedon the ascending-sorted distance arrays in_search_in_compiled(). This handles both the HNSW and brute-force exact search paths without changinglib.cpp;lib.cpp(pybind11 bindings) is intentionally not changed -- the module-levelsearch(exact=True)path forwards**kwargsto_exact_search, which doesn't acceptradius. Extractingradiusas a named parameter in_search_in_compiled()avoids this cleanly.Tests
test_radius_search()passes (default, tight, zero, infinite radius)build_debug/test_cpp)