Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
c6e880d
Add multi-segment GPU search: cuvsSelectK C API and Java bindings
jamxia155 Mar 31, 2026
390adec
Add parallel multi-segment CAGRA search with async memory resource
jamxia155 Apr 2, 2026
92dbcf9
Fix CudaStreamPool races and reduce multi-segment search overhead
jamxia155 Apr 2, 2026
82dcf71
Default initialize CAGRA search parameters
jamxia155 Apr 13, 2026
fad76cb
Enable persistent CAGRA kernel to be shared across index segments
jamxia155 Apr 13, 2026
22a2c8d
java: parallelize persistent-mode segment searches in MultiSegmentCag…
jamxia155 Apr 14, 2026
69c4771
Add native multi-segment CAGRA search and per-resources workspace pool
jamxia155 Apr 16, 2026
49e5a14
java: add DataType.HALF (float16) support to CuVSMatrix
jamxia155 Apr 20, 2026
29751c7
Fix errors after merge
jamxia155 Apr 23, 2026
2fffcb8
Remove dead code
jamxia155 Apr 23, 2026
d284bd0
Remove remnants of experimental code
jamxia155 May 1, 2026
1e012c0
Load libcudart.so automatically when libcuvs_c.so uses static CUDA
jamxia155 May 11, 2026
235fb32
Add multi-segment CAGRA search with bitset prefilter support
jamxia155 May 16, 2026
86a4f70
Add prefiltered ground truth generation to cuvs_bench
jamxia155 May 18, 2026
21bd700
Check for sufficient itopk_size
jamxia155 May 20, 2026
e1954b3
Update nomenclature to multi-partition
jamxia155 May 20, 2026
fdb025c
Refactor multi-partition CAGRA search to return merged global top-k
jamxia155 May 21, 2026
12d7f55
Allow multi-partition CAGRA search topk to exceed per-partition itopk…
jamxia155 May 30, 2026
7f479b8
Revert "Allow multi-partition CAGRA search topk to exceed per-partiti…
jamxia155 Jun 1, 2026
6b4e34f
Route multi-partition CAGRA search by params.algo
jamxia155 Jun 2, 2026
cf679b9
Enable MULTI_KERNEL in multi-partition CAGRA search
jamxia155 Jun 2, 2026
37a65d7
Tighten SINGLE_CTA multi-partition feasibility check
jamxia155 Jun 3, 2026
56e99ee
Add partition-aware MULTI_KERNEL expansion kernels
jamxia155 Jun 3, 2026
aa93362
Add unit tests for partition-aware MULTI_KERNEL kernels
jamxia155 Jun 3, 2026
4db0941
Fuse MULTI_KERNEL multi-partition into a single search call
jamxia155 Jun 5, 2026
876fb4d
Revert MULTI_KERNEL multi-partition work
jamxia155 Jun 5, 2026
f071508
Tighten SINGLE_CTA multi-partition feasibility check
jamxia155 Jun 5, 2026
efc7283
Generalize multi-partition post-processing for variable per-partition…
jamxia155 Jun 8, 2026
837767d
Add multi-partition MULTI_CTA search path
jamxia155 Jun 8, 2026
4b423ea
Gate multi-partition AUTO on (query, partition) CTA count
jamxia155 Jun 9, 2026
54a55f5
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jun 10, 2026
134f899
Updates to snapshotRepository and plugins
jolorunyomi Jun 25, 2026
0aa4b03
Resolve cudart symbols via FFI lookup for static CUDA builds
jamxia155 Jun 25, 2026
b1c3e12
Rename public CAGRA multi-partition search overloads to `search`
jamxia155 Jun 25, 2026
b35575f
Sync build.sh VERSION to 26.08.0-SNAPSHOT to match the pom
jamxia155 Jun 25, 2026
0c41987
Extract shared search_core for MULTI_CTA CAGRA search
jamxia155 Jun 26, 2026
22e337c
Formatting
jamxia155 Jun 29, 2026
301f5ef
Remove code remnants
jamxia155 Jun 29, 2026
d7e6b68
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jun 30, 2026
69d3db1
Fix InnerProduct top-k selection in multi-partition CAGRA search
jamxia155 Jun 30, 2026
416eca5
Add multi-partition CAGRA search tests (float/uint32)
jamxia155 Jun 30, 2026
47e1499
Add half/int8/uint8 coverage for multi-partition CAGRA search tests
jamxia155 Jun 30, 2026
0cf23a4
Reduce runtime of multi-partition CAGRA search tests
jamxia155 Jun 30, 2026
6cf505a
Add C-API tests for cuvsCagraSearchMultiPartition and cuvsSelectK; ex…
jamxia155 Jun 30, 2026
c4d3554
Make multi-partition CAGRA Java API reachable from the base source set
jamxia155 Jun 30, 2026
f99b065
Add MultiPartitionCagraSearchIT (host + device queries, filtering)
jamxia155 Jun 30, 2026
fe903ce
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jun 30, 2026
dbcab41
Add TODO and issue tracking
jamxia155 Jul 1, 2026
7e8adc5
Formatting
jamxia155 Jul 2, 2026
d2a9583
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jul 2, 2026
fc8be02
Add cuvs/selection/select_k.h to core/all.h binding header list
jamxia155 Jul 2, 2026
5955c64
Pin SINGLE_CTA in CagraBuildAndSearchIT tiny-dataset tests
jamxia155 Jul 3, 2026
643bd3f
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jul 3, 2026
99e3cb7
Recompute multi-partition CAGRA filter offsets in-search; drop multi_…
jamxia155 Jul 3, 2026
5ba81f3
Remove unused #include
jamxia155 Jul 3, 2026
6b2b0b3
Restore unchanged files
jamxia155 Jul 3, 2026
7864d6a
Document nonequivalence of APIs
jamxia155 Jul 4, 2026
21e243d
Validate DLPack tensor contract in cuvsSelectK before dereferencing
jamxia155 Jul 4, 2026
23ad23e
Validate and synchronize setWorkspacePool in Java CuVSResources
jamxia155 Jul 4, 2026
a70f58b
Simplify cuvsRMMAsyncMemoryResourceEnable by letting RMM own the reso…
jamxia155 Jul 4, 2026
c9d131b
Support all index and neighbor dtypes in multi-partition CAGRA search…
jamxia155 Jul 4, 2026
7a7c3e6
Add Doxygen for overloads
jamxia155 Jul 4, 2026
4e0b4eb
Move validations from detail layer to dispatching
jamxia155 Jul 4, 2026
102962d
Fix multi-partition ordinal sentinel check to preserve valid uint32 hits
jamxia155 Jul 4, 2026
1c347de
Slightly relax the recall threshold to reduce test flakiness
jamxia155 Jul 4, 2026
4c37724
Add destroyed-state guard in delegate method
jamxia155 Jul 5, 2026
061ad9e
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jul 5, 2026
43bbc53
Chunk multi-partition CAGRA search by max_queries
jamxia155 Jul 5, 2026
1770971
Require uniform metric and graph degree across CAGRA partitions
jamxia155 Jul 5, 2026
fa29064
Update a comment
jamxia155 Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ add_library(
src/preprocessing/quantize/pq.cpp
src/preprocessing/quantize/scalar.cpp
src/distance/pairwise_distance.cpp
src/selection/select_k.cpp
)
add_library(cuvs::c_api ALIAS cuvs_c)
set_target_properties(
Expand Down
2 changes: 2 additions & 0 deletions c/include/cuvs/core/all.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,5 @@
#include <cuvs/preprocessing/quantize/binary.h>
#include <cuvs/preprocessing/quantize/pq.h>
#include <cuvs/preprocessing/quantize/scalar.h>

#include <cuvs/selection/select_k.h>
32 changes: 31 additions & 1 deletion c/include/cuvs/core/c_api.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -131,6 +131,23 @@ CUVS_EXPORT cuvsError_t cuvsStreamSync(cuvsResources_t res);
*/
CUVS_EXPORT cuvsError_t cuvsDeviceIdGet(cuvsResources_t res, int* device_id);

/**
* @brief Configure the temporary workspace on this resources object as an uncapped pool, backed
* by the current device memory resource. After the initial reservation is allocated on
* first use, subsequent calls to cuvsRMMAlloc / cuvsRMMFree on the same resources handle
* hit the pool cache rather than calling cudaMallocAsync / cudaFreeAsync, reducing CUDA
* context lock contention under concurrent query threads. The pool grows without shrinking:
* freed allocations are returned to the pool rather than to the device, so the pool's
* high-water mark only increases until the resources object is destroyed.
*
* @param[in] res cuvsResources_t opaque C handle
* @param[in] initial_size_bytes initial pool reservation in bytes; size to cover the
* steady-state working set to avoid growth after warmup
* @return cuvsError_t
*/
CUVS_EXPORT cuvsError_t cuvsResourcesSetWorkspacePool(cuvsResources_t res,
size_t initial_size_bytes);

/**
* @brief Create an Initialized opaque C handle for C++ type `raft::device_resources_snmg`
* for multi-GPU operations
Expand Down Expand Up @@ -212,6 +229,19 @@ CUVS_EXPORT cuvsError_t cuvsRMMFree(cuvsResources_t res, void* ptr, size_t bytes
CUVS_EXPORT cuvsError_t cuvsRMMPoolMemoryResourceEnable(int initial_pool_size_percent,
int max_pool_size_percent,
bool managed);
/**
* @brief Switches the working memory resource to use stream-ordered asynchronous allocation
* (cudaMallocAsync / cudaFreeAsync). Unlike the pool resource, this resource returns memory to
* the stream immediately without blocking the CPU, eliminating device-wide synchronization on
* deallocation. This is especially beneficial when multiple CAGRA searches run concurrently on
* separate CUDA streams, because the internal workspace allocations no longer serialize kernel
* launches. Be aware that this function will change the memory resource for the whole process
* and the new memory resource will be used until explicitly changed.
*
* @return cuvsError_t
*/
CUVS_EXPORT cuvsError_t cuvsRMMAsyncMemoryResourceEnable();

/**
* @brief Resets the memory resource to use the default memory resource (cuda_memory_resource)
* @return cuvsError_t
Expand Down
44 changes: 43 additions & 1 deletion c/include/cuvs/neighbors/cagra.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -714,6 +714,48 @@ CUVS_EXPORT cuvsError_t cuvsCagraSearch(cuvsResources_t res,
DLManagedTensor* distances,
cuvsFilter filter);

/**
* @brief Search multiple CAGRA index partitions concurrently and return the global top-k per
* query.
*
* For each query row, the function searches all partitions in parallel into an internal
* intermediate buffer, applies per-partition distance post-processing, runs a batched top-k
* merge across partitions, and writes the final outputs to the caller-supplied device tensors.
* All work is submitted to the CUDA stream associated with @p res; use @c cuvsStreamSync to
* wait for completion.
*
* The index element type may be float32, float16, int8, or uint8. All partitions must share the
* same element type, and the queries must use that same type.
*
* @param[in] res cuvsResources_t opaque C handle
* @param[in] params search parameters (shared across partitions)
* @param[in] num_partitions number of index partitions
* @param[in] indices array of num_partitions cuvsCagraIndex_t pointers, all of the same
* element type
* @param[in] queries DLManagedTensor* (device, same dtype as the indices, [n_queries,
* dim]); the queries matrix is searched against every partition
* @param[out] partition_ids DLManagedTensor* (device, uint32, [n_queries, k]); which partition
* each returned neighbor came from
* @param[out] neighbors DLManagedTensor* (device, uint32 or int64, [n_queries, k]); ordinal
* in the corresponding partition's dataset
* @param[out] distances DLManagedTensor* (device, float32, [n_queries, k]); post-processed
* distance for each (query, neighbor)
* @param[in] filter filter to apply during search; use {.type=NO_FILTER, .addr=0} for
* unfiltered search, or {.type=BITSET, .addr=ptr} where ptr is a
* uintptr_t-cast DLManagedTensor* holding the concatenation of the
* per-partition bitsets (each word-aligned). Per-partition bit offsets
* are recomputed internally from the index sizes.
*/
CUVS_EXPORT cuvsError_t cuvsCagraSearchMultiPartition(cuvsResources_t res,
cuvsCagraSearchParams_t params,
uint32_t num_partitions,
cuvsCagraIndex_t* indices,
DLManagedTensor* queries,
DLManagedTensor* partition_ids,
DLManagedTensor* neighbors,
DLManagedTensor* distances,
cuvsFilter filter);

/**
* @}
*/
Expand Down
37 changes: 37 additions & 0 deletions c/include/cuvs/selection/select_k.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <cuvs/core/c_api.h>
#include <dlpack/dlpack.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Select the k smallest values from a flat device array of n candidates.
*
* Treats `in_val` as a matrix of shape [1, n] and selects the `k` smallest
* float values. `out_idx` receives the int64 column positions of the selected
* values in [0, n), so the caller can recover per-segment identity as:
*
* segment_index = out_idx[j] / segment_k
* position_in_segment = out_idx[j] % segment_k
*
* @param[in] res cuvsResources_t handle
* @param[in] in_val DLManagedTensor* shape [1, n], float32, device memory
* @param[out] out_val DLManagedTensor* shape [1, k], float32, device memory
* @param[out] out_idx DLManagedTensor* shape [1, k], int64, device memory
* @return cuvsError_t
*/
CUVS_EXPORT cuvsError_t cuvsSelectK(cuvsResources_t res,
DLManagedTensor* in_val,
DLManagedTensor* out_val,
DLManagedTensor* out_idx);

#ifdef __cplusplus
}
#endif
36 changes: 30 additions & 6 deletions c/src/core/c_api.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -9,11 +9,13 @@
#include <raft/core/device_resources_snmg.hpp>
#include <raft/core/resource/cuda_stream.hpp>
#include <raft/core/resource/device_id.hpp>
#include <raft/core/resource/device_memory_resource.hpp>
#include <raft/core/resource/resource_types.hpp>
#include <raft/core/resources.hpp>
#include <raft/util/cudart_utils.hpp>
#include <rapids_logger/logger.hpp>
#include <rmm/cuda_stream_view.hpp>
#include <rmm/mr/cuda_async_memory_resource.hpp>
#include <rmm/mr/cuda_memory_resource.hpp>
#include <rmm/mr/managed_memory_resource.hpp>
#include <rmm/mr/per_device_resource.hpp>
Expand All @@ -35,6 +37,19 @@ extern "C" cuvsError_t cuvsResourcesCreate(cuvsResources_t* res)
});
}

