faiss 0.6.4 → 0.6.5

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/faiss/extconf.rb +1 -1
  4. data/lib/faiss/version.rb +1 -1
  5. data/vendor/faiss/faiss/AutoTune.cpp +175 -0
  6. data/vendor/faiss/faiss/Clustering.cpp +150 -60
  7. data/vendor/faiss/faiss/Clustering.h +29 -0
  8. data/vendor/faiss/faiss/IVFlib.cpp +99 -0
  9. data/vendor/faiss/faiss/IVFlib.h +15 -0
  10. data/vendor/faiss/faiss/Index.cpp +44 -0
  11. data/vendor/faiss/faiss/Index.h +19 -14
  12. data/vendor/faiss/faiss/IndexBinary.cpp +8 -0
  13. data/vendor/faiss/faiss/IndexBinary.h +8 -0
  14. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +82 -4
  15. data/vendor/faiss/faiss/IndexBinaryHNSW.h +19 -0
  16. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +34 -0
  17. data/vendor/faiss/faiss/IndexFastScan.cpp +33 -17
  18. data/vendor/faiss/faiss/IndexFastScan.h +6 -3
  19. data/vendor/faiss/faiss/IndexFlat.cpp +56 -0
  20. data/vendor/faiss/faiss/IndexFlat.h +31 -0
  21. data/vendor/faiss/faiss/IndexFlatCodes.cpp +6 -1
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +456 -10
  23. data/vendor/faiss/faiss/IndexHNSW.h +38 -0
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +32 -0
  25. data/vendor/faiss/faiss/IndexIDMap.h +7 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +281 -31
  27. data/vendor/faiss/faiss/IndexIVF.h +53 -1
  28. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +46 -14
  29. data/vendor/faiss/faiss/IndexIVFFastScan.h +4 -2
  30. data/vendor/faiss/faiss/IndexIVFFlat.cpp +33 -0
  31. data/vendor/faiss/faiss/IndexIVFFlat.h +16 -0
  32. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1 -0
  33. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +3 -20
  34. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +50 -14
  35. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -2
  36. data/vendor/faiss/faiss/IndexIVFSQFastScan.cpp +855 -0
  37. data/vendor/faiss/faiss/IndexIVFSQFastScan.h +145 -0
  38. data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -3
  39. data/vendor/faiss/faiss/IndexPiPNN.cpp +201 -0
  40. data/vendor/faiss/faiss/IndexPiPNN.h +83 -0
  41. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +6 -3
  42. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +10 -4
  43. data/vendor/faiss/faiss/IndexReplicas.cpp +20 -0
  44. data/vendor/faiss/faiss/IndexReplicas.h +9 -0
  45. data/vendor/faiss/faiss/IndexSQFastScan.cpp +648 -0
  46. data/vendor/faiss/faiss/IndexSQFastScan.h +129 -0
  47. data/vendor/faiss/faiss/IndexShards.cpp +10 -0
  48. data/vendor/faiss/faiss/IndexShards.h +5 -0
  49. data/vendor/faiss/faiss/SuperKMeans.cpp +57 -15
  50. data/vendor/faiss/faiss/SuperKMeans.h +9 -4
  51. data/vendor/faiss/faiss/VectorTransform.cpp +3 -2
  52. data/vendor/faiss/faiss/clone_index.cpp +24 -0
  53. data/vendor/faiss/faiss/gpu/Dataset.h +112 -0
  54. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +16 -13
  55. data/vendor/faiss/faiss/gpu/GpuCloner.h +4 -0
  56. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -0
  57. data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -13
  58. data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +26 -13
  59. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +45 -22
  60. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -0
  61. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
  62. data/vendor/faiss/faiss/gpu/test/TestGpuDatasetHeader.cpp +18 -0
  63. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +215 -0
  64. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +98 -0
  65. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +11 -0
  66. data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -1
  67. data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +11 -0
  68. data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +92 -0
  69. data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +4 -0
  70. data/vendor/faiss/faiss/gpu_metal/MetalIndexBinaryFlat.h +69 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +38 -0
  72. data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +106 -0
  73. data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +10 -0
  74. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -0
  75. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -6
  76. data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +134 -45
  77. data/vendor/faiss/faiss/impl/ClusteringHelpers.h +36 -0
  78. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +286 -136
  79. data/vendor/faiss/faiss/impl/DistanceComputer.cpp +63 -0
  80. data/vendor/faiss/faiss/impl/DistanceComputer.h +3 -29
  81. data/vendor/faiss/faiss/impl/HNSW.cpp +46 -10
  82. data/vendor/faiss/faiss/impl/HNSW.h +72 -0
  83. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -19
  84. data/vendor/faiss/faiss/impl/NNDescent.cpp +2 -1
  85. data/vendor/faiss/faiss/impl/NSG.cpp +3 -2
  86. data/vendor/faiss/faiss/impl/Panorama.h +3 -2
  87. data/vendor/faiss/faiss/impl/PiPNN.cpp +822 -0
  88. data/vendor/faiss/faiss/impl/PiPNN.h +122 -0
  89. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +54 -11
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.h +1 -1
  91. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +81 -57
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +15 -0
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -0
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -6
  95. data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +0 -4
  96. data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +0 -4
  97. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +5 -2
  98. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +0 -4
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +0 -4
  100. data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +0 -4
  101. data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +0 -4
  102. data/vendor/faiss/faiss/impl/expanded_scanners.h +88 -0
  103. data/vendor/faiss/faiss/impl/fast_scan/FastScanDistancePostProcessing.h +4 -0
  104. data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +61 -64
  105. data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +13 -14
  106. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +17 -129
  107. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +25 -19
  108. data/vendor/faiss/faiss/impl/fast_scan/fast_scan.cpp +5 -0
  109. data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +0 -4
  110. data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +0 -4
  111. data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +0 -88
  112. data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +0 -4
  113. data/vendor/faiss/faiss/impl/fast_scan/kernels_neon.h +155 -0
  114. data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +22 -1
  115. data/vendor/faiss/faiss/impl/fast_scan/kernels_simd512.h +3 -2
  116. data/vendor/faiss/faiss/impl/fast_scan/simd_result_handlers.h +41 -23
  117. data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +0 -4
  118. data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +0 -4
  119. data/vendor/faiss/faiss/impl/index_read.cpp +172 -0
  120. data/vendor/faiss/faiss/impl/index_write.cpp +95 -0
  121. data/vendor/faiss/faiss/impl/pipnn/HashPrune.cpp +159 -0
  122. data/vendor/faiss/faiss/impl/pipnn/HashPrune.h +69 -0
  123. data/vendor/faiss/faiss/impl/pipnn/Partition.cpp +587 -0
  124. data/vendor/faiss/faiss/impl/pipnn/Partition.h +93 -0
  125. data/vendor/faiss/faiss/impl/pipnn/kernels.cpp +326 -0
  126. data/vendor/faiss/faiss/impl/pipnn/kernels.h +92 -0
  127. data/vendor/faiss/faiss/impl/platform_macros.h +45 -0
  128. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +0 -4
  129. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +79 -4
  130. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +6 -0
  131. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +0 -4
  132. data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +0 -4
  133. data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +0 -4
  134. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx2.h +4 -0
  135. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx512.h +4 -1
  136. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +19 -0
  137. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +6 -6
  138. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +131 -6
  139. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +0 -4
  140. data/vendor/faiss/faiss/impl/pq_code_distance/pq_rvv_kernel.h +89 -0
  141. data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +21 -10
  142. data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +45 -18
  143. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +2 -1
  144. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +0 -4
  145. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +0 -4
  146. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +0 -4
  147. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +0 -4
  148. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +5 -1
  149. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +28 -52
  150. data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +59 -11
  151. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +226 -77
  152. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +482 -103
  153. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +2 -149
  154. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +3 -698
  155. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +66 -57
  156. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +101 -96
  157. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +3185 -144
  158. data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_coefficients.h +48 -0
  159. data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_rvv_kernel.h +546 -0
  160. data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +2 -2
  161. data/vendor/faiss/faiss/impl/simd_dispatch.h +7 -0
  162. data/vendor/faiss/faiss/impl/simdlib/simdlib_avx2.h +14 -0
  163. data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +7 -8
  164. data/vendor/faiss/faiss/impl/sq_fastscan_utils.h +232 -0
  165. data/vendor/faiss/faiss/index_factory.cpp +76 -0
  166. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -1
  167. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +3 -2
  168. data/vendor/faiss/faiss/utils/AlignedTable.h +6 -1
  169. data/vendor/faiss/faiss/utils/Heap.cpp +4 -3
  170. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +16 -5
  171. data/vendor/faiss/faiss/utils/bf16.h +36 -0
  172. data/vendor/faiss/faiss/utils/distances.cpp +226 -15
  173. data/vendor/faiss/faiss/utils/distances.h +34 -0
  174. data/vendor/faiss/faiss/utils/distances_dispatch.h +6 -4
  175. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +2 -5
  176. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +0 -14
  177. data/vendor/faiss/faiss/utils/distances_fused/rvv.cpp +25 -0
  178. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +0 -4
  179. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +0 -4
  180. data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +2 -1
  181. data/vendor/faiss/faiss/utils/distances_simd.cpp +9 -0
  182. data/vendor/faiss/faiss/utils/fp16-fp16c.h +4 -0
  183. data/vendor/faiss/faiss/utils/fp16-inl.h +26 -52
  184. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +0 -4
  185. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +0 -4
  186. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +0 -4
  187. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +33 -5
  188. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h +15 -30
  189. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +0 -4
  190. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +2 -1
  191. data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +0 -4
  192. data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +0 -4
  193. data/vendor/faiss/faiss/utils/pq_code_distance.h +8 -4
  194. data/vendor/faiss/faiss/utils/prefetch.h +1 -26
  195. data/vendor/faiss/faiss/utils/quantize_lut.cpp +26 -27
  196. data/vendor/faiss/faiss/utils/quantize_lut.h +11 -0
  197. data/vendor/faiss/faiss/utils/rabitq_simd.h +51 -16
  198. data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +9 -4
  199. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +37 -5
  200. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +64 -5
  201. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +64 -5
  202. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +353 -71
  203. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv_kernel.h +68 -0
  204. data/vendor/faiss/faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h +93 -0
  205. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels.h +76 -0
  206. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx2.cpp +52 -0
  207. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx512.cpp +52 -0
  208. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_neon.cpp +48 -0
  209. data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx2.h +44 -0
  210. data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx512.h +43 -0
  211. data/vendor/faiss/faiss/utils/simd_impl/masked_sum.h +38 -0
  212. data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +0 -4
  213. data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +0 -4
  214. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +54 -15
  215. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +38 -21
  216. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_vpopcnt.cpp +51 -14
  217. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +297 -10
  218. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +0 -4
  219. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +0 -4
  220. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +0 -4
  221. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +0 -4
  222. data/vendor/faiss/faiss/utils/simd_levels.cpp +19 -3
  223. data/vendor/faiss/faiss/utils/simd_levels.h +74 -1
  224. data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +0 -4
  225. data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +0 -4
  226. data/vendor/faiss/faiss/utils/utils.cpp +80 -0
  227. data/vendor/faiss/faiss/utils/utils.h +24 -0
  228. metadata +33 -1
