faiss 0.6.2 → 0.6.3
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 +4 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +3 -1
- data/vendor/faiss/faiss/Clustering.cpp +9 -1
- data/vendor/faiss/faiss/IVFlib.cpp +14 -3
- data/vendor/faiss/faiss/Index.h +2 -2
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +1 -2
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +4 -5
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +2 -4
- data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
- data/vendor/faiss/faiss/IndexEDEN.h +57 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
- data/vendor/faiss/faiss/IndexFlat.cpp +13 -50
- data/vendor/faiss/faiss/IndexHNSW.cpp +10 -11
- data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +17 -6
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
- data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +40 -22
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
- data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
- data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
- data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
- data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
- data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
- data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
- data/vendor/faiss/faiss/IndexShards.cpp +2 -2
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
- data/vendor/faiss/faiss/SuperKMeans.h +30 -0
- data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
- data/vendor/faiss/faiss/clone_index.cpp +5 -0
- data/vendor/faiss/faiss/factory_tools.cpp +47 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
- data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
- data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
- data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +109 -152
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +9 -7
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +34 -22
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +44 -36
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +168 -67
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
- data/vendor/faiss/faiss/impl/ResultHandler.h +25 -31
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +258 -57
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +20 -0
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
- data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
- data/vendor/faiss/faiss/impl/index_read.cpp +376 -36
- data/vendor/faiss/faiss/impl/index_write.cpp +55 -4
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
- data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
- data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +85 -23
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +136 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +16 -16
- data/vendor/faiss/faiss/impl/simd_dispatch.h +30 -9
- data/vendor/faiss/faiss/index_factory.cpp +32 -6
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +2 -2
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
- data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +31 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +15 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +1 -2
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +14 -2
- data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
- data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
- data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
- data/vendor/faiss/faiss/utils/hamming.cpp +1 -1
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
- data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +92 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
- data/vendor/faiss/faiss/utils/simd_levels.cpp +44 -0
- data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +16 -1
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 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
|
+
#include <faiss/IndexIVFEDEN.h>
|
|
9
|
+
|
|
10
|
+
#include <omp.h>
|
|
11
|
+
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <cstring>
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
#include <faiss/impl/EDENQuantizer.h>
|
|
19
|
+
#include <faiss/impl/FaissAssert.h>
|
|
20
|
+
#include <faiss/impl/expanded_scanners.h>
|
|
21
|
+
|
|
22
|
+
namespace faiss {
|
|
23
|
+
|
|
24
|
+
IndexIVFEDEN::IndexIVFEDEN(
|
|
25
|
+
Index* quantizer_in,
|
|
26
|
+
const size_t d_in,
|
|
27
|
+
const size_t nlist_in,
|
|
28
|
+
MetricType metric,
|
|
29
|
+
bool own_invlists_in,
|
|
30
|
+
uint8_t nb_bits_in,
|
|
31
|
+
EDENScaleType scale_type_in)
|
|
32
|
+
: IndexIVF(quantizer_in, d_in, nlist_in, 0, metric, own_invlists_in),
|
|
33
|
+
sq(d_in, eden_utils::quantizer_type_for_bits(nb_bits_in)),
|
|
34
|
+
scale_type(scale_type_in) {
|
|
35
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
36
|
+
scale_type == EDENScaleType_UNBIASED ||
|
|
37
|
+
scale_type == EDENScaleType_BIASED,
|
|
38
|
+
"invalid EDEN scale type");
|
|
39
|
+
sq.train(0, nullptr);
|
|
40
|
+
code_size = eden_utils::code_size(d, sq.bits);
|
|
41
|
+
if (own_invlists_in) {
|
|
42
|
+
invlists->code_size = code_size;
|
|
43
|
+
}
|
|
44
|
+
is_trained = false;
|
|
45
|
+
by_residual = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
IndexIVFEDEN::IndexIVFEDEN() {
|
|
49
|
+
by_residual = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void IndexIVFEDEN::train_encoder(
|
|
53
|
+
idx_t n,
|
|
54
|
+
const float* x,
|
|
55
|
+
const idx_t* /*assign*/) {
|
|
56
|
+
sq.train(n, x);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
void IndexIVFEDEN::encode_vectors(
|
|
60
|
+
idx_t n,
|
|
61
|
+
const float* x,
|
|
62
|
+
const idx_t* list_nos,
|
|
63
|
+
uint8_t* codes,
|
|
64
|
+
bool include_listnos) const {
|
|
65
|
+
const size_t coarse_size = include_listnos ? coarse_code_size() : 0;
|
|
66
|
+
memset(codes, 0, (code_size + coarse_size) * n);
|
|
67
|
+
|
|
68
|
+
#pragma omp parallel if (n > 1000)
|
|
69
|
+
{
|
|
70
|
+
std::vector<float> centroid(d);
|
|
71
|
+
|
|
72
|
+
#pragma omp for
|
|
73
|
+
for (idx_t i = 0; i < n; i++) {
|
|
74
|
+
const int64_t list_no = list_nos[i];
|
|
75
|
+
if (list_no >= 0) {
|
|
76
|
+
const float* xi = x + i * d;
|
|
77
|
+
uint8_t* code = codes + i * (code_size + coarse_size);
|
|
78
|
+
|
|
79
|
+
quantizer->reconstruct(list_no, centroid.data());
|
|
80
|
+
eden_utils::compute_codes(
|
|
81
|
+
sq,
|
|
82
|
+
metric_type,
|
|
83
|
+
scale_type,
|
|
84
|
+
xi,
|
|
85
|
+
code + coarse_size,
|
|
86
|
+
1,
|
|
87
|
+
centroid.data());
|
|
88
|
+
|
|
89
|
+
if (coarse_size) {
|
|
90
|
+
encode_listno(list_no, code);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void IndexIVFEDEN::decode_vectors(
|
|
98
|
+
idx_t n,
|
|
99
|
+
const uint8_t* codes,
|
|
100
|
+
const idx_t* listnos,
|
|
101
|
+
float* x) const {
|
|
102
|
+
#pragma omp parallel
|
|
103
|
+
{
|
|
104
|
+
std::vector<float> centroid(d);
|
|
105
|
+
|
|
106
|
+
#pragma omp for
|
|
107
|
+
for (idx_t i = 0; i < n; i++) {
|
|
108
|
+
const uint8_t* code = codes + i * code_size;
|
|
109
|
+
const int64_t list_no = listnos[i];
|
|
110
|
+
float* xi = x + i * d;
|
|
111
|
+
|
|
112
|
+
quantizer->reconstruct(list_no, centroid.data());
|
|
113
|
+
eden_utils::decode(sq, code, xi, 1, centroid.data());
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
void IndexIVFEDEN::add_core(
|
|
119
|
+
idx_t n,
|
|
120
|
+
const float* x,
|
|
121
|
+
const idx_t* xids,
|
|
122
|
+
const idx_t* precomputed_idx,
|
|
123
|
+
void* inverted_list_context) {
|
|
124
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
125
|
+
|
|
126
|
+
DirectMapAdd dm_add(direct_map, n, xids);
|
|
127
|
+
|
|
128
|
+
#pragma omp parallel
|
|
129
|
+
{
|
|
130
|
+
std::vector<uint8_t> one_code(code_size);
|
|
131
|
+
std::vector<float> centroid(d);
|
|
132
|
+
|
|
133
|
+
const int nt = omp_get_num_threads();
|
|
134
|
+
const int rank = omp_get_thread_num();
|
|
135
|
+
|
|
136
|
+
for (idx_t i = 0; i < n; i++) {
|
|
137
|
+
const int64_t list_no = precomputed_idx[i];
|
|
138
|
+
if (list_no >= 0 && list_no % nt == rank) {
|
|
139
|
+
const int64_t id = xids ? xids[i] : ntotal + i;
|
|
140
|
+
const float* xi = x + i * d;
|
|
141
|
+
|
|
142
|
+
quantizer->reconstruct(list_no, centroid.data());
|
|
143
|
+
eden_utils::compute_codes(
|
|
144
|
+
sq,
|
|
145
|
+
metric_type,
|
|
146
|
+
scale_type,
|
|
147
|
+
xi,
|
|
148
|
+
one_code.data(),
|
|
149
|
+
1,
|
|
150
|
+
centroid.data());
|
|
151
|
+
|
|
152
|
+
const size_t ofs = invlists->add_entry(
|
|
153
|
+
list_no, id, one_code.data(), inverted_list_context);
|
|
154
|
+
dm_add.add(i, list_no, ofs);
|
|
155
|
+
} else if (rank == 0 && list_no == -1) {
|
|
156
|
+
dm_add.add(i, -1, 0);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
ntotal += n;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
namespace {
|
|
165
|
+
|
|
166
|
+
struct EDENInvertedListScanner : InvertedListScanner {
|
|
167
|
+
using InvertedListScanner::scan_codes;
|
|
168
|
+
|
|
169
|
+
const IndexIVFEDEN& ivf_eden;
|
|
170
|
+
std::vector<float> reconstructed_centroid;
|
|
171
|
+
std::vector<float> query_vector;
|
|
172
|
+
std::unique_ptr<FlatCodesDistanceComputer> dc;
|
|
173
|
+
|
|
174
|
+
explicit EDENInvertedListScanner(
|
|
175
|
+
const IndexIVFEDEN& ivf_eden_in,
|
|
176
|
+
bool store_pairs_in = false,
|
|
177
|
+
const IDSelector* sel_in = nullptr)
|
|
178
|
+
: InvertedListScanner(store_pairs_in, sel_in),
|
|
179
|
+
ivf_eden(ivf_eden_in) {
|
|
180
|
+
keep_max = is_similarity_metric(ivf_eden.metric_type);
|
|
181
|
+
code_size = ivf_eden.code_size;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
void set_query(const float* query_vector_in) override {
|
|
185
|
+
query_vector.assign(query_vector_in, query_vector_in + ivf_eden.d);
|
|
186
|
+
internal_try_setup_dc();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
void set_list(idx_t list_no_in, float /*coarse_dis*/) override {
|
|
190
|
+
list_no = list_no_in;
|
|
191
|
+
|
|
192
|
+
reconstructed_centroid.resize(ivf_eden.d);
|
|
193
|
+
ivf_eden.quantizer->reconstruct(
|
|
194
|
+
list_no_in, reconstructed_centroid.data());
|
|
195
|
+
internal_try_setup_dc();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
float distance_to_code(const uint8_t* code) const final {
|
|
199
|
+
return dc->distance_to_code(code);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
size_t scan_codes(
|
|
203
|
+
size_t list_size,
|
|
204
|
+
const uint8_t* codes,
|
|
205
|
+
const idx_t* ids,
|
|
206
|
+
ResultHandler& handler) const override {
|
|
207
|
+
return run_scan_codes(*this, list_size, codes, ids, handler);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
void internal_try_setup_dc() {
|
|
211
|
+
if (!query_vector.empty() && !reconstructed_centroid.empty()) {
|
|
212
|
+
dc.reset(
|
|
213
|
+
eden_utils::get_distance_computer(
|
|
214
|
+
ivf_eden.sq,
|
|
215
|
+
ivf_eden.metric_type,
|
|
216
|
+
reconstructed_centroid.data()));
|
|
217
|
+
dc->set_query(query_vector.data());
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
} // namespace
|
|
223
|
+
|
|
224
|
+
InvertedListScanner* IndexIVFEDEN::get_InvertedListScanner(
|
|
225
|
+
bool store_pairs,
|
|
226
|
+
const IDSelector* sel,
|
|
227
|
+
const IVFSearchParameters* /*params*/) const {
|
|
228
|
+
return new EDENInvertedListScanner(*this, store_pairs, sel);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void IndexIVFEDEN::reconstruct_from_offset(
|
|
232
|
+
int64_t list_no,
|
|
233
|
+
int64_t offset,
|
|
234
|
+
float* recons) const {
|
|
235
|
+
const uint8_t* code = invlists->get_single_code(list_no, offset);
|
|
236
|
+
|
|
237
|
+
std::vector<float> centroid(d);
|
|
238
|
+
quantizer->reconstruct(list_no, centroid.data());
|
|
239
|
+
eden_utils::decode(sq, code, recons, 1, centroid.data());
|
|
240
|
+
|
|
241
|
+
invlists->release_codes(list_no, code);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
void IndexIVFEDEN::sa_decode(idx_t n, const uint8_t* bytes, float* x) const {
|
|
245
|
+
const size_t coarse_size = coarse_code_size();
|
|
246
|
+
|
|
247
|
+
#pragma omp parallel
|
|
248
|
+
{
|
|
249
|
+
std::vector<float> centroid(d);
|
|
250
|
+
|
|
251
|
+
#pragma omp for
|
|
252
|
+
for (idx_t i = 0; i < n; i++) {
|
|
253
|
+
const uint8_t* code = bytes + i * (code_size + coarse_size);
|
|
254
|
+
const int64_t list_no = decode_listno(code);
|
|
255
|
+
float* xi = x + i * d;
|
|
256
|
+
|
|
257
|
+
quantizer->reconstruct(list_no, centroid.data());
|
|
258
|
+
eden_utils::decode(sq, code + coarse_size, xi, 1, centroid.data());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
struct IVFEDENDistanceComputer : DistanceComputer {
|
|
264
|
+
const float* q = nullptr;
|
|
265
|
+
const IndexIVFEDEN* parent = nullptr;
|
|
266
|
+
|
|
267
|
+
void set_query(const float* x) override {
|
|
268
|
+
q = x;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
float operator()(idx_t i) override {
|
|
272
|
+
const idx_t lo = parent->direct_map.get(i);
|
|
273
|
+
const uint64_t list_no = lo_listno(lo);
|
|
274
|
+
const uint64_t offset = lo_offset(lo);
|
|
275
|
+
const uint8_t* code =
|
|
276
|
+
parent->invlists->get_single_code(list_no, offset);
|
|
277
|
+
|
|
278
|
+
std::vector<float> centroid(parent->d);
|
|
279
|
+
parent->quantizer->reconstruct(list_no, centroid.data());
|
|
280
|
+
|
|
281
|
+
std::unique_ptr<FlatCodesDistanceComputer> dc(
|
|
282
|
+
eden_utils::get_distance_computer(
|
|
283
|
+
parent->sq, parent->metric_type, centroid.data()));
|
|
284
|
+
dc->set_query(q);
|
|
285
|
+
const float distance = dc->distance_to_code(code);
|
|
286
|
+
|
|
287
|
+
parent->invlists->release_codes(list_no, code);
|
|
288
|
+
return distance;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
float symmetric_dis(idx_t /*i*/, idx_t /*j*/) override {
|
|
292
|
+
FAISS_THROW_MSG("Not implemented");
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
DistanceComputer* IndexIVFEDEN::get_distance_computer() const {
|
|
297
|
+
IVFEDENDistanceComputer* dc = new IVFEDENDistanceComputer;
|
|
298
|
+
dc->parent = this;
|
|
299
|
+
return dc;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
} // namespace faiss
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 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
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
|
|
13
|
+
#include <faiss/IndexIVF.h>
|
|
14
|
+
#include <faiss/impl/EDENQuantizer.h>
|
|
15
|
+
|
|
16
|
+
namespace faiss {
|
|
17
|
+
|
|
18
|
+
struct IndexIVFEDEN : IndexIVF {
|
|
19
|
+
ScalarQuantizer sq;
|
|
20
|
+
EDENScaleType scale_type = EDENScaleType_UNBIASED;
|
|
21
|
+
|
|
22
|
+
// Factory strings: IVF<nlist>,EDEN, IVF<nlist>,EDEN<n>, and the same
|
|
23
|
+
// forms with the BIASED suffix for EDEN's MSE-minimizing scale.
|
|
24
|
+
IndexIVFEDEN(
|
|
25
|
+
Index* quantizer,
|
|
26
|
+
const size_t d,
|
|
27
|
+
const size_t nlist,
|
|
28
|
+
MetricType metric = METRIC_L2,
|
|
29
|
+
bool own_invlists = true,
|
|
30
|
+
uint8_t nb_bits = 1,
|
|
31
|
+
EDENScaleType scale_type = EDENScaleType_UNBIASED);
|
|
32
|
+
|
|
33
|
+
IndexIVFEDEN();
|
|
34
|
+
|
|
35
|
+
void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
|
|
36
|
+
|
|
37
|
+
void encode_vectors(
|
|
38
|
+
idx_t n,
|
|
39
|
+
const float* x,
|
|
40
|
+
const idx_t* list_nos,
|
|
41
|
+
uint8_t* codes,
|
|
42
|
+
bool include_listnos = false) const override;
|
|
43
|
+
|
|
44
|
+
void decode_vectors(
|
|
45
|
+
idx_t n,
|
|
46
|
+
const uint8_t* codes,
|
|
47
|
+
const idx_t* list_nos,
|
|
48
|
+
float* x) const override;
|
|
49
|
+
|
|
50
|
+
void add_core(
|
|
51
|
+
idx_t n,
|
|
52
|
+
const float* x,
|
|
53
|
+
const idx_t* xids,
|
|
54
|
+
const idx_t* precomputed_idx,
|
|
55
|
+
void* inverted_list_context = nullptr) override;
|
|
56
|
+
|
|
57
|
+
InvertedListScanner* get_InvertedListScanner(
|
|
58
|
+
bool store_pairs,
|
|
59
|
+
const IDSelector* sel,
|
|
60
|
+
const IVFSearchParameters* params) const override;
|
|
61
|
+
|
|
62
|
+
void reconstruct_from_offset(int64_t list_no, int64_t offset, float* recons)
|
|
63
|
+
const override;
|
|
64
|
+
|
|
65
|
+
void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
|
|
66
|
+
|
|
67
|
+
DistanceComputer* get_distance_computer() const override;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
} // namespace faiss
|
|
@@ -376,9 +376,8 @@ void IndexIVFFastScan::search_preassigned(
|
|
|
376
376
|
cur_nprobe = params->nprobe;
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
FAISS_THROW_IF_NOT_MSG(!stats, "stats not supported for this index");
|
|
379
|
+
FAISS_THROW_IF_MSG(store_pairs, "store_pairs not supported for this index");
|
|
380
|
+
FAISS_THROW_IF_MSG(stats, "stats not supported for this index");
|
|
382
381
|
FAISS_THROW_IF_NOT(k > 0);
|
|
383
382
|
FastScanDistancePostProcessing empty_context{};
|
|
384
383
|
|
|
@@ -404,8 +403,8 @@ void IndexIVFFastScan::range_search(
|
|
|
404
403
|
params->max_lists_num == 0,
|
|
405
404
|
"max_lists_num is a knn knob and is not honored by "
|
|
406
405
|
"fastscan range search");
|
|
407
|
-
|
|
408
|
-
|
|
406
|
+
FAISS_THROW_IF_MSG(
|
|
407
|
+
params->ensure_topk_full,
|
|
409
408
|
"ensure_topk_full is a knn knob and is not honored by "
|
|
410
409
|
"fastscan range search");
|
|
411
410
|
FAISS_THROW_IF_NOT_MSG(
|
|
@@ -1592,7 +1591,7 @@ void IndexIVFFastScan::reconstruct_from_offset(
|
|
|
1592
1591
|
}
|
|
1593
1592
|
|
|
1594
1593
|
void IndexIVFFastScan::reconstruct_orig_invlists() {
|
|
1595
|
-
FAISS_THROW_IF_NOT(orig_invlists
|
|
1594
|
+
FAISS_THROW_IF_NOT(orig_invlists);
|
|
1596
1595
|
FAISS_THROW_IF_NOT(orig_invlists->list_size(0) == 0);
|
|
1597
1596
|
|
|
1598
1597
|
#pragma omp parallel for if (nlist > 100)
|
|
@@ -65,7 +65,7 @@ void IndexIVFFlat::add_core(
|
|
|
65
65
|
void* inverted_list_context) {
|
|
66
66
|
FAISS_THROW_IF_NOT(is_trained);
|
|
67
67
|
FAISS_THROW_IF_NOT(coarse_idx);
|
|
68
|
-
|
|
68
|
+
FAISS_THROW_IF_MSG(by_residual, "by_residual not supported for this index");
|
|
69
69
|
FAISS_THROW_IF_NOT_MSG(invlists, "invlists not initialized");
|
|
70
70
|
direct_map.check_can_add(xids);
|
|
71
71
|
|
|
@@ -110,7 +110,7 @@ void IndexIVFFlat::encode_vectors(
|
|
|
110
110
|
const idx_t* list_nos,
|
|
111
111
|
uint8_t* codes,
|
|
112
112
|
bool include_listnos) const {
|
|
113
|
-
|
|
113
|
+
FAISS_THROW_IF_MSG(by_residual, "by_residual not supported for this index");
|
|
114
114
|
if (!include_listnos) {
|
|
115
115
|
memcpy(codes, x, code_size * n);
|
|
116
116
|
} else {
|
|
@@ -291,8 +291,7 @@ void IndexIVFFlatDedup::search_preassigned(
|
|
|
291
291
|
bool store_pairs,
|
|
292
292
|
const IVFSearchParameters* params,
|
|
293
293
|
IndexIVFStats* /*stats*/) const {
|
|
294
|
-
|
|
295
|
-
!store_pairs, "store_pairs not supported in IVFDedup");
|
|
294
|
+
FAISS_THROW_IF_MSG(store_pairs, "store_pairs not supported in IVFDedup");
|
|
296
295
|
|
|
297
296
|
IndexIVFFlat::search_preassigned(
|
|
298
297
|
n, x, k, assign, centroid_dis, distances, labels, false, params);
|
|
@@ -90,7 +90,7 @@ void IndexIVFIndependentQuantizer::search(
|
|
|
90
90
|
float* distances,
|
|
91
91
|
idx_t* labels,
|
|
92
92
|
const SearchParameters* params) const {
|
|
93
|
-
|
|
93
|
+
FAISS_THROW_IF_MSG(params, "search parameters not supported");
|
|
94
94
|
size_t nprobe = index_ivf->nprobe;
|
|
95
95
|
std::vector<float> D(n * nprobe);
|
|
96
96
|
std::vector<idx_t> I(n * nprobe);
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
#include <cstdint>
|
|
15
15
|
#include <cstdio>
|
|
16
16
|
|
|
17
|
+
#include <omp.h>
|
|
18
|
+
|
|
17
19
|
#include <algorithm>
|
|
18
20
|
|
|
19
21
|
#include <faiss/utils/distances_dispatch.h>
|
|
@@ -28,6 +30,7 @@
|
|
|
28
30
|
#include <faiss/impl/IDSelector.h>
|
|
29
31
|
#include <faiss/impl/ProductQuantizer.h>
|
|
30
32
|
#include <faiss/impl/ResultHandler.h>
|
|
33
|
+
// NOLINTNEXTLINE(facebook-hte-InlineHeader,facebook-unused-include-check)
|
|
31
34
|
#include <faiss/impl/pq_code_distance/pq_code_distance-generic.h>
|
|
32
35
|
#include <faiss/impl/simd_dispatch.h>
|
|
33
36
|
|
|
@@ -292,34 +295,49 @@ void IndexIVFPQ::add_core_o(
|
|
|
292
295
|
pq.compute_codes(to_encode, xcodes.get(), n);
|
|
293
296
|
|
|
294
297
|
double t2 = getmillisecs();
|
|
295
|
-
// TODO: parallelize?
|
|
296
298
|
size_t n_ignore = 0;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
299
|
+
DirectMapAdd dm_adder(direct_map, n, xids);
|
|
300
|
+
|
|
301
|
+
#pragma omp parallel reduction(+ : n_ignore)
|
|
302
|
+
{
|
|
303
|
+
int nt = omp_get_num_threads();
|
|
304
|
+
int rank = omp_get_thread_num();
|
|
305
|
+
|
|
306
|
+
// each thread takes care of a subset of lists
|
|
307
|
+
for (idx_t i = 0; i < n; i++) {
|
|
308
|
+
idx_t key = idx[i];
|
|
309
|
+
if (key < 0) {
|
|
310
|
+
if (rank == 0) {
|
|
311
|
+
dm_adder.add(i, -1, 0);
|
|
312
|
+
n_ignore++;
|
|
313
|
+
if (residuals_2) {
|
|
314
|
+
memset(residuals_2 + i * d,
|
|
315
|
+
0,
|
|
316
|
+
sizeof(*residuals_2) * d);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (key % nt != rank) {
|
|
322
|
+
continue;
|
|
305
323
|
}
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
324
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
325
|
+
idx_t id = xids ? xids[i] : ntotal + i;
|
|
326
|
+
uint8_t* code = xcodes.get() + i * code_size;
|
|
327
|
+
size_t offset =
|
|
328
|
+
invlists->add_entry(key, id, code, inverted_list_context);
|
|
312
329
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
330
|
+
if (residuals_2) {
|
|
331
|
+
float* res2 = residuals_2 + i * d;
|
|
332
|
+
const float* xi = to_encode + i * d;
|
|
333
|
+
pq.decode(code, res2);
|
|
334
|
+
for (int j = 0; j < d; j++) {
|
|
335
|
+
res2[j] = xi[j] - res2[j];
|
|
336
|
+
}
|
|
319
337
|
}
|
|
320
|
-
}
|
|
321
338
|
|
|
322
|
-
|
|
339
|
+
dm_adder.add(i, key, offset);
|
|
340
|
+
}
|
|
323
341
|
}
|
|
324
342
|
|
|
325
343
|
double t3 = getmillisecs();
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
#include <faiss/impl/FaissAssert.h>
|
|
17
17
|
#include <faiss/impl/ResultHandler.h>
|
|
18
18
|
#include <faiss/impl/simdlib/simdlib_dispatch.h>
|
|
19
|
-
#include <faiss/utils/distances.h>
|
|
20
19
|
#include <faiss/utils/distances_dispatch.h>
|
|
21
20
|
#include <faiss/utils/extra_distances.h>
|
|
22
21
|
|
|
@@ -229,60 +229,30 @@ struct RaBitInvertedListScanner : InvertedListScanner {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
// Multi-bit: Two-stage search with adaptive filtering
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
float est_distance = rabitq_dc->distance_to_code_1bit(codes);
|
|
244
|
-
|
|
245
|
-
size_t code_size_base = (ivf_rabitq.d + 7) / 8;
|
|
246
|
-
const rabitq_utils::SignBitFactorsWithError* base_fac =
|
|
247
|
-
reinterpret_cast<
|
|
248
|
-
const rabitq_utils::SignBitFactorsWithError*>(
|
|
249
|
-
codes + code_size_base);
|
|
250
|
-
|
|
251
|
-
bool should_refine = rabitq_utils::should_refine_candidate(
|
|
252
|
-
est_distance,
|
|
253
|
-
base_fac->f_error,
|
|
254
|
-
rabitq_dc->g_error,
|
|
255
|
-
handler.threshold,
|
|
256
|
-
keep_max);
|
|
257
|
-
if (should_refine) {
|
|
258
|
-
// Refining computes the full distance — counts as a
|
|
259
|
-
// post-filter "distance computed" for stats purposes.
|
|
260
|
-
handler.stats.scan_cnt++;
|
|
261
|
-
float dis = distance_to_code(codes);
|
|
262
|
-
int64_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
263
|
-
|
|
264
|
-
if (handler.add_result(dis, id)) {
|
|
265
|
-
handler.stats.nheap_updates++;
|
|
266
|
-
nup++;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
codes += code_size;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return nup;
|
|
232
|
+
return rabitq_dc->scan_codes_multibit(
|
|
233
|
+
list_size,
|
|
234
|
+
codes,
|
|
235
|
+
ids,
|
|
236
|
+
code_size,
|
|
237
|
+
list_no,
|
|
238
|
+
store_pairs,
|
|
239
|
+
sel,
|
|
240
|
+
keep_max,
|
|
241
|
+
handler);
|
|
273
242
|
}
|
|
274
243
|
|
|
275
244
|
void internal_try_setup_dc() {
|
|
276
245
|
if (!query_vector.empty() && !reconstructed_centroid.empty()) {
|
|
277
|
-
// both query_vector and centroid are available
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
246
|
+
// both query_vector and centroid are available
|
|
247
|
+
if (!dc) {
|
|
248
|
+
dc.reset(ivf_rabitq.rabitq.get_distance_computer(
|
|
249
|
+
qb, nullptr, centered));
|
|
250
|
+
// Try to cast to RaBitQDistanceComputer for multi-bit support
|
|
251
|
+
rabitq_dc = dynamic_cast<RaBitQDistanceComputer*>(dc.get());
|
|
252
|
+
FAISS_THROW_IF_NOT(rabitq_dc);
|
|
253
|
+
}
|
|
254
|
+
rabitq_dc->set_centroid(reconstructed_centroid.data());
|
|
282
255
|
dc->set_query(query_vector.data());
|
|
283
|
-
|
|
284
|
-
// Try to cast to RaBitQDistanceComputer for multi-bit support
|
|
285
|
-
rabitq_dc = dynamic_cast<RaBitQDistanceComputer*>(dc.get());
|
|
286
256
|
}
|
|
287
257
|
}
|
|
288
258
|
};
|