extern "C" cuvsError_t cuvsResourcesSetWorkspacePool(cuvsResources_t res, size_t initial_size_bytes)
{
return cuvs::core::translate_exceptions([=] {
auto res_ptr = reinterpret_cast<raft::resources*>(res);
// Create an uncapped pool: pre-warms with initial_size_bytes to avoid cudaMalloc on every
// query, but can grow beyond that if an allocation exceeds the initial reservation.
raft::resource::set_workspace_resource(
*res_ptr,
rmm::mr::pool_memory_resource{rmm::mr::get_current_device_resource_ref(),
initial_size_bytes});
});
}

extern "C" cuvsError_t cuvsResourcesDestroy(cuvsResources_t res)
{
return cuvs::core::translate_exceptions([=] {
Expand Down Expand Up @@ -132,17 +147,17 @@ extern "C" cuvsError_t cuvsRMMAlloc(cuvsResources_t res, void** ptr, size_t byte
{
return cuvs::core::translate_exceptions([=] {
auto res_ptr = reinterpret_cast<raft::resources*>(res);
auto mr = rmm::mr::get_current_device_resource_ref();
*ptr = mr.allocate(raft::resource::get_cuda_stream(*res_ptr), bytes);
auto stream = raft::resource::get_cuda_stream(*res_ptr);
*ptr = raft::resource::get_workspace_resource_ref(*res_ptr).allocate(stream, bytes);
});
}

extern "C" cuvsError_t cuvsRMMFree(cuvsResources_t res, void* ptr, size_t bytes)
{
return cuvs::core::translate_exceptions([=] {
auto res_ptr = reinterpret_cast<raft::resources*>(res);
auto mr = rmm::mr::get_current_device_resource_ref();
mr.deallocate(raft::resource::get_cuda_stream(*res_ptr), ptr, bytes);
auto stream = raft::resource::get_cuda_stream(*res_ptr);
raft::resource::get_workspace_resource_ref(*res_ptr).deallocate(stream, ptr, bytes);
});
}

Expand All @@ -164,9 +179,18 @@ extern "C" cuvsError_t cuvsRMMPoolMemoryResourceEnable(int initial_pool_size_per
});
}

extern "C" cuvsError_t cuvsRMMAsyncMemoryResourceEnable()
{
return cuvs::core::translate_exceptions([=] {
rmm::mr::set_current_device_resource(rmm::mr::cuda_async_memory_resource{});
});
}

extern "C" cuvsError_t cuvsRMMMemoryResourceReset()
{
return cuvs::core::translate_exceptions([=] { rmm::mr::reset_current_device_resource(); });
return cuvs::core::translate_exceptions([=] {
rmm::mr::reset_current_device_resource();
});
}

thread_local std::unique_ptr<rmm::mr::pinned_host_memory_resource> pinned_mr;
Expand Down
137 changes: 136 additions & 1 deletion c/src/neighbors/cagra.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -263,6 +263,93 @@ void _search(cuvsResources_t res,
}
}

template <typename T, typename OutIdxT>
void _search_multi_partition(cuvsResources_t res,
cuvsCagraSearchParams params,
uint32_t num_partitions,
cuvsCagraIndex_t* indices,
DLManagedTensor* queries,
DLManagedTensor* partition_ids,
DLManagedTensor* neighbors,
DLManagedTensor* distances,
cuvsFilter filter)
{
using IdxT = uint32_t;
using DistanceT = float;
using IndexT = cuvs::neighbors::cagra::index<T, IdxT>;

auto res_ptr = reinterpret_cast<raft::resources*>(res);
auto search_params = cuvs::neighbors::cagra::search_params();
convert_c_search_params(params, &search_params);

std::vector<const IndexT*> idx_vec(num_partitions);
for (uint32_t i = 0; i < num_partitions; i++) {
idx_vec[i] = reinterpret_cast<const IndexT*>(indices[i]->addr);
}

using queries_view_t = raft::device_matrix_view<const T, int64_t, raft::row_major>;
using pid_view_t = raft::device_matrix_view<uint32_t, int64_t, raft::row_major>;
using nbrs_view_t = raft::device_matrix_view<OutIdxT, int64_t, raft::row_major>;
using dist_view_t = raft::device_matrix_view<DistanceT, int64_t, raft::row_major>;

auto queries_view = cuvs::core::from_dlpack<queries_view_t>(queries);
auto partition_ids_view = cuvs::core::from_dlpack<pid_view_t>(partition_ids);
auto neighbors_view = cuvs::core::from_dlpack<nbrs_view_t>(neighbors);
auto distances_view = cuvs::core::from_dlpack<dist_view_t>(distances);

if (filter.type == NO_FILTER) {
cuvs::neighbors::cagra::search(
*res_ptr, search_params, idx_vec, queries_view, partition_ids_view, neighbors_view, distances_view);
} else if (filter.type == BITSET) {
auto* bitset_tensor = reinterpret_cast<DLManagedTensor*>(filter.addr);
RAFT_EXPECTS(bitset_tensor != nullptr, "BITSET filter addr must be non-null");

using bitset_mdspan_t = raft::device_vector_view<std::uint32_t, int64_t, raft::row_major>;
auto bitset_mds = cuvs::core::from_dlpack<bitset_mdspan_t>(bitset_tensor);

// The bitset is the concatenation of the per-partition bitsets; use its full word capacity as
// the logical bit length. Per-partition bit offsets and the size-consistency check against the
// partition sizes are handled in search_multi_partition, which already loops the partitions.
cuvs::core::bitset_view<std::uint32_t, int64_t> combined_bitset_view(
bitset_mds, static_cast<int64_t>(bitset_mds.size()) * 32);
cuvs::neighbors::filtering::bitset_filter<std::uint32_t, int64_t> bitset_filter_obj(
combined_bitset_view);

cuvs::neighbors::cagra::search(*res_ptr,
search_params,
idx_vec,
queries_view,
partition_ids_view,
neighbors_view,
distances_view,
bitset_filter_obj);
} else {
RAFT_FAIL("Unsupported filter type for multi-partition search: %d", (int)filter.type);
}
}

template <typename T>
void _search_multi_partition(cuvsResources_t res,
cuvsCagraSearchParams params,
uint32_t num_partitions,
cuvsCagraIndex_t* indices,
DLManagedTensor* queries,
DLManagedTensor* partition_ids,
DLManagedTensor* neighbors,
DLManagedTensor* distances,
cuvsFilter filter)
{
if (neighbors->dl_tensor.dtype.code == kDLUInt && neighbors->dl_tensor.dtype.bits == 32) {
_search_multi_partition<T, uint32_t>(
res, params, num_partitions, indices, queries, partition_ids, neighbors, distances, filter);
} else if (neighbors->dl_tensor.dtype.code == kDLInt && neighbors->dl_tensor.dtype.bits == 64) {
_search_multi_partition<T, int64_t>(
res, params, num_partitions, indices, queries, partition_ids, neighbors, distances, filter);
} else {
RAFT_FAIL("neighbors should be of type uint32_t or int64_t");
}
}

template <typename T>
void _serialize(cuvsResources_t res,
const char* filename,
Expand Down Expand Up @@ -690,6 +777,54 @@ extern "C" cuvsError_t cuvsCagraSearch(cuvsResources_t res,
});
}

