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
@@ -8,6 +8,7 @@
8
8
  #include <faiss/IndexFastScan.h>
9
9
 
10
10
  #include <omp.h>
11
+ #include <algorithm>
11
12
  #include <cstring>
12
13
  #include <memory>
13
14
 
@@ -266,8 +267,7 @@ void IndexFastScan::search(
266
267
  float* distances,
267
268
  idx_t* labels,
268
269
  const SearchParameters* params) const {
269
- FAISS_THROW_IF_NOT_MSG(
270
- !params, "search params not supported for this index");
270
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
271
271
  FAISS_THROW_IF_NOT(k > 0);
272
272
 
273
273
  FastScanDistancePostProcessing empty_context{};
@@ -316,7 +316,7 @@ void IndexFastScan::search_dispatch_implem(
316
316
  if (implem == 1) {
317
317
  FAISS_THROW_MSG("not implemented");
318
318
  } else if (implem == 2 || implem == 3 || implem == 4) {
319
- FAISS_THROW_IF_NOT(orig_codes != nullptr);
319
+ FAISS_THROW_IF_NOT(orig_codes);
320
320
  search_implem_234<Cfloat>(n, x, k, distances, labels, context);
321
321
  } else if (impl >= 12 && impl <= 15) {
322
322
  FAISS_THROW_IF_NOT(ntotal < INT_MAX);
@@ -617,8 +617,19 @@ template void IndexFastScan::search_dispatch_implem<false>(
617
617
  const FastScanDistancePostProcessing& context) const;
618
618
 
619
619
  void IndexFastScan::reconstruct(idx_t key, float* recons) const {
620
- std::vector<uint8_t> code(code_size, 0);
620
+ FAISS_THROW_IF_NOT_FMT(
621
+ key >= 0 && key < ntotal,
622
+ "IndexFastScan::reconstruct: key %zd out of range (ntotal=%zd)",
623
+ (size_t)key,
624
+ (size_t)ntotal);
621
625
  std::unique_ptr<CodePacker> packer(get_CodePacker());
626
+ size_t block_no = (size_t)key / packer->nvec;
627
+ FAISS_THROW_IF_NOT_MSG(
628
+ mul_no_overflow(
629
+ block_no + 1, packer->block_size, "IndexFastScan codes") <=
630
+ codes.size(),
631
+ "IndexFastScan::reconstruct: packed codes buffer too small");
632
+ std::vector<uint8_t> code(std::max(code_size, packer->code_size), 0);
622
633
  packer->unpack_1(codes.data(), key, code.data());
623
634
  sa_decode(1, code.data(), recons);
624
635
  }
@@ -77,7 +77,8 @@ void IndexFlat::range_search(
77
77
  range_search_L2sqr(x, get_xb(), d, n, ntotal, radius, result, sel);
78
78
  break;
79
79
  default:
80
- FAISS_THROW_MSG("metric type not supported");
80
+ IndexFlatCodes::range_search(n, x, radius, result, params);
81
+ break;
81
82
  }
82
83
  }
83
84
 
@@ -105,13 +106,8 @@ namespace {
105
106
  template <SIMDLevel SL>
106
107
  struct FlatL2Dis : FlatCodesDistanceComputer {
107
108
  size_t d;
108
- idx_t nb;
109
- const float* b;
110
- size_t ndis;
111
- size_t npartial_dot_products;
112
109
 
113
110
  float distance_to_code(const uint8_t* code) final {
114
- ndis++;
115
111
  return fvec_L2sqr<SL>(q, (float*)code, d);
116
112
  }
117
113
 
@@ -119,25 +115,21 @@ struct FlatL2Dis : FlatCodesDistanceComputer {
119
115
  const idx_t i,
120
116
  const uint32_t offset,
121
117
  const uint32_t num_components) final override {
122
- npartial_dot_products++;
118
+ const float* b = (const float*)this->codes;
123
119
  return fvec_inner_product<SL>(
124
120
  q + offset, b + i * d + offset, num_components);
125
121
  }
126
122
 
127
123
  float symmetric_dis(idx_t i, idx_t j) override {
124
+ const float* b = (const float*)this->codes;
128
125
  return fvec_L2sqr<SL>(b + j * d, b + i * d, d);
129
126
  }
130
127
 
131
- explicit FlatL2Dis(const IndexFlat& storage, const float* q_ = nullptr)
128
+ explicit FlatL2Dis(const IndexFlat& storage)
132
129
  : FlatCodesDistanceComputer(
133
130
  storage.codes.data(),
134
- storage.code_size,
135
- q_),
136
- d(storage.d),
137
- nb(storage.ntotal),
138
- b(storage.get_xb()),
139
- ndis(0),
140
- npartial_dot_products(0) {}
131
+ storage.code_size),
132
+ d(storage.d) {}
141
133
 
142
134
  void set_query(const float* x) override {
143
135
  q = x;
@@ -153,8 +145,6 @@ struct FlatL2Dis : FlatCodesDistanceComputer {
153
145
  float& dis1,
154
146
  float& dis2,
155
147
  float& dis3) final override {
156
- ndis += 4;
157
-
158
148
  // compute first, assign next
159
149
  const float* __restrict y0 =
160
150
  reinterpret_cast<const float*>(codes + idx0 * code_size);
@@ -187,8 +177,6 @@ struct FlatL2Dis : FlatCodesDistanceComputer {
187
177
  float& dp3,
188
178
  const uint32_t offset,
189
179
  const uint32_t num_components) final override {
190
- npartial_dot_products += 4;
191
-
192
180
  // compute first, assign next
193
181
  const float* __restrict y0 =
194
182
  reinterpret_cast<const float*>(codes + idx0 * code_size);
@@ -224,29 +212,21 @@ struct FlatL2Dis : FlatCodesDistanceComputer {
224
212
  template <SIMDLevel SL>
225
213
  struct FlatIPDis : FlatCodesDistanceComputer {
226
214
  size_t d;
227
- idx_t nb;
228
- const float* q;
229
- const float* b;
230
- size_t ndis;
231
215
 
232
216
  float symmetric_dis(idx_t i, idx_t j) final override {
217
+ const float* b = (const float*)this->codes;
233
218
  return fvec_inner_product<SL>(b + j * d, b + i * d, d);
234
219
  }
235
220
 
236
221
  float distance_to_code(const uint8_t* code) final override {
237
- ndis++;
238
222
  return fvec_inner_product<SL>(q, (const float*)code, d);
239
223
  }
240
224
 
241
- explicit FlatIPDis(const IndexFlat& storage, const float* q_in = nullptr)
225
+ explicit FlatIPDis(const IndexFlat& storage)
242
226
  : FlatCodesDistanceComputer(
243
227
  storage.codes.data(),
244
228
  storage.code_size),
245
- d(storage.d),
246
- nb(storage.ntotal),
247
- q(q_in),
248
- b(storage.get_xb()),
249
- ndis(0) {}
229
+ d(storage.d) {}
250
230
 
251
231
  void set_query(const float* x) override {
252
232
  q = x;
@@ -262,8 +242,6 @@ struct FlatIPDis : FlatCodesDistanceComputer {
262
242
  float& dis1,
263
243
  float& dis2,
264
244
  float& dis3) final override {
265
- ndis += 4;
266
-
267
245
  // compute first, assign next
268
246
  const float* __restrict y0 =
269
247
  reinterpret_cast<const float*>(codes + idx0 * code_size);
@@ -296,8 +274,7 @@ FlatCodesDistanceComputer* IndexFlat::get_FlatCodesDistanceComputer() const {
296
274
  } else if (metric_type == METRIC_INNER_PRODUCT) {
297
275
  with_simd_level([&]<SIMDLevel SL>() { dc = new FlatIPDis<SL>(*this); });
298
276
  } else {
299
- dc = get_extra_distance_computer(
300
- d, metric_type, metric_arg, ntotal, get_xb());
277
+ dc = get_extra_distance_computer(d, metric_type, metric_arg, get_xb());
301
278
  }
302
279
  return dc;
303
280
  }
@@ -327,16 +304,11 @@ namespace {
327
304
  template <SIMDLevel SL>
328
305
  struct FlatL2WithNormsDis : FlatCodesDistanceComputer {
329
306
  size_t d;
330
- idx_t nb;
331
- const float* q;
332
- const float* b;
333
- size_t ndis;
334
307
 
335
308
  const float* l2norms;
336
309
  float query_l2norm;
337
310
 
338
311
  float distance_to_code(const uint8_t* code) final override {
339
- ndis++;
340
312
  return fvec_L2sqr<SL>(q, (float*)code, d);
341
313
  }
342
314
 
@@ -361,17 +333,11 @@ struct FlatL2WithNormsDis : FlatCodesDistanceComputer {
361
333
  return l2norms[i] + l2norms[j] - 2 * dp0;
362
334
  }
363
335
 
364
- explicit FlatL2WithNormsDis(
365
- const IndexFlatL2& storage,
366
- const float* q_in = nullptr)
336
+ explicit FlatL2WithNormsDis(const IndexFlatL2& storage)
367
337
  : FlatCodesDistanceComputer(
368
338
  storage.codes.data(),
369
339
  storage.code_size),
370
340
  d(storage.d),
371
- nb(storage.ntotal),
372
- q(q_in),
373
- b(storage.get_xb()),
374
- ndis(0),
375
341
  l2norms(storage.cached_l2norms.data()),
376
342
  query_l2norm(0) {}
377
343
 
@@ -390,8 +356,6 @@ struct FlatL2WithNormsDis : FlatCodesDistanceComputer {
390
356
  float& dis1,
391
357
  float& dis2,
392
358
  float& dis3) final override {
393
- ndis += 4;
394
-
395
359
  // compute first, assign next
396
360
  const float* __restrict y0 =
397
361
  reinterpret_cast<const float*>(codes + idx0 * code_size);
@@ -487,8 +451,7 @@ void IndexFlat1D::search(
487
451
  float* distances,
488
452
  idx_t* labels,
489
453
  const SearchParameters* params) const {
490
- FAISS_THROW_IF_NOT_MSG(
491
- !params, "search params not supported for this index");
454
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
492
455
  FAISS_THROW_IF_NOT(k > 0);
493
456
  FAISS_THROW_IF_NOT_MSG(
494
457
  perm.size() == static_cast<size_t>(ntotal),
@@ -280,12 +280,12 @@ void hnsw_search(
280
280
 
281
281
  #pragma omp parallel if (i1 - i0 > 1)
282
282
  {
283
- std::unique_ptr<VisitedTable> vt;
283
+ VisitedTable* vt = nullptr;
284
284
  std::unique_ptr<typename BlockResultHandler::SingleResultHandler>
285
285
  res;
286
286
  std::unique_ptr<DistanceComputer> dis;
287
287
  try {
288
- vt = VisitedTable::create(
288
+ vt = &VisitedTable::get_reusable(
289
289
  index->ntotal, hnsw.use_visited_hashset);
290
290
  res = std::make_unique<
291
291
  typename BlockResultHandler::SingleResultHandler>(bres);
@@ -479,11 +479,11 @@ void IndexHNSW::search_level_0(
479
479
  {
480
480
  std::unique_ptr<DistanceComputer> qdis;
481
481
  HNSWStats search_stats;
482
- std::unique_ptr<VisitedTable> vt;
482
+ VisitedTable* vt = nullptr;
483
483
  std::unique_ptr<typename RH::SingleResultHandler> res;
484
484
  try {
485
485
  qdis.reset(storage_distance_computer(storage));
486
- vt = VisitedTable::create(
486
+ vt = &VisitedTable::get_reusable(
487
487
  hnsw_ntotal, hnsw.use_visited_hashset);
488
488
  res = std::make_unique<typename RH::SingleResultHandler>(bres);
489
489
  } catch (...) {
@@ -903,8 +903,7 @@ void IndexHNSW2Level::search(
903
903
  idx_t* labels,
904
904
  const SearchParameters* params) const {
905
905
  FAISS_THROW_IF_NOT(k > 0);
906
- FAISS_THROW_IF_NOT_MSG(
907
- !params, "search params not supported for this index");
906
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
908
907
 
909
908
  if (dynamic_cast<const Index2Layer*>(storage)) {
910
909
  IndexHNSW::search(n, x, k, distances, labels);
@@ -1084,8 +1083,8 @@ IndexHNSWCagra::IndexHNSWCagra(
1084
1083
  }
1085
1084
 
1086
1085
  void IndexHNSWCagra::add(idx_t n, const float* x) {
1087
- FAISS_THROW_IF_NOT_MSG(
1088
- !base_level_only,
1086
+ FAISS_THROW_IF_MSG(
1087
+ base_level_only,
1089
1088
  "Cannot add vectors when base_level_only is set to True");
1090
1089
 
1091
1090
  IndexHNSW::add(n, x);
@@ -1208,11 +1207,11 @@ void IndexHNSWCagra::range_search(
1208
1207
 
1209
1208
  RangeQueryResult& qres = pres.new_result(i);
1210
1209
  RangeResultHandler<C> res(&qres, radius);
1211
- std::unique_ptr<VisitedTable> vt =
1212
- VisitedTable::create(ntotal, hnsw.use_visited_hashset);
1210
+ VisitedTable& vt = VisitedTable::get_reusable(
1211
+ ntotal, hnsw.use_visited_hashset);
1213
1212
  HNSWStats stats;
1214
1213
  hnsw.search_level_0(
1215
- *dis, res, 1, &nearest, &nearest_d, 1, stats, *vt, params);
1214
+ *dis, res, 1, &nearest, &nearest_d, 1, stats, vt, params);
1216
1215
  n1 += stats.n1;
1217
1216
  n2 += stats.n2;
1218
1217
  ndis += stats.ndis;
@@ -138,7 +138,8 @@ void IndexIDMapTemplate<IndexT>::add_sa_codes(
138
138
  idx_t n,
139
139
  const uint8_t* codes,
140
140
  const idx_t* xids) {
141
- index->add_sa_codes(n, codes, xids);
141
+ // don't pass the ids to the sub-index, they are kept in id_map
142
+ index->add_sa_codes(n, codes, nullptr);
142
143
  for (idx_t i = 0; i < n; i++) {
143
144
  id_map.push_back(xids[i]);
144
145
  }
@@ -228,14 +229,14 @@ void IndexIDMapTemplate<IndexT>::range_search(
228
229
  typename IndexT::distance_t radius,
229
230
  RangeSearchResult* result,
230
231
  const SearchParameters* params) const {
231
- if (params) {
232
+ if (params && params->sel) {
232
233
  SearchParameters internal_search_parameters;
233
234
  IDSelectorTranslated id_selector_translated(id_map, params->sel);
234
235
  internal_search_parameters.sel = &id_selector_translated;
235
236
 
236
237
  index->range_search(n, x, radius, result, &internal_search_parameters);
237
238
  } else {
238
- index->range_search(n, x, radius, result);
239
+ index->range_search(n, x, radius, result, params);
239
240
  }
240
241
 
241
242
  const idx_t id_map_size = static_cast<idx_t>(id_map.size());
@@ -329,6 +330,18 @@ void IndexIDMap2Template<IndexT>::add_with_ids(
329
330
  xids);
330
331
  }
331
332
 
333
+ template <typename IndexT>
334
+ void IndexIDMap2Template<IndexT>::add_sa_codes(
335
+ idx_t n,
336
+ const uint8_t* codes,
337
+ const idx_t* xids) {
338
+ idx_t prev_ntotal = this->ntotal;
339
+ IndexIDMapTemplate<IndexT>::add_sa_codes(n, codes, xids);
340
+ for (idx_t i = prev_ntotal; i < this->ntotal; i++) {
341
+ rev_map[this->id_map[i]] = i;
342
+ }
343
+ }
344
+
332
345
  template <typename IndexT>
333
346
  void IndexIDMap2Template<IndexT>::check_consistency() const {
334
347
  FAISS_THROW_IF_NOT(rev_map.size() == this->id_map.size());
@@ -110,6 +110,8 @@ struct IndexIDMap2Template : IndexIDMapTemplate<IndexT> {
110
110
  NumericType numeric_type,
111
111
  const idx_t* xids) override;
112
112
 
113
+ void add_sa_codes(idx_t n, const uint8_t* x, const idx_t* xids) override;
114
+
113
115
  size_t remove_ids(const IDSelector& sel) override;
114
116
 
115
117
  void reconstruct(idx_t key, component_t* recons) const override;
@@ -17,7 +17,6 @@
17
17
  #include <cstdio>
18
18
  #include <limits>
19
19
 
20
- #include <faiss/utils/hamming.h>
21
20
  #include <faiss/utils/utils.h>
22
21
 
23
22
  #include <faiss/IndexFlat.h>
@@ -501,7 +500,7 @@ void IndexIVF::search_preassigned(
501
500
  if (!do_heap_init) {
502
501
  return;
503
502
  }
504
- if (metric_type == METRIC_INNER_PRODUCT) {
503
+ if (is_similarity_metric(metric_type)) {
505
504
  heap_heapify<HeapForIP>(k, simi, idxi);
506
505
  } else {
507
506
  heap_heapify<HeapForL2>(k, simi, idxi);
@@ -512,7 +511,7 @@ void IndexIVF::search_preassigned(
512
511
  const idx_t* local_idx,
513
512
  float* simi,
514
513
  idx_t* idxi) {
515
- if (metric_type == METRIC_INNER_PRODUCT) {
514
+ if (is_similarity_metric(metric_type)) {
516
515
  heap_addn<HeapForIP>(
517
516
  k, simi, idxi, local_dis, local_idx, k);
518
517
  } else {
@@ -525,7 +524,7 @@ void IndexIVF::search_preassigned(
525
524
  if (!do_heap_init) {
526
525
  return;
527
526
  }
528
- if (metric_type == METRIC_INNER_PRODUCT) {
527
+ if (is_similarity_metric(metric_type)) {
529
528
  heap_reorder<HeapForIP>(k, simi, idxi);
530
529
  } else {
531
530
  heap_reorder<HeapForL2>(k, simi, idxi);
@@ -599,7 +598,7 @@ void IndexIVF::search_preassigned(
599
598
 
600
599
  size_t old_scan_cnt = 0;
601
600
  size_t old_heap_updates = 0;
602
- if (metric_type == METRIC_INNER_PRODUCT) {
601
+ if (is_similarity_metric(metric_type)) {
603
602
  HeapResultHandler<HeapForIP, false> handler(
604
603
  k, simi, idxi);
605
604
  old_scan_cnt = handler.stats.scan_cnt;
@@ -1056,7 +1055,19 @@ InvertedListScanner* IndexIVF::get_InvertedListScanner(
1056
1055
 
1057
1056
  void IndexIVF::reconstruct(idx_t key, float* recons) const {
1058
1057
  idx_t lo = direct_map.get(key);
1059
- reconstruct_from_offset(lo_listno(lo), lo_offset(lo), recons);
1058
+ const size_t list_no = lo_listno(lo);
1059
+ const size_t offset = lo_offset(lo);
1060
+ FAISS_THROW_IF_NOT_FMT(
1061
+ list_no < nlist,
1062
+ "IndexIVF::reconstruct: list_no %zd out of range (nlist=%zd)",
1063
+ list_no,
1064
+ nlist);
1065
+ FAISS_THROW_IF_NOT_FMT(
1066
+ offset < invlists->list_size(list_no),
1067
+ "IndexIVF::reconstruct: offset %zd out of range (list_size=%zd)",
1068
+ offset,
1069
+ invlists->list_size(list_no));
1070
+ reconstruct_from_offset(list_no, offset, recons);
1060
1071
  }
1061
1072
 
1062
1073
  void IndexIVF::reconstruct_n(idx_t i0, idx_t ni, float* recons) const {
@@ -283,7 +283,7 @@ InvertedListScanner* IndexIVFAdditiveQuantizer::get_InvertedListScanner(
283
283
  bool store_pairs,
284
284
  const IDSelector* sel,
285
285
  const IVFSearchParameters*) const {
286
- FAISS_THROW_IF_NOT(!sel);
286
+ FAISS_THROW_IF_MSG(sel, "id selector not supported for this index");
287
287
  if (metric_type == METRIC_INNER_PRODUCT) {
288
288
  if (aq->search_type == AdditiveQuantizer::ST_decompress) {
289
289
  return new AQInvertedListScannerDecompress<true>(
@@ -48,8 +48,8 @@ void IndexIVFAdditiveQuantizerFastScan::init(
48
48
  MetricType metric,
49
49
  int bbs_,
50
50
  bool own_invlists_) {
51
- FAISS_THROW_IF_NOT(aq_ != nullptr);
52
- FAISS_THROW_IF_NOT(!aq_->nbits.empty());
51
+ FAISS_THROW_IF_NOT(aq_);
52
+ FAISS_THROW_IF_MSG(aq_->nbits.empty(), "quantizer nbits must not be empty");
53
53
  FAISS_THROW_IF_NOT(aq_->nbits[0] == 4);
54
54
  if (metric == METRIC_INNER_PRODUCT) {
55
55
  FAISS_THROW_IF_NOT_MSG(
@@ -310,8 +310,7 @@ void IndexIVFAdditiveQuantizerFastScan::search(
310
310
  float* distances,
311
311
  idx_t* labels,
312
312
  const SearchParameters* params) const {
313
- FAISS_THROW_IF_NOT_MSG(
314
- !params, "search params not supported for this index");
313
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
315
314
 
316
315
  FAISS_THROW_IF_NOT(k > 0);
317
316
  bool rescale = (rescale_norm && norm_scale > 1 && metric_type == METRIC_L2);