faiss 0.6.2 → 0.6.4

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -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/Clustering.h +8 -0
  7. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  8. data/vendor/faiss/faiss/Index.h +2 -2
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  10. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  11. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
  12. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
  13. data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
  14. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  15. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
  16. data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
  17. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  18. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  19. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  20. data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
  21. data/vendor/faiss/faiss/IndexFlat.h +2 -2
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
  23. data/vendor/faiss/faiss/IndexHNSW.h +31 -7
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
  25. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
  27. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  28. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  29. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  30. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  31. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  32. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  33. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  34. data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
  35. data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
  36. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  37. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  38. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  39. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  40. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  41. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  42. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  43. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  44. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  45. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  46. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  47. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  48. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  49. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  50. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  51. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  52. data/vendor/faiss/faiss/IndexShards.cpp +5 -5
  53. data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
  54. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  55. data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
  56. data/vendor/faiss/faiss/SuperKMeans.h +33 -2
  57. data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
  58. data/vendor/faiss/faiss/VectorTransform.h +3 -0
  59. data/vendor/faiss/faiss/clone_index.cpp +8 -0
  60. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
  63. data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
  64. data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
  65. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
  66. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  67. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  68. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  69. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  70. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  72. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  73. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  74. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
  75. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
  76. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  77. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  78. data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
  79. data/vendor/faiss/faiss/impl/HNSW.h +46 -7
  80. data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
  81. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  82. data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
  83. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  84. data/vendor/faiss/faiss/impl/Panorama.h +20 -9
  85. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  86. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
  87. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  88. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  89. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
  90. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
  91. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
  92. data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
  95. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  96. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  97. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  98. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  100. data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
  101. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
  102. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  103. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  104. data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
  105. data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
  106. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  107. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  108. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  109. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  110. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
  111. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  112. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  113. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  114. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
  115. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  116. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  117. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  118. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  119. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  120. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
  121. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
  122. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  123. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
  124. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  125. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  126. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  127. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
  128. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
  129. data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
  130. data/vendor/faiss/faiss/index_factory.cpp +40 -7
  131. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  132. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
  133. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
  134. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  135. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  136. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  137. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  138. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  139. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  140. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
  141. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
  142. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
  143. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  144. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
  145. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
  146. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  147. data/vendor/faiss/faiss/utils/distances.cpp +30 -11
  148. data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
  149. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
  150. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  151. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  152. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  153. data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
  154. data/vendor/faiss/faiss/utils/hamming.h +10 -1
  155. data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
  156. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
  157. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
  158. data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
  159. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
  160. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  161. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  162. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
  163. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  164. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  165. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
  166. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  167. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
  168. data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
  169. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  170. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  171. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
  172. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
  173. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
  174. data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
  175. data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
  176. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  177. metadata +21 -5
  178. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
@@ -280,7 +280,7 @@ void compute_1_code(const ProductQuantizer& pq, const float* x, uint8_t* code) {
280
280
  } // namespace
281
281
 