extern "C" cuvsError_t cuvsCagraSearchMultiPartition(cuvsResources_t res,
cuvsCagraSearchParams_t params,
uint32_t num_partitions,
cuvsCagraIndex_t* indices,
DLManagedTensor* queries,
DLManagedTensor* partition_ids,
DLManagedTensor* neighbors,
DLManagedTensor* distances,
cuvsFilter filter)
{
return cuvs::core::translate_exceptions([=] {
RAFT_EXPECTS(num_partitions > 0, "num_partitions must be > 0");
RAFT_EXPECTS(indices != nullptr && queries != nullptr && partition_ids != nullptr &&
neighbors != nullptr && distances != nullptr,
"All pointer arguments must be non-null");

// Every partition index must be present, built, and share one dtype; the search dispatches on
// that common dtype. The queries dtype is validated against T inside from_dlpack.
RAFT_EXPECTS(indices[0] != nullptr, "Index at position 0 is null");
auto index_dtype = indices[0]->dtype;
for (uint32_t i = 0; i < num_partitions; i++) {
RAFT_EXPECTS(indices[i] != nullptr && indices[i]->addr != 0,
"Index at position %u is null or not built", i);
RAFT_EXPECTS(
indices[i]->dtype.code == index_dtype.code && indices[i]->dtype.bits == index_dtype.bits,
"All partition indices must share the same dtype; position %u differs from position 0", i);
}

if (index_dtype.code == kDLFloat && index_dtype.bits == 32) {
_search_multi_partition<float>(
res, *params, num_partitions, indices, queries, partition_ids, neighbors, distances, filter);
} else if (index_dtype.code == kDLFloat && index_dtype.bits == 16) {
_search_multi_partition<half>(
res, *params, num_partitions, indices, queries, partition_ids, neighbors, distances, filter);
} else if (index_dtype.code == kDLInt && index_dtype.bits == 8) {
_search_multi_partition<int8_t>(
res, *params, num_partitions, indices, queries, partition_ids, neighbors, distances, filter);
} else if (index_dtype.code == kDLUInt && index_dtype.bits == 8) {
_search_multi_partition<uint8_t>(
res, *params, num_partitions, indices, queries, partition_ids, neighbors, distances, filter);
} else {
RAFT_FAIL("Unsupported multi-partition index DLtensor dtype: %d and bits: %d",
index_dtype.code,
index_dtype.bits);
}
});
}

extern "C" cuvsError_t cuvsCagraMerge(cuvsResources_t res,
cuvsCagraIndexParams_t params,
cuvsCagraIndex_t* indices,
Expand Down
Loading
Loading