@@ -152,4 +152,58 @@ TEST(AnnCagraMultiPartition, MixedGraphDegreeRejected)
152152 cagra::search_params{});
153153}
154154
155+ // CAGRA-Q smoke test mirroring the C / Python / Rust wrappers: build the graph on dense rows, train
156+ // VPQ storage from the same padded rows, attach it, then search.
157+ TEST (AnnCagraVpq, BuildAttachVpqSearch)
158+ {
159+ raft::resources handle;
160+ auto stream = raft::resource::get_cuda_stream (handle);
161+
162+ constexpr int n_rows = 256 , dim = 32 , n_queries = 4 , k = 1 ;
163+
164+ auto dataset = raft::make_device_matrix<float , int64_t >(handle, n_rows, dim);
165+ raft::random::RngState r (1234ULL );
166+ InitDataset (
167+ handle, dataset.data_handle (), n_rows, dim, cuvs::distance::DistanceType::L2Expanded, r);
168+ raft::resource::sync_stream (handle);
169+
170+ cuvs::neighbors::test::padded_device_matrix_for_cagra<float > padded (
171+ handle, raft::make_const_mdspan (dataset.view ()));
172+
173+ cagra::index_params index_params;
174+ index_params.metric = cuvs::distance::DistanceType::L2Expanded;
175+ auto dense_index = cagra::build (handle, index_params, padded.view );
176+
177+ cuvs::neighbors::vpq_params vpq_params{.pq_bits = 8 , .pq_dim = 8 };
178+ auto vpq =
179+ cuvs::preprocessing::quantize::pq::make_device_pq_dataset (handle, vpq_params, padded.view );
180+ raft::resource::sync_stream (handle);
181+
182+ EXPECT_EQ (vpq.n_rows (), n_rows);
183+ EXPECT_EQ (vpq.dim (), dim);
184+
185+ auto vpq_index = cagra::attach_dataset (handle, dense_index, vpq.as_dataset_view ());
186+
187+ auto queries = raft::make_device_matrix<float , int64_t >(handle, n_queries, dim);
188+ raft::copy (queries.data_handle (), dataset.data_handle (), queries.size (), stream);
189+
190+ auto neighbors = raft::make_device_matrix<uint32_t , int64_t >(handle, n_queries, k);
191+ auto distances = raft::make_device_matrix<float , int64_t >(handle, n_queries, k);
192+ cagra::search (handle,
193+ cagra::search_params{},
194+ vpq_index,
195+ raft::make_const_mdspan (queries.view ()),
196+ neighbors.view (),
197+ distances.view ());
198+
199+ auto neighbors_h = raft::make_host_matrix<uint32_t , int64_t >(n_queries, k);
200+ raft::copy (neighbors_h.data_handle (), neighbors.data_handle (), neighbors.size (), stream);
201+ raft::resource::sync_stream (handle);
202+
203+ // Queries are exact dataset rows, so the top hit must be the row itself.
204+ for (int i = 0 ; i < n_queries; i++) {
205+ EXPECT_EQ (neighbors_h (i, 0 ), static_cast <uint32_t >(i));
206+ }
207+ }
208+
155209} // namespace cuvs::neighbors::cagra
0 commit comments