Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ target_compile_definitions(cuvs::cuvs INTERFACE $<$<BOOL:${CUVS_NVTX}>:NVTX_ENAB
src/neighbors/nn_descent_c.cpp
src/neighbors/refine/refine_c.cpp
src/neighbors/tiered_index_c.cpp
src/neighbors/all_neighbors_c.cpp
src/preprocessing/quantize/binary_c.cpp
src/preprocessing/quantize/scalar_c.cpp
src/distance/pairwise_distance_c.cpp
Expand Down
29 changes: 29 additions & 0 deletions cpp/include/cuvs/core/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,35 @@ cuvsError_t cuvsStreamGet(cuvsResources_t res, cudaStream_t* stream);
* @return cuvsError_t
*/
cuvsError_t cuvsStreamSync(cuvsResources_t res);
/**
* @brief An opaque C handle for C++ type `raft::device_resources_snmg`
*/
typedef uintptr_t cuvsSNMGResources_t;

/**
* @brief Create a SNMG resources handle with all available GPUs
*/
cuvsError_t cuvsSNMGResourcesCreate(cuvsSNMGResources_t* res);

/**
* @brief Create a SNMG resources handle with a subset of GPUs
* @param[in] res output handle
* @param[in] device_ids pointer to device ids array
* @param[in] num_ids number of device ids
*/
cuvsError_t cuvsSNMGResourcesCreateWithDevices(cuvsSNMGResources_t* res,
const int* device_ids,
int num_ids);

/**
* @brief Destroy a SNMG resources handle
*/
cuvsError_t cuvsSNMGResourcesDestroy(cuvsSNMGResources_t res);

/**
* @brief Synchronize all streams in a SNMG resources handle
*/
cuvsError_t cuvsSNMGResourcesSync(cuvsSNMGResources_t res);
/** @} */

/**
Expand Down
121 changes: 121 additions & 0 deletions cpp/include/cuvs/neighbors/all_neighbors.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2025, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <cuvs/core/c_api.h>
#include <cuvs/distance/distance.h>
#include <cuvs/neighbors/ivf_pq.h>
#include <cuvs/neighbors/nn_descent.h>
#include <dlpack/dlpack.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup all_neighbors_c_build All-neighbors C-API build (SNMG only)
Comment thread
viclafargue marked this conversation as resolved.
Outdated
* @{
*
* All-neighbors constructs an approximate k-NN graph for all vectors in a dataset.
* This SNMG C API always expects a multi-GPU resources handle (`cuvsSNMGResources_t`)
* created from `raft::device_resources_snmg` and will distribute work across GPUs.
*
* Notes:
* - Outputs (indices, distances, core_distances) are expected to be on device memory.
* - Host variant accepts host-resident dataset; device variant accepts device-resident dataset.
* - For batching, `overlap_factor < n_clusters` must hold.
* - When `core_distances` is provided, mutual-reachability distances are produced (see alpha).
*/

/**
* @brief Graph build algorithm selection.
*/
typedef enum {
CUVS_ALL_NEIGHBORS_ALGO_BRUTE_FORCE = 0, ///< Use Brute Force for local kNN subgraphs
CUVS_ALL_NEIGHBORS_ALGO_IVF_PQ = 1, ///< Use IVF-PQ for local kNN subgraphs (host dataset only)
CUVS_ALL_NEIGHBORS_ALGO_NN_DESCENT = 2 ///< Use NN-Descent for local kNN subgraphs
} cuvsAllNeighborsAlgo;

/**
* @brief Parameters controlling SNMG all-neighbors build.
*/
struct cuvsAllNeighborsIndexParams {
cuvsAllNeighborsAlgo algo; ///< Local kNN graph build algorithm
size_t overlap_factor; ///< Number of clusters each point is assigned to (must be < n_clusters)
size_t
n_clusters; ///< Number of clusters/batches to partition the dataset into (> overlap_factor)
cuvsDistanceType metric; ///< Distance metric used for graph construction

// Algorithm-specific parameters (only one should be set based on algo)
cuvsIvfPqIndexParams_t ivf_pq_params; ///< Parameters for IVF-PQ algorithm (when algo ==
///< CUVS_ALL_NEIGHBORS_ALGO_IVF_PQ)
cuvsNNDescentIndexParams_t nn_descent_params; ///< Parameters for NN-Descent algorithm (when algo
///< == CUVS_ALL_NEIGHBORS_ALGO_NN_DESCENT)
};

typedef struct cuvsAllNeighborsIndexParams* cuvsAllNeighborsIndexParams_t;

/**
* @brief Build an all-neighbors k-NN graph from a host-resident dataset (SNMG).
Comment thread
viclafargue marked this conversation as resolved.
Outdated
*
* @param[in] snmg_res SNMG multi-GPU resources (raft::device_resources_snmg)
* @param[in] params Build parameters (see cuvsAllNeighborsIndexParams)
* @param[in] dataset 2D tensor [num_rows x dim] on host (CPU or CUDAHost)
* @param[out] indices 2D tensor [num_rows x k] on device (int64)
* @param[out] distances Optional 2D tensor [num_rows x k] on device (float32); can be NULL
* @param[out] core_distances Optional 1D tensor [num_rows] on device (float32); can be NULL
* @param[in] alpha Mutual-reachability scaling; used only when core_distances is provided
*
* The function partitions data into `n_clusters` clusters and assigns each row to
* `overlap_factor` nearest clusters. Work is balanced across GPUs according to the
* number of available ranks in `snmg`. Outputs always reside in device memory.
*/
cuvsError_t cuvsAllNeighborsBuildHost(cuvsSNMGResources_t snmg_res,
cuvsAllNeighborsIndexParams_t params,
DLManagedTensor* dataset,
DLManagedTensor* indices,
DLManagedTensor* distances,
DLManagedTensor* core_distances,
float alpha);

/**
* @brief Build an all-neighbors k-NN graph from a device-resident dataset (single-GPU, no
* batching).
*
* @param[in] res Single-GPU resources (raft::device_resources)
* @param[in] params Build parameters (see cuvsAllNeighborsIndexParams). For device
* datasets, `n_clusters` must be 1 (no batching); `overlap_factor` is ignored.
* @param[in] dataset 2D tensor [num_rows x dim] on device (CUDA/CUDAManaged)
* @param[out] indices 2D tensor [num_rows x k] on device (int64)
* @param[out] distances Optional 2D tensor [num_rows x k] on device (float32); can be NULL
* @param[out] core_distances Optional 1D tensor [num_rows] on device (float32); can be NULL
* @param[in] alpha Mutual-reachability scaling; used only when core_distances is provided
*/
cuvsError_t cuvsAllNeighborsBuildDevice(cuvsResources_t res,
Comment thread
viclafargue marked this conversation as resolved.
Outdated
cuvsAllNeighborsIndexParams_t params,
DLManagedTensor* dataset,
DLManagedTensor* indices,
DLManagedTensor* distances,
DLManagedTensor* core_distances,
float alpha);

/** @} */

#ifdef __cplusplus
}
#endif
36 changes: 36 additions & 0 deletions cpp/src/core/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <cuvs/core/exceptions.hpp>
#include <cuvs/version_config.h>

