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_RISCV_RVV
9
-
10
8
  #define THE_SIMD_LEVEL SIMDLevel::RISCV_RVV
11
9
 
12
10
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
@@ -22,5 +20,3 @@
22
20
  #include <faiss/impl/binary_hamming/IndexIVFSpectralHash_impl.h>
23
21
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
24
22
  #include <faiss/impl/binary_hamming/IndexPQ_impl.h>
25
-
26
- #endif // COMPILE_SIMD_RISCV_RVV
@@ -67,6 +67,66 @@ size_t run_scan_codes1(
67
67
  return nup;
68
68
  }
69
69
 
70
+ // Batched variant of run_scan_codes1 for the SQ scanners: distances four codes
71
+ // per step via distance_to_codes_batch_4, then applies the threshold and heap
72
+ // updates in id order so results match run_scan_codes1. No-selector path only.
73
+ template <class ScannerType, typename C, bool store_pairs>
74
+ size_t run_scan_codes4(
75
+ const ScannerType& scanner,
76
+ size_t list_size,
77
+ const uint8_t* codes,
78
+ const idx_t* ids,
79
+ ResultHandler& handler) {
80
+ size_t nup = 0;
81
+ size_t list_no = scanner.list_no;
82
+ size_t code_size = scanner.code_size;
83
+ float threshold = handler.threshold;
84
+
85
+ size_t j = 0;
86
+ for (; j + 4 <= list_size; j += 4) {
87
+ float dis[4];
88
+ scanner.distance_to_codes_batch_4(
89
+ codes,
90
+ codes + code_size,
91
+ codes + 2 * code_size,
92
+ codes + 3 * code_size,
93
+ dis[0],
94
+ dis[1],
95
+ dis[2],
96
+ dis[3]);
97
+ handler.stats.scan_cnt += 4;
98
+ for (size_t b = 0; b < 4; b++) {
99
+ if (C::cmp(threshold, dis[b])) {
100
+ int64_t id =
101
+ store_pairs ? lo_build(list_no, j + b) : ids[j + b];
102
+ if (handler.add_result(dis[b], id)) {
103
+ handler.stats.nheap_updates++;
104
+ nup++;
105
+ threshold = handler.threshold;
106
+ }
107
+ }
108
+ }
109
+ codes += 4 * code_size;
110
+ }
111
+
112
+ // tail: the final < 4 codes, one at a time
113
+ for (; j < list_size; j++) {
114
+ handler.stats.scan_cnt++;
115
+ float dis = scanner.distance_to_code(codes);
116
+ if (C::cmp(threshold, dis)) {
117
+ int64_t id = store_pairs ? lo_build(list_no, j) : ids[j];
118
+ if (handler.add_result(dis, id)) {
119
+ handler.stats.nheap_updates++;
120
+ nup++;
121
+ threshold = handler.threshold;
122
+ }
123
+ }
124
+ codes += code_size;
125
+ }
126
+
127
+ return nup;
128
+ }
129
+
70
130
  /*****************************************************************************
71
131
  * The following functions dispatch runtime parameters to templates, with
72
132
  * possibly some already-fixed templates.
@@ -136,6 +196,34 @@ size_t run_scan_codes_fix_C(
136
196
  }
137
197
  }
138
198
 
199
+ // Routing wrapper for the SQ scanners: the no-selector path takes the batched
200
+ // run_scan_codes4, the selector path stays on run_scan_codes1.
201
+ template <class C, class ScannerType>
202
+ size_t run_scan_codes4_fix_C(
203
+ const ScannerType& scanner,
204
+ size_t list_size,
205
+ const uint8_t* codes,
206
+ const idx_t* ids,
207
+ ResultHandler& handler) {
208
+ if (scanner.sel) {
209
+ if (scanner.store_pairs) {
210
+ return run_scan_codes1<ScannerType, C, true, true>(
211
+ scanner, list_size, codes, ids, handler);
212
+ } else {
213
+ return run_scan_codes1<ScannerType, C, false, true>(
214
+ scanner, list_size, codes, ids, handler);
215
+ }
216
+ } else {
217
+ if (scanner.store_pairs) {
218
+ return run_scan_codes4<ScannerType, C, true>(
219
+ scanner, list_size, codes, ids, handler);
220
+ } else {
221
+ return run_scan_codes4<ScannerType, C, false>(
222
+ scanner, list_size, codes, ids, handler);
223
+ }
224
+ }
225
+ }
226
+
139
227
  template <class ScannerType>
140
228
  size_t run_scan_codes(
141
229
  const ScannerType& scanner,
@@ -29,6 +29,10 @@ struct FastScanDistancePostProcessing {
29
29
  /// QueryFactorsData subset for this context.
30
30
  rabitq_utils::QueryFactorsData* query_factors = nullptr;
31
31
 
32
+ /// Multi-bit IVF RaBitQ: rotated query per (query, probe), d floats each,
33
+ /// indexed like query_factors (nullptr if unused).
34
+ float* rotated_q = nullptr;
35
+
32
36
  /// The nprobe value used when allocating query_factors storage.
33
37
  /// This is needed because the allocation size (n * nprobe) may use a
34
38
  /// different nprobe than index->nprobe if search params override it.
@@ -1,5 +1,13 @@
1
1
  /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /*
9
+ * Portions Copyright 2026 Arm Limited and/or its affiliates
10
+ * <open-source-office@arm.com>
3
11
  *
4
12
  * This source code is licensed under the MIT license found in the
5
13
  * LICENSE file in the root directory of this source tree.
@@ -14,22 +22,14 @@
14
22
  * Contains:
15
23
  * - accumulate_fixed_blocks / pq4_accumulate_loop_fixed_scaler
16
24
  * (search_1 multi-BB path, bbs > 32)
17
- * - accumulate_q_4step_256 / pq4_accumulate_loop_qbs_fixed_scaler_256
18
- * (QBS path, bbs == 32, 256-bit kernel only)
25
+ * - SIMD-level-selected QBS traversal (bbs == 32)
19
26
  *
20
- * The QBS helpers here use pq4_kernel_qbs_256 exclusively (not
21
- * decompose_qbs.h) because decompose_qbs.h includes kernels_simd512.h
22
- * whose 512-bit types need explicit SIMD levels. The 512-bit QBS path
23
- * lives in accumulate_loops_512.h, used by the AVX512 per-ISA TU.
27
+ * The default PQ4QBSKernel<SL> uses the 256-bit kernel. Architecture-specific
28
+ * headers may specialize it while reusing the traversal and QBS dispatch.
24
29
  *
25
30
  * All functions live in `namespace faiss` (not anonymous) so they can be
26
31
  * shared by both the per-SIMD TU dispatcher (dispatching.h) and the old
27
32
  * free-function search paths (pq4_fast_scan_search_1.cpp).
28
- *
29
- * The QBS helpers here always use pq4_kernel_qbs_256 (never 512-bit).
30
- * This is required for the per-SIMD DD TUs where SINGLE_SIMD_LEVEL=NONE
31
- * leaves 512-bit types empty. The old pq4_fast_scan_search_qbs.cpp
32
- * continues to use decompose_qbs.h which includes both 256 and 512 paths.
33
33
  */