@@ -15,6 +15,7 @@
15
15
  #include <faiss/impl/scalar_quantizer/similarities.h>
16
16
  #include <faiss/utils/distances.h>
17
17
  #include <faiss/utils/rabitq_simd.h>
18
+ #include <faiss/utils/simd_impl/masked_sum.h>
18
19
  #include <limits>
19
20
 
20
21
  #ifndef THE_LEVEL_TO_DISPATCH
@@ -36,35 +37,6 @@ template <SIMDLevel SL0>
36
37
  inline constexpr SIMDLevel rabitq_popcount_level =
37
38
  SL0 == SIMDLevel::AVX512_SPR ? SIMDLevel::AVX512_VPOPCNT : SL0;
38
39
 
39
- /*******************************************************************
40
- * TurboQuant SIMD kernel: masked_sum
41
- * Compute sum of arr[j] where bit j of the bitmask is set.
42
- * NONE specialization is inline; AVX2/AVX512/NEON specializations
43
- * live in sq-avx2.cpp / sq-avx512.cpp / sq-neon.cpp.
44
- *******************************************************************/
45
-
46
- template <SIMDLevel SL0>
47
- float turboq_masked_sum(const float* arr, const uint8_t* bits, size_t d);
48
-
49
- template <>
50
- inline float turboq_masked_sum<SIMDLevel::NONE>(
51
- const float* arr,
52
- const uint8_t* bits,
53
- size_t d) {
54
- float result = 0;
55
- for (size_t byte_idx = 0; byte_idx < (d + 7) / 8; byte_idx++) {
56
- uint8_t b = bits[byte_idx];
57
- size_t base = byte_idx * 8;
58
- size_t end = std::min(base + 8, d);
59
- for (size_t j = base; j < end; j++) {
60
- if (b & (1 << (j - base))) {
61
- result += arr[j];
62
- }
63
- }
64
- }
65
- return result;
66
- }
67
-
68
40
  /*******************************************************************
69
41
  * Full TurboQuant DC — lives here because it needs both
70
42
  * quantizers.h (QuantizerTurboQuantFull, SQTurboQFactors) and
@@ -73,8 +45,10 @@ inline float turboq_masked_sum<SIMDLevel::NONE>(
73
45
  *******************************************************************/
