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.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/faiss/version.rb +1 -1
  4. data/vendor/faiss/faiss/AutoTune.cpp +3 -1
  5. data/vendor/faiss/faiss/Clustering.cpp +9 -1
  6. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  7. data/vendor/faiss/faiss/Index.h +2 -2
  8. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  10. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +1 -2
  11. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +4 -5
  12. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  13. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +2 -4
  14. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  15. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  16. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  17. data/vendor/faiss/faiss/IndexFlat.cpp +13 -50
  18. data/vendor/faiss/faiss/IndexHNSW.cpp +10 -11
  19. data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
  20. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  21. data/vendor/faiss/faiss/IndexIVF.cpp +17 -6
  22. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  23. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  24. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  25. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  26. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  27. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  28. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  29. data/vendor/faiss/faiss/IndexIVFPQ.cpp +40 -22
  30. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  31. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  32. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  33. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  34. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  35. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  36. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  37. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  38. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  39. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  40. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  41. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  42. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  43. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  44. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  45. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  46. data/vendor/faiss/faiss/IndexShards.cpp +2 -2
  47. data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
  48. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  49. data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
  50. data/vendor/faiss/faiss/SuperKMeans.h +30 -0
  51. data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
  52. data/vendor/faiss/faiss/clone_index.cpp +5 -0
  53. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  54. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  55. data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
  56. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
  57. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  58. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  59. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  60. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  61. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  62. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  63. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  64. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  65. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
  66. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  67. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  68. data/vendor/faiss/faiss/impl/HNSW.cpp +109 -152
  69. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  70. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  71. data/vendor/faiss/faiss/impl/Panorama.h +9 -7
  72. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  73. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +34 -22
  74. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +44 -36
  75. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  76. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +168 -67
  77. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
  78. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
  79. data/vendor/faiss/faiss/impl/ResultHandler.h +25 -31
  80. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +258 -57
  81. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +20 -0
  82. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  83. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  84. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  85. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
  86. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  87. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  88. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  89. data/vendor/faiss/faiss/impl/index_read.cpp +376 -36
  90. data/vendor/faiss/faiss/impl/index_write.cpp +55 -4
  91. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  92. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  93. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  94. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  95. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  96. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  97. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  98. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  99. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  100. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  101. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  102. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  103. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
  104. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  105. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +85 -23
  106. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  107. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  108. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  109. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +136 -0
  110. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +16 -16
  111. data/vendor/faiss/faiss/impl/simd_dispatch.h +30 -9
  112. data/vendor/faiss/faiss/index_factory.cpp +32 -6
  113. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  114. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +2 -2
  115. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
  116. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  117. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  118. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  119. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  120. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  121. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  122. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +31 -1
  123. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +15 -2
  124. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +1 -2
  125. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  126. data/vendor/faiss/faiss/utils/distances.cpp +14 -2
  127. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  128. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  129. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  130. data/vendor/faiss/faiss/utils/hamming.cpp +1 -1
  131. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  132. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  133. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  134. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  135. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
  136. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  137. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
  138. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +92 -0
  139. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  140. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  141. data/vendor/faiss/faiss/utils/simd_levels.cpp +44 -0
  142. data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
  143. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  144. 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
- FAISS_THROW_IF_NOT_MSG(
380
- !store_pairs, "store_pairs not supported for this index");
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
- FAISS_THROW_IF_NOT_MSG(
408
- !params->ensure_topk_full,
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 != nullptr);
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
- FAISS_THROW_IF_NOT(!by_residual);
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
- FAISS_THROW_IF_NOT(!by_residual);
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
- FAISS_THROW_IF_NOT_MSG(
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
- FAISS_THROW_IF_NOT_MSG(!params, "search parameters not supported");
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
- for (idx_t i = 0; i < n; i++) {
298
- idx_t key = idx[i];
299
- idx_t id = xids ? xids[i] : ntotal + i;
300
- if (key < 0) {
301
- direct_map.add_single_id(id, -1, 0);
302
- n_ignore++;
303
- if (residuals_2) {
304
- memset(residuals_2, 0, sizeof(*residuals_2) * d);
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
- uint8_t* code = xcodes.get() + i * code_size;
310
- size_t offset =
311
- invlists->add_entry(key, id, code, inverted_list_context);
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
- if (residuals_2) {
314
- float* res2 = residuals_2 + i * d;
315
- const float* xi = to_encode + i * d;
316
- pq.decode(code, res2);
317
- for (int j = 0; j < d; j++) {
318
- res2[j] = xi[j] - res2[j];
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
- direct_map.add_single_id(id, key, offset);
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
- size_t nup = 0;
233
-
234
- for (size_t j = 0; j < list_size; j++) {
235
- if (sel != nullptr) {
236
- int64_t id = store_pairs ? lo_build(list_no, j) : ids[j];
237
- if (!sel->is_member(id)) {
238
- codes += code_size;
239
- continue;
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
- // set up DistanceComputer
279
- dc.reset(ivf_rabitq.rabitq.get_distance_computer(
280
- qb, reconstructed_centroid.data(), centered));
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
  };