282
282
  void ProductQuantizer::compute_code(const float* x, uint8_t* code) const {
283
- with_simd_level([&]<SIMDLevel SL>() {
283
+ with_simd_level_with_sve([&]<SIMDLevel SL>() {
284
284
  switch (nbits) {
285
285
  case 8:
286
286
  compute_1_code<PQEncoder8, SL>(*this, x, code);
@@ -294,7 +294,7 @@ void ProductQuantizer::compute_code(const float* x, uint8_t* code) const {
294
294
  compute_1_code<PQEncoderGeneric, SL>(*this, x, code);
295
295
  break;
296
296
  }
297
- }); // with_simd_level
297
+ }); // with_simd_level_with_sve
298
298
  }
299
299
 
300
300
  template <class PQDecoder>
@@ -442,7 +442,7 @@ void ProductQuantizer::compute_codes(const float* x, uint8_t* codes, size_t n)
442
442
 
443
443
  void ProductQuantizer::compute_distance_table(const float* x, float* dis_table)
444
444
  const {
445
- with_simd_level([&]<SIMDLevel SL>() {
445
+ with_simd_level_with_sve([&]<SIMDLevel SL>() {
446
446
  if (transposed_centroids.empty()) {
447
447
  // use regular version
448
448
  for (size_t m = 0; m < M; m++) {
@@ -824,7 +824,7 @@ void ProductQuantizer::compute_sdc_table() {
824
824
  sdc_table.resize(M * ksub * ksub);
825
825
 
826
826
  if (dsub < 4) {
827
- with_simd_level([&]<SIMDLevel SL>() {
827
+ with_simd_level_with_sve([&]<SIMDLevel SL>() {
828
828
  #pragma omp parallel for
829
829
  for (int64_t mk = 0; mk < static_cast<int64_t>(M * ksub); mk++) {
830
830
  // allow omp to schedule in a more fine-grained way
@@ -862,32 +862,44 @@ void ProductQuantizer::search_sdc(
862
862
  size_t k = res->k;
863
863
  int64_t nq_signed = nq;
864
864
 
865
- #pragma omp parallel for
866
- for (int64_t i = 0; i < nq_signed; i++) {
867
- /* Compute distances and keep smallest values */
868
- idx_t* heap_ids = res->ids + i * k;
869
- float* heap_dis = res->val + i * k;
870
- const uint8_t* qcode = qcodes + i * code_size;
871
-
872
- if (init_finalize_heap)
873
- maxheap_heapify(k, heap_dis, heap_ids);
874
-
875
- const uint8_t* bcode = bcodes;
876
- for (size_t j = 0; j < nb; j++) {
877
- float dis = 0;
878
- const float* tab = sdc_table.data();
865
+ #pragma omp parallel
866
+ {
867
+ // One allocation per OMP thread instead of one per query.
868
+ std::vector<const float*> q_row(M);
869
+ #pragma omp for
870
+ for (int64_t i = 0; i < nq_signed; i++) {
871
+ idx_t* heap_ids = res->ids + i * k;
872
+ float* heap_dis = res->val + i * k;
873
+ const uint8_t* qcode = qcodes + i * code_size;
874
+
875
+ if (init_finalize_heap)
876
+ maxheap_heapify(k, heap_dis, heap_ids);
877
+
878
+ // Precompute per-subquantizer row pointers: q_row[m] points to
879
+ // sdc_table[m*ksub^2 + qcode[m]*ksub], eliminating M
880
+ // multiplications and M pointer advances per database vector in the
881
+ // j-loop.
882
+ const float* sdc = sdc_table.data();
879
883
  for (size_t m = 0; m < M; m++) {
880
- dis += tab[bcode[m] + qcode[m] * ksub];
881
- tab += ksub * ksub;
884
+ q_row[m] = sdc + m * (size_t)(ksub * ksub) +
885
+ (size_t)qcode[m] * ksub;
882
886
  }
883
- if (dis < heap_dis[0]) {
884
- maxheap_replace_top(k, heap_dis, heap_ids, dis, j);
887
+
888
+ const uint8_t* bcode = bcodes;
889
+ for (size_t j = 0; j < nb; j++) {
890
+ float dis = 0;
891
+ for (size_t m = 0; m < M; m++) {
892
+ dis += q_row[m][bcode[m]];
893
+ }
894
+ if (dis < heap_dis[0]) {
895
+ maxheap_replace_top(k, heap_dis, heap_ids, dis, j);
896
+ }
897
+ bcode += code_size;
885
898
  }
886
- bcode += code_size;
887
- }
888
899
 
889
- if (init_finalize_heap)
890
- maxheap_reorder(k, heap_dis, heap_ids);
900
+ if (init_finalize_heap)
901
+ maxheap_reorder(k, heap_dis, heap_ids);
902
+ }
891
903
  }
892
904
  }
893
905
 
@@ -188,46 +188,54 @@ QueryFactorsData compute_query_factors(
188
188
 
189
189
  const float inv_d_sqrt = 1.0f / std::sqrt(static_cast<float>(d));
190
190
 
191
- // Compute quantization range
192
- float v_min = std::numeric_limits<float>::max();
193
- float v_max = std::numeric_limits<float>::lowest();
194
-
195
191
  const float* rq = rotated_q.data();
196
- if (centered) {
197
- float z_max = Z_MAX_BY_QB[qb - 1];
198
- float v_radius = z_max * std::sqrt(query_factors.qr_to_c_L2sqr / d);
199
- v_min = -v_radius;
200
- v_max = v_radius;
201
- } else {
202
- for (size_t i = 0; i < d; i++) {
203
- const float v_q = rq[i];
204
- v_min = std::min(v_min, v_q);
205
- v_max = std::max(v_max, v_q);
206
- }
207
- }
208
-
209
- // Quantize the query
210
- const uint8_t max_code = (1 << qb) - 1;
211
- const float delta = (v_max - v_min) / max_code;
212
- const float inv_delta = 1.0f / delta;
213
-
214
- rotated_qq.resize(d);
192
+ float v_min;
193
+ float v_max;
194
+ float delta;
215
195
  size_t sum_qq = 0;
216
196
  int64_t sum2_signed_odd_int = 0;
217
-
197
+ const uint8_t max_code = (1 << qb) - 1;
198
+ rotated_qq.resize(d);
218
199
  uint8_t* rqq = rotated_qq.data();
219
- for (size_t i = 0; i < d; i++) {
220
- const float v_q = rq[i];
221
- const uint8_t v_qq = std::clamp<float>(
222
- std::round((v_q - v_min) * inv_delta), 0, max_code);
223
- rqq[i] = v_qq;
224
- sum_qq += v_qq;
225
-
226
- if (centered) {
227
- int64_t signed_odd_int = int64_t(v_qq) * 2 - max_code;
228
- sum2_signed_odd_int += signed_odd_int * signed_odd_int;
229
- }
230
- }
200
+
201
+ // Select the SIMD implementation once for both range computation and
202
+ // quantization. This function runs once per query/probe pair.
203
+ with_selected_simd_levels<rabitq::RABITQ_QUANTIZATION_SIMD_LEVELS>(
204
+ [&]<SIMDLevel SL>() {
205
+ if (centered) {
206
+ const float z_max = Z_MAX_BY_QB[qb - 1];
207
+ const float v_radius =
208
+ z_max * std::sqrt(query_factors.qr_to_c_L2sqr / d);
209
+ v_min = -v_radius;
210
+ v_max = v_radius;
211
+ } else {
212
+ v_min = std::numeric_limits<float>::max();
213
+ v_max = std::numeric_limits<float>::lowest();
214
+ rabitq::minmax_values<SL>(rq, d, v_min, v_max);
215
+ }
216
+
217
+ delta = (v_max - v_min) / max_code;
218
+ // A constant (or zero-norm) query has delta == 0. Preserve the
219
+ // scalar path's centered correction terms while avoiding
220
+ // 0 * inf during quantization.
221
+ if (delta <= 0.0f) {
222
+ memset(rqq, 0, d * sizeof(uint8_t));
223
+ if (centered) {
224
+ sum2_signed_odd_int = int64_t(d) * max_code * max_code;
225
+ }
226
+ } else {
227
+ rabitq::quantize_query_values<SL>(
228
+ rq,
229
+ d,
230
+ v_min,
231
+ 1.0f / delta,
232
+ max_code,
233
+ centered,
234
+ rqq,
235
+ sum_qq,
236
+ sum2_signed_odd_int);
237
+ }
238
+ });
231
239
 
232
240
  // Compute query factors
233
241
  query_factors.c1 = 2 * delta * inv_d_sqrt;
@@ -321,7 +329,7 @@ float compute_full_multibit_distance(
321
329
  size_t d,
322
330
  size_t ex_bits,
323
331
  MetricType metric_type) {
324
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A0_SPR>(
332
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_VPOPCNT>(
325
333
  [&]<SIMDLevel SL>() {
326
334
  return compute_full_multibit_distance<SL>(
327
335
  sign_bits,
@@ -13,6 +13,7 @@
13
13
  #include <faiss/utils/rabitq_simd.h>
14
14
  #include <faiss/utils/simd_levels.h>
15
15
  #include <algorithm>
16
+ #include <cassert>
16
17
  #include <cstddef>
17
18
  #include <cstdint>
18
19
  #include <cstring>
@@ -86,6 +87,40 @@ struct QueryFactorsData {
86
87
  */
87
88
  FAISS_API extern const float Z_MAX_BY_QB[8];
88
89
 
90
+ /** Fast half-away rounding for non-negative RaBitQ quantization values.
91
+ *
92
+ * Contract: x must be finite, non-NaN, and in [0, 255.5). This is not a
93
+ * bit-exact replacement for roundf within a few ulps below k + 0.5, where the
94
+ * addition may round across the tie. It is intended only for RaBitQ LUT
95
+ * quantization paths where a +/- 1 code difference at those boundaries is
96
+ * acceptable.
97
+ */
98
+ inline uint8_t round_nonnegative_to_uint8(float x) {
99
+ assert(x == x);
100
+ assert(x >= 0.0f);
101
+ assert(x < 255.5f);
102
+ return rabitq::round_nonnegative_byte_scalar(x);
103
+ }
104
+
105
+ /** Same as round_nonnegative_to_uint8 for uint16 RaBitQ bias values. */
106
+ inline uint16_t round_nonnegative_to_uint16(float x) {
107
+ assert(x == x);
108
+ assert(x >= 0.0f);
109
+ assert(x < 65535.5f);
110
+ return static_cast<uint16_t>(static_cast<int>(x + 0.5f));
111
+ }
112
+
113
+ /** Fast clamped rounding for query-byte quantization.
114
+ *
115
+ * Contract: x must be non-NaN. Values outside [0, max_code] are clamped before
116
+ * applying the same non-bit-exact rounding used by
117
+ * round_nonnegative_to_uint8().
118
+ */
119
+ inline uint8_t round_clamped_to_uint8(float x, uint8_t max_code) {
120
+ assert(x == x);
121
+ return rabitq::round_clamped_byte_scalar(x, max_code);
122
+ }
123
+
89
124
  /** Compute factors for a single database vector using RaBitQ algorithm.
90
125
  * This function consolidates the mathematical logic that was duplicated
91
126
  * between IndexRaBitQ and IndexRaBitQFastScan.