#include <raft/core/device_resources_snmg.hpp>
#include <raft/core/resource/cuda_stream.hpp>
#include <raft/core/resources.hpp>
#include <raft/util/cudart_utils.hpp>
Expand Down Expand Up @@ -281,3 +282,38 @@ extern "C" cuvsError_t cuvsMatrixSliceRows(cuvsResources_t res,
dst_managed->deleter = cuvsMatrixDestroy;
});
}

extern "C" cuvsError_t cuvsSNMGResourcesCreate(cuvsSNMGResources_t* res)
{
return cuvs::core::translate_exceptions([=] {
auto res_ptr = new raft::device_resources_snmg{};
*res = reinterpret_cast<uintptr_t>(res_ptr);
});
}

extern "C" cuvsError_t cuvsSNMGResourcesCreateWithDevices(cuvsSNMGResources_t* res,
const int* device_ids,
int num_ids)
{
return cuvs::core::translate_exceptions([=] {
std::vector<int> ids(device_ids, device_ids + num_ids);
auto res_ptr = new raft::device_resources_snmg{ids};
*res = reinterpret_cast<uintptr_t>(res_ptr);
});
}

extern "C" cuvsError_t cuvsSNMGResourcesDestroy(cuvsSNMGResources_t res)
{
return cuvs::core::translate_exceptions([=] {
auto res_ptr = reinterpret_cast<raft::device_resources_snmg*>(res);
delete res_ptr;
});
}

extern "C" cuvsError_t cuvsSNMGResourcesSync(cuvsSNMGResources_t res)
{
return cuvs::core::translate_exceptions([=] {
auto res_ptr = reinterpret_cast<raft::device_resources_snmg*>(res);
res_ptr->sync_stream();
});
}
Loading
Loading