74
46
  template <int NBits, class Similarity, SIMDLevel SL2>
75
47
  struct DCTurboQuantFull : ScalarQuantizer::TurboQuantRefine::DistanceComputer {
48
+ // The AVX-512 levels share the AVX512 masked_sum specialization.
49
+ static constexpr SIMDLevel SUM_LEVEL = simd512_level_selector<SL2>::value;
76
50
  using Sim = Similarity;
77
- QuantizerTurboQuantFull<NBits, SIMDLevel::NONE> quant;
51
+ QuantizerTurboQuantFull<NBits, SL2> quant;
78
52
  std::vector<float> query;
79
53
  std::vector<float> query_proj;
80
54
  float q_norm_sq = 0;
@@ -277,19 +251,19 @@ struct DCTurboQuantFull : ScalarQuantizer::TurboQuantRefine::DistanceComputer {
277
251
  mse_popcnt_scale * static_cast<float>(pop);
278
252
  } else {
279
253
  // Float path: masked accumulation
280
- float pos_sum = turboq_masked_sum<SL2>(query.data(), code, d);
254
+ float pos_sum = masked_sum<SUM_LEVEL>(query.data(), code, d);
281
255
  mse_dot = scaled_c0 * total_q_sum + delta_centroid * pos_sum;
282
256
  }
283
257
  } else if constexpr (NBits == 3) {
284
258
  // 2-bit MSE: decompose into 3 masked sums over bit-planes.
285
259
  size_t pb = quant.mse_plane_bytes;
286
- float s0 = turboq_masked_sum<SL2>(query.data(), code, d);
287
- float s1 = turboq_masked_sum<SL2>(query.data(), code + pb, d);
260
+ float s0 = masked_sum<SUM_LEVEL>(query.data(), code, d);
261
+ float s1 = masked_sum<SUM_LEVEL>(query.data(), code + pb, d);
288
262
  for (size_t i = 0; i < pb; i++) {
289
263
  scratch_and[i] = code[i] & code[pb + i];
290
264
  }
291
265
  float s01 =
292
- turboq_masked_sum<SL2>(query.data(), scratch_and.data(), d);
266
+ masked_sum<SUM_LEVEL>(query.data(), scratch_and.data(), d);
293
267
  mse_dot = mse_multi_base + mse_coeff_s0 * s0 + mse_coeff_s1 * s1 +
294
268
  mse_coeff_s01 * s01;
295
269
  } else {
@@ -336,7 +310,7 @@ struct DCTurboQuantFull : ScalarQuantizer::TurboQuantRefine::DistanceComputer {
336
310
  qjl_dot = qjl_coeff * gamma * (2.0f * pos_sum - total_qproj_sum);
337
311
  } else {
338
312
  float pos_sum =
339
- turboq_masked_sum<SL2>(query_proj.data(), qjl_code, d);
313
+ masked_sum<SUM_LEVEL>(query_proj.data(), qjl_code, d);
340
314
  qjl_dot = qjl_coeff * gamma * (2.0f * pos_sum - total_qproj_sum);
341
315
  }
342
316
 
@@ -373,6 +347,50 @@ constexpr bool is_dimension_compatible(size_t d) {
373
347
  }
374
348
  }
