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
@@ -5,8 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifdef COMPILE_SIMD_AVX2
9
-
10
8
  #include <faiss/impl/simdlib/simdlib_avx2.h>
11
9
 
12
10
  #include <cstring>
@@ -16,6 +14,8 @@
16
14
  #include <faiss/impl/scalar_quantizer/quantizers.h>
17
15
  #include <faiss/impl/scalar_quantizer/scanners.h>
18
16
  #include <faiss/impl/scalar_quantizer/similarities.h>
17
+ #include <faiss/impl/scalar_quantizer/sq8_coefficients.h>
18
+ #include <faiss/utils/simd_impl/masked_sum-avx2.h>
19
19
 
20
20
  namespace faiss {
21
21
 
@@ -236,13 +236,14 @@ struct QuantizerTemplate<
236
236
  **********************************************************/
237
237
 
238
238
  // 1-bit MSE: boundary is always at centroids midpoint.
239
- // Encode: 8 comparisons → 1 byte via movemask.
239
+ // Encode: 8 comparisons → 1 byte via movemask. NLT_UQ is !(x < b), matching
240
+ // the scalar upper_bound tie-break: x == b (and NaN) encodes to the upper bin.
240
241
  // Decode: gather 8 centroids via index unpack.
241
242
  // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization,facebook-hte-ShadowingClass)
242
243
  template <>
243
244
  struct QuantizerLloydMax<1, SIMDLevel::AVX2>
244
- : QuantizerLloydMax<1, SIMDLevel::NONE> {
245
- using Base = QuantizerLloydMax<1, SIMDLevel::NONE>;
245
+ : QuantizerLloydMaxBase<1, SIMDLevel::AVX2> {
246
+ using Base = QuantizerLloydMaxBase<1, SIMDLevel::AVX2>;
246
247
 
247
248
  QuantizerLloydMax(size_t d, const std::vector<float>& trained)
248
249
  : Base(d, trained) {
@@ -260,7 +261,7 @@ struct QuantizerLloydMax<1, SIMDLevel::AVX2>
260
261
  for (size_t i = 0; i < this->d; i += 8) {
261
262
  __m256 vals = _mm256_loadu_ps(x + i);
262
263
  int mask = _mm256_movemask_ps(
263
- _mm256_cmp_ps(vals, boundary, _CMP_GT_OQ));
264
+ _mm256_cmp_ps(vals, boundary, _CMP_NLT_UQ));
264
265
  code[i / 8] = static_cast<uint8_t>(mask);
265
266
  }
266
267
  }
@@ -280,8 +281,8 @@ struct QuantizerLloydMax<1, SIMDLevel::AVX2>
280
281
  // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization,facebook-hte-ShadowingClass)
281
282
  template <>
282
283
  struct QuantizerLloydMax<2, SIMDLevel::AVX2>
283
- : QuantizerLloydMax<2, SIMDLevel::NONE> {
284
- using Base = QuantizerLloydMax<2, SIMDLevel::NONE>;
284
+ : QuantizerLloydMaxBase<2, SIMDLevel::AVX2> {
285
+ using Base = QuantizerLloydMaxBase<2, SIMDLevel::AVX2>;
285
286
 
286
287
  QuantizerLloydMax(size_t d, const std::vector<float>& trained)
287
288
  : Base(d, trained) {
@@ -295,7 +296,8 @@ struct QuantizerLloydMax<2, SIMDLevel::AVX2>
295
296
  }
296
297
 
297
298
  void encode_vector(const float* x, uint8_t* code) const final {
298
- // 3 boundaries → branchless: idx = (x>b0) + (x>b1) + (x>b2)
299
+ // 3 boundaries → branchless: idx = !(x<b0) + !(x<b1) + !(x<b2),
300
+ // matching the scalar upper_bound tie-break.
299
301
  // _mm256_cmp_ps returns all-ones (-1 as int32) for true,
300
302
  // so we negate the sum to get positive indices.
301
303
  __m256 b0 = _mm256_set1_ps(this->boundaries[0]);
@@ -303,16 +305,16 @@ struct QuantizerLloydMax<2, SIMDLevel::AVX2>
303
305
  __m256 b2 = _mm256_set1_ps(this->boundaries[2]);
304
306
  for (size_t i = 0; i < this->d; i += 8) {
305
307
  __m256 vals = _mm256_loadu_ps(x + i);
306
- __m256i gt0 =
307
- _mm256_castps_si256(_mm256_cmp_ps(vals, b0, _CMP_GT_OQ));
308
- __m256i gt1 =
309
- _mm256_castps_si256(_mm256_cmp_ps(vals, b1, _CMP_GT_OQ));
310
- __m256i gt2 =
311
- _mm256_castps_si256(_mm256_cmp_ps(vals, b2, _CMP_GT_OQ));
312
- // Each gt is 0 or -1 (0xFFFFFFFF). Sum = -(index).
308
+ __m256i ge0 =
309
+ _mm256_castps_si256(_mm256_cmp_ps(vals, b0, _CMP_NLT_UQ));
310
+ __m256i ge1 =
311
+ _mm256_castps_si256(_mm256_cmp_ps(vals, b1, _CMP_NLT_UQ));
312
+ __m256i ge2 =
313
+ _mm256_castps_si256(_mm256_cmp_ps(vals, b2, _CMP_NLT_UQ));
314
+ // Each ge is 0 or -1 (0xFFFFFFFF). Sum = -(index).
313
315
  __m256i idx = _mm256_sub_epi32(
314
316
  _mm256_setzero_si256(),
315
- _mm256_add_epi32(_mm256_add_epi32(gt0, gt1), gt2));
317
+ _mm256_add_epi32(_mm256_add_epi32(ge0, ge1), ge2));
316
318
  // Pack 8 x 2-bit indices into 2 bytes.
317
319
  // Store to temp array and pack scalarly - faster than
318
320
  // extract+permute.
@@ -339,8 +341,8 @@ struct QuantizerLloydMax<2, SIMDLevel::AVX2>
339
341
  #define DEFINE_LLOYD_MAX_AVX2_MULTIBIT(NBITS, UNPACK_EXPR) \
340
342
  template <> \
341
343
  struct QuantizerLloydMax<NBITS, SIMDLevel::AVX2> \
342
- : QuantizerLloydMax<NBITS, SIMDLevel::NONE> { \
343
- using Base = QuantizerLloydMax<NBITS, SIMDLevel::NONE>; \
344
+ : QuantizerLloydMaxBase<NBITS, SIMDLevel::AVX2> { \
345
+ using Base = QuantizerLloydMaxBase<NBITS, SIMDLevel::AVX2>; \
344
346
  \
345
347
  QuantizerLloydMax(size_t d, const std::vector<float>& trained) \
346
348
  : Base(d, trained) { \
@@ -370,8 +372,8 @@ DEFINE_LLOYD_MAX_AVX2_MULTIBIT(4, unpack_8x4bit_to_u32(code, i));
370
372
  // 8-bit Lloyd-Max: indices are raw bytes, no bit packing.
371
373
  template <>
372
374
  struct QuantizerLloydMax<8, SIMDLevel::AVX2>
373
- : QuantizerLloydMax<8, SIMDLevel::NONE> {
374
- using Base = QuantizerLloydMax<8, SIMDLevel::NONE>;
375
+ : QuantizerLloydMaxBase<8, SIMDLevel::AVX2> {
376
+ using Base = QuantizerLloydMaxBase<8, SIMDLevel::AVX2>;
375
377
 
376
378
  QuantizerLloydMax(size_t d, const std::vector<float>& trained)
377
379
  : Base(d, trained) {
@@ -401,9 +403,9 @@ struct QuantizerLloydMax<8, SIMDLevel::AVX2>
401
403
  **********************************************************/
402
404
 
403
405
  template <>
404
- struct QuantizerFP16<SIMDLevel::AVX2> : QuantizerFP16<SIMDLevel::NONE> {
406
+ struct QuantizerFP16<SIMDLevel::AVX2> : QuantizerFP16Base<SIMDLevel::AVX2> {
405
407
  QuantizerFP16(size_t d, const std::vector<float>& trained)
406
- : QuantizerFP16<SIMDLevel::NONE>(d, trained) {
408
+ : QuantizerFP16Base<SIMDLevel::AVX2>(d, trained) {
407
409
  assert(d % 8 == 0);
408
410
  }
409
411
 
@@ -419,9 +421,9 @@ struct QuantizerFP16<SIMDLevel::AVX2> : QuantizerFP16<SIMDLevel::NONE> {
419
421
  **********************************************************/
420
422
 
421
423
  template <>
422
- struct QuantizerBF16<SIMDLevel::AVX2> : QuantizerBF16<SIMDLevel::NONE> {
424
+ struct QuantizerBF16<SIMDLevel::AVX2> : QuantizerBF16Base<SIMDLevel::AVX2> {
423
425
  QuantizerBF16(size_t d, const std::vector<float>& trained)
424
- : QuantizerBF16<SIMDLevel::NONE>(d, trained) {
426
+ : QuantizerBF16Base<SIMDLevel::AVX2>(d, trained) {
425
427
  assert(d % 8 == 0);
426
428
  }
427
429
 
@@ -440,9 +442,9 @@ struct QuantizerBF16<SIMDLevel::AVX2> : QuantizerBF16<SIMDLevel::NONE> {
440
442
 
441
443
  template <>
442
444
  struct Quantizer8bitDirect<SIMDLevel::AVX2>
443
- : Quantizer8bitDirect<SIMDLevel::NONE> {
445
+ : Quantizer8bitDirectBase<SIMDLevel::AVX2> {
444
446
  Quantizer8bitDirect(size_t d, const std::vector<float>& trained)
445
- : Quantizer8bitDirect<SIMDLevel::NONE>(d, trained) {
447
+ : Quantizer8bitDirectBase<SIMDLevel::AVX2>(d, trained) {
446
448
  assert(d % 8 == 0);
447
449
  }
448
450
 
@@ -460,9 +462,9 @@ struct Quantizer8bitDirect<SIMDLevel::AVX2>
460
462
 
461
463
  template <>
462
464
  struct Quantizer8bitDirectSigned<SIMDLevel::AVX2>
463
- : Quantizer8bitDirectSigned<SIMDLevel::NONE> {
465
+ : Quantizer8bitDirectSignedBase<SIMDLevel::AVX2> {
464
466
  Quantizer8bitDirectSigned(size_t d, const std::vector<float>& trained)
465
- : Quantizer8bitDirectSigned<SIMDLevel::NONE>(d, trained) {
467
+ : Quantizer8bitDirectSignedBase<SIMDLevel::AVX2>(d, trained) {
466
468
  assert(d % 8 == 0);
467
469
  }
468
470
 
@@ -602,8 +604,18 @@ struct SimilarityIP<SIMDLevel::AVX2> {
602
604
  * Distance computers
603
605
  **********************************************************/
604
606
 
605
- template <class Quantizer, class Similarity>
606
- struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX2> : SQDistanceComputer {
607
+ namespace {
608
+
609
+ /// 8 lanes to 4: lanes j and j + 4 summed into lane j.
610
+ FAISS_ALWAYS_INLINE __m128 reduce_8_to_4(__m256 a) {
611
+ return _mm_add_ps(_mm256_castps256_ps128(a), _mm256_extractf128_ps(a, 1));
612
+ }
613
+
614
+ } // namespace
615
+
616
+ template <class Quantizer, class Similarity, bool four_acc>
617
+ struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX2, four_acc>
618
+ : SQDistanceComputer {
607
619
  using Sim = Similarity;
608
620
 
609
621
  Quantizer quant;
@@ -626,7 +638,40 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX2> : SQDistanceComputer {
626
638
  }
627
639
  }
628
640
 
641
+ /// Similarity terms of one code with four accumulators.
642
+ FAISS_ALWAYS_INLINE __m256
643
+ accumulate_4(const float* x, const uint8_t* code) const {
644
+ struct Acc : Similarity {
645
+ Acc() : Similarity(nullptr) {}
646
+ };
647
+ Acc s[4];
648
+ for (int j = 0; j < 4; j++) {
649
+ s[j].begin_8();
650
+ }
651
+ const size_t d = quant.d;
652
+ size_t i = 0;
653
+ for (; i + 32 <= d; i += 32) {
654
+ for (int j = 0; j < 4; j++) {
655
+ s[j].add_8_components_2(
656
+ quant.reconstruct_8_components(
657
+ code, static_cast<int>(i + 8 * j)),
658
+ simd8float32(x + i + 8 * j));
659
+ }
660
+ }
661
+ for (; i < d; i += 8) {
662
+ s[0].add_8_components_2(
663
+ quant.reconstruct_8_components(code, static_cast<int>(i)),
664
+ simd8float32(x + i));
665
+ }
666
+ return _mm256_add_ps(
667
+ _mm256_add_ps(s[0].accu8.f, s[1].accu8.f),
668
+ _mm256_add_ps(s[2].accu8.f, s[3].accu8.f));
669
+ }
670
+
629
671
  float compute_distance(const float* x, const uint8_t* code) const {
672
+ if constexpr (four_acc) {
673
+ return reduce_4(reduce_8_to_4(accumulate_4(x, code)));
674
+ }
630
675
  Similarity sim(x);
631
676
  sim.begin_8();
632
677
  for (size_t i = 0; i < quant.d; i += 8) {
@@ -697,6 +742,21 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX2> : SQDistanceComputer {
697
742
  float& dis1,
698
743
  float& dis2,
699
744
  float& dis3) const final {
745
+ if constexpr (four_acc) {
746
+ alignas(16) float dis[4];
747
+ _mm_store_ps(
748
+ dis,
749
+ reduce_4x4(
750
+ reduce_8_to_4(accumulate_4(q, code_0)),
751
+ reduce_8_to_4(accumulate_4(q, code_1)),
752
+ reduce_8_to_4(accumulate_4(q, code_2)),
753
+ reduce_8_to_4(accumulate_4(q, code_3))));
754
+ dis0 = dis[0];
755
+ dis1 = dis[1];
756
+ dis2 = dis[2];
757
+ dis3 = dis[3];
758
+ return;
759
+ }
700
760
  Similarity sim0(q);
701
761
  Similarity sim1(q);
702
762
  Similarity sim2(q);
@@ -726,6 +786,141 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX2> : SQDistanceComputer {
726
786
  }
727
787
  };
728
788
 
789
+ // QT_8bit + IP. With a, rmin from sq8_coefficients.h,
790
+ // <q, reconstruct(c)> = sum_i q_i * rmin_i + sum_i (q_i * a_i) * c_i.
791
+ // set_query folds the first sum into bias and the products into qa, so each
792
+ // 8 dims cost one convert and one FMA instead of the decode, vmin/vdiff and
793
+ // query FMAs.
794
+ template <bool four_acc>
795
+ struct DCTemplate<
796
+ QuantizerTemplate<
797
+ Codec8bit<SIMDLevel::AVX2>,
798
+ QuantizerTemplateScaling::NON_UNIFORM,
799
+ SIMDLevel::AVX2>,
800
+ SimilarityIP<SIMDLevel::AVX2>,
801
+ SIMDLevel::AVX2,
802
+ four_acc> : SQDistanceComputer {
803
+ using Quantizer = QuantizerTemplate<
804
+ Codec8bit<SIMDLevel::AVX2>,
805
+ QuantizerTemplateScaling::NON_UNIFORM,
806
+ SIMDLevel::AVX2>;
807
+ using Sim = SimilarityIP<SIMDLevel::AVX2>;
808
+
809
+ Quantizer quant;
810
+ std::vector<float> a, rmin, qa;
811
+ float bias = 0;
812
+
813
+ DCTemplate(size_t d, const std::vector<float>& trained)
814
+ : quant(d, trained), a(d), rmin(d), qa(d) {
815
+ sq8::make_coefficients(trained.data(), d, a.data(), rmin.data());
816
+ }
817
+
818
+ void set_query(const float* x) final {
819
+ q = x;
820
+ bias = 0;
821
+ for (size_t i = 0; i < quant.d; i++) {
822
+ qa[i] = x[i] * a[i];
823
+ bias += x[i] * rmin[i];
824
+ }
825
+ }
826
+
827
+ static FAISS_ALWAYS_INLINE __m256 codes_8(const uint8_t* code) {
828
+ return _mm256_cvtepi32_ps(
829
+ _mm256_cvtepu8_epi32(_mm_loadl_epi64((const __m128i*)code)));
830
+ }
831
+
832
+ /// sum_i qa[i] * code[i] of N codes, in 4 lanes each. The N codes share
833
+ /// each qa load. With four_acc, dims i + 8 * j of each 32 go to
834
+ /// accumulator j of the code, so a code sums the same way for any N.
835
+ template <size_t N>
836
+ FAISS_ALWAYS_INLINE void accumulate(
837
+ const uint8_t* const* codes,
838
+ __m128* sums) const {
839
+ constexpr size_t n_acc = four_acc ? 4 : 1;
840
+ __m256 acc[N][n_acc];
841
+ for (size_t n = 0; n < N; n++) {
842
+ for (size_t j = 0; j < n_acc; j++) {
843
+ acc[n][j] = _mm256_setzero_ps();
844
+ }
845
+ }
846
+ const size_t d = quant.d;
847
+ size_t i = 0;
848
+ if constexpr (four_acc) {
849
+ for (; i + 32 <= d; i += 32) {
850
+ for (size_t j = 0; j < 4; j++) {
851
+ const __m256 qa8 = _mm256_loadu_ps(qa.data() + i + 8 * j);
852
+ for (size_t n = 0; n < N; n++) {
853
+ acc[n][j] = _mm256_fmadd_ps(
854
+ qa8, codes_8(codes[n] + i + 8 * j), acc[n][j]);
855
+ }
856
+ }
857
+ }
858
+ }
859
+ for (; i < d; i += 8) {
860
+ const __m256 qa8 = _mm256_loadu_ps(qa.data() + i);
861
+ for (size_t n = 0; n < N; n++) {
862
+ acc[n][0] =
863
+ _mm256_fmadd_ps(qa8, codes_8(codes[n] + i), acc[n][0]);
864
+ }
865
+ }
866
+ for (size_t n = 0; n < N; n++) {
867
+ __m256 sum = acc[n][0];
868
+ if constexpr (four_acc) {
869
+ sum = _mm256_add_ps(
870
+ _mm256_add_ps(acc[n][0], acc[n][1]),
871
+ _mm256_add_ps(acc[n][2], acc[n][3]));
872
+ }
873
+ sums[n] = reduce_8_to_4(sum);
874
+ }
875
+ }
876
+
877
+ float query_to_code(const uint8_t* code) const final {
878
+ __m128 sum;
879
+ accumulate<1>(&code, &sum);
880
+ return bias + reduce_4(sum);
881
+ }
882
+
883
+ void query_to_codes_batch_4(
884
+ const uint8_t* code_0,
885
+ const uint8_t* code_1,
886
+ const uint8_t* code_2,
887
+ const uint8_t* code_3,
888
+ float& dis0,
889
+ float& dis1,
890
+ float& dis2,
891
+ float& dis3) const final {
892
+ const uint8_t* codes[4] = {code_0, code_1, code_2, code_3};
893
+ __m128 sums[4];
894
+ if constexpr (four_acc) {
895
+ // 16 accumulators would take all 16 AVX2 registers.
896
+ accumulate<2>(codes, sums);
897
+ accumulate<2>(codes + 2, sums + 2);
898
+ } else {
899
+ accumulate<4>(codes, sums);
900
+ }
901
+ alignas(16) float dis[4];
902
+ _mm_store_ps(dis, reduce_4x4(sums[0], sums[1], sums[2], sums[3]));
903
+ dis0 = bias + dis[0];
904
+ dis1 = bias + dis[1];
905
+ dis2 = bias + dis[2];
906
+ dis3 = bias + dis[3];
907
+ }
908
+
909
+ float symmetric_dis(idx_t i, idx_t j) override {
910
+ const uint8_t* c1 = codes + i * code_size;
911
+ const uint8_t* c2 = codes + j * code_size;
912
+ Sim sim(nullptr);
913
+ sim.begin_8();
914
+ for (size_t k = 0; k < quant.d; k += 8) {
915
+ const int kk = static_cast<int>(k);
916
+ sim.add_8_components_2(
917
+ quant.reconstruct_8_components(c1, kk),
918
+ quant.reconstruct_8_components(c2, kk));
919
+ }
920
+ return sim.result_8();
921
+ }
922
+ };
923
+
729
924
  template <class Similarity>
730
925
  struct DistanceComputerByte<Similarity, SIMDLevel::AVX2> : SQDistanceComputer {
731
926
  using Sim = Similarity;
@@ -853,54 +1048,8 @@ struct DistanceComputerByteSigned<Similarity, SIMDLevel::AVX2>
853
1048
  }
854
1049
  };
855
1050
 
856
- /**********************************************************
857
- * TurboQuant masked_sum AVX2 specialization
858
- **********************************************************/
859
-
860
- template <SIMDLevel SL0>
861
- float turboq_masked_sum(const float* arr, const uint8_t* bits, size_t d);
862
-
863
- template <>
864
- float turboq_masked_sum<SIMDLevel::AVX2>(
865
- const float* arr,
866
- const uint8_t* bits,
867
- size_t d) {
868
- const __m256i bit_masks = _mm256_set_epi32(128, 64, 32, 16, 8, 4, 2, 1);
869
- __m256 acc = _mm256_setzero_ps();
870
- size_t full_bytes = d / 8;
871
- for (size_t byte_idx = 0; byte_idx < full_bytes; byte_idx++) {
872
- __m256i byte_broadcast =
873
- _mm256_set1_epi32(static_cast<int>(bits[byte_idx]));
874
- __m256i masked = _mm256_and_si256(byte_broadcast, bit_masks);
875
- __m256i cmp = _mm256_cmpeq_epi32(masked, bit_masks);
876
- __m256 mask = _mm256_castsi256_ps(cmp);
877
- __m256 vals = _mm256_loadu_ps(arr + byte_idx * 8);
878
- acc = _mm256_add_ps(acc, _mm256_and_ps(mask, vals));
879
- }
880
- __m128 hi = _mm256_extractf128_ps(acc, 1);
881
- __m128 lo = _mm256_castps256_ps128(acc);
882
- __m128 sum128 = _mm_add_ps(lo, hi);
883
- __m128 shuf = _mm_movehdup_ps(sum128);
884
- __m128 sums = _mm_add_ps(sum128, shuf);
885
- shuf = _mm_movehl_ps(shuf, sums);
886
- sums = _mm_add_ss(sums, shuf);
887
- float result = _mm_cvtss_f32(sums);
888
- size_t tail_start = full_bytes * 8;
889
- if (tail_start < d) {
890
- uint8_t last_byte = bits[full_bytes];
891
- for (size_t j = tail_start; j < d; j++) {
892
- if (last_byte & (1 << (j - tail_start))) {
893
- result += arr[j];
894
- }
895
- }
896
- }
897
- return result;
898
- }
899
-
900
1051
  } // namespace scalar_quantizer
901
1052
  } // namespace faiss
902
1053
 
903
1054
  #define THE_LEVEL_TO_DISPATCH SIMDLevel::AVX2
904
1055
  #include <faiss/impl/scalar_quantizer/sq-dispatch.h>
905
-
906
- #endif // COMPILE_SIMD_AVX2