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,13 +8,15 @@
8
8
  #include <faiss/impl/RaBitQuantizer.h>
9
9
 
10
10
  #include <faiss/impl/FaissAssert.h>
11
+ #include <faiss/impl/IDSelector.h>
11
12
  #include <faiss/impl/RaBitQUtils.h>
12
13
  #include <faiss/impl/RaBitQuantizerMultiBit.h>
14
+ #include <faiss/impl/ResultHandler.h>
13
15
  #include <faiss/impl/simd_dispatch.h>
16
+ #include <faiss/invlists/DirectMap.h>
14
17
  #include <faiss/utils/distances.h>
15
18
  #include <faiss/utils/rabitq_simd.h>
16
19
 
17
- #include <algorithm>
18
20
  #include <cmath>
19
21
  #include <cstring>
20
22
  #include <memory>
@@ -183,8 +185,10 @@ void RaBitQuantizer::decode_core(
183
185
  float* x,
184
186
  size_t n,
185
187
  const float* centroid_in) const {
186
- FAISS_ASSERT(codes != nullptr);
187
- FAISS_ASSERT(x != nullptr);
188
+ FAISS_THROW_IF_MSG(
189
+ codes == nullptr, "RaBitQuantizer::decode_core: null codes buffer");
190
+ FAISS_THROW_IF_MSG(
191
+ x == nullptr, "RaBitQuantizer::decode_core: null output buffer");
188
192
 
189
193
  const float inv_d_sqrt = (d == 0) ? 1.0f : (1.0f / std::sqrt((float)d));
190
194
  const size_t ex_bits = nb_bits - 1;
@@ -228,7 +232,7 @@ namespace {
228
232
  // directly to the SIMD-specialized code.
229
233
 
230
234
  template <SIMDLevel SL>
231
- struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
235
+ struct RaBitQDistanceComputerNotQ final : RaBitQDistanceComputer {
232
236
  // the rotated query (qr - c)
233
237
  std::vector<float> rotated_q;
234
238
  // some additional numbers for the query
@@ -237,26 +241,9 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
237
241
  RaBitQDistanceComputerNotQ() = default;
238
242
 
239
243
  // Compute distance using only 1-bit codes (fast)
240
- float distance_to_code_1bit(const uint8_t* code) override {
241
- FAISS_ASSERT(code != nullptr);
242
- FAISS_ASSERT(
243
- (metric_type == MetricType::METRIC_L2 ||
244
- metric_type == MetricType::METRIC_INNER_PRODUCT));
245
- FAISS_ASSERT(rotated_q.size() == d);
246
-
247
- // split the code into parts
248
- const uint8_t* binary_data = code;
249
-
250
- // Cast to appropriate type based on nb_bits
251
- // For 1-bit: use SignBitFactors (8 bytes)
252
- // For multi-bit: use SignBitFactorsWithError (12 bytes) which includes
253
- // f_error
254
- size_t ex_bits = nb_bits - 1;
255
- const SignBitFactors* base_fac = (ex_bits == 0)
256
- ? reinterpret_cast<const SignBitFactors*>(code + (d + 7) / 8)
257
- : reinterpret_cast<const SignBitFactorsWithError*>(
258
- code + (d + 7) / 8);
259
-
244
+ float distance_to_code_1bit_impl(
245
+ const uint8_t* binary_data,
246
+ const SignBitFactors* base_fac) const {
260
247
  // this is the baseline code
261
248
  //
262
249
  // compute <q,o> using floats
@@ -286,7 +273,7 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
286
273
 
287
274
  if (metric_type == MetricType::METRIC_L2) {
288
275
  // ||or - q||^ 2
289
- return pre_dist;
276
+ return std::max(0.0f, pre_dist);
290
277
  } else {
291
278
  // metric == MetricType::METRIC_INNER_PRODUCT
292
279
  // 2 * (or, q) = (||or - q||^2 - ||q||^2 - ||or||^2)
@@ -294,8 +281,24 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
294
281
  }
295
282
  }
296
283
 
284
+ float distance_to_code_1bit(const uint8_t* code) final {
285
+ FAISS_ASSERT(code != nullptr);
286
+ FAISS_ASSERT(
287
+ (metric_type == MetricType::METRIC_L2 ||
288
+ metric_type == MetricType::METRIC_INNER_PRODUCT));
289
+ FAISS_ASSERT(rotated_q.size() == d);
290
+
291
+ const size_t code_size_base = (d + 7) / 8;
292
+ const size_t ex_bits = nb_bits - 1;
293
+ const SignBitFactors* base_fac = (ex_bits == 0)
294
+ ? reinterpret_cast<const SignBitFactors*>(code + code_size_base)
295
+ : reinterpret_cast<const SignBitFactorsWithError*>(
296
+ code + code_size_base);
297
+ return distance_to_code_1bit_impl(code, base_fac);
298
+ }
299
+
297
300
  // Compute full distance using 1-bit + ex-bits (accurate)
298
- float distance_to_code_full(const uint8_t* code) override {
301
+ float distance_to_code_full(const uint8_t* code) final {
299
302
  FAISS_ASSERT(code != nullptr);
300
303
  FAISS_ASSERT(
301
304
  (metric_type == MetricType::METRIC_L2 ||
@@ -331,7 +334,7 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
331
334
  metric_type);
332
335
  }
333
336
 
334
- void set_query(const float* x) override {
337
+ void set_query(const float* x) final {
335
338
  q = x;
336
339
  FAISS_ASSERT(x != nullptr);
337
340
  FAISS_ASSERT(
@@ -372,10 +375,62 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
372
375
  centroid ? fvec_inner_product(x, centroid, d) : 0.0f;
373
376
  }
374
377
  }
378
+
379
+ size_t scan_codes_multibit(
380
+ size_t list_size,
381
+ const uint8_t* codes,
382
+ const idx_t* ids,
383
+ size_t code_size,
384
+ idx_t list_no,
385
+ bool store_pairs,
386
+ const IDSelector* sel,
387
+ bool keep_max,
388
+ ResultHandler& handler) final {
389
+ const size_t code_size_base = (d + 7) / 8;
390
+ const size_t ex_bits = nb_bits - 1;
391
+ FAISS_ASSERT(ex_bits > 0);
392
+
393
+ size_t nup = 0;
394
+ for (size_t j = 0; j < list_size; j++) {
395
+ if (sel != nullptr) {
396
+ idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
397
+ if (!sel->is_member(id)) {
398
+ codes += code_size;
399
+ continue;
400
+ }
401
+ }
402
+
403
+ const auto* base_fac =
404
+ reinterpret_cast<const SignBitFactorsWithError*>(
405
+ codes + code_size_base);
406
+ const float est_distance =
407
+ distance_to_code_1bit_impl(codes, base_fac);
408
+
409
+ const bool should_refine = rabitq_utils::should_refine_candidate(
410
+ est_distance,
411
+ base_fac->f_error,
412
+ g_error,
413
+ handler.threshold,
414
+ keep_max);
415
+ if (should_refine) {
416
+ handler.stats.scan_cnt++;
417
+ const float dis = distance_to_code_full(codes);
418
+ idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
419
+
420
+ if (handler.add_result(dis, id)) {
421
+ handler.stats.nheap_updates++;
422
+ nup++;
423
+ }
424
+ }
425
+ codes += code_size;
426
+ }
427
+
428
+ return nup;
429
+ }
375
430
  };
376
431
 
377
432
  template <SIMDLevel SL>
378
- struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
433
+ struct RaBitQDistanceComputerQ final : RaBitQDistanceComputer {
379
434
  // the rotated and quantized query (qr - c)
380
435
  std::vector<float> rotated_q;
381
436
  // the rotated and quantized query (qr - c) for fast 1-bit computation
@@ -395,25 +450,10 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
395
450
  RaBitQDistanceComputerQ() = default;
396
451
 
397
452
  // Compute distance using only 1-bit codes (fast)
398
- float distance_to_code_1bit(const uint8_t* code) override {
399
- FAISS_ASSERT(code != nullptr);
400
- FAISS_ASSERT(
401
- (metric_type == MetricType::METRIC_L2 ||
402
- metric_type == MetricType::METRIC_INNER_PRODUCT));
403
-
404
- // split the code into parts
405
- size_t size = (d + 7) / 8;
406
- const uint8_t* binary_data = code;
407
-
408
- // Cast to appropriate type based on nb_bits
409
- // For 1-bit: use SignBitFactors (8 bytes)
410
- // For multi-bit: use SignBitFactorsWithError (12 bytes) which
411
- // includes f_error
412
- size_t ex_bits = nb_bits - 1;
413
- const SignBitFactors* base_fac = (ex_bits == 0)
414
- ? reinterpret_cast<const SignBitFactors*>(code + size)
415
- : reinterpret_cast<const SignBitFactorsWithError*>(code + size);
416
-
453
+ float distance_to_code_1bit_impl(
454
+ const uint8_t* binary_data,
455
+ const SignBitFactors* base_fac,
456
+ size_t size) const {
417
457
  // this is ||or - c||^2 - (IP ? ||or||^2 : 0)
418
458
  float final_dot = 0;
419
459
  if (centered) {
@@ -428,17 +468,16 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
428
468
  qb);
429
469
  final_dot += int_dot * query_fac.int_dot_scale;
430
470
  } else {
431
- auto dot_qo = rabitq::bitwise_and_dot_product<SL>(
432
- rearranged_rotated_qq.data(), binary_data, size, qb);
433
- // It was a willful decision (after the discussion) to not to
434
- // pre-cache the sum of all bits, just in order to reduce the
435
- // overhead per vector.
436
- // process 64-bit popcounts
437
- auto sum_q = rabitq::popcount<SL>(binary_data, size);
471
+ auto bitwise_result =
472
+ rabitq::bitwise_and_dot_product_with_popcount<SL>(
473
+ rearranged_rotated_qq.data(),
474
+ binary_data,
475
+ size,
476
+ qb);
438
477
  // dot-product itself
439
- final_dot += query_fac.c1 * dot_qo;
478
+ final_dot += query_fac.c1 * bitwise_result.dot_product;
440
479
  // normalizer coefficients
441
- final_dot += query_fac.c2 * sum_q;
480
+ final_dot += query_fac.c2 * bitwise_result.popcount;
442
481
  // normalizer coefficients
443
482
  final_dot -= query_fac.c34;
444
483
  }
@@ -449,7 +488,7 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
449
488
 
450
489
  if (metric_type == MetricType::METRIC_L2) {
451
490
  // ||or - q||^ 2
452
- return pre_dist;
491
+ return std::max(0.0f, pre_dist);
453
492
  } else {
454
493
  // metric == MetricType::METRIC_INNER_PRODUCT
455
494
  // 2 * (or, q) = (||or - q||^2 - ||q||^2 - ||or||^2)
@@ -457,8 +496,22 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
457
496
  }
458
497
  }
459
498
 
499
+ float distance_to_code_1bit(const uint8_t* code) final {
500
+ FAISS_ASSERT(code != nullptr);
501
+ FAISS_ASSERT(
502
+ (metric_type == MetricType::METRIC_L2 ||
503
+ metric_type == MetricType::METRIC_INNER_PRODUCT));
504
+
505
+ const size_t size = (d + 7) / 8;
506
+ const size_t ex_bits = nb_bits - 1;
507
+ const SignBitFactors* base_fac = (ex_bits == 0)
508
+ ? reinterpret_cast<const SignBitFactors*>(code + size)
509
+ : reinterpret_cast<const SignBitFactorsWithError*>(code + size);
510
+ return distance_to_code_1bit_impl(code, base_fac, size);
511
+ }
512
+
460
513
  // Compute full distance using 1-bit + ex-bits (accurate)
461
- float distance_to_code_full(const uint8_t* code) override {
514
+ float distance_to_code_full(const uint8_t* code) final {
462
515
  FAISS_ASSERT(code != nullptr);
463
516
  FAISS_ASSERT(
464
517
  (metric_type == MetricType::METRIC_L2 ||
@@ -494,7 +547,7 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
494
547
  metric_type);
495
548
  }
496
549
 
497
- void set_query(const float* x) override {
550
+ void set_query(const float* x) final {
498
551
  q = x;
499
552
  FAISS_ASSERT(x != nullptr);
500
553
  FAISS_ASSERT(
@@ -526,16 +579,64 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
526
579
  size_t offset = (d + 7) / 8;
527
580
 
528
581
  rearranged_rotated_qq.resize(offset * qb);
529
- std::fill(
530
- rearranged_rotated_qq.begin(), rearranged_rotated_qq.end(), 0);
531
-
532
- for (size_t idim = 0; idim < d; idim++) {
533
- for (size_t iv = 0; iv < qb; iv++) {
534
- const bool bit = ((rotated_qq[idim] & (1 << iv)) != 0);
535
- rearranged_rotated_qq[iv * offset + idim / 8] |=
536
- bit ? (1 << (idim % 8)) : 0;
582
+ with_selected_simd_levels<
583
+ AVAILABLE_SIMD_LEVELS_NONE | (1 << int(SIMDLevel::AVX2)) |
584
+ (1 << int(SIMDLevel::AVX512))>([&]<SIMDLevel RSL>() {
585
+ rabitq::rearrange_bit_planes<RSL>(
586
+ rotated_qq.data(), d, qb, rearranged_rotated_qq.data());
587
+ });
588
+ }
589
+
590
+ size_t scan_codes_multibit(
591
+ size_t list_size,
592
+ const uint8_t* codes,
593
+ const idx_t* ids,
594
+ size_t code_size,
595
+ idx_t list_no,
596
+ bool store_pairs,
597
+ const IDSelector* sel,
598
+ bool keep_max,
599
+ ResultHandler& handler) final {
600
+ const size_t code_size_base = (d + 7) / 8;
601
+ const size_t ex_bits = nb_bits - 1;
602
+ FAISS_ASSERT(ex_bits > 0);
603
+
604
+ size_t nup = 0;
605
+ for (size_t j = 0; j < list_size; j++) {
606
+ if (sel != nullptr) {
607
+ idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
608
+ if (!sel->is_member(id)) {
609
+ codes += code_size;
610
+ continue;
611
+ }
537
612
  }
613
+
614
+ const auto* base_fac =
615
+ reinterpret_cast<const SignBitFactorsWithError*>(
616
+ codes + code_size_base);
617
+ const float est_distance =
618
+ distance_to_code_1bit_impl(codes, base_fac, code_size_base);
619
+
620
+ const bool should_refine = rabitq_utils::should_refine_candidate(
621
+ est_distance,
622
+ base_fac->f_error,
623
+ g_error,
624
+ handler.threshold,
625
+ keep_max);
626
+ if (should_refine) {
627
+ handler.stats.scan_cnt++;
628
+ const float dis = distance_to_code_full(codes);
629
+ idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
630
+
631
+ if (handler.add_result(dis, id)) {
632
+ handler.stats.nheap_updates++;
633
+ nup++;
634
+ }
635
+ }
636
+ codes += code_size;
538
637
  }
638
+
639
+ return nup;
539
640
  }
540
641
  };
541
642
 
@@ -16,6 +16,10 @@
16
16
 
17
17
  namespace faiss {
18
18
 
19
+ struct IDSelector;
20
+ template <typename T, typename TI>
21
+ struct ResultHandlerUnordered;
22
+
19
23
  // the reference implementation of the https://arxiv.org/pdf/2405.12497
20
24
  // Jianyang Gao, Cheng Long, "RaBitQ: Quantizing High-Dimensional Vectors
21
25
  // with a Theoretical Error Bound for Approximate Nearest Neighbor Search".
@@ -129,6 +133,21 @@ struct RaBitQDistanceComputer : FlatCodesDistanceComputer {
129
133
  // Compute full multi-bit distance (accurate)
130
134
  virtual float distance_to_code_full(const uint8_t* code) = 0;
131
135
 
136
+ virtual void set_centroid(const float* centroid_in) {
137
+ centroid = centroid_in;
138
+ }
139
+
140
+ virtual size_t scan_codes_multibit(
141
+ size_t list_size,
142
+ const uint8_t* codes,
143
+ const idx_t* ids,
144
+ size_t code_size,
145
+ idx_t list_no,
146
+ bool store_pairs,
147
+ const IDSelector* sel,
148
+ bool keep_max,
149
+ ResultHandlerUnordered<float, idx_t>& handler) = 0;
150
+
132
151
  // Override from FlatCodesDistanceComputer
133
152
  // Delegates to distance_to_code_full() for multi-bit distance computation
134
153
  float distance_to_code(const uint8_t* code) final {
@@ -257,8 +257,8 @@ void quantize_ex_bits(
257
257
  const size_t ex_bits = nb_bits - 1;
258
258
  FAISS_THROW_IF_NOT_MSG(
259
259
  ex_bits >= 1 && ex_bits <= 8, "ex_bits must be in range [1, 8]");
260
- FAISS_THROW_IF_NOT_MSG(residual != nullptr, "residual cannot be null");
261
- FAISS_THROW_IF_NOT_MSG(ex_code != nullptr, "ex_code cannot be null");
260
+ FAISS_THROW_IF_MSG(residual == nullptr, "residual cannot be null");
261
+ FAISS_THROW_IF_MSG(ex_code == nullptr, "ex_code cannot be null");
262
262
 
263
263
  // Step 1: Compute L2 norm of residual
264
264
  float norm_sqr = fvec_norm_L2sqr(residual, d);
@@ -312,15 +312,6 @@ void quantize_ex_bits(
312
312
  // Step 7: Pack codes into byte array
313
313
  pack_multibit_codes(tmp_code.data(), ex_code, d, nb_bits);
314
314
 
315
- // Step 8: Compute factors for distance computation
316
- // Reconstruct total_code for factor computation
317
- std::vector<int> total_code(d);
318
- for (size_t i = 0; i < d; i++) {
319
- // Form total_code = (sign << ex_bits) + ex_code
320
- bool sign_bit = (residual[i] >= 0);
321
- total_code[i] = tmp_code[i] + ((sign_bit ? 1 : 0) << ex_bits);
322
- }
323
-
324
315
  // Compute ex-factors; centroid is needed for IP metric correction
325
316
  compute_ex_factors(
326
317
  residual,
@@ -18,6 +18,7 @@
18
18
  #include <faiss/impl/InvertedListScannerStats.h>
19
19
  #include <faiss/utils/Heap.h>
20
20
  #include <faiss/utils/partitioning.h>
21
+ #include <faiss/utils/simd_levels.h>
21
22
  #include <algorithm>
22
23
  #include <iostream>
23
24
 
@@ -234,23 +235,9 @@ struct Top1BlockResultHandler : TopkBlockResultHandler<C, use_sel> {
234
235
  }
235
236
 
236
237
  /// add results for query i0..i1 and j0..j1
237
- void add_results(size_t j0, size_t j1, const T* dis_tab_2) final {
238
- for (size_t i = i0; i < i1; i++) {
239
- const T* dis_tab_i = dis_tab_2 + (j1 - j0) * (i - i0) - j0;
240
-
241
- auto& min_distance = this->dis_tab[i];
242
- auto& min_index = this->ids_tab[i];
243
-
244
- for (size_t j = j0; j < j1; j++) {
245
- const T distance = dis_tab_i[j];
246
-
247
- if (C::cmp(min_distance, distance)) {
248
- min_distance = distance;
249
- min_index = j;
250
- }
251
- }
252
- }
253
- }
238
+ /// Implemented in result_handler.cpp; dispatches via
239
+ /// with_selected_simd_levels to top1_add_results_tpl<C, use_sel, SL>.
240
+ void add_results(size_t j0, size_t j1, const T* dis_tab_2) final;
254
241
 
255
242
  void add_result(const size_t i, const T dis, const TI idx) {
256
243
  auto& min_distance = this->dis_tab[i];
@@ -553,20 +540,9 @@ struct ReservoirBlockResultHandler : TopkBlockResultHandler<C, use_sel> {
553
540
  }
554
541
 
555
542
  /// add results for query i0..i1 and j0..j1
556
- void add_results(size_t j0, size_t j1, const T* dis_in) {
557
- #pragma omp parallel for
558
- for (int64_t i = static_cast<int64_t>(i0); i < static_cast<int64_t>(i1);
559
- i++) {
560
- ReservoirTopN<C>& reservoir =
561
- reservoirs[i - static_cast<int64_t>(i0)];
562
- const T* dis_tab_i =
563
- dis_in + (j1 - j0) * (i - static_cast<int64_t>(i0)) - j0;
564
- for (size_t j = j0; j < j1; j++) {
565
- T dis = dis_tab_i[j];
566
- reservoir.add_result(dis, j);
567
- }
568
- }
569
- }
543
+ /// Implemented in result_handler.cpp; dispatches via
544
+ /// with_selected_simd_levels to reservoir_add_results_tpl<C, use_sel, SL>.
545
+ void add_results(size_t j0, size_t j1, const T* dis_in);
570
546
 
571
547
  /// series of results for queries i0..i1 is done
572
548
  void end_multiple() final {
@@ -799,4 +775,22 @@ typename Consumer::T dispatch_range_ResultHandler(
799
775
  #undef DISPATCH_C_SEL
800
776
  }
801
777
 
778
+ // ------------------------------------------------------------------
779
+ // SIMD-dispatch entry points for Top1 and Reservoir add_results.
780
+ // ------------------------------------------------------------------
781
+
782
+ template <class C, bool use_sel, SIMDLevel SL>
783
+ void top1_add_results_tpl(
784
+ Top1BlockResultHandler<C, use_sel>* self,
785
+ size_t j0,
786
+ size_t j1,
787
+ const typename C::T* dis_tab);
788
+
789
+ template <class C, bool use_sel, SIMDLevel SL>
790
+ void reservoir_add_results_tpl(
791
+ ReservoirBlockResultHandler<C, use_sel>* self,
792
+ size_t j0,
793
+ size_t j1,
794
+ const typename C::T* dis_in);
795
+
802
796
  } // namespace faiss