375
349
 
350
+ // Distance computers and scanners. At AVX512 the 16-bit float codecs decode
351
+ // a partial last block, so they take any d.
352
+ template <SIMDLevel SL2>
353
+ constexpr bool is_dimension_compatible(
354
+ size_t d,
355
+ ScalarQuantizer::QuantizerType qtype) {
356
+ return (SL2 == SIMDLevel::AVX512 &&
357
+ (qtype == ScalarQuantizer::QT_fp16 ||
358
+ qtype == ScalarQuantizer::QT_bf16)) ||
359
+ is_dimension_compatible<SL2>(d);
360
+ }
361
+
362
+ /// Calls f with the DCTemplate type for (Quantizer, Sim, SL2) and d. The
363
+ /// 16-bit float quantizers and the QT_8bit inner product use it. Four
364
+ /// accumulators per code hide the FMA latency at a large d. At a small d their
365
+ /// reduction costs more than it saves. At AVX512 they are faster only on AMD
366
+ /// (SIMDConfig::sq_avx512_4_accumulators).
367
+ template <class Quantizer, class Sim, SIMDLevel SL2, class F>
368
+ auto with_dc_template(size_t d, F f) {
369
+ if constexpr (SL2 == SIMDLevel::AVX2 || SL2 == SIMDLevel::AVX512) {
370
+ if (d >= 384 &&
371
+ (SL2 == SIMDLevel::AVX2 || SIMDConfig::sq_avx512_4_accumulators)) {
372
+ return f.template
373
+ operator()<DCTemplate<Quantizer, Sim, SL2, true>>();
374
+ }
375
+ }
376
+ return f.template operator()<DCTemplate<Quantizer, Sim, SL2>>();
377
+ }
378
+
379
+ /// with_dc_template for QT_8bit. Only its inner product has a four-accumulator
380
+ /// loop.
381
+ template <class Sim, SIMDLevel SL2, class F>
382
+ auto with_8bit_dc_template(size_t d, F f) {
383
+ using Quantizer = QuantizerTemplate<
384
+ Codec8bit<SL2>,
385
+ QuantizerTemplateScaling::NON_UNIFORM,
386
+ SL2>;
387
+ if constexpr (Sim::metric_type == METRIC_INNER_PRODUCT) {
388
+ return with_dc_template<Quantizer, Sim, SL2>(d, f);
389
+ } else {
390
+ return f.template operator()<DCTemplate<Quantizer, Sim, SL2>>();
391
+ }
392
+ }
393
+
376
394
  /*******************************************************************
377
395
  * sq_select_quantizer: the big switch returning SQuantizer*
378
396
  *******************************************************************/
