faiss 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +2 -0
- data/ext/faiss/index.cpp +8 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/IVFlib.cpp +25 -49
- data/vendor/faiss/faiss/Index.cpp +11 -0
- data/vendor/faiss/faiss/Index.h +24 -1
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +1 -0
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
- data/vendor/faiss/faiss/IndexFastScan.cpp +1 -1
- data/vendor/faiss/faiss/IndexFastScan.h +3 -8
- data/vendor/faiss/faiss/IndexFlat.cpp +374 -4
- data/vendor/faiss/faiss/IndexFlat.h +80 -0
- data/vendor/faiss/faiss/IndexHNSW.cpp +90 -1
- data/vendor/faiss/faiss/IndexHNSW.h +57 -1
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +34 -149
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +86 -2
- data/vendor/faiss/faiss/IndexIVFRaBitQ.h +3 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +293 -115
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +52 -16
- data/vendor/faiss/faiss/IndexPQ.cpp +4 -1
- data/vendor/faiss/faiss/IndexPreTransform.cpp +14 -0
- data/vendor/faiss/faiss/IndexPreTransform.h +9 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +96 -16
- data/vendor/faiss/faiss/IndexRaBitQ.h +5 -1
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +238 -93
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +35 -9
- data/vendor/faiss/faiss/IndexRefine.cpp +49 -0
- data/vendor/faiss/faiss/IndexRefine.h +17 -0
- data/vendor/faiss/faiss/clone_index.cpp +2 -0
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -1
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +1 -1
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +1 -1
- data/vendor/faiss/faiss/impl/DistanceComputer.h +74 -3
- data/vendor/faiss/faiss/impl/HNSW.cpp +294 -15
- data/vendor/faiss/faiss/impl/HNSW.h +31 -2
- data/vendor/faiss/faiss/impl/IDSelector.h +3 -3
- data/vendor/faiss/faiss/impl/Panorama.cpp +193 -0
- data/vendor/faiss/faiss/impl/Panorama.h +204 -0
- data/vendor/faiss/faiss/impl/RaBitQStats.cpp +29 -0
- data/vendor/faiss/faiss/impl/RaBitQStats.h +56 -0
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +54 -6
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +183 -6
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +269 -84
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +71 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +362 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.h +112 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +6 -9
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -3
- data/vendor/faiss/faiss/impl/index_read.cpp +156 -12
- data/vendor/faiss/faiss/impl/index_write.cpp +142 -19
- data/vendor/faiss/faiss/impl/platform_macros.h +12 -0
- data/vendor/faiss/faiss/impl/svs_io.cpp +86 -0
- data/vendor/faiss/faiss/impl/svs_io.h +67 -0
- data/vendor/faiss/faiss/index_factory.cpp +182 -15
- data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +1 -1
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +18 -109
- data/vendor/faiss/faiss/invlists/InvertedLists.h +2 -18
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +1 -1
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +261 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +117 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +66 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +245 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +137 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +39 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +42 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +149 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +58 -0
- data/vendor/faiss/faiss/utils/distances.cpp +0 -3
- data/vendor/faiss/faiss/utils/utils.cpp +4 -0
- metadata +18 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Portions Copyright 2025 Intel Corporation
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
* you may not use this file except in compliance with the License.
|
|
13
|
+
* You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
#pragma once
|
|
25
|
+
|
|
26
|
+
#include <svs/runtime/api_defs.h>
|
|
27
|
+
|
|
28
|
+
#include <faiss/Index.h>
|
|
29
|
+
#include <faiss/MetricType.h>
|
|
30
|
+
#include <faiss/impl/AuxIndexStructures.h>
|
|
31
|
+
#include <faiss/impl/FaissAssert.h>
|
|
32
|
+
#include <faiss/impl/IDSelector.h>
|
|
33
|
+
|
|
34
|
+
#include <algorithm>
|
|
35
|
+
#include <concepts>
|
|
36
|
+
#include <memory>
|
|
37
|
+
#include <span>
|
|
38
|
+
#include <type_traits>
|
|
39
|
+
#include <vector>
|
|
40
|
+
|
|
41
|
+
// validate FAISS_SVS_RUNTIME_VERSION is set
|
|
42
|
+
#ifndef FAISS_SVS_RUNTIME_VERSION
|
|
43
|
+
#error "FAISS_SVS_RUNTIME_VERSION is not defined"
|
|
44
|
+
#endif
|
|
45
|
+
// create svs_runtime as alias for svs::runtime::FAISS_SVS_RUNTIME_VERSION
|
|
46
|
+
SVS_RUNTIME_CREATE_API_ALIAS(svs_runtime, FAISS_SVS_RUNTIME_VERSION);
|
|
47
|
+
|
|
48
|
+
// SVS forward declarations
|
|
49
|
+
namespace svs {
|
|
50
|
+
namespace runtime {
|
|
51
|
+
inline namespace v0 {
|
|
52
|
+
struct FlatIndex;
|
|
53
|
+
struct VamanaIndex;
|
|
54
|
+
struct DynamicVamanaIndex;
|
|
55
|
+
struct LeanVecTrainingData;
|
|
56
|
+
} // namespace v0
|
|
57
|
+
} // namespace runtime
|
|
58
|
+
} // namespace svs
|
|
59
|
+
|
|
60
|
+
namespace faiss {
|
|
61
|
+
|
|
62
|
+
inline svs_runtime::MetricType to_svs_metric(faiss::MetricType metric) {
|
|
63
|
+
switch (metric) {
|
|
64
|
+
case METRIC_INNER_PRODUCT:
|
|
65
|
+
return svs_runtime::MetricType::INNER_PRODUCT;
|
|
66
|
+
case METRIC_L2:
|
|
67
|
+
return svs_runtime::MetricType::L2;
|
|
68
|
+
default:
|
|
69
|
+
FAISS_ASSERT(!"not supported SVS distance");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
struct FaissIDFilter : public svs_runtime::IDFilter {
|
|
74
|
+
FaissIDFilter(const faiss::IDSelector& sel) : selector(sel) {}
|
|
75
|
+
|
|
76
|
+
bool is_member(size_t id) const override {
|
|
77
|
+
return selector.is_member(static_cast<faiss::idx_t>(id));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private:
|
|
81
|
+
const faiss::IDSelector& selector;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
inline std::unique_ptr<FaissIDFilter> make_faiss_id_filter(
|
|
85
|
+
const SearchParameters* params = nullptr) {
|
|
86
|
+
if (params && params->sel) {
|
|
87
|
+
return std::make_unique<FaissIDFilter>(*params->sel);
|
|
88
|
+
}
|
|
89
|
+
return nullptr;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
template <typename T, typename U, typename = void>
|
|
93
|
+
struct InputBufferConverter {
|
|
94
|
+
InputBufferConverter(std::span<const U> data = {}) : buffer(data.size()) {
|
|
95
|
+
FAISS_ASSERT(
|
|
96
|
+
!"InputBufferConverter: there is no suitable user code for this type conversion");
|
|
97
|
+
std::transform(
|
|
98
|
+
data.begin(), data.end(), buffer.begin(), [](const U& val) {
|
|
99
|
+
return static_cast<T>(val);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
operator T*() {
|
|
104
|
+
return buffer.data();
|
|
105
|
+
}
|
|
106
|
+
operator const T*() const {
|
|
107
|
+
return buffer.data();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
operator std::span<T>() {
|
|
111
|
+
return buffer;
|
|
112
|
+
}
|
|
113
|
+
operator std::span<const T>() const {
|
|
114
|
+
return buffer;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private:
|
|
118
|
+
std::vector<T> buffer;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Specialization for reinterpret cast when types are integral and have the same
|
|
122
|
+
// size
|
|
123
|
+
template <typename T, typename U>
|
|
124
|
+
struct InputBufferConverter<
|
|
125
|
+
T,
|
|
126
|
+
U,
|
|
127
|
+
std::enable_if_t<
|
|
128
|
+
std::is_same_v<T, U> ||
|
|
129
|
+
(std::is_integral_v<T> && std::is_integral_v<U> &&
|
|
130
|
+
sizeof(T) == sizeof(U))>> {
|
|
131
|
+
InputBufferConverter(std::span<const U> data = {}) : data_span(data) {}
|
|
132
|
+
operator T*() {
|
|
133
|
+
return reinterpret_cast<T*>(data_span.data());
|
|
134
|
+
}
|
|
135
|
+
operator const T*() const {
|
|
136
|
+
return reinterpret_cast<const T*>(data_span.data());
|
|
137
|
+
}
|
|
138
|
+
operator std::span<T>() {
|
|
139
|
+
return std::span<T>(
|
|
140
|
+
reinterpret_cast<T*>(data_span.data()), data_span.size());
|
|
141
|
+
}
|
|
142
|
+
operator std::span<const T>() const {
|
|
143
|
+
return std::span<const T>(
|
|
144
|
+
reinterpret_cast<const T*>(data_span.data()), data_span.size());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private:
|
|
148
|
+
std::span<const U> data_span;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
template <typename T, typename U, typename = void>
|
|
152
|
+
struct OutputBufferConverter {
|
|
153
|
+
OutputBufferConverter(std::span<U> data = {})
|
|
154
|
+
: data_span(data), buffer(data.size()) {
|
|
155
|
+
FAISS_ASSERT(
|
|
156
|
+
!"OutputBufferConverter: there is no suitable user code for this type conversion");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
~OutputBufferConverter() {
|
|
160
|
+
std::transform(
|
|
161
|
+
buffer.begin(),
|
|
162
|
+
buffer.end(),
|
|
163
|
+
data_span.begin(),
|
|
164
|
+
[](const T& val) { return static_cast<U>(val); });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
operator T*() {
|
|
168
|
+
return buffer.data();
|
|
169
|
+
}
|
|
170
|
+
operator std::span<T>() {
|
|
171
|
+
return buffer;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private:
|
|
175
|
+
std::span<U> data_span;
|
|
176
|
+
std::vector<T> buffer;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Specialization for reinterpret cast when types are integral and have the same
|
|
180
|
+
// size
|
|
181
|
+
template <typename T, typename U>
|
|
182
|
+
struct OutputBufferConverter<
|
|
183
|
+
T,
|
|
184
|
+
U,
|
|
185
|
+
std::enable_if_t<
|
|
186
|
+
std::is_same_v<T, U> ||
|
|
187
|
+
(std::is_integral_v<T> && std::is_integral_v<U> &&
|
|
188
|
+
sizeof(T) == sizeof(U))>> {
|
|
189
|
+
OutputBufferConverter(std::span<U> data = {}) : data_span(data) {}
|
|
190
|
+
operator T*() {
|
|
191
|
+
return reinterpret_cast<T*>(data_span.data());
|
|
192
|
+
}
|
|
193
|
+
operator std::span<T>() {
|
|
194
|
+
return std::span<T>(
|
|
195
|
+
reinterpret_cast<T*>(data_span.data()), data_span.size());
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private:
|
|
199
|
+
std::span<U> data_span;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
template <typename T, typename U>
|
|
203
|
+
auto convert_input_buffer(std::span<const U> data) {
|
|
204
|
+
// Create temporary buffer and convert input data
|
|
205
|
+
// to target type T in the temporary buffer
|
|
206
|
+
// The temporary buffer will be destroyed
|
|
207
|
+
// when going out of scope
|
|
208
|
+
return InputBufferConverter<T, U>(data);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
template <typename T, typename U>
|
|
212
|
+
auto convert_input_buffer(const U* data, size_t size) {
|
|
213
|
+
return convert_input_buffer<T, U>(std::span<const U>(data, size));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Output buffer conversion
|
|
217
|
+
template <typename T, typename U>
|
|
218
|
+
auto convert_output_buffer(std::span<U> data) {
|
|
219
|
+
// Create temporary buffer for output data
|
|
220
|
+
// The temporary buffer will be destroyed
|
|
221
|
+
// when going out of scope, copying back
|
|
222
|
+
// the converted data to original buffer
|
|
223
|
+
return OutputBufferConverter<T, U>(data);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
template <typename T, typename U>
|
|
227
|
+
auto convert_output_buffer(U* data, size_t size) {
|
|
228
|
+
return convert_output_buffer<T, U>(std::span<U>(data, size));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
struct FaissResultsAllocator : public svs_runtime::ResultsAllocator {
|
|
232
|
+
FaissResultsAllocator(faiss::RangeSearchResult* result) : result(result) {
|
|
233
|
+
FAISS_ASSERT(result != nullptr);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
svs_runtime::SearchResultsStorage allocate(
|
|
237
|
+
std::span<size_t> result_counts) const override {
|
|
238
|
+
FAISS_ASSERT(result != nullptr);
|
|
239
|
+
FAISS_ASSERT(result_counts.size() == result->nq);
|
|
240
|
+
|
|
241
|
+
// RangeSearchResult .ctor() allows unallocated lims
|
|
242
|
+
if (result->lims == nullptr) {
|
|
243
|
+
result->lims = new size_t[result->nq + 1];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
std::copy(result_counts.begin(), result_counts.end(), result->lims);
|
|
247
|
+
result->do_allocation();
|
|
248
|
+
this->labels_converter = LabelsConverter{
|
|
249
|
+
std::span(result->labels, result->lims[result_counts.size()])};
|
|
250
|
+
return svs_runtime::SearchResultsStorage{
|
|
251
|
+
labels_converter,
|
|
252
|
+
std::span<float>(
|
|
253
|
+
result->distances, result->lims[result_counts.size()])};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private:
|
|
257
|
+
faiss::RangeSearchResult* result;
|
|
258
|
+
using LabelsConverter = OutputBufferConverter<size_t, faiss::idx_t>;
|
|
259
|
+
mutable LabelsConverter labels_converter;
|
|
260
|
+
};
|
|
261
|
+
} // namespace faiss
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Portions Copyright 2025 Intel Corporation
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
* you may not use this file except in compliance with the License.
|
|
13
|
+
* You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
#include <faiss/Index.h>
|
|
25
|
+
#include <faiss/svs/IndexSVSFaissUtils.h>
|
|
26
|
+
#include <faiss/svs/IndexSVSFlat.h>
|
|
27
|
+
|
|
28
|
+
#include <svs/runtime/flat_index.h>
|
|
29
|
+
|
|
30
|
+
#include <iostream>
|
|
31
|
+
|
|
32
|
+
namespace faiss {
|
|
33
|
+
|
|
34
|
+
IndexSVSFlat::IndexSVSFlat(idx_t d, MetricType metric) : Index(d, metric) {}
|
|
35
|
+
|
|
36
|
+
IndexSVSFlat::~IndexSVSFlat() {
|
|
37
|
+
if (impl) {
|
|
38
|
+
auto status = svs_runtime::FlatIndex::destroy(impl);
|
|
39
|
+
FAISS_ASSERT(status.ok());
|
|
40
|
+
impl = nullptr;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void IndexSVSFlat::add(idx_t n, const float* x) {
|
|
45
|
+
if (!impl) {
|
|
46
|
+
create_impl();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
auto status = impl->add(n, x);
|
|
50
|
+
if (!status.ok()) {
|
|
51
|
+
FAISS_THROW_MSG(status.message());
|
|
52
|
+
}
|
|
53
|
+
ntotal += n;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void IndexSVSFlat::reset() {
|
|
57
|
+
if (impl) {
|
|
58
|
+
auto status = impl->reset();
|
|
59
|
+
if (!status.ok()) {
|
|
60
|
+
FAISS_THROW_MSG(status.message());
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
ntotal = 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void IndexSVSFlat::search(
|
|
67
|
+
idx_t n,
|
|
68
|
+
const float* x,
|
|
69
|
+
idx_t k,
|
|
70
|
+
float* distances,
|
|
71
|
+
idx_t* labels,
|
|
72
|
+
const SearchParameters* params) const {
|
|
73
|
+
FAISS_THROW_IF_NOT(impl);
|
|
74
|
+
auto status = impl->search(
|
|
75
|
+
n,
|
|
76
|
+
x,
|
|
77
|
+
static_cast<size_t>(k),
|
|
78
|
+
distances,
|
|
79
|
+
reinterpret_cast<size_t*>(labels));
|
|
80
|
+
if (!status.ok()) {
|
|
81
|
+
FAISS_THROW_MSG(status.message());
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Initializes the implementation*/
|
|
86
|
+
void IndexSVSFlat::create_impl() {
|
|
87
|
+
FAISS_ASSERT(impl == nullptr);
|
|
88
|
+
auto svs_metric = to_svs_metric(metric_type);
|
|
89
|
+
auto status = svs_runtime::FlatIndex::build(&impl, d, svs_metric);
|
|
90
|
+
if (!status.ok()) {
|
|
91
|
+
FAISS_THROW_MSG(status.message());
|
|
92
|
+
}
|
|
93
|
+
FAISS_THROW_IF_NOT(impl);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Serialization */
|
|
97
|
+
void IndexSVSFlat::serialize_impl(std::ostream& out) const {
|
|
98
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
99
|
+
impl, "Cannot serialize: SVS index not initialized.");
|
|
100
|
+
|
|
101
|
+
auto status = impl->save(out);
|
|
102
|
+
if (!status.ok()) {
|
|
103
|
+
FAISS_THROW_MSG(status.message());
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
void IndexSVSFlat::deserialize_impl(std::istream& in) {
|
|
108
|
+
FAISS_THROW_IF_MSG(impl, "Cannot deserialize: SVS index already loaded.");
|
|
109
|
+
auto metric = to_svs_metric(metric_type);
|
|
110
|
+
auto status = impl->load(&impl, in, metric);
|
|
111
|
+
if (!status.ok()) {
|
|
112
|
+
FAISS_THROW_MSG(status.message());
|
|
113
|
+
}
|
|
114
|
+
FAISS_THROW_IF_NOT(impl);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
} // namespace faiss
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Portions Copyright 2025 Intel Corporation
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
* you may not use this file except in compliance with the License.
|
|
13
|
+
* You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
#pragma once
|
|
25
|
+
|
|
26
|
+
#include <faiss/Index.h>
|
|
27
|
+
#include <faiss/svs/IndexSVSFaissUtils.h>
|
|
28
|
+
|
|
29
|
+
#include <iostream>
|
|
30
|
+
|
|
31
|
+
namespace faiss {
|
|
32
|
+
|
|
33
|
+
struct IndexSVSFlat : Index {
|
|
34
|
+
// sequential labels
|
|
35
|
+
size_t nlabels{0};
|
|
36
|
+
|
|
37
|
+
IndexSVSFlat() = default;
|
|
38
|
+
IndexSVSFlat(idx_t d, MetricType metric = METRIC_L2);
|
|
39
|
+
|
|
40
|
+
~IndexSVSFlat() override;
|
|
41
|
+
|
|
42
|
+
void add(idx_t n, const float* x) override;
|
|
43
|
+
|
|
44
|
+
void search(
|
|
45
|
+
idx_t n,
|
|
46
|
+
const float* x,
|
|
47
|
+
idx_t k,
|
|
48
|
+
float* distances,
|
|
49
|
+
idx_t* labels,
|
|
50
|
+
const SearchParameters* params = nullptr) const override;
|
|
51
|
+
|
|
52
|
+
void reset() override;
|
|
53
|
+
|
|
54
|
+
/* The actual SVS implementation */
|
|
55
|
+
svs_runtime::FlatIndex* impl{nullptr};
|
|
56
|
+
|
|
57
|
+
/* Serialization */
|
|
58
|
+
void serialize_impl(std::ostream& out) const;
|
|
59
|
+
void deserialize_impl(std::istream& in);
|
|
60
|
+
|
|
61
|
+
protected:
|
|
62
|
+
/* Initializes the implementation*/
|
|
63
|
+
virtual void create_impl();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
} // namespace faiss
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Portions Copyright 2025 Intel Corporation
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
* you may not use this file except in compliance with the License.
|
|
13
|
+
* You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
#include <faiss/svs/IndexSVSFaissUtils.h>
|
|
25
|
+
#include <faiss/svs/IndexSVSVamana.h>
|
|
26
|
+
|
|
27
|
+
#include <faiss/Index.h>
|
|
28
|
+
|
|
29
|
+
#include <svs/runtime/api_defs.h>
|
|
30
|
+
#include <svs/runtime/dynamic_vamana_index.h>
|
|
31
|
+
#include <svs/runtime/vamana_index.h>
|
|
32
|
+
|
|
33
|
+
#include <cstddef>
|
|
34
|
+
#include <numeric>
|
|
35
|
+
#include <span>
|
|
36
|
+
#include <type_traits>
|
|
37
|
+
#include <vector>
|
|
38
|
+
|
|
39
|
+
namespace faiss {
|
|
40
|
+
namespace {
|
|
41
|
+
svs_runtime::VamanaIndex::SearchParams make_search_parameters(
|
|
42
|
+
const IndexSVSVamana& index,
|
|
43
|
+
const SearchParameters* params) {
|
|
44
|
+
FAISS_THROW_IF_NOT(index.impl);
|
|
45
|
+
|
|
46
|
+
auto search_window_size = index.search_window_size;
|
|
47
|
+
auto search_buffer_capacity = index.search_buffer_capacity;
|
|
48
|
+
|
|
49
|
+
if (auto svs_params =
|
|
50
|
+
dynamic_cast<const SearchParametersSVSVamana*>(params)) {
|
|
51
|
+
if (svs_params->search_window_size > 0)
|
|
52
|
+
search_window_size = svs_params->search_window_size;
|
|
53
|
+
if (svs_params->search_buffer_capacity > 0)
|
|
54
|
+
search_buffer_capacity = svs_params->search_buffer_capacity;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {search_window_size, search_buffer_capacity};
|
|
58
|
+
}
|
|
59
|
+
} // namespace
|
|
60
|
+
|
|
61
|
+
IndexSVSVamana::IndexSVSVamana() = default;
|
|
62
|
+
|
|
63
|
+
IndexSVSVamana::IndexSVSVamana(
|
|
64
|
+
idx_t d,
|
|
65
|
+
size_t degree,
|
|
66
|
+
MetricType metric,
|
|
67
|
+
SVSStorageKind storage)
|
|
68
|
+
: Index(d, metric), graph_max_degree{degree}, storage_kind{storage} {
|
|
69
|
+
prune_to = graph_max_degree < 4 ? graph_max_degree : graph_max_degree - 4;
|
|
70
|
+
alpha = metric == METRIC_L2 ? 1.2f : 0.95f;
|
|
71
|
+
|
|
72
|
+
// Validate the requested storage kind is available in current runtime.
|
|
73
|
+
// NB: LVQ/LeanVec are only available on Intel(R) hardware AND when using
|
|
74
|
+
// a build based on LVQ/LeanVec-enabled SVS.
|
|
75
|
+
auto svs_storage = to_svs_storage_kind(storage_kind);
|
|
76
|
+
auto status =
|
|
77
|
+
svs_runtime::DynamicVamanaIndex::check_storage_kind(svs_storage);
|
|
78
|
+
if (!status.ok()) {
|
|
79
|
+
FAISS_THROW_MSG(status.message());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
bool IndexSVSVamana::is_lvq_leanvec_enabled() {
|
|
84
|
+
auto lvq = to_svs_storage_kind(SVS_LVQ4x0);
|
|
85
|
+
auto status = svs_runtime::DynamicVamanaIndex::check_storage_kind(lvq);
|
|
86
|
+
if (!status.ok()) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
auto leanvec = to_svs_storage_kind(SVS_LeanVec4x4);
|
|
90
|
+
status = svs_runtime::DynamicVamanaIndex::check_storage_kind(leanvec);
|
|
91
|
+
if (!status.ok()) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
IndexSVSVamana::~IndexSVSVamana() {
|
|
98
|
+
if (impl) {
|
|
99
|
+
auto status = svs_runtime::DynamicVamanaIndex::destroy(impl);
|
|
100
|
+
FAISS_ASSERT(status.ok());
|
|
101
|
+
impl = nullptr;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
void IndexSVSVamana::add(idx_t n, const float* x) {
|
|
106
|
+
if (!impl) {
|
|
107
|
+
create_impl();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
std::vector<size_t> labels(n);
|
|
111
|
+
std::iota(labels.begin(), labels.end(), ntotal);
|
|
112
|
+
|
|
113
|
+
auto status = impl->add(n, labels.data(), x);
|
|
114
|
+
if (!status.ok()) {
|
|
115
|
+
FAISS_THROW_MSG(status.message());
|
|
116
|
+
}
|
|
117
|
+
ntotal += n;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void IndexSVSVamana::reset() {
|
|
121
|
+
if (impl) {
|
|
122
|
+
impl->reset();
|
|
123
|
+
}
|
|
124
|
+
is_trained = false;
|
|
125
|
+
ntotal = 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
void IndexSVSVamana::search(
|
|
129
|
+
idx_t n,
|
|
130
|
+
const float* x,
|
|
131
|
+
idx_t k,
|
|
132
|
+
float* distances,
|
|
133
|
+
idx_t* labels,
|
|
134
|
+
const SearchParameters* params) const {
|
|
135
|
+
if (!impl) {
|
|
136
|
+
for (idx_t i = 0; i < n; ++i) {
|
|
137
|
+
distances[i] = std::numeric_limits<float>::infinity();
|
|
138
|
+
labels[i] = -1;
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
FAISS_THROW_IF_NOT(k > 0);
|
|
143
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
144
|
+
|
|
145
|
+
auto sp = make_search_parameters(*this, params);
|
|
146
|
+
auto id_filter = make_faiss_id_filter(params);
|
|
147
|
+
auto status = impl->search(
|
|
148
|
+
static_cast<size_t>(n),
|
|
149
|
+
x,
|
|
150
|
+
static_cast<size_t>(k),
|
|
151
|
+
distances,
|
|
152
|
+
convert_output_buffer<size_t>(labels, static_cast<size_t>(n * k)),
|
|
153
|
+
&sp,
|
|
154
|
+
id_filter.get());
|
|
155
|
+
|
|
156
|
+
if (!status.ok()) {
|
|
157
|
+
FAISS_THROW_MSG(status.message());
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void IndexSVSVamana::range_search(
|
|
162
|
+
idx_t n,
|
|
163
|
+
const float* x,
|
|
164
|
+
float radius,
|
|
165
|
+
RangeSearchResult* result,
|
|
166
|
+
const SearchParameters* params) const {
|
|
167
|
+
FAISS_THROW_IF_NOT(impl);
|
|
168
|
+
FAISS_THROW_IF_NOT(radius > 0);
|
|
169
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
170
|
+
FAISS_THROW_IF_NOT(result->nq == static_cast<size_t>(n));
|
|
171
|
+
|
|
172
|
+
auto sp = make_search_parameters(*this, params);
|
|
173
|
+
auto id_filter = make_faiss_id_filter(params);
|
|
174
|
+
auto status = impl->range_search(
|
|
175
|
+
static_cast<size_t>(n),
|
|
176
|
+
x,
|
|
177
|
+
radius,
|
|
178
|
+
FaissResultsAllocator{result},
|
|
179
|
+
&sp,
|
|
180
|
+
id_filter.get());
|
|
181
|
+
if (!status.ok()) {
|
|
182
|
+
FAISS_THROW_MSG(status.message());
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
size_t IndexSVSVamana::remove_ids(const IDSelector& sel) {
|
|
187
|
+
FAISS_THROW_IF_NOT(impl);
|
|
188
|
+
auto id_filter = FaissIDFilter{sel};
|
|
189
|
+
size_t removed = 0;
|
|
190
|
+
auto Status = impl->remove_selected(&removed, id_filter);
|
|
191
|
+
ntotal -= removed;
|
|
192
|
+
return removed;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void IndexSVSVamana::create_impl() {
|
|
196
|
+
FAISS_THROW_IF_NOT(!impl);
|
|
197
|
+
ntotal = 0;
|
|
198
|
+
auto svs_metric = to_svs_metric(metric_type);
|
|
199
|
+
auto svs_storage_kind = to_svs_storage_kind(storage_kind);
|
|
200
|
+
auto build_params = svs_runtime::VamanaIndex::BuildParams{
|
|
201
|
+
.graph_max_degree = graph_max_degree,
|
|
202
|
+
.prune_to = prune_to,
|
|
203
|
+
.alpha = alpha,
|
|
204
|
+
.construction_window_size = construction_window_size,
|
|
205
|
+
.max_candidate_pool_size = max_candidate_pool_size,
|
|
206
|
+
.use_full_search_history = use_full_search_history,
|
|
207
|
+
};
|
|
208
|
+
auto search_params = svs_runtime::VamanaIndex::SearchParams{
|
|
209
|
+
.search_window_size = search_window_size,
|
|
210
|
+
.search_buffer_capacity = search_buffer_capacity,
|
|
211
|
+
};
|
|
212
|
+
auto Status = svs_runtime::DynamicVamanaIndex::build(
|
|
213
|
+
&impl,
|
|
214
|
+
d,
|
|
215
|
+
svs_metric,
|
|
216
|
+
svs_storage_kind,
|
|
217
|
+
build_params,
|
|
218
|
+
search_params);
|
|
219
|
+
if (!Status.ok()) {
|
|
220
|
+
FAISS_THROW_MSG(Status.message());
|
|
221
|
+
}
|
|
222
|
+
FAISS_THROW_IF_NOT(impl);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
void IndexSVSVamana::serialize_impl(std::ostream& out) const {
|
|
226
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
227
|
+
impl, "Cannot serialize: SVS index not initialized.");
|
|
228
|
+
|
|
229
|
+
auto status = impl->save(out);
|
|
230
|
+
if (!status.ok()) {
|
|
231
|
+
FAISS_THROW_MSG(status.message());
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
void IndexSVSVamana::deserialize_impl(std::istream& in) {
|
|
236
|
+
FAISS_THROW_IF_MSG(impl, "Cannot deserialize: SVS index already loaded.");
|
|
237
|
+
auto svs_metric = to_svs_metric(metric_type);
|
|
238
|
+
auto svs_storage_kind = to_svs_storage_kind(storage_kind);
|
|
239
|
+
auto status = impl->load(&impl, in, svs_metric, svs_storage_kind);
|
|
240
|
+
if (!status.ok()) {
|
|
241
|
+
FAISS_THROW_MSG(status.message());
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
} // namespace faiss
|