34
34
 
35
35
  #include <cassert>
@@ -37,7 +37,11 @@
37
37
  #include <faiss/impl/FaissAssert.h>
38
38
  #include <faiss/impl/fast_scan/LookupTableScaler.h>
39
39
  #include <faiss/impl/fast_scan/kernels_simd256.h>
40
+ #if FAISS_SIMD_TU(ARM_NEON)
41
+ #include <faiss/impl/fast_scan/kernels_neon.h>
42
+ #endif
40
43
  #include <faiss/impl/fast_scan/simd_result_handlers.h>
44
+ #include <faiss/utils/simd_levels.h>
41
45
 
42
46
  namespace faiss {
43
47
 
@@ -112,15 +116,11 @@ void pq4_accumulate_loop_fixed_scaler(
112
116
  }
113
117
 
114
118
  /***************************************************************
115
- * QBS path helpers (bbs == 32, 256-bit kernel only)
119
+ * QBS path helpers (bbs == 32)
116
120
  ***************************************************************/
117
121
 
118
- template <
119
- int QBS,
120
- SIMDLevel KernelSL = SINGLE_SIMD_LEVEL,
121
- class ResultHandler,
122
- class Scaler>
123
- void accumulate_q_4step_256(
122
+ template <int QBS, SIMDLevel SL, class ResultHandler, class Scaler>
123
+ void accumulate_q_4step_for_simd(
124
124
  size_t ntotal2,
125
125
  int nsq,
126
126
  const uint8_t* codes,
@@ -135,33 +135,31 @@ void accumulate_q_4step_256(
135
135
  constexpr int SQ = Q1 + Q2 + Q3 + Q4;
136
136
 
137
137
  for_each_block<32>(ntotal2, codes, block_stride, res, [&](size_t) {
138
- FixedStorageHandler<SQ, 2, KernelSL> res2;
138
+ // Scaler as LinkageTag: see FixedStorageHandler.
139
+ FixedStorageHandler<SQ, 2, SL, Scaler> res2;
139
140
  const uint8_t* LUT = LUT0;
140
- pq4_kernel_qbs_256<Q1, KernelSL>(nsq, codes, LUT, res2, scaler);
141
+ PQ4QBSKernel<SL>::template run<Q1>(nsq, codes, LUT, res2, scaler);
141
142
  LUT += Q1 * nsq * 16;
142
143
  if (Q2 > 0) {
143
144
  res2.set_block_origin(Q1, 0);
144
- pq4_kernel_qbs_256<Q2, KernelSL>(nsq, codes, LUT, res2, scaler);
145
+ PQ4QBSKernel<SL>::template run<Q2>(nsq, codes, LUT, res2, scaler);
145
146
  LUT += Q2 * nsq * 16;
146
147
  }
147
148
  if (Q3 > 0) {
148
149
  res2.set_block_origin(Q1 + Q2, 0);
149
- pq4_kernel_qbs_256<Q3, KernelSL>(nsq, codes, LUT, res2, scaler);
150
+ PQ4QBSKernel<SL>::template run<Q3>(nsq, codes, LUT, res2, scaler);
150
151
  LUT += Q3 * nsq * 16;
151
152
  }
152
153
  if (Q4 > 0) {
153
154
  res2.set_block_origin(Q1 + Q2 + Q3, 0);
154
- pq4_kernel_qbs_256<Q4, KernelSL>(nsq, codes, LUT, res2, scaler);
155
+ PQ4QBSKernel<SL>::template run<Q4>(nsq, codes, LUT, res2, scaler);
155
156
  }
156
157
  res2.to_other_handler(res);
157
158
  });
158
159
  }
159
160
 
160
- template <
161
- SIMDLevel KernelSL = SINGLE_SIMD_LEVEL,
162
- class ResultHandler,
163
- class Scaler>
164
- void pq4_accumulate_loop_qbs_fixed_scaler_256(
161
+ template <SIMDLevel SL = SINGLE_SIMD_LEVEL, class ResultHandler, class Scaler>
162
+ void pq4_accumulate_loop_qbs_fixed_scaler_simd(
165
163
  int qbs,
166
164
  size_t ntotal2,
167
165
  int nsq,
@@ -175,38 +173,37 @@ void pq4_accumulate_loop_qbs_fixed_scaler_256(
175
173
  assert(is_aligned_pointer(LUT0));
176
174
 
177
175
  switch (qbs) {
178
- #define FAISS_QBS256_DISPATCH(QBS) \
176
+ #define FAISS_QBS_DISPATCH(QBS) \
179
177
  case QBS: \
180
- accumulate_q_4step_256<QBS, KernelSL>( \
178
+ accumulate_q_4step_for_simd<QBS, SL>( \
181
179
  ntotal2, nsq, codes, LUT0, res, scaler, block_stride); \
182
180
  return;
183
- FAISS_QBS256_DISPATCH(0x3333); // 12
184
- FAISS_QBS256_DISPATCH(0x2333); // 11
185
- FAISS_QBS256_DISPATCH(0x2233); // 10
186
- FAISS_QBS256_DISPATCH(0x333); // 9
187
- FAISS_QBS256_DISPATCH(0x2223); // 9
188
- FAISS_QBS256_DISPATCH(0x233); // 8
189
- FAISS_QBS256_DISPATCH(0x1223); // 8
190
- FAISS_QBS256_DISPATCH(0x223); // 7
191
- FAISS_QBS256_DISPATCH(0x34); // 7
192
- FAISS_QBS256_DISPATCH(0x133); // 7
193
- FAISS_QBS256_DISPATCH(0x6); // 6
194
- FAISS_QBS256_DISPATCH(0x33); // 6
195
- FAISS_QBS256_DISPATCH(0x123); // 6
196
- FAISS_QBS256_DISPATCH(0x222); // 6
197
- FAISS_QBS256_DISPATCH(0x23); // 5
198
- FAISS_QBS256_DISPATCH(0x5); // 5
199
- FAISS_QBS256_DISPATCH(0x13); // 4
200
- FAISS_QBS256_DISPATCH(0x22); // 4
201
- FAISS_QBS256_DISPATCH(0x4); // 4
202
- FAISS_QBS256_DISPATCH(0x3); // 3
203
- FAISS_QBS256_DISPATCH(0x21); // 3
204
- FAISS_QBS256_DISPATCH(0x2); // 2
205
- FAISS_QBS256_DISPATCH(0x1); // 1
206
- #undef FAISS_QBS256_DISPATCH
181
+ FAISS_QBS_DISPATCH(0x3333); // 12
182
+ FAISS_QBS_DISPATCH(0x2333); // 11
183
+ FAISS_QBS_DISPATCH(0x2233); // 10
184
+ FAISS_QBS_DISPATCH(0x333); // 9
185
+ FAISS_QBS_DISPATCH(0x2223); // 9
186
+ FAISS_QBS_DISPATCH(0x233); // 8
187
+ FAISS_QBS_DISPATCH(0x1223); // 8
188
+ FAISS_QBS_DISPATCH(0x223); // 7
189
+ FAISS_QBS_DISPATCH(0x34); // 7
190
+ FAISS_QBS_DISPATCH(0x133); // 7
191
+ FAISS_QBS_DISPATCH(0x6); // 6
192
+ FAISS_QBS_DISPATCH(0x33); // 6
193
+ FAISS_QBS_DISPATCH(0x123); // 6
194
+ FAISS_QBS_DISPATCH(0x222); // 6
195
+ FAISS_QBS_DISPATCH(0x23); // 5
196
+ FAISS_QBS_DISPATCH(0x5); // 5
197
+ FAISS_QBS_DISPATCH(0x13); // 4
198
+ FAISS_QBS_DISPATCH(0x22); // 4
199
+ FAISS_QBS_DISPATCH(0x4); // 4
200
+ FAISS_QBS_DISPATCH(0x3); // 3
201
+ FAISS_QBS_DISPATCH(0x21); // 3
202
+ FAISS_QBS_DISPATCH(0x2); // 2
203
+ FAISS_QBS_DISPATCH(0x1); // 1
204
+ #undef FAISS_QBS_DISPATCH
207
205
  }
208
206
 
209
- // Default: qbs not known at compile time
210
207
  for_each_block<32>(ntotal2, codes, block_stride, res, [&](size_t j0) {
211
208
  const uint8_t* LUT = LUT0;
212
209
  int qi = qbs;
@@ -215,16 +212,16 @@ void pq4_accumulate_loop_qbs_fixed_scaler_256(
215
212
  int nq = qi & 15;
216
213
  qi >>= 4;
217
214
  res.set_block_origin(i0, j0);
218
- #define FAISS_NQ256_DISPATCH(NQ) \
219
- case NQ: \
220
- pq4_kernel_qbs_256<NQ, KernelSL>(nsq, codes, LUT, res, scaler); \
215
+ #define FAISS_NQ_DISPATCH(NQ) \
216
+ case NQ: \
217
+ PQ4QBSKernel<SL>::template run<NQ>(nsq, codes, LUT, res, scaler); \
221
218
  break
222
219
  switch (nq) {
223
- FAISS_NQ256_DISPATCH(1);
224
- FAISS_NQ256_DISPATCH(2);
225
- FAISS_NQ256_DISPATCH(3);
226
- FAISS_NQ256_DISPATCH(4);
227
- #undef FAISS_NQ256_DISPATCH
220
+ FAISS_NQ_DISPATCH(1);
221
+ FAISS_NQ_DISPATCH(2);
222
+ FAISS_NQ_DISPATCH(3);
223
+ FAISS_NQ_DISPATCH(4);
224
+ #undef FAISS_NQ_DISPATCH
228
225
  default:
229
226
  FAISS_THROW_FMT("accumulate nq=%d not instantiated", nq);
230
227
  }
@@ -1,5 +1,13 @@
1
1
  /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /*
9
+ * Portions Copyright 2026 Arm Limited and/or its affiliates
10
+ * <open-source-office@arm.com>
3
11
  *
4
12
  * This source code is licensed under the MIT license found in the
5
13
  * LICENSE file in the root directory of this source tree.
@@ -23,8 +31,6 @@
23
31
  * dispatching.h's conditional include.
24
32
  */
25
33
 
26
- #if defined(COMPILE_SIMD_AVX512) && defined(__AVX512F__)
27
-
28
34
  #include <cassert>
29
35
 
30
36
  #include <faiss/impl/FaissAssert.h>
@@ -169,17 +175,10 @@ void pq4_accumulate_loop_qbs_fixed_scaler_512(
169
175
 
170
176
  // Fallback for unknown QBS values: use 256-bit path.
171
177
  // This is rare — pq4_preferred_qbs() covers all values above.
172
- if constexpr (Scaler::nscale == 0) {
173
- DummyScaler<SIMDLevel::AVX2> scaler_avx2;
174
- pq4_accumulate_loop_qbs_fixed_scaler_256<SIMDLevel::AVX2>(
175
- qbs, ntotal2, nsq, codes, LUT0, res, scaler_avx2, block_stride);
176
- } else {
177
- NormTableScaler<SIMDLevel::AVX2> scaler_avx2(scaler.scale_int);
178
- pq4_accumulate_loop_qbs_fixed_scaler_256<SIMDLevel::AVX2>(
179
- qbs, ntotal2, nsq, codes, LUT0, res, scaler_avx2, block_stride);
180
- }
178
+ // The caller's AVX512-level scaler gives these instantiations symbol names
179
+ // that the AVX2 TU does not emit.
180
+ pq4_accumulate_loop_qbs_fixed_scaler_simd<SIMDLevel::AVX2>(
181
+ qbs, ntotal2, nsq, codes, LUT0, res, scaler, block_stride);
181
182
  }
182
183
 
183
184
  } // namespace faiss
184
-
185
- #endif // COMPILE_SIMD_AVX512 && __AVX512F__
@@ -1,5 +1,13 @@
1
1
  /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /*
9
+ * Portions Copyright 2026 Arm Limited and/or its affiliates
10
+ * <open-source-office@arm.com>
3
11
  *
4
12
  * This source code is licensed under the MIT license found in the
5
13
  * LICENSE file in the root directory of this source tree.
@@ -12,7 +20,11 @@
12
20
  #include <faiss/impl/FaissAssert.h>
13
21
  #include <faiss/impl/fast_scan/kernels_simd256.h>
14
22
  #include <faiss/impl/fast_scan/kernels_simd512.h>
23
+ #if FAISS_SIMD_TU(ARM_NEON)
24
+ #include <faiss/impl/fast_scan/kernels_neon.h>
25
+ #endif
15
26
  #include <faiss/impl/fast_scan/simd_result_handlers.h>
27
+ #include <faiss/utils/simd_levels.h>
16
28
 
17
29
  namespace faiss {
18
30
 
@@ -20,7 +32,7 @@ using namespace simd_result_handlers;
20
32
 
21
33
  /*
22
34
  * Unified kernel: selects 256-bit vs 512-bit path based on
23
- * compile-time __AVX512F__ guard.
35
+ * compile-time COMPILE_SIMD_AVX512 && __AVX512F__ guard.
24
36
  *
25
37
  * KernelSL selects the SIMD type width used for the inner accumulation
26
38
  * loop. In DD mode the caller passes the dispatch level so the kernel
@@ -37,66 +49,20 @@ void kernel_accumulate_block(
37
49
  const uint8_t* LUT,
38
50
  ResultHandler& res,
39
51
  const Scaler& scaler) {
40
- #ifdef __AVX512F__
52
+ #if FAISS_SIMD_TU(AVX512)
41
53
  if constexpr (
42
54
  KernelSL == SIMDLevel::AVX512 ||
43
55
  KernelSL == SIMDLevel::AVX512_VPOPCNT ||
44
56
  KernelSL == SIMDLevel::AVX512_SPR) {
45
57
  pq4_kernel_qbs_512<NQ>(nsq, codes, LUT, res, scaler);
46
58
  } else {
47
- pq4_kernel_qbs_256<NQ, KernelSL>(nsq, codes, LUT, res, scaler);
59
+ PQ4QBSKernel<KernelSL>::template run<NQ>(nsq, codes, LUT, res, scaler);
48
60
  }
49
61
  #else
50
- pq4_kernel_qbs_256<NQ, KernelSL>(nsq, codes, LUT, res, scaler);
62
+ PQ4QBSKernel<KernelSL>::template run<NQ>(nsq, codes, LUT, res, scaler);
51
63
  #endif
52
64
  }
53
65
 
54
- // handle at most 4 blocks of queries
55
- template <
56
- int QBS,
57
- SIMDLevel KernelSL = SINGLE_SIMD_LEVEL,
58
- class ResultHandler,
59
- class Scaler>
60
- void accumulate_q_4step(
61
- size_t ntotal2,
62
- int nsq,
63
- const uint8_t* codes,
64
- const uint8_t* LUT0,
65
- ResultHandler& res,
66
- const Scaler& scaler,
67
- size_t block_stride) {
68
- constexpr int Q1 = QBS & 15;
69
- constexpr int Q2 = (QBS >> 4) & 15;
70
- constexpr int Q3 = (QBS >> 8) & 15;
71
- constexpr int Q4 = (QBS >> 12) & 15;
72
- constexpr int SQ = Q1 + Q2 + Q3 + Q4;
73
-
74
- for_each_block<32>(ntotal2, codes, block_stride, res, [&](size_t) {
75
- FixedStorageHandler<SQ, 2, KernelSL> res2;
76
- const uint8_t* LUT = LUT0;
77
- kernel_accumulate_block<Q1, KernelSL>(nsq, codes, LUT, res2, scaler);
78
- LUT += Q1 * nsq * 16;
79
- if (Q2 > 0) {
80
- res2.set_block_origin(Q1, 0);
81
- kernel_accumulate_block<Q2, KernelSL>(
82
- nsq, codes, LUT, res2, scaler);
83
- LUT += Q2 * nsq * 16;
84
- }
85
- if (Q3 > 0) {
86
- res2.set_block_origin(Q1 + Q2, 0);
87
- kernel_accumulate_block<Q3, KernelSL>(
88
- nsq, codes, LUT, res2, scaler);
89
- LUT += Q3 * nsq * 16;
90
- }
91
- if (Q4 > 0) {
92
- res2.set_block_origin(Q1 + Q2 + Q3, 0);
93
- kernel_accumulate_block<Q4, KernelSL>(
94
- nsq, codes, LUT, res2, scaler);
95
- }
96
- res2.to_other_handler(res);
97
- });
98
- }
99
-
100
66
  template <
101
67
  int NQ,
102
68
  SIMDLevel KernelSL = SINGLE_SIMD_LEVEL,
@@ -149,82 +115,4 @@ void accumulate(
149
115
  #undef DISPATCH
150
116
  }
151
117
 
152
- template <
153
- SIMDLevel KernelSL = SINGLE_SIMD_LEVEL,
154
- class ResultHandler,
155
- class Scaler>
156
- void pq4_accumulate_loop_qbs_fixed_scaler(
157
- int qbs,
158
- size_t ntotal2,
159
- int nsq,
160
- const uint8_t* codes,
161
- const uint8_t* LUT0,
162
- ResultHandler& res,
163
- const Scaler& scaler,
164
- size_t block_stride = 0) {
165
- assert(nsq % 2 == 0);
166
- assert(is_aligned_pointer(codes));
167
- assert(is_aligned_pointer(LUT0));
168
-
169
- // try out optimized versions
170
- switch (qbs) {
171
- #define DISPATCH(QBS) \
172
- case QBS: \
173
- accumulate_q_4step<QBS, KernelSL>( \
174
- ntotal2, nsq, codes, LUT0, res, scaler, block_stride); \
175
- return;
176
- DISPATCH(0x3333); // 12
177
- DISPATCH(0x2333); // 11
178
- DISPATCH(0x2233); // 10
179
- DISPATCH(0x333); // 9
180
- DISPATCH(0x2223); // 9
181
- DISPATCH(0x233); // 8
182
- DISPATCH(0x1223); // 8
183
- DISPATCH(0x223); // 7
184
- DISPATCH(0x34); // 7
185
- DISPATCH(0x133); // 7
186
- DISPATCH(0x6); // 6
187
- DISPATCH(0x33); // 6
188
- DISPATCH(0x123); // 6
189
- DISPATCH(0x222); // 6
190
- DISPATCH(0x23); // 5
191
- DISPATCH(0x5); // 5
192
- DISPATCH(0x13); // 4
193
- DISPATCH(0x22); // 4
194
- DISPATCH(0x4); // 4
195
- DISPATCH(0x3); // 3
196
- DISPATCH(0x21); // 3
197
- DISPATCH(0x2); // 2
198
- DISPATCH(0x1); // 1
199
- #undef DISPATCH
200
- }
201
-
202
- // default implementation where qbs is not known at compile time
203
- for_each_block<32>(ntotal2, codes, block_stride, res, [&](size_t j0) {
204
- const uint8_t* LUT = LUT0;
205
- int qi = qbs;
206
- int i0 = 0;
207
- while (qi) {
208
- int nq = qi & 15;
209
- qi >>= 4;
210
- res.set_block_origin(i0, j0);
211
- #define DISPATCH(NQ) \
212
- case NQ: \
213
- kernel_accumulate_block<NQ, KernelSL>(nsq, codes, LUT, res, scaler); \
214
- break
215
- switch (nq) {
216
- DISPATCH(1);
217
- DISPATCH(2);
218
- DISPATCH(3);
219
- DISPATCH(4);
220
- #undef DISPATCH
221
- default:
222
- FAISS_THROW_FMT("accumulate nq=%d not instantiated", nq);
223
- }
224
- i0 += nq;
225
- LUT += nq * nsq * 16;
226
- }
227
- });
228
- }
229
-
230
118
  } // namespace faiss
@@ -1,5 +1,13 @@
1
1
  /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /*
9
+ * Portions Copyright 2026 Arm Limited and/or its affiliates
10
+ * <open-source-office@arm.com>
3
11
  *
4
12
  * This source code is licensed under the MIT license found in the
5
13
  * LICENSE file in the root directory of this source tree.
@@ -20,8 +28,8 @@
20
28
  * #define THE_LEVEL_TO_DISPATCH SIMDLevel::AVX2
21
29
  * #include <faiss/impl/fast_scan/dispatching.h>
22
30
  *
23
- * Kernel helpers come from accumulate_loops.h (search_1 multi-BB path
24
- * and QBS 256-bit path) and accumulate_loops_512.h (QBS 512-bit path,
31
+ * Kernel helpers come from accumulate_loops.h (search_1 multi-BB path and
32
+ * SIMD-level-selected QBS path) and accumulate_loops_512.h (QBS 512-bit path,
25
33
  * AVX512 TU only).
26
34
  */
27
35
 
@@ -35,7 +43,7 @@
35
43
  #include <faiss/impl/fast_scan/fast_scan.h>
36
44
  #include <faiss/utils/simd_levels.h>
37
45
 
38
- #if defined(COMPILE_SIMD_AVX512) && defined(__AVX512F__)
46
+ #if FAISS_SIMD_TU(AVX512)
39
47
  #include <faiss/impl/fast_scan/accumulate_loops_512.h>
40
48
  #endif
41
49
 
@@ -107,7 +115,7 @@ struct ScannerMixIn : FastScanCodeScanner {
107
115
  const uint8_t* LUT,
108
116
  int pq2x4_scale,
109
117
  size_t block_stride) override {
110
- #if defined(COMPILE_SIMD_AVX512) && defined(__AVX512F__)
118
+ #if FAISS_SIMD_TU(AVX512)
111
119
  constexpr bool use_avx512_qbs =
112
120
  (THE_LEVEL_TO_DISPATCH == SIMDLevel::AVX512 ||
113
121
  THE_LEVEL_TO_DISPATCH == SIMDLevel::AVX512_SPR);
@@ -115,18 +123,14 @@ struct ScannerMixIn : FastScanCodeScanner {
115
123
  constexpr bool use_avx512_qbs = false;
116
124
  #endif
117
125
  if constexpr (use_avx512_qbs) {
118
- // AMD Zen 4 / Zen 4c ("Bergamo", family 0x19) split 512-bit
119
- // ops over a 256-bit datapath, so the 512-bit QBS kernel yields no
120
- // throughput gain but pays extra per-block LUT-assembly and
121
- // cross-lane reduction overhead (measured ~14% search regression
122
- // for PQ8x4fs / PQ16x4fs). Route those CPUs to the 256-bit (AVX2)
123
- // QBS kernel instead -- same output, no downside on Zen 4. This is
124
- // a process-constant runtime branch, hoisted out of the inner
125
- // accumulate loop. Intel AVX-512 keeps the 512-bit kernel.
126
+ // Zen 4 runs 512-bit ops on a 256-bit datapath, so the 512-bit QBS
127
+ // kernel is slower there; use the AVX2 kernel.
126
128
  if (SIMDConfig::avx512_split) {
129
+ // THE_LEVEL_TO_DISPATCH scalers give these AVX2-loop
130
+ // instantiations symbol names that the AVX2 TU does not emit.
127
131
  if (pq2x4_scale) {
128
- NormTableScaler<SIMDLevel::AVX2> scaler(pq2x4_scale);
129
- pq4_accumulate_loop_qbs_fixed_scaler_256<SIMDLevel::AVX2>(
132
+ NormTableScaler<THE_LEVEL_TO_DISPATCH> scaler(pq2x4_scale);
133
+ pq4_accumulate_loop_qbs_fixed_scaler_simd<SIMDLevel::AVX2>(
130
134
  qbs,
131
135
  nb,
132
136
  nsq,
@@ -136,8 +140,8 @@ struct ScannerMixIn : FastScanCodeScanner {
136
140
  scaler,
137
141
  block_stride);
138
142
  } else {
139
- DummyScaler<SIMDLevel::AVX2> dummy;
140
- pq4_accumulate_loop_qbs_fixed_scaler_256<SIMDLevel::AVX2>(
143
+ DummyScaler<THE_LEVEL_TO_DISPATCH> dummy;
144
+ pq4_accumulate_loop_qbs_fixed_scaler_simd<SIMDLevel::AVX2>(
141
145
  qbs,
142
146
  nb,
143
147
  nsq,
@@ -174,7 +178,8 @@ struct ScannerMixIn : FastScanCodeScanner {
174
178
  } else {
175
179
  if (pq2x4_scale) {
176
180
  NormTableScaler<THE_LEVEL_TO_DISPATCH> scaler(pq2x4_scale);
177
- pq4_accumulate_loop_qbs_fixed_scaler_256<THE_LEVEL_TO_DISPATCH>(
181
+ pq4_accumulate_loop_qbs_fixed_scaler_simd<
182
+ THE_LEVEL_TO_DISPATCH>(
178
183
  qbs,
179
184
  nb,
180
185
  nsq,
@@ -185,7 +190,8 @@ struct ScannerMixIn : FastScanCodeScanner {
185
190
  block_stride);
186
191
  } else {
187
192
  DummyScaler<THE_LEVEL_TO_DISPATCH> dummy;
188
- pq4_accumulate_loop_qbs_fixed_scaler_256<THE_LEVEL_TO_DISPATCH>(
193
+ pq4_accumulate_loop_qbs_fixed_scaler_simd<
194
+ THE_LEVEL_TO_DISPATCH>(
189
195
  qbs,
190
196
  nb,
191
197
  nsq,
@@ -16,6 +16,11 @@
16
16
 
17
17
  namespace faiss {
18
18
 
19
+ void SIMDResultHandlerToFloat::end() {
20
+ normalizers = nullptr;
21
+ scan_cnt = 0;
22
+ }
23
+
19
24
  using namespace simd_result_handlers;
20
25
 
21
26
  /***************************************************************