@@ -487,10 +505,13 @@ SQDistanceComputer* select_distance_computer_body(
487
505
  const std::vector<float>& trained) {
488
506
  // Return nullptr for incompatible dimensions in SIMD cases
489
507
  if constexpr (SL2 != SIMDLevel::NONE) {
490
- if (!is_dimension_compatible<SL2>(d)) {
508
+ if (!is_dimension_compatible<SL2>(d, qtype)) {
491
509
  return nullptr;
492
510
  }
493
511
  }
512
+ auto new_dc = [&]<class DC>() -> SQDistanceComputer* {
513
+ return new DC(d, trained);
514
+ };
494
515
  switch (qtype) {
495
516
  case ScalarQuantizer::QT_8bit_uniform:
496
517
  return new DCTemplate<
@@ -511,13 +532,7 @@ SQDistanceComputer* select_distance_computer_body(
511
532
  SL2>(d, trained);
512
533
 
513
534
  case ScalarQuantizer::QT_8bit:
514
- return new DCTemplate<
515
- QuantizerTemplate<
516
- Codec8bit<SL2>,
517
- QuantizerTemplateScaling::NON_UNIFORM,
518
- SL2>,
519
- Sim,
520
- SL2>(d, trained);
535
+ return with_8bit_dc_template<Sim, SL2>(d, new_dc);
521
536
 
522
537
  case ScalarQuantizer::QT_6bit:
523
538
  return new DCTemplate<
@@ -538,10 +553,10 @@ SQDistanceComputer* select_distance_computer_body(
538
553
  SL2>(d, trained);
539
554
 
540
555
  case ScalarQuantizer::QT_fp16:
541
- return new DCTemplate<QuantizerFP16<SL2>, Sim, SL2>(d, trained);
556
+ return with_dc_template<QuantizerFP16<SL2>, Sim, SL2>(d, new_dc);
542
557
 
543
558
  case ScalarQuantizer::QT_bf16:
544
- return new DCTemplate<QuantizerBF16<SL2>, Sim, SL2>(d, trained);
559
+ return with_dc_template<QuantizerBF16<SL2>, Sim, SL2>(d, new_dc);
545
560
 
546
561
  case ScalarQuantizer::QT_8bit_direct:
547
562
  if constexpr (is_avx512_family<SL2>) {
@@ -705,7 +720,7 @@ InvertedListScanner* sq_select_InvertedListScanner<THE_LEVEL_TO_DISPATCH>(
705
720
  [&]<SIMDLevel SL2, class Similarity>() -> InvertedListScanner* {
706
721
  // Return nullptr for incompatible dimensions in SIMD cases
707
722
  if constexpr (SL2 != SIMDLevel::NONE) {
708
- if (!is_dimension_compatible<SL2>(d)) {
723
+ if (!is_dimension_compatible<SL2>(d, qtype)) {
709
724
  return nullptr;
710
725
  }
711
726
  }
@@ -727,13 +742,7 @@ InvertedListScanner* sq_select_InvertedListScanner<THE_LEVEL_TO_DISPATCH>(
727
742
  Similarity,
728
743
  SL2>>();
729
744
  case ScalarQuantizer::QT_8bit:
730
- return scan.template operator()<DCTemplate<
731
- QuantizerTemplate<
732
- Codec8bit<SL2>,
733
- QuantizerTemplateScaling::NON_UNIFORM,
734
- SL2>,
735
- Similarity,
736
- SL2>>();
745
+ return with_8bit_dc_template<Similarity, SL2>(d, scan);
737
746
  case ScalarQuantizer::QT_4bit:
738
747
  return scan.template operator()<DCTemplate<
739
748
  QuantizerTemplate<
@@ -751,11 +760,11 @@ InvertedListScanner* sq_select_InvertedListScanner<THE_LEVEL_TO_DISPATCH>(
751
760
  Similarity,
752
761
  SL2>>();
753
762
  case ScalarQuantizer::QT_fp16:
754
- return scan.template
755
- operator()<DCTemplate<QuantizerFP16<SL2>, Similarity, SL2>>();
763
+ return with_dc_template<QuantizerFP16<SL2>, Similarity, SL2>(
764
+ d, scan);
756
765
  case ScalarQuantizer::QT_bf16:
757
- return scan.template
758
- operator()<DCTemplate<QuantizerBF16<SL2>, Similarity, SL2>>();
766
+ return with_dc_template<QuantizerBF16<SL2>, Similarity, SL2>(
767
+ d, scan);
759
768
  case ScalarQuantizer::QT_8bit_direct:
760
769
  if constexpr (is_avx512_family<SL2>) {
761
770
  if (d % 32 == 0) {
@@ -5,11 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifdef COMPILE_SIMD_ARM_NEON
9
-
10
8
  #include <faiss/impl/simdlib/simdlib_neon.h>
11
9
 
12
- #include <algorithm>
13
10
  #include <cstring>
14
11
 
15
12
  #include <faiss/impl/scalar_quantizer/codecs.h>
@@ -17,6 +14,7 @@
17
14
  #include <faiss/impl/scalar_quantizer/quantizers.h>
18
15
  #include <faiss/impl/scalar_quantizer/scanners.h>
19
16
  #include <faiss/impl/scalar_quantizer/similarities.h>
17
+ #include <faiss/impl/scalar_quantizer/sq8_coefficients.h>
20
18
 
21
19
  namespace faiss {
22
20
 
@@ -105,14 +103,15 @@ template <>
105
103
  struct Codec8bit<SIMDLevel::ARM_NEON> : Codec8bit<SIMDLevel::NONE> {
106
104
  static FAISS_ALWAYS_INLINE simd8float32
107
105
  decode_8_components(const uint8_t* code, size_t i) {
108
- float32_t result[8] = {};
109
- for (size_t j = 0; j < 8; j++) {
110
- result[j] =
111
- Codec8bit<SIMDLevel::NONE>::decode_component(code, i + j);
112
- }
113
- float32x4_t res1 = vld1q_f32(result);
114
- float32x4_t res2 = vld1q_f32(result + 4);
115
- return simd8float32(float32x4x2_t{res1, res2});
106
+ const uint16x8_t c16 = vmovl_u8(vld1_u8(code + i));
107
+ const float32x4_t lo = vcvtq_f32_u32(vmovl_u16(vget_low_u16(c16)));
108
+ const float32x4_t hi = vcvtq_f32_u32(vmovl_u16(vget_high_u16(c16)));
109
+ const float32x4_t one_255 = vdupq_n_f32(1.f / 255.f);
110
+ const float32x4_t half_one_255 = vdupq_n_f32(0.5f / 255.f);
111
+ return simd8float32(
112
+ float32x4x2_t{
113
+ vfmaq_f32(half_one_255, lo, one_255),
114
+ vfmaq_f32(half_one_255, hi, one_255)});
116
115
  }
117
116
  };
118
117
 
@@ -618,6 +617,97 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::ARM_NEON>
618
617
  }
619
618
  };
620
619
 
620
+ // QT_8bit + L2. With a, rmin from sq8_coefficients.h and e = q - rmin, each
621
+ // term is (e_i - a_i * c_i)^2: one fmls and one fmla per 4 dims, instead of
622
+ // separate codec, vmin/vdiff, sub, mul and add steps.
623
+ template <>
624
+ struct DCTemplate<
625
+ QuantizerTemplate<
626
+ Codec8bit<SIMDLevel::ARM_NEON>,
627
+ QuantizerTemplateScaling::NON_UNIFORM,
628
+ SIMDLevel::ARM_NEON>,
629
+ SimilarityL2<SIMDLevel::ARM_NEON>,
630
+ SIMDLevel::ARM_NEON> : SQDistanceComputer {
631
+ using Sim = SimilarityL2<SIMDLevel::ARM_NEON>;
632
+
633
+ size_t d;
634
+ std::vector<float> a, rmin, e;
635
+
636
+ DCTemplate(size_t d_in, const std::vector<float>& trained)
637
+ : d(d_in), a(d_in), rmin(d_in), e(d_in) {
638
+ assert(d % 8 == 0);
639
+ sq8::make_coefficients(trained.data(), d, a.data(), rmin.data());
640
+ }
641
+
642
+ void set_query(const float* x) final {
643
+ q = x;
644
+ for (size_t i = 0; i < d; i++) {
645
+ e[i] = x[i] - rmin[i];
646
+ }
647
+ }
648
+
649
+ // Each code has its own accumulators, so the batched results equal the
650
+ // single-code ones bit for bit.
651
+ template <size_t N>
652
+ FAISS_ALWAYS_INLINE void l2(
653
+ const uint8_t* const (&codes)[N],
654
+ float (&dis)[N]) const {
655
+ float32x4_t acc[N][2] = {};
656
+ for (size_t i = 0; i < d; i += 8) {
657
+ const float32x4_t a0 = vld1q_f32(a.data() + i);
658
+ const float32x4_t a1 = vld1q_f32(a.data() + i + 4);
659
+ const float32x4_t e0 = vld1q_f32(e.data() + i);
660
+ const float32x4_t e1 = vld1q_f32(e.data() + i + 4);
661
+ for (size_t n = 0; n < N; n++) {
662
+ const uint16x8_t c16 = vmovl_u8(vld1_u8(codes[n] + i));
663
+ const float32x4_t t0 = vfmsq_f32(
664
+ e0, a0, vcvtq_f32_u32(vmovl_u16(vget_low_u16(c16))));
665
+ const float32x4_t t1 =
666
+ vfmsq_f32(e1, a1, vcvtq_f32_u32(vmovl_high_u16(c16)));
667
+ acc[n][0] = vfmaq_f32(acc[n][0], t0, t0);
668
+ acc[n][1] = vfmaq_f32(acc[n][1], t1, t1);
669
+ }
670
+ }
671
+ for (size_t n = 0; n < N; n++) {
672
+ dis[n] = vaddvq_f32(vaddq_f32(acc[n][0], acc[n][1]));
673
+ }
674
+ }
675
+
676
+ float query_to_code(const uint8_t* code) const final {
677
+ float dis[1];
678
+ l2<1>({code}, dis);
679
+ return dis[0];
680
+ }
681
+
682
+ void query_to_codes_batch_4(
683
+ const uint8_t* code_0,
684
+ const uint8_t* code_1,
685
+ const uint8_t* code_2,
686
+ const uint8_t* code_3,
687
+ float& dis0,
688
+ float& dis1,
689
+ float& dis2,
690
+ float& dis3) const final {
691
+ float dis[4];
692
+ l2<4>({code_0, code_1, code_2, code_3}, dis);
693
+ dis0 = dis[0];
694
+ dis1 = dis[1];
695
+ dis2 = dis[2];
696
+ dis3 = dis[3];
697
+ }
698
+
699
+ float symmetric_dis(idx_t i, idx_t j) override {
700
+ const uint8_t* c1 = codes + i * code_size;
701
+ const uint8_t* c2 = codes + j * code_size;
702
+ float accu = 0;
703
+ for (size_t k = 0; k < d; k++) {
704
+ const float diff = a[k] * float(int(c1[k]) - int(c2[k]));
705
+ accu += diff * diff;
706
+ }
707
+ return accu;
708
+ }
709
+ };
710
+
621
711
  // Byte-domain kernels for QT_8bit_direct{,_signed}. The dispatch only
622
712
  // selects them when d % 16 == 0, so no loop needs a tail.
623
713
 
@@ -762,93 +852,8 @@ struct DistanceComputerByteSigned<Similarity, SIMDLevel::ARM_NEON>
762
852
  }
763
853
  };
764
854
 
765
- /**********************************************************
766
- * TurboQuant masked_sum NEON specialization (scalar fallback)
767
- **********************************************************/
768
-
769
- template <SIMDLevel SL0>
770
- float turboq_masked_sum(const float* arr, const uint8_t* bits, size_t d);
771
-
772
- template <>
773
- float turboq_masked_sum<SIMDLevel::ARM_NEON>(
774
- const float* arr,
775
- const uint8_t* bits,
776
- size_t d) {
777
- float result = 0;
778
- for (size_t byte_idx = 0; byte_idx < (d + 7) / 8; byte_idx++) {
779
- uint8_t b = bits[byte_idx];
780
- size_t base = byte_idx * 8;
781
- size_t end = std::min(base + 8, d);
782
- for (size_t j = base; j < end; j++) {
783
- if (b & (1 << (j - base))) {
784
- result += arr[j];
785
- }
786
- }
787
- }
788
- return result;
789
- }
790
-
791
855
  } // namespace scalar_quantizer
792
856
  } // namespace faiss
793
857
 
794
858
  #define THE_LEVEL_TO_DISPATCH SIMDLevel::ARM_NEON
795
859
  #include <faiss/impl/scalar_quantizer/sq-dispatch.h>
796
-
797
- #ifdef COMPILE_SIMD_ARM_SVE
798
-
799
- // ARM_SVE: SVE is a superset of NEON. Forward to the NEON implementation
800
- // until a dedicated SVE specialization is written.
801
-
802
- namespace faiss {
803
- namespace scalar_quantizer {
804
-
805
- // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization)
806
- template <>
807
- ScalarQuantizer::SQuantizer* sq_select_quantizer<SIMDLevel::ARM_SVE>(
808
- QuantizerType qtype,
809
- size_t d,
810
- const std::vector<float>& trained) {
811
- return sq_select_quantizer<SIMDLevel::ARM_NEON>(qtype, d, trained);
812
- }
813
-
814
- // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization)
815
- template <>
816
- SQDistanceComputer* sq_select_distance_computer<SIMDLevel::ARM_SVE>(
817
- MetricType metric,
818
- ScalarQuantizer::QuantizerType qtype,
819
- size_t d,
820
- const std::vector<float>& trained) {
821
- return sq_select_distance_computer<SIMDLevel::ARM_NEON>(
822
- metric, qtype, d, trained);
823
- }
824
-
825
- // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization)
826
- template <>
827
- InvertedListScanner* sq_select_InvertedListScanner<SIMDLevel::ARM_SVE>(
828
- QuantizerType qtype,
829
- MetricType mt,
830
- size_t d,
831
- size_t code_size,
832
- const std::vector<float>& trained,
833
- const Index* quantizer,
834
- bool store_pairs,
835
- const IDSelector* sel,
836
- bool by_residual) {
837
- return sq_select_InvertedListScanner<SIMDLevel::ARM_NEON>(
838
- qtype,
839
- mt,
840
- d,
841
- code_size,
842
- trained,
843
- quantizer,
844
- store_pairs,
845
- sel,
846
- by_residual);
847
- }
848
-
849
- } // namespace scalar_quantizer
850
- } // namespace faiss
851
-
852
- #endif // COMPILE_SIMD_ARM_SVE
853
-
854
- #endif // COMPILE_SIMD_ARM_NEON