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
@@ -7,6 +7,12 @@
7
7
 
8
8
  #pragma once
9
9
 
10
+ #include <faiss/impl/scalar_quantizer/codecs.h>
11
+ #include <faiss/impl/scalar_quantizer/distance_computers.h>
12
+ #include <faiss/impl/scalar_quantizer/quantizers.h>
13
+ #include <faiss/impl/scalar_quantizer/similarities.h>
14
+ #include <faiss/impl/scalar_quantizer/sq8_coefficients.h>
15
+ #include <faiss/impl/simdlib/simdlib_avx512.h>
10
16
  #include <cstring>
11
17
 
12
18
  namespace faiss {
@@ -14,11 +20,6 @@ namespace faiss {
14
20
  namespace scalar_quantizer {
15
21
 
16
22
  using simd16float32 = faiss::simd16float32_tpl<SIMDLevel::AVX512>;
17
- using simd512bit = faiss::simd512bit_tpl<SIMDLevel::AVX512>;
18
-
19
- /**********************************************************
20
- * TurboQuant bit-unpacking helpers
21
- **********************************************************/
22
23
 
23
24
  namespace {
24
25
 
@@ -100,7 +101,7 @@ FAISS_ALWAYS_INLINE __m512i unpack_16x4bit_to_u32(const uint8_t* code, int i) {
100
101
  **********************************************************/
101
102
 
102
103
  template <>
103
- struct Codec8bit<SIMDLevel::AVX512> : Codec8bit<SIMDLevel::NONE> {
104
+ struct Codec8bit<THE_LEVEL_TO_DISPATCH> : Codec8bit<SIMDLevel::NONE> {
104
105
  static FAISS_ALWAYS_INLINE simd16float32
105
106
  decode_16_components(const uint8_t* code, size_t i) {
106
107
  const __m128i c16 = _mm_loadu_si128((__m128i*)(code + i));
@@ -113,7 +114,7 @@ struct Codec8bit<SIMDLevel::AVX512> : Codec8bit<SIMDLevel::NONE> {
113
114
  };
114
115
 
115
116
  template <>
116
- struct Codec4bit<SIMDLevel::AVX512> : Codec4bit<SIMDLevel::NONE> {
117
+ struct Codec4bit<THE_LEVEL_TO_DISPATCH> : Codec4bit<SIMDLevel::NONE> {
117
118
  static FAISS_ALWAYS_INLINE simd16float32
118
119
  decode_16_components(const uint8_t* code, size_t i) {
119
120
  uint64_t c8 = *(uint64_t*)(code + (i >> 1));
@@ -135,7 +136,7 @@ struct Codec4bit<SIMDLevel::AVX512> : Codec4bit<SIMDLevel::NONE> {
135
136
  };
136
137
 
137
138
  template <>
138
- struct Codec6bit<SIMDLevel::AVX512> : Codec6bit<SIMDLevel::NONE> {
139
+ struct Codec6bit<THE_LEVEL_TO_DISPATCH> : Codec6bit<SIMDLevel::NONE> {
139
140
  static FAISS_ALWAYS_INLINE simd16float32
140
141
  decode_16_components(const uint8_t* code, size_t i) {
141
142
  // pure AVX512 implementation (not necessarily the fastest).
@@ -192,7 +193,7 @@ template <class Codec>
192
193
  struct QuantizerTemplate<
193
194
  Codec,
194
195
  scalar_quantizer::QuantizerTemplateScaling::UNIFORM,
195
- SIMDLevel::AVX512>
196
+ THE_LEVEL_TO_DISPATCH>
196
197
  : QuantizerTemplate<
197
198
  Codec,
198
199
  scalar_quantizer::QuantizerTemplateScaling::UNIFORM,
@@ -211,13 +212,19 @@ struct QuantizerTemplate<
211
212
  return simd16float32(_mm512_fmadd_ps(
212
213
  xi, _mm512_set1_ps(this->vdiff), _mm512_set1_ps(this->vmin)));
213
214
  }
215
+
216
+ /// Raw codec decode without denormalization
217
+ FAISS_ALWAYS_INLINE simd16float32
218
+ decode_16_raw(const uint8_t* code, int i) const {
219
+ return Codec::decode_16_components(code, i);
220
+ }
214
221
  };
215
222
 
216
223
  template <class Codec>
217
224
  struct QuantizerTemplate<
218
225
  Codec,
219
226
  scalar_quantizer::QuantizerTemplateScaling::NON_UNIFORM,
220
- SIMDLevel::AVX512>
227
+ THE_LEVEL_TO_DISPATCH>
221
228
  : QuantizerTemplate<
222
229
  Codec,
223
230
  scalar_quantizer::QuantizerTemplateScaling::NON_UNIFORM,
@@ -244,36 +251,83 @@ struct QuantizerTemplate<
244
251
  * Lloyd-Max scalar quantizer
245
252
  **********************************************************/
246
253
 
247
- #define DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(NBITS, INDEX_EXPR) \
248
- template <> \
249
- struct QuantizerLloydMax<NBITS, SIMDLevel::AVX512> \
250
- : QuantizerLloydMax<NBITS, SIMDLevel::NONE> { \
251
- using Base = QuantizerLloydMax<NBITS, SIMDLevel::NONE>; \
252
- \
253
- QuantizerLloydMax(size_t d, const std::vector<float>& trained) \
254
- : Base(d, trained) { \
255
- assert(d % 16 == 0); \
256
- } \
257
- \
258
- FAISS_ALWAYS_INLINE simd16float32 \
259
- reconstruct_16_components(const uint8_t* code, int i) const { \
260
- const __m512i indices = (INDEX_EXPR); \
261
- return simd16float32(_mm512_i32gather_ps( \
262
- indices, this->centroids, sizeof(float))); \
263
- } \
264
- }
265
-
266
- DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(1, unpack_16x1bit_to_u32(code, i));
267
- DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(2, unpack_16x2bit_to_u32(code, i));
268
- DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(3, unpack_16x3bit_to_u32(code, i));
269
- DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(4, unpack_16x4bit_to_u32(code, i));
270
-
271
- #undef DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION
254
+ // 1-bit Lloyd-Max AVX512: 16 comparisons → 2 bytes via mask compare.
255
+ // NLT_UQ is !(x < b), matching the scalar upper_bound tie-break.
256
+ template <>
257
+ struct QuantizerLloydMax<1, THE_LEVEL_TO_DISPATCH>
258
+ : QuantizerLloydMaxBase<1, THE_LEVEL_TO_DISPATCH> {
259
+ using Base = QuantizerLloydMaxBase<1, THE_LEVEL_TO_DISPATCH>;
260
+
261
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
262
+ : Base(d, trained) {
263
+ assert(d % 16 == 0);
264
+ }
265
+
266
+ FAISS_ALWAYS_INLINE simd16float32
267
+ reconstruct_16_components(const uint8_t* code, int i) const {
268
+ return simd16float32(_mm512_i32gather_ps(
269
+ unpack_16x1bit_to_u32(code, i),
270
+ this->centroids,
271
+ sizeof(float)));
272
+ }
273
+
274
+ void encode_vector(const float* x, uint8_t* code) const final {
275
+ __m512 boundary = _mm512_set1_ps(this->boundaries[0]);
276
+ for (size_t i = 0; i < this->d; i += 16) {
277
+ __m512 vals = _mm512_loadu_ps(x + i);
278
+ __mmask16 mask = _mm512_cmp_ps_mask(vals, boundary, _CMP_NLT_UQ);
279
+ uint16_t bits = _cvtmask16_u32(mask);
280
+ memcpy(code + i / 8, &bits, sizeof(uint16_t));
281
+ }
282
+ }
283
+
284
+ void decode_vector(const uint8_t* code, float* x) const final {
285
+ for (size_t i = 0; i < this->d; i += 16) {
286
+ simd16float32 xi =
287
+ reconstruct_16_components(code, static_cast<int>(i));
288
+ _mm512_storeu_ps(x + i, xi.f);
289
+ }
290
+ }
291
+ };
272
292
 
293
+ // 2-4 bit Lloyd-Max AVX512: decode via gather, encode stays scalar.
294
+ #define DEFINE_LLOYD_MAX_AVX512_MULTIBIT(NBITS, UNPACK_EXPR) \
295
+ template <> \
296
+ struct QuantizerLloydMax<NBITS, THE_LEVEL_TO_DISPATCH> \
297
+ : QuantizerLloydMaxBase<NBITS, THE_LEVEL_TO_DISPATCH> { \
298
+ using Base = QuantizerLloydMaxBase<NBITS, THE_LEVEL_TO_DISPATCH>; \
299
+ \
300
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained) \
301
+ : Base(d, trained) { \
302
+ assert(d % 16 == 0); \
303
+ } \
304
+ \
305
+ FAISS_ALWAYS_INLINE simd16float32 \
306
+ reconstruct_16_components(const uint8_t* code, int i) const { \
307
+ return simd16float32(_mm512_i32gather_ps( \
308
+ (UNPACK_EXPR), this->centroids, sizeof(float))); \
309
+ } \
310
+ \
311
+ void decode_vector(const uint8_t* code, float* x) const final { \
312
+ for (size_t i = 0; i < this->d; i += 16) { \
313
+ simd16float32 xi = \
314
+ reconstruct_16_components(code, static_cast<int>(i)); \
315
+ _mm512_storeu_ps(x + i, xi.f); \
316
+ } \
317
+ } \
318
+ }
319
+
320
+ DEFINE_LLOYD_MAX_AVX512_MULTIBIT(2, unpack_16x2bit_to_u32(code, i));
321
+ DEFINE_LLOYD_MAX_AVX512_MULTIBIT(3, unpack_16x3bit_to_u32(code, i));
322
+ DEFINE_LLOYD_MAX_AVX512_MULTIBIT(4, unpack_16x4bit_to_u32(code, i));
323
+
324
+ #undef DEFINE_LLOYD_MAX_AVX512_MULTIBIT
325
+
326
+ // 8-bit Lloyd-Max AVX512
273
327
  template <>
274
- struct QuantizerLloydMax<8, SIMDLevel::AVX512>
275
- : QuantizerLloydMax<8, SIMDLevel::NONE> {
276
- using Base = QuantizerLloydMax<8, SIMDLevel::NONE>;
328
+ struct QuantizerLloydMax<8, THE_LEVEL_TO_DISPATCH>
329
+ : QuantizerLloydMaxBase<8, THE_LEVEL_TO_DISPATCH> {
330
+ using Base = QuantizerLloydMaxBase<8, THE_LEVEL_TO_DISPATCH>;
277
331
 
278
332
  QuantizerLloydMax(size_t d, const std::vector<float>& trained)
279
333
  : Base(d, trained) {
@@ -288,6 +342,14 @@ struct QuantizerLloydMax<8, SIMDLevel::AVX512>
288
342
  return simd16float32(
289
343
  _mm512_i32gather_ps(indices, this->centroids, sizeof(float)));
290
344
  }
345
+
346
+ void decode_vector(const uint8_t* code, float* x) const final {
347
+ for (size_t i = 0; i < this->d; i += 16) {
348
+ simd16float32 xi =
349
+ reconstruct_16_components(code, static_cast<int>(i));
350
+ _mm512_storeu_ps(x + i, xi.f);
351
+ }
352
+ }
291
353
  };
292
354
 
293
355
  /**********************************************************
@@ -295,17 +357,25 @@ struct QuantizerLloydMax<8, SIMDLevel::AVX512>
295
357
  **********************************************************/
296
358
 
297
359
  template <>
298
- struct QuantizerFP16<SIMDLevel::AVX512> : QuantizerFP16<SIMDLevel::NONE> {
299
- QuantizerFP16(size_t d, const std::vector<float>& trained)
300
- : QuantizerFP16<SIMDLevel::NONE>(d, trained) {
301
- assert(d % 16 == 0);
302
- }
360
+ struct QuantizerFP16<THE_LEVEL_TO_DISPATCH>
361
+ : QuantizerFP16Base<THE_LEVEL_TO_DISPATCH> {
362
+ using QuantizerFP16Base<THE_LEVEL_TO_DISPATCH>::QuantizerFP16Base;
303
363
 
304
364
  FAISS_ALWAYS_INLINE simd16float32
305
365
  reconstruct_16_components(const uint8_t* code, int i) const {
306
366
  __m256i codei = _mm256_loadu_si256((const __m256i*)(code + 2 * i));
307
367
  return simd16float32(_mm512_cvtph_ps(codei));
308
368
  }
369
+
370
+ /// Components i .. i + 15 selected by mask, the others 0. Reads no byte
371
+ /// past the selected components.
372
+ FAISS_ALWAYS_INLINE simd16float32 reconstruct_16_components_masked(
373
+ const uint8_t* code,
374
+ int i,
375
+ __mmask16 mask) const {
376
+ __m256i codei = _mm256_maskz_loadu_epi16(mask, code + 2 * i);
377
+ return simd16float32(_mm512_cvtph_ps(codei));
378
+ }
309
379
  };
310
380
 
311
381
  /**********************************************************
@@ -313,15 +383,26 @@ struct QuantizerFP16<SIMDLevel::AVX512> : QuantizerFP16<SIMDLevel::NONE> {
313
383
  **********************************************************/
314
384
 
315
385
  template <>
316
- struct QuantizerBF16<SIMDLevel::AVX512> : QuantizerBF16<SIMDLevel::NONE> {
317
- QuantizerBF16(size_t d, const std::vector<float>& trained)
318
- : QuantizerBF16<SIMDLevel::NONE>(d, trained) {
319
- assert(d % 16 == 0);
320
- }
386
+ struct QuantizerBF16<THE_LEVEL_TO_DISPATCH>
387
+ : QuantizerBF16Base<THE_LEVEL_TO_DISPATCH> {
388
+ using QuantizerBF16Base<THE_LEVEL_TO_DISPATCH>::QuantizerBF16Base;
321
389
 
322
390
  FAISS_ALWAYS_INLINE simd16float32
323
391
  reconstruct_16_components(const uint8_t* code, int i) const {
324
392
  __m256i code_256i = _mm256_loadu_si256((const __m256i*)(code + 2 * i));
393
+ return widen(code_256i);
394
+ }
395
+
396
+ /// Components i .. i + 15 selected by mask, the others 0. Reads no byte
397
+ /// past the selected components.
398
+ FAISS_ALWAYS_INLINE simd16float32 reconstruct_16_components_masked(
399
+ const uint8_t* code,
400
+ int i,
401
+ __mmask16 mask) const {
402
+ return widen(_mm256_maskz_loadu_epi16(mask, code + 2 * i));
403
+ }
404
+
405
+ static FAISS_ALWAYS_INLINE simd16float32 widen(__m256i code_256i) {
325
406
  __m512i code_512i = _mm512_cvtepu16_epi32(code_256i);
326
407
  code_512i = _mm512_slli_epi32(code_512i, 16);
327
408
  return simd16float32(_mm512_castsi512_ps(code_512i));
@@ -333,10 +414,10 @@ struct QuantizerBF16<SIMDLevel::AVX512> : QuantizerBF16<SIMDLevel::NONE> {
333
414
  **********************************************************/
334
415
 
335
416
  template <>
336
- struct Quantizer8bitDirect<SIMDLevel::AVX512>
337
- : Quantizer8bitDirect<SIMDLevel::NONE> {
417
+ struct Quantizer8bitDirect<THE_LEVEL_TO_DISPATCH>
418
+ : Quantizer8bitDirectBase<THE_LEVEL_TO_DISPATCH> {
338
419
  Quantizer8bitDirect(size_t d, const std::vector<float>& trained)
339
- : Quantizer8bitDirect<SIMDLevel::NONE>(d, trained) {
420
+ : Quantizer8bitDirectBase<THE_LEVEL_TO_DISPATCH>(d, trained) {
340
421
  assert(d % 16 == 0);
341
422
  }
342
423
 
@@ -353,10 +434,10 @@ struct Quantizer8bitDirect<SIMDLevel::AVX512>
353
434
  **********************************************************/
354
435
 
355
436
  template <>
356
- struct Quantizer8bitDirectSigned<SIMDLevel::AVX512>
357
- : Quantizer8bitDirectSigned<SIMDLevel::NONE> {
437
+ struct Quantizer8bitDirectSigned<THE_LEVEL_TO_DISPATCH>
438
+ : Quantizer8bitDirectSignedBase<THE_LEVEL_TO_DISPATCH> {
358
439
  Quantizer8bitDirectSigned(size_t d, const std::vector<float>& trained)
359
- : Quantizer8bitDirectSigned<SIMDLevel::NONE>(d, trained) {
440
+ : Quantizer8bitDirectSignedBase<THE_LEVEL_TO_DISPATCH>(d, trained) {
360
441
  assert(d % 16 == 0);
361
442
  }
362
443
 
@@ -375,9 +456,9 @@ struct Quantizer8bitDirectSigned<SIMDLevel::AVX512>
375
456
  **********************************************************/
376
457
 
377
458
  template <>
378
- struct SimilarityL2<SIMDLevel::AVX512> {
459
+ struct SimilarityL2<THE_LEVEL_TO_DISPATCH> {
379
460
  static constexpr int simdwidth = 16;
380
- static constexpr SIMDLevel simd_level = SIMDLevel::AVX512;
461
+ static constexpr SIMDLevel simd_level = THE_LEVEL_TO_DISPATCH;
381
462
  static constexpr MetricType metric_type = METRIC_L2;
382
463
 
383
464
  const float *y, *yi;
@@ -405,15 +486,38 @@ struct SimilarityL2<SIMDLevel::AVX512> {
405
486
  accu16 = accu16 + tmp * tmp;
406
487
  }
407
488
 
489
+ FAISS_ALWAYS_INLINE void fmadd_16_components_2(
490
+ simd16float32 x,
491
+ simd16float32 y_2) {
492
+ simd16float32 tmp = y_2 - x;
493
+ accu16 = fmadd(tmp, tmp, accu16);
494
+ }
495
+
408
496
  FAISS_ALWAYS_INLINE float result_16() {
409
497
  return horizontal_add(accu16);
410
498
  }
499
+
500
+ static void adjust_query_for_raw_decode(
501
+ const float* x,
502
+ float* q_adj,
503
+ size_t d,
504
+ float vmin,
505
+ float vdiff,
506
+ float& scale_factor,
507
+ float& bias) {
508
+ float inv_vdiff = (vdiff != 0) ? 1.0f / vdiff : 0.0f;
509
+ for (size_t i = 0; i < d; i++) {
510
+ q_adj[i] = (x[i] - vmin) * inv_vdiff;
511
+ }
512
+ scale_factor = vdiff * vdiff;
513
+ bias = 0;
514
+ }
411
515
  };
412
516
 
413
517
  template <>
414
- struct SimilarityIP<SIMDLevel::AVX512> {
518
+ struct SimilarityIP<THE_LEVEL_TO_DISPATCH> {
415
519
  static constexpr int simdwidth = 16;
416
- static constexpr SIMDLevel simd_level = SIMDLevel::AVX512;
520
+ static constexpr SIMDLevel simd_level = THE_LEVEL_TO_DISPATCH;
417
521
  static constexpr MetricType metric_type = METRIC_INNER_PRODUCT;
418
522
 
419
523
  const float *y, *yi;
@@ -439,32 +543,144 @@ struct SimilarityIP<SIMDLevel::AVX512> {
439
543
  accu16 = accu16 + x1 * x2;
440
544
  }
441
545
 
546
+ FAISS_ALWAYS_INLINE void fmadd_16_components_2(
547
+ simd16float32 x1,
548
+ simd16float32 x2) {
549
+ accu16 = fmadd(x1, x2, accu16);
550
+ }
551
+
442
552
  FAISS_ALWAYS_INLINE float result_16() {
443
553
  return horizontal_add(accu16);
444
554
  }
555
+
556
+ static void adjust_query_for_raw_decode(
557
+ const float* x,
558
+ float* q_adj,
559
+ size_t d,
560
+ float vmin,
561
+ float vdiff,
562
+ float& scale_factor,
563
+ float& bias) {
564
+ float sum_q = 0;
565
+ for (size_t i = 0; i < d; i++) {
566
+ q_adj[i] = x[i];
567
+ sum_q += x[i];
568
+ }
569
+ scale_factor = vdiff;
570
+ bias = vmin * sum_q;
571
+ }
445
572
  };
446
573
 
447
574
  /**********************************************************
448
575
  * Distance Computers
449
576
  **********************************************************/
450
577
 
451
- template <class Quantizer, class Similarity>
452
- struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX512>
578
+ namespace {
579
+
580
+ /// 16 lanes to 4: lanes j, j + 4, j + 8 and j + 12 summed into lane j.
581
+ FAISS_ALWAYS_INLINE __m128 reduce_16_to_4(__m512 a) {
582
+ const __m256 hi =
583
+ _mm256_castpd_ps(_mm512_extractf64x4_pd(_mm512_castps_pd(a), 1));
584
+ const __m256 s8 = _mm256_add_ps(_mm512_castps512_ps256(a), hi);
585
+ return _mm_add_ps(_mm256_castps256_ps128(s8), _mm256_extractf128_ps(s8, 1));
586
+ }
587
+
588
+ } // namespace
589
+
590
+ template <class Quantizer, class Similarity, bool four_acc>
591
+ struct DCTemplate<Quantizer, Similarity, THE_LEVEL_TO_DISPATCH, four_acc>
453
592
  : SQDistanceComputer {
454
593
  using Sim = Similarity;
455
594
 
456
595
  Quantizer quant;
457
596
 
597
+ // Pre-adjusted query buffer for uniform quantizers
598
+ std::vector<float> q_adj;
599
+ float scale_factor = 0;
600
+ float bias = 0;
601
+
602
+ static constexpr bool has_decode_raw() {
603
+ return requires(const Quantizer& q, const uint8_t* c, int i) {
604
+ { q.decode_16_raw(c, i) };
605
+ };
606
+ }
607
+
458
608
  DCTemplate(size_t d, const std::vector<float>& trained)
459
- : quant(d, trained) {}
609
+ : quant(d, trained) {
610
+ if constexpr (has_decode_raw()) {
611
+ q_adj.resize(d);
612
+ }
613
+ }
614
+
615
+ /// The quantizer can decode a partial block, so d need not be a
616
+ /// multiple of 16.
617
+ static constexpr bool has_masked_tail() {
618
+ return requires(const Quantizer& q, const uint8_t* c) {
619
+ { q.reconstruct_16_components_masked(c, 0, __mmask16(0)) };
620
+ };
621
+ }
622
+
623
+ /// Adds the partial last block, from component i, of a d that is not a
624
+ /// multiple of 16.
625
+ FAISS_ALWAYS_INLINE void add_tail(
626
+ Similarity& sim,
627
+ const float* x,
628
+ const uint8_t* code,
629
+ size_t i) const {
630
+ if constexpr (has_masked_tail()) {
631
+ if (i < quant.d) {
632
+ const __mmask16 mask = __mmask16((1u << (quant.d - i)) - 1);
633
+ sim.fmadd_16_components_2(
634
+ quant.reconstruct_16_components_masked(
635
+ code, static_cast<int>(i), mask),
636
+ simd16float32(_mm512_maskz_loadu_ps(mask, x + i)));
637
+ }
638
+ }
639
+ }
640
+
641
+ /// Similarity terms of one code with four accumulators.
642
+ FAISS_ALWAYS_INLINE __m512
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_16();
650
+ }
651
+ const size_t d = quant.d;
652
+ size_t i = 0;
653
+ for (; i + 64 <= d; i += 64) {
654
+ for (int j = 0; j < 4; j++) {
655
+ s[j].fmadd_16_components_2(
656
+ quant.reconstruct_16_components(
657
+ code, static_cast<int>(i + 16 * j)),
658
+ simd16float32(x + i + 16 * j));
659
+ }
660
+ }
661
+ for (; i + 16 <= d; i += 16) {
662
+ s[0].fmadd_16_components_2(
663
+ quant.reconstruct_16_components(code, static_cast<int>(i)),
664
+ simd16float32(x + i));
665
+ }
666
+ add_tail(s[0], x, code, i);
667
+ return _mm512_add_ps(
668
+ _mm512_add_ps(s[0].accu16.f, s[1].accu16.f),
669
+ _mm512_add_ps(s[2].accu16.f, s[3].accu16.f));
670
+ }
460
671
 
461
672
  float compute_distance(const float* x, const uint8_t* code) const {
673
+ if constexpr (four_acc) {
674
+ return reduce_4(reduce_16_to_4(accumulate_4(x, code)));
675
+ }
462
676
  Similarity sim(x);
463
677
  sim.begin_16();
464
- for (size_t i = 0; i < quant.d; i += 16) {
678
+ const size_t d16 = quant.d & ~size_t(15);
679
+ for (size_t i = 0; i < d16; i += 16) {
465
680
  simd16float32 xi = quant.reconstruct_16_components(code, i);
466
681
  sim.add_16_components(xi);
467
682
  }
683
+ add_tail(sim, x, code, d16);
468
684
  return sim.result_16();
469
685
  }
470
686
 
@@ -472,16 +688,46 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX512>
472
688
  const {
473
689
  Similarity sim(nullptr);
474
690
  sim.begin_16();
475
- for (size_t i = 0; i < quant.d; i += 16) {
691
+ const size_t d16 = quant.d & ~size_t(15);
692
+ for (size_t i = 0; i < d16; i += 16) {
476
693
  simd16float32 x1 = quant.reconstruct_16_components(code1, i);
477
694
  simd16float32 x2 = quant.reconstruct_16_components(code2, i);
478
695
  sim.add_16_components_2(x1, x2);
479
696
  }
697
+ if constexpr (has_masked_tail()) {
698
+ if (d16 < quant.d) {
699
+ const __mmask16 mask = __mmask16((1u << (quant.d - d16)) - 1);
700
+ const int i = static_cast<int>(d16);
701
+ sim.add_16_components_2(
702
+ quant.reconstruct_16_components_masked(code1, i, mask),
703
+ quant.reconstruct_16_components_masked(code2, i, mask));
704
+ }
705
+ }
480
706
  return sim.result_16();
481
707
  }
482
708
 
483
709
  void set_query(const float* x) final {
484
710
  q = x;
711
+ if constexpr (has_decode_raw()) {
712
+ Sim::adjust_query_for_raw_decode(
713
+ x,
714
+ q_adj.data(),
715
+ quant.d,
716
+ quant.vmin,
717
+ quant.vdiff,
718
+ scale_factor,
719
+ bias);
720
+ }
721
+ }
722
+
723
+ float query_to_code_predecoded(const uint8_t* code) const {
724
+ Similarity sim(q_adj.data());
725
+ sim.begin_16();
726
+ for (size_t i = 0; i < quant.d; i += 16) {
727
+ simd16float32 xi = quant.decode_16_raw(code, i);
728
+ sim.add_16_components(xi);
729
+ }
730
+ return bias + scale_factor * sim.result_16();
485
731
  }
486
732
 
487
733
  float symmetric_dis(idx_t i, idx_t j) override {
@@ -490,64 +736,197 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::AVX512>
490
736
  }
491
737
 
492
738
  float query_to_code(const uint8_t* code) const final {
493
- return compute_distance(q, code);
739
+ if constexpr (has_decode_raw()) {
740
+ return query_to_code_predecoded(code);
741
+ } else {
742
+ return compute_distance(q, code);
743
+ }
494
744
  }
495
- };
496
745
 
497
- template <class Similarity>
498
- struct DistanceComputerByte<Similarity, SIMDLevel::AVX512>
499
- : SQDistanceComputer {
500
- using Sim = Similarity;
746
+ void query_to_codes_batch_4(
747
+ const uint8_t* code_0,
748
+ const uint8_t* code_1,
749
+ const uint8_t* code_2,
750
+ const uint8_t* code_3,
751
+ float& dis0,
752
+ float& dis1,
753
+ float& dis2,
754
+ float& dis3) const final {
755
+ if constexpr (four_acc) {
756
+ alignas(16) float dis[4];
757
+ _mm_store_ps(
758
+ dis,
759
+ reduce_4x4(
760
+ reduce_16_to_4(accumulate_4(q, code_0)),
761
+ reduce_16_to_4(accumulate_4(q, code_1)),
762
+ reduce_16_to_4(accumulate_4(q, code_2)),
763
+ reduce_16_to_4(accumulate_4(q, code_3))));
764
+ dis0 = dis[0];
765
+ dis1 = dis[1];
766
+ dis2 = dis[2];
767
+ dis3 = dis[3];
768
+ return;
769
+ }
770
+ Similarity sim0(q);
771
+ Similarity sim1(q);
772
+ Similarity sim2(q);
773
+ Similarity sim3(q);
774
+
775
+ sim0.begin_16();
776
+ sim1.begin_16();
777
+ sim2.begin_16();
778
+ sim3.begin_16();
779
+
780
+ const size_t d16 = quant.d & ~size_t(15);
781
+ for (size_t i = 0; i < d16; i += 16) {
782
+ simd16float32 xi0 = quant.reconstruct_16_components(code_0, i);
783
+ simd16float32 xi1 = quant.reconstruct_16_components(code_1, i);
784
+ simd16float32 xi2 = quant.reconstruct_16_components(code_2, i);
785
+ simd16float32 xi3 = quant.reconstruct_16_components(code_3, i);
786
+ sim0.add_16_components(xi0);
787
+ sim1.add_16_components(xi1);
788
+ sim2.add_16_components(xi2);
789
+ sim3.add_16_components(xi3);
790
+ }
791
+ add_tail(sim0, q, code_0, d16);
792
+ add_tail(sim1, q, code_1, d16);
793
+ add_tail(sim2, q, code_2, d16);
794
+ add_tail(sim3, q, code_3, d16);
501
795
 
502
- int d;
503
- std::vector<uint8_t> tmp;
796
+ dis0 = sim0.result_16();
797
+ dis1 = sim1.result_16();
798
+ dis2 = sim2.result_16();
799
+ dis3 = sim3.result_16();
800
+ }
801
+ };
504
802
 
505
- DistanceComputerByte(int d, const std::vector<float>&) : d(d), tmp(d) {}
803
+ // QT_8bit + IP: the precomputed form of the AVX2 specialization, 16 dims per
804
+ // convert and FMA.
805
+ template <bool four_acc>
806
+ struct DCTemplate<
807
+ QuantizerTemplate<
808
+ Codec8bit<THE_LEVEL_TO_DISPATCH>,
809
+ QuantizerTemplateScaling::NON_UNIFORM,
810
+ THE_LEVEL_TO_DISPATCH>,
811
+ SimilarityIP<THE_LEVEL_TO_DISPATCH>,
812
+ THE_LEVEL_TO_DISPATCH,
813
+ four_acc> : SQDistanceComputer {
814
+ using Quantizer = QuantizerTemplate<
815
+ Codec8bit<THE_LEVEL_TO_DISPATCH>,
816
+ QuantizerTemplateScaling::NON_UNIFORM,
817
+ THE_LEVEL_TO_DISPATCH>;
818
+ using Sim = SimilarityIP<THE_LEVEL_TO_DISPATCH>;
506
819
 
507
- int compute_code_distance(const uint8_t* code1, const uint8_t* code2)
508
- const {
509
- // compute 16 lanes of 32-bit products (16-bytes) at once for
510
- // the supported metrics
511
- __m512i accu = _mm512_setzero_si512();
512
- constexpr int kLanes = 16;
513
- for (int i = 0; i < d; i += kLanes) {
514
- __m128i c1 = _mm_loadu_si128((__m128i*)(code1 + i));
515
- __m128i c2 = _mm_loadu_si128((__m128i*)(code2 + i));
516
- __m512i c1i = _mm512_cvtepu8_epi32(c1);
517
- __m512i c2i = _mm512_cvtepu8_epi32(c2);
518
-
519
- __m512i v;
520
- if (Sim::metric_type == METRIC_INNER_PRODUCT) {
521
- v = _mm512_mullo_epi32(c1i, c2i);
522
- } else {
523
- __m512i diff = _mm512_sub_epi32(c1i, c2i);
524
- v = _mm512_mullo_epi32(diff, diff);
525
- }
526
- accu = _mm512_add_epi32(accu, v);
527
- }
528
- return _mm512_reduce_add_epi32(accu);
820
+ Quantizer quant;
821
+ std::vector<float> a, rmin, qa;
822
+ float bias = 0;
823
+
824
+ DCTemplate(size_t d, const std::vector<float>& trained)
825
+ : quant(d, trained), a(d), rmin(d), qa(d) {
826
+ sq8::make_coefficients(trained.data(), d, a.data(), rmin.data());
529
827
  }
530
828
 
531
829
  void set_query(const float* x) final {
532
- for (int i = 0; i < d; i++) {
533
- tmp[i] = int(x[i]);
830
+ q = x;
831
+ bias = 0;
832
+ for (size_t i = 0; i < quant.d; i++) {
833
+ qa[i] = x[i] * a[i];
834
+ bias += x[i] * rmin[i];
534
835
  }
535
836
  }
536
837
 
537
- int compute_distance(const float* x, const uint8_t* code) {
538
- set_query(x);
539
- return compute_code_distance(tmp.data(), code);
838
+ static FAISS_ALWAYS_INLINE __m512 codes_16(const uint8_t* code) {
839
+ return _mm512_cvtepi32_ps(
840
+ _mm512_cvtepu8_epi32(_mm_loadu_si128((const __m128i*)code)));
540
841
  }
541
842
 
542
- float symmetric_dis(idx_t i, idx_t j) override {
543
- return compute_code_distance(
544
- codes + i * code_size, codes + j * code_size);
843
+ /// sum_i qa[i] * code[i] of N codes, in 4 lanes each. The N codes share
844
+ /// each qa load. With four_acc, dims i + 16 * j of each 64 go to
845
+ /// accumulator j of the code, so a code sums the same way for any N.
846
+ template <size_t N>
847
+ FAISS_ALWAYS_INLINE void accumulate(
848
+ const uint8_t* const* codes,
849
+ __m128* sums) const {
850
+ constexpr size_t n_acc = four_acc ? 4 : 1;
851
+ __m512 acc[N][n_acc];
852
+ for (size_t n = 0; n < N; n++) {
853
+ for (size_t j = 0; j < n_acc; j++) {
854
+ acc[n][j] = _mm512_setzero_ps();
855
+ }
856
+ }
857
+ const size_t d = quant.d;
858
+ size_t i = 0;
859
+ if constexpr (four_acc) {
860
+ for (; i + 64 <= d; i += 64) {
861
+ for (size_t j = 0; j < 4; j++) {
862
+ const __m512 qa16 = _mm512_loadu_ps(qa.data() + i + 16 * j);
863
+ for (size_t n = 0; n < N; n++) {
864
+ acc[n][j] = _mm512_fmadd_ps(
865
+ qa16,
866
+ codes_16(codes[n] + i + 16 * j),
867
+ acc[n][j]);
868
+ }
869
+ }
870
+ }
871
+ }
872
+ for (; i < d; i += 16) {
873
+ const __m512 qa16 = _mm512_loadu_ps(qa.data() + i);
874
+ for (size_t n = 0; n < N; n++) {
875
+ acc[n][0] = _mm512_fmadd_ps(
876
+ qa16, codes_16(codes[n] + i), acc[n][0]);
877
+ }
878
+ }
879
+ for (size_t n = 0; n < N; n++) {
880
+ __m512 sum = acc[n][0];
881
+ if constexpr (four_acc) {
882
+ sum = _mm512_add_ps(
883
+ _mm512_add_ps(acc[n][0], acc[n][1]),
884
+ _mm512_add_ps(acc[n][2], acc[n][3]));
885
+ }
886
+ sums[n] = reduce_16_to_4(sum);
887
+ }
545
888
  }
546
889
 
547
890
  float query_to_code(const uint8_t* code) const final {
548
- return compute_code_distance(tmp.data(), code);
891
+ __m128 sum;
892
+ accumulate<1>(&code, &sum);
893
+ return bias + reduce_4(sum);
894
+ }
895
+
896
+ void query_to_codes_batch_4(
897
+ const uint8_t* code_0,
898
+ const uint8_t* code_1,
899
+ const uint8_t* code_2,
900
+ const uint8_t* code_3,
901
+ float& dis0,
902
+ float& dis1,
903
+ float& dis2,
904
+ float& dis3) const final {
905
+ const uint8_t* codes[4] = {code_0, code_1, code_2, code_3};
906
+ __m128 sums[4];
907
+ accumulate<4>(codes, sums);
908
+ alignas(16) float dis[4];
909
+ _mm_store_ps(dis, reduce_4x4(sums[0], sums[1], sums[2], sums[3]));
910
+ dis0 = bias + dis[0];
911
+ dis1 = bias + dis[1];
912
+ dis2 = bias + dis[2];
913
+ dis3 = bias + dis[3];
914
+ }
915
+
916
+ float symmetric_dis(idx_t i, idx_t j) override {
917
+ const uint8_t* c1 = codes + i * code_size;
918
+ const uint8_t* c2 = codes + j * code_size;
919
+ Sim sim(nullptr);
920
+ sim.begin_16();
921
+ for (size_t k = 0; k < quant.d; k += 16) {
922
+ simd16float32 x1 = quant.reconstruct_16_components(c1, k);
923
+ simd16float32 x2 = quant.reconstruct_16_components(c2, k);
924
+ sim.add_16_components_2(x1, x2);
925
+ }
926
+ return sim.result_16();
549
927
  }
550
928
  };
551
929
 
552
930
  } // namespace scalar_quantizer
931
+
553
932
  } // namespace faiss