Skip to content

Commit fc631e1

Browse files
committed
Merge remote-tracking branch 'origin/branch-25.08' into c-api-version-bump
2 parents 3cb508e + 97c5a49 commit fc631e1

10 files changed

Lines changed: 397 additions & 105 deletions

File tree

cpp/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,6 @@ if(BUILD_SHARED_LIBS)
416416
src/neighbors/iface/iface_pq_half_int64_t.cu
417417
src/neighbors/iface/iface_pq_int8_t_int64_t.cu
418418
src/neighbors/iface/iface_pq_uint8_t_int64_t.cu
419-
src/neighbors/detail/cagra/cagra_build.cpp
420419
src/neighbors/detail/cagra/topk_for_cagra/topk.cu
421420
src/neighbors/dynamic_batching.cu
422421
src/neighbors/cagra_index_wrapper.cu

cpp/include/cuvs/neighbors/all_neighbors.hpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#pragma once
1818

19+
#include <cuvs/neighbors/graph_build_types.hpp>
1920
#include <cuvs/neighbors/ivf_pq.hpp>
2021
#include <cuvs/neighbors/nn_descent.hpp>
2122

@@ -27,22 +28,6 @@ namespace cuvs::neighbors::all_neighbors {
2728
* @{
2829
*/
2930

30-
/**
31-
* @brief Parameters used to build an all-neighbors knn graph (find nearest neighbors for all the
32-
* training vectors)
33-
*/
34-
namespace graph_build_params {
35-
36-
/** Specialized parameters utilizing IVF-PQ to build knn graph */
37-
struct ivf_pq_params {
38-
cuvs::neighbors::ivf_pq::index_params build_params;
39-
cuvs::neighbors::ivf_pq::search_params search_params;
40-
float refinement_rate = 2.0;
41-
};
42-
43-
using nn_descent_params = cuvs::neighbors::nn_descent::index_params;
44-
} // namespace graph_build_params
45-
4631
using GraphBuildParams =
4732
std::variant<graph_build_params::ivf_pq_params, graph_build_params::nn_descent_params>;
4833

cpp/include/cuvs/neighbors/cagra.hpp

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023-2024, NVIDIA CORPORATION.
2+
* Copyright (c) 2023-2025, NVIDIA CORPORATION.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
#include "common.hpp"
2020
#include <cuvs/distance/distance.hpp>
2121
#include <cuvs/neighbors/common.hpp>
22+
#include <cuvs/neighbors/graph_build_types.hpp>
2223
#include <cuvs/neighbors/ivf_pq.hpp>
2324
#include <cuvs/neighbors/nn_descent.hpp>
2425
#include <raft/core/device_mdspan.hpp>
@@ -35,49 +36,13 @@
3536
#include <variant>
3637

3738
namespace cuvs::neighbors::cagra {
39+
// For re-exporting into cagra namespace
40+
namespace graph_build_params = cuvs::neighbors::graph_build_params;
3841
/**
3942
* @defgroup cagra_cpp_index_params CAGRA index build parameters
4043
* @{
4144
*/
4245

43-
/**
44-
* @brief ANN parameters used by CAGRA to build knn graph
45-
*
46-
*/
47-
namespace graph_build_params {
48-
49-
/** Specialized parameters utilizing IVF-PQ to build knn graph */
50-
struct ivf_pq_params {
51-
cuvs::neighbors::ivf_pq::index_params build_params;
52-
cuvs::neighbors::ivf_pq::search_params search_params;
53-
float refinement_rate;
54-
55-
ivf_pq_params() = default;
56-
/**
57-
* Set default parameters based on shape of the input dataset.
58-
* Usage example:
59-
* @code{.cpp}
60-
* using namespace cuvs::neighbors;
61-
* raft::resources res;
62-
* // create index_params for a [N. D] dataset
63-
* auto dataset = raft::make_device_matrix<float, int64_t>(res, N, D);
64-
* auto pq_params =
65-
* cagra::graph_build_params::ivf_pq_params(dataset.extents());
66-
* // modify/update index_params as needed
67-
* pq_params.kmeans_trainset_fraction = 0.1;
68-
* @endcode
69-
*/
70-
ivf_pq_params(raft::matrix_extent<int64_t> dataset_extents,
71-
cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2Expanded);
72-
};
73-
74-
using nn_descent_params = cuvs::neighbors::nn_descent::index_params;
75-
76-
// **** Experimental ****
77-
using iterative_search_params = cuvs::neighbors::search_params;
78-
79-
} // namespace graph_build_params
80-
8146
struct index_params : cuvs::neighbors::index_params {
8247
/** Degree of input graph for pruning. */
8348
size_t intermediate_graph_degree = 128;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2025, NVIDIA CORPORATION.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <cuvs/neighbors/ivf_pq.hpp>
20+
#include <cuvs/neighbors/nn_descent.hpp>
21+
22+
namespace cuvs::neighbors {
23+
24+
/**
25+
* @defgroup neighbors_build_algo Graph build algorithm types
26+
* @{
27+
*/
28+
29+
enum GRAPH_BUILD_ALGO { BRUTE_FORCE = 0, IVF_PQ = 1, NN_DESCENT = 1 };
30+
31+
namespace graph_build_params {
32+
33+
/** Specialized parameters utilizing IVF-PQ to build knn graph */
34+
struct ivf_pq_params {
35+
cuvs::neighbors::ivf_pq::index_params build_params;
36+
cuvs::neighbors::ivf_pq::search_params search_params;
37+
float refinement_rate = 1.0;
38+
39+
ivf_pq_params() = default;
40+
41+
/**
42+
* Set default parameters based on shape of the input dataset.
43+
* Usage example:
44+
* @code{.cpp}
45+
* using namespace cuvs::neighbors;
46+
* raft::resources res;
47+
* // create index_params for a [N. D] dataset
48+
* auto dataset = raft::make_device_matrix<float, int64_t>(res, N, D);
49+
* auto pq_params =
50+
* graph_build_params::ivf_pq_params(dataset.extents());
51+
* // modify/update index_params as needed
52+
* pq_params.kmeans_trainset_fraction = 0.1;
53+
* @endcode
54+
*/
55+
ivf_pq_params(raft::matrix_extent<int64_t> dataset_extents,
56+
cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2Expanded)
57+
{
58+
build_params = cuvs::neighbors::ivf_pq::index_params::from_dataset(dataset_extents, metric);
59+
60+
search_params = cuvs::neighbors::ivf_pq::search_params{};
61+
search_params.n_probes = std::max<uint32_t>(10, build_params.n_lists * 0.01);
62+
search_params.lut_dtype = CUDA_R_16F;
63+
search_params.internal_distance_dtype = CUDA_R_16F;
64+
search_params.coarse_search_dtype = CUDA_R_16F;
65+
search_params.max_internal_batch_size = 128 * 1024;
66+
67+
refinement_rate = 1;
68+
}
69+
};
70+
71+
using nn_descent_params = cuvs::neighbors::nn_descent::index_params;
72+
73+
// **** Experimental ****
74+
using iterative_search_params = cuvs::neighbors::search_params;
75+
} // namespace graph_build_params
76+
77+
/** @} */ // end group neighbors_build_algo
78+
} // namespace cuvs::neighbors

cpp/src/cluster/detail/mst.cuh

Lines changed: 142 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021-2024, NVIDIA CORPORATION.
2+
* Copyright (c) 2021-2025, NVIDIA CORPORATION.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,7 +17,11 @@
1717
#pragma once
1818

1919
#include "../../sparse/neighbors/cross_component_nn.cuh"
20+
#include <cuvs/distance/distance.hpp>
2021
#include <raft/core/resource/cuda_stream.hpp>
22+
#include <raft/label/classlabels.cuh>
23+
#include <raft/matrix/detail/gather.cuh>
24+
#include <raft/matrix/diagonal.cuh>
2125
#include <raft/sparse/op/sort.cuh>
2226
#include <raft/sparse/solver/mst.cuh>
2327
#include <raft/util/cuda_utils.cuh>
@@ -59,7 +63,7 @@ void merge_msts(raft::sparse::solver::Graph_COO<value_idx, value_idx, value_t>&
5963
* @tparam value_idx index type
6064
* @tparam value_t floating-point value type
6165
* @param[in] handle raft handle
62-
* @param[in] X original dense data from which knn grpah was constructed
66+
* @param[in] X original dense data on device memory from which knn graph was constructed
6367
* @param[inout] msf edge list containing the mst result
6468
* @param[in] m number of rows in X
6569
* @param[in] n number of columns in X
@@ -117,6 +121,132 @@ void connect_knn_graph(
117121
merge_msts<value_idx, value_t>(msf, new_mst, stream);
118122
}
119123

124+
/**
125+
* Connect an unconnected knn graph (one in which mst returns an msf). The
126+
* device buffers underlying the Graph_COO object are modified in-place.
127+
* @tparam value_idx index type
128+
* @tparam value_t floating-point value type
129+
* @param[in] handle raft handle
130+
* @param[in] X original dense data on host memory from which knn graph was constructed
131+
* @param[inout] msf edge list containing the mst result
132+
* @param[in] m number of rows in X
133+
* @param[in] n number of columns in X
134+
* @param[in] n_components number of components in color
135+
* @param[inout] color the color labels array returned from the mst invocation
136+
* @return updated MST edge list
137+
*/
138+
template <typename value_idx, typename value_t>
139+
void connect_knn_graph(
140+
raft::resources const& handle,
141+
const value_t* X,
142+
raft::sparse::solver::Graph_COO<value_idx, value_idx, value_t>& msf,
143+
size_t m,
144+
size_t n,
145+
int n_components,
146+
value_idx* color,
147+
cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2SqrtExpanded)
148+
{
149+
auto stream = raft::resource::get_cuda_stream(handle);
150+
151+
rmm::device_uvector<value_idx> d_color_remapped(m, stream);
152+
raft::label::make_monotonic(d_color_remapped.data(), color, m, stream, true);
153+
154+
std::vector<value_idx> h_color(m);
155+
raft::copy(h_color.data(), d_color_remapped.data(), m, stream);
156+
raft::resource::sync_stream(handle, stream);
157+
158+
// make key (color) : value (vector of ids that have that color)
159+
std::unordered_map<value_idx, std::vector<value_idx>> component_map;
160+
for (value_idx i = 0; i < static_cast<value_idx>(m); ++i) {
161+
component_map[h_color[i]].push_back(i);
162+
}
163+
164+
std::vector<std::tuple<value_idx, value_idx, value_t>> selected_edges;
165+
166+
std::random_device rd;
167+
std::mt19937 gen(rd());
168+
std::uniform_int_distribution<> dis;
169+
170+
std::vector<value_idx> host_u_indices;
171+
std::vector<value_idx> host_v_indices;
172+
173+
// connect i-1 component and i component
174+
for (int i = 1; i < n_components; ++i) {
175+
value_idx color_a = i - 1;
176+
value_idx color_b = i;
177+
178+
const auto& nodes_a = component_map[color_a];
179+
const auto& nodes_b = component_map[color_b];
180+
181+
// Randomly pick a data index from each component
182+
dis.param(std::uniform_int_distribution<>::param_type(0, nodes_a.size() - 1));
183+
value_idx u = nodes_a[dis(gen)];
184+
185+
dis.param(std::uniform_int_distribution<>::param_type(0, nodes_b.size() - 1));
186+
value_idx v = nodes_b[dis(gen)];
187+
188+
host_u_indices.push_back(u);
189+
host_v_indices.push_back(v);
190+
}
191+
192+
auto device_u_indices = raft::make_device_vector<value_idx, int64_t>(handle, n_components - 1);
193+
auto device_v_indices = raft::make_device_vector<value_idx, int64_t>(handle, n_components - 1);
194+
195+
raft::copy(device_u_indices.data_handle(), host_u_indices.data(), n_components - 1, stream);
196+
raft::copy(device_v_indices.data_handle(), host_v_indices.data(), n_components - 1, stream);
197+
198+
auto X_view = raft::make_host_matrix_view<const value_t, int64_t>(X, m, n);
199+
auto data_u = raft::make_device_matrix<value_t, int64_t>(handle, n_components - 1, n);
200+
auto data_v = raft::make_device_matrix<value_t, int64_t>(handle, n_components - 1, n);
201+
202+
raft::matrix::detail::gather(
203+
handle, X_view, raft::make_const_mdspan(device_u_indices.view()), data_u.view());
204+
raft::matrix::detail::gather(
205+
handle, X_view, raft::make_const_mdspan(device_v_indices.view()), data_v.view());
206+
207+
auto pairwise_dist =
208+
raft::make_device_matrix<value_t, int64_t>(handle, n_components - 1, n_components - 1);
209+
cuvs::distance::pairwise_distance(handle,
210+
raft::make_const_mdspan(data_u.view()),
211+
raft::make_const_mdspan(data_v.view()),
212+
pairwise_dist.view(),
213+
metric);
214+
215+
auto pairwise_dist_vec = raft::make_device_vector<value_t, int64_t>(handle, n_components - 1);
216+
raft::matrix::get_diagonal(
217+
handle, raft::make_const_mdspan(pairwise_dist.view()), pairwise_dist_vec.view());
218+
219+
size_t new_nnz = n_components - 1;
220+
221+
// sort in order of rows to run sorted_coo_to_csr
222+
auto rows_begin = thrust::device_pointer_cast(device_u_indices.data_handle());
223+
auto cols_begin = thrust::device_pointer_cast(device_v_indices.data_handle());
224+
auto dist_begin = thrust::device_pointer_cast(pairwise_dist_vec.data_handle());
225+
226+
auto zipped_begin = thrust::make_zip_iterator(thrust::make_tuple(cols_begin, dist_begin));
227+
thrust::sort_by_key(rows_begin, rows_begin + new_nnz, zipped_begin);
228+
229+
rmm::device_uvector<value_idx> indptr2(m + 1, stream);
230+
raft::sparse::convert::sorted_coo_to_csr(
231+
device_u_indices.data_handle(), new_nnz, indptr2.data(), m + 1, stream);
232+
233+
// On the second call, we hand the MST the original colors
234+
// and the new set of edges and let it restart the optimization process
235+
auto new_mst = raft::sparse::solver::mst<value_idx, value_idx, value_t, double>(
236+
handle,
237+
indptr2.data(),
238+
device_v_indices.data_handle(),
239+
pairwise_dist_vec.data_handle(),
240+
m,
241+
new_nnz,
242+
color,
243+
stream,
244+
false,
245+
false);
246+
247+
merge_msts<value_idx, value_t>(msf, new_mst, stream);
248+
}
249+
120250
/**
121251
* Constructs an MST and sorts the resulting edges in ascending
122252
* order by their weight.
@@ -130,6 +260,7 @@ void connect_knn_graph(
130260
* @tparam value_idx
131261
* @tparam value_t
132262
* @param[in] handle raft handle
263+
* @param[in] X dataset residing on host or device memory
133264
* @param[in] indptr CSR indptr of connectivities graph
134265
* @param[in] indices CSR indices array of connectivities graph
135266
* @param[in] pw_dists CSR weights array of connectivities graph
@@ -168,8 +299,16 @@ void build_sorted_mst(
168299
int iters = 1;
169300
int n_components = cuvs::sparse::neighbors::get_n_components(color, m, stream);
170301

302+
cudaPointerAttributes attr;
303+
RAFT_CUDA_TRY(cudaPointerGetAttributes(&attr, X));
304+
bool data_on_device = attr.type == cudaMemoryTypeDevice;
305+
171306
while (n_components > 1 && iters < max_iter) {
172-
connect_knn_graph<value_idx, value_t>(handle, X, mst_coo, m, n, color, reduction_op);
307+
if (data_on_device) {
308+
connect_knn_graph<value_idx, value_t>(handle, X, mst_coo, m, n, color, reduction_op);
309+
} else {
310+
connect_knn_graph<value_idx, value_t>(handle, X, mst_coo, m, n, n_components, color, metric);
311+
}
173312

174313
iters++;
175314

cpp/src/neighbors/all_neighbors/all_neighbors_builder.cuh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ struct all_neighbors_builder_ivfpq : public all_neighbors_builder<T, IdxT> {
116116
size_t min_cluster_size,
117117
size_t max_cluster_size,
118118
size_t k,
119-
all_neighbors::graph_build_params::ivf_pq_params& params,
119+
graph_build_params::ivf_pq_params& params,
120120
std::optional<raft::device_matrix_view<IdxT, IdxT, row_major>> indices = std::nullopt,
121121
std::optional<raft::device_matrix_view<T, IdxT, row_major>> distances = std::nullopt)
122122
: all_neighbors_builder<T, IdxT>(
@@ -287,7 +287,7 @@ struct all_neighbors_builder_ivfpq : public all_neighbors_builder<T, IdxT> {
287287
dataset_h.data_handle(), dataset.extent(0), dataset.extent(1)));
288288
}
289289

290-
all_neighbors::graph_build_params::ivf_pq_params all_ivf_pq_params;
290+
graph_build_params::ivf_pq_params all_ivf_pq_params;
291291
size_t candidate_k;
292292

293293
std::optional<raft::device_matrix<T, IdxT>> data_d;
@@ -308,7 +308,7 @@ struct all_neighbors_builder_nn_descent : public all_neighbors_builder<T, IdxT>
308308
size_t min_cluster_size,
309309
size_t max_cluster_size,
310310
size_t k,
311-
all_neighbors::graph_build_params::nn_descent_params& params,
311+
graph_build_params::nn_descent_params& params,
312312
std::optional<raft::device_matrix_view<IdxT, IdxT, row_major>> indices = std::nullopt,
313313
std::optional<raft::device_matrix_view<T, IdxT, row_major>> distances = std::nullopt)
314314
: all_neighbors_builder<T, IdxT>(

0 commit comments

Comments
 (0)