-
Notifications
You must be signed in to change notification settings - Fork 184
[FEA] IVF-PQ to Write Flat PQ Codes #1607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 38 commits
b54188f
0568ae2
c9cb3eb
fc0ff9a
2fef6e7
6332964
ee28540
dc99bfb
fdff302
75e9ea1
28957ca
d504d3f
d3bab42
b36a47a
d787a07
0038daa
3644d9e
c0a111d
63a2969
2309b7a
3dec2dd
d41aa96
5e9a32c
f4a0f7f
8a0ac38
52f3534
42b930f
f6cf637
645cac5
d9c9b62
02f4c76
bcbbca9
550fbdf
a5e482b
855e460
a549e44
252cfbd
b5cfc7e
c96b7f7
03fd421
4551976
b0ff258
36339c8
c0b6423
4f761fb
400d234
cb3fec1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,15 @@ enum codebook_gen { // NOLINT | |
| PER_CLUSTER = 1, // NOLINT | ||
| }; | ||
|
|
||
| /** | ||
| * @brief A type for specifying the memory layout of IVF-PQ list data | ||
| * | ||
| */ | ||
| enum list_layout { // NOLINT | ||
| FLAT = 0, // NOLINT | ||
| INTERLEAVED = 1, // NOLINT | ||
| }; | ||
|
|
||
| /** | ||
| * @brief Supplemental parameters to build IVF-PQ Index | ||
| * | ||
|
|
@@ -114,6 +123,14 @@ struct cuvsIvfPqIndexParams { | |
| * points to train each codebook. | ||
| */ | ||
| uint32_t max_train_points_per_pq_code; | ||
| /** | ||
| * Memory layout of the IVF-PQ list data. | ||
| * | ||
| * - FLAT: Codes are stored contiguously, one vector's codes after another. | ||
| * - INTERLEAVED: Codes are interleaved for optimized search performance. | ||
| * This is the default and recommended for search workloads. | ||
| */ | ||
| enum list_layout codes_layout; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just making a note here that this is going to break the C ABI. No action needed, but we will need to track these things in the future. I'll share the POR with you (and the team) for more info. |
||
| }; | ||
|
|
||
| typedef struct cuvsIvfPqIndexParams* cuvsIvfPqIndexParams_t; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION. | ||
| * SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
|
|
@@ -683,11 +683,50 @@ template <typename IdxT> | |
| constexpr static IdxT kInvalidRecord = | ||
| (std::is_signed_v<IdxT> ? IdxT{0} : std::numeric_limits<IdxT>::max()) - 1; | ||
|
|
||
| /** | ||
| * Abstract base class for IVF list data. | ||
| * This allows polymorphic access to list data regardless of the underlying layout. | ||
| * | ||
| * @tparam ValueT The data element type (e.g., uint8_t for PQ codes, float for raw vectors) | ||
| * @tparam IdxT The index type for source indices | ||
| * @tparam SizeT The size type | ||
| */ | ||
| template <typename ValueT, typename IdxT, typename SizeT = uint32_t> | ||
| struct list_base { | ||
| using value_type = ValueT; | ||
| using index_type = IdxT; | ||
| using size_type = SizeT; | ||
|
|
||
| virtual ~list_base() = default; | ||
|
|
||
| /** Get the raw data pointer. */ | ||
| virtual value_type* data_ptr() noexcept = 0; | ||
| virtual const value_type* data_ptr() const noexcept = 0; | ||
|
|
||
| /** Get the indices pointer. */ | ||
| virtual index_type* indices_ptr() noexcept = 0; | ||
| virtual const index_type* indices_ptr() const noexcept = 0; | ||
|
|
||
| /** Get the current size (number of records). */ | ||
| virtual size_type get_size() const noexcept = 0; | ||
|
|
||
| /** Set the current size (number of records). */ | ||
| virtual void set_size(size_type new_size) noexcept = 0; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose as long as users are never direclty mutating this object then we shouldn't have to be too vigilent. Would be nice if we could make this internal, though, so that only cuVS funcitons are capable of changing it. Just concerned for users shooting themselves in the foot.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tracking here #1726 |
||
|
|
||
| /** Get the total size of the data array in bytes. */ | ||
| virtual size_t data_byte_size() const noexcept = 0; | ||
|
|
||
| /** Get the capacity (number of indices that can be stored). */ | ||
| virtual size_type indices_capacity() const noexcept = 0; | ||
| }; | ||
|
|
||
| /** The data for a single IVF list. */ | ||
| template <template <typename, typename...> typename SpecT, | ||
| typename SizeT, | ||
| typename... SpecExtraArgs> | ||
| struct list { | ||
| struct list : public list_base<typename SpecT<SizeT, SpecExtraArgs...>::value_type, | ||
| typename SpecT<SizeT, SpecExtraArgs...>::index_type, | ||
| SizeT> { | ||
| using size_type = SizeT; | ||
| using spec_type = SpecT<size_type, SpecExtraArgs...>; | ||
| using value_type = typename spec_type::value_type; | ||
|
|
@@ -703,6 +742,18 @@ struct list { | |
|
|
||
| /** Allocate a new list capable of holding at least `n_rows` data records and indices. */ | ||
| list(raft::resources const& res, const spec_type& spec, size_type n_rows); | ||
|
|
||
| value_type* data_ptr() noexcept override { return data.data_handle(); } | ||
| const value_type* data_ptr() const noexcept override { return data.data_handle(); } | ||
|
|
||
| index_type* indices_ptr() noexcept override { return indices.data_handle(); } | ||
| const index_type* indices_ptr() const noexcept override { return indices.data_handle(); } | ||
|
|
||
| size_type get_size() const noexcept override { return size.load(); } | ||
| void set_size(size_type new_size) noexcept override { size.store(new_size); } | ||
|
|
||
| size_t data_byte_size() const noexcept override { return data.size() * sizeof(value_type); } | ||
| size_type indices_capacity() const noexcept override { return indices.extent(0); } | ||
| }; | ||
|
|
||
| template <typename ListT, class T = void> | ||
|
|
@@ -727,6 +778,10 @@ using enable_if_valid_list_t = typename enable_if_valid_list<ListT, T>::type; | |
| /** | ||
| * Resize a list by the given id, so that it can contain the given number of records; | ||
| * copy the data if necessary. | ||
| * | ||
| * @note This is an internal function that requires the concrete list type. | ||
| * For IVF-PQ indexes, prefer using the helper functions in | ||
| * `cuvs::neighbors::ivf_pq::helpers::resize_list` which handle type casting internally. | ||
| */ | ||
| template <typename ListT> | ||
| void resize_list(raft::resources const& res, | ||
|
|
@@ -735,13 +790,23 @@ void resize_list(raft::resources const& res, | |
| typename ListT::size_type new_used_size, | ||
| typename ListT::size_type old_used_size); | ||
|
|
||
| /** | ||
| * Serialize a list to an output stream. | ||
| * | ||
| * @note This function requires the concrete list type (not the base class) because: | ||
| * 1. It needs access to the spec_type to determine the data layout for serialization | ||
| * 2. The serialized format depends on the spec's make_list_extents() method | ||
| * When calling from code that only has a base class pointer, use std::static_pointer_cast | ||
| * to obtain the typed pointer first. | ||
| */ | ||
| template <typename ListT> | ||
| enable_if_valid_list_t<ListT> serialize_list( | ||
| const raft::resources& handle, | ||
| std::ostream& os, | ||
| const ListT& ld, | ||
| const typename ListT::spec_type& store_spec, | ||
| std::optional<typename ListT::size_type> size_override = std::nullopt); | ||
|
|
||
| template <typename ListT> | ||
| enable_if_valid_list_t<ListT> serialize_list( | ||
| const raft::resources& handle, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.