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,12 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifdef COMPILE_SIMD_AVX2
9
-
10
8
  #define THE_SIMD_LEVEL SIMDLevel::AVX2
11
9
  // NOLINTBEGIN(facebook-hte-InlineHeader,facebook-unused-include-check)
12
10
  #include <faiss/utils/hamming_distance/hamming_computer-avx2.h>
13
11
  #include <faiss/utils/hamming_distance/hamming_impl.h>
14
12
  // NOLINTEND(facebook-hte-InlineHeader,facebook-unused-include-check)
15
-
16
- #endif // COMPILE_SIMD_AVX2
@@ -5,11 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifdef COMPILE_SIMD_AVX512
9
-
10
8
  #define THE_SIMD_LEVEL SIMDLevel::AVX512
11
9
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
12
10
  #include <faiss/utils/hamming_distance/hamming_computer-avx512.h>
13
11
  #include <faiss/utils/hamming_distance/hamming_impl.h>
14
-
15
- #endif // COMPILE_SIMD_AVX512
@@ -5,8 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifdef COMPILE_SIMD_AVX512_VPOPCNT
9
-
10
8
  #define THE_SIMD_LEVEL SIMDLevel::AVX512_VPOPCNT
11
9
  #include <faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h>
12
10
  #include <faiss/utils/hamming_distance/hamming_impl.h>
@@ -20,5 +18,3 @@
20
18
  // Fails the build if the batch path stops being selected for this computer.
21
19
  static_assert(faiss::has_hamming_batch<
22
20
  faiss::HammingComputer20_tpl<faiss::SIMDLevel::AVX512_VPOPCNT>>);
23
-
24
- #endif // COMPILE_SIMD_AVX512_VPOPCNT
@@ -103,12 +103,40 @@ struct HammingComputerDefault_tpl<SIMDLevel::AVX512> {
103
103
  remainder8 = code_size % 8;
104
104
  }
105
105
 
106
+ /// No VPOPCNTDQ at this level: count the bits of each nibble with a
107
+ /// 16-entry table (vpshufb), then sum the bytes per 64-bit lane (vpsadbw).
108
+ /// The partial last block is a masked load, so no byte past the code is
109
+ /// read.
106
110
  int hamming(const uint8_t* b8) const {
107
- const uint64_t* a64 = reinterpret_cast<const uint64_t*>(a8);
108
- const uint64_t* b64 = reinterpret_cast<const uint64_t*>(b8);
109
-
110
- return hamming_popcount_tail(
111
- a64, b64, 0, quotient8, a8, b8, remainder8);
111
+ const int code_size = quotient8 * 8 + remainder8;
112
+ const __m512i lut = _mm512_broadcast_i32x4(
113
+ _mm_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4));
114
+ const __m512i low4 = _mm512_set1_epi8(0x0f);
115
+ const auto count = [&](__m512i x) {
116
+ const __m512i lo = _mm512_and_si512(x, low4);
117
+ const __m512i hi = _mm512_and_si512(_mm512_srli_epi16(x, 4), low4);
118
+ const __m512i c = _mm512_add_epi8(
119
+ _mm512_shuffle_epi8(lut, lo), _mm512_shuffle_epi8(lut, hi));
120
+ return _mm512_sad_epu8(c, _mm512_setzero_si512());
121
+ };
122
+ __m512i accu = _mm512_setzero_si512();
123
+ int i = 0;
124
+ for (; i + 64 <= code_size; i += 64) {
125
+ accu = _mm512_add_epi64(
126
+ accu,
127
+ count(_mm512_xor_si512(
128
+ _mm512_loadu_si512(a8 + i),
129
+ _mm512_loadu_si512(b8 + i))));
130
+ }
131
+ if (i < code_size) {
132
+ const __mmask64 mask = _bzhi_u64(~uint64_t(0), code_size - i);
133
+ accu = _mm512_add_epi64(
134
+ accu,
135
+ count(_mm512_xor_si512(
136
+ _mm512_maskz_loadu_epi8(mask, a8 + i),
137
+ _mm512_maskz_loadu_epi8(mask, b8 + i))));
138
+ }
139
+ return static_cast<int>(_mm512_reduce_add_epi64(accu));
112
140
  }
113
141
 
114
142
  inline int get_code_size() const {
@@ -186,40 +186,25 @@ struct HammingComputerDefault_tpl<SIMDLevel::AVX512_VPOPCNT> {
186
186
  remainder8 = code_size % 8;
187
187
  }
188
188
 
189
+ /// One vector accumulator, reduced once. The partial last block is a
190
+ /// masked load, so no byte past the code is read.
189
191
  int hamming(const uint8_t* b8) const {
190
- int accu = 0;
191
-
192
- const uint64_t* a64 = reinterpret_cast<const uint64_t*>(a8);
193
- const uint64_t* b64 = reinterpret_cast<const uint64_t*>(b8);
194
-
192
+ const int code_size = quotient8 * 8 + remainder8;
193
+ __m512i accu = _mm512_setzero_si512();
195
194
  int i = 0;
196
- int quotient64 = quotient8 / 8;
197
- for (; i < quotient64; ++i) {
198
- __m512i vxor = _mm512_xor_si512(
199
- _mm512_loadu_si512(&a64[i * 8]),
200
- _mm512_loadu_si512(&b64[i * 8]));
201
- __m512i vpcnt = _mm512_popcnt_epi64(vxor);
202
- accu += _mm512_reduce_add_epi32(vpcnt);
195
+ for (; i + 64 <= code_size; i += 64) {
196
+ const __m512i vxor = _mm512_xor_si512(
197
+ _mm512_loadu_si512(a8 + i), _mm512_loadu_si512(b8 + i));
198
+ accu = _mm512_add_epi64(accu, _mm512_popcnt_epi64(vxor));
203
199
  }
204
- i *= 8;
205
-
206
- // Handle 4-word (256-bit) remainder with VPOPCNTDQ VL
207
- if (i + 4 <= quotient8) {
208
- __m256i vxor = _mm256_xor_si256(
209
- _mm256_loadu_si256((const __m256i*)&a64[i]),
210
- _mm256_loadu_si256((const __m256i*)&b64[i]));
211
- __m256i vpcnt = _mm256_popcnt_epi64(vxor);
212
- __m128i lo = _mm256_castsi256_si128(vpcnt);
213
- __m128i hi = _mm256_extracti128_si256(vpcnt, 1);
214
- __m128i sum = _mm_add_epi64(lo, hi);
215
- accu += static_cast<int>(
216
- _mm_extract_epi64(sum, 0) + _mm_extract_epi64(sum, 1));
217
- i += 4;
200
+ if (i < code_size) {
201
+ const __mmask64 mask = _bzhi_u64(~uint64_t(0), code_size - i);
202
+ const __m512i vxor = _mm512_xor_si512(
203
+ _mm512_maskz_loadu_epi8(mask, a8 + i),
204
+ _mm512_maskz_loadu_epi8(mask, b8 + i));
205
+ accu = _mm512_add_epi64(accu, _mm512_popcnt_epi64(vxor));
218
206
  }
219
-
220
- accu += hamming_popcount_tail(
221
- a64, b64, i, quotient8, a8, b8, remainder8);
222
- return accu;
207
+ return static_cast<int>(_mm512_reduce_add_epi64(accu));
223
208
  }
224
209
 
225
210
  inline int get_code_size() const {
@@ -16,8 +16,6 @@
16
16
  // hamming_computer-generic.h. SIMDLevel::ARM_NEON specializations for the
17
17
  // ISA-varying HammingComputer and GenHammingComputer structs live in this file.
18
18
 
19
- #ifdef __aarch64__
20
-
21
19
  #include <arm_neon.h>
22
20
 
23
21
  #include <cassert>
@@ -318,5 +316,3 @@ struct GenHammingComputerM8_tpl<SIMDLevel::ARM_NEON> {
318
316
  } // namespace faiss
319
317
 
320
318
  #endif
321
-
322
- #endif
@@ -102,7 +102,8 @@ void hammings_knn_hc_impl(
102
102
  CMax<hamdis_t, int64_t>, \
103
103
  NB, \
104
104
  BD, \
105
- HammingComputer>:: \
105
+ HammingComputer, \
106
+ THE_SIMD_LEVEL>:: \
106
107
  addn(j1 - j0, hc, bs2_, k, bh_val_, bh_ids_, sel); \
107
108
  break;
108
109
 
@@ -5,11 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifdef COMPILE_SIMD_ARM_NEON
9
-
10
8
  #define THE_SIMD_LEVEL SIMDLevel::ARM_NEON
11
9
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
12
10
  #include <faiss/utils/hamming_distance/hamming_computer-neon.h>
13
11
  #include <faiss/utils/hamming_distance/hamming_impl.h>
14
-
15
- #endif // COMPILE_SIMD_ARM_NEON
@@ -5,11 +5,7 @@
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
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
12
10
  #include <faiss/utils/hamming_distance/hamming_computer-rvv.h>
13
11
  #include <faiss/utils/hamming_distance/hamming_impl.h>
14
-
15
- #endif // COMPILE_SIMD_RISCV_RVV
@@ -53,10 +53,14 @@ namespace pq_code_distance {
53
53
  *********************************************************************/
54
54
 
55
55
  /// Scalar PQ code distance implementation.
56
- /// Templated only on decoder type, independent of SIMD level.
57
56
  /// Used directly by non-PQDecoder8 decoders (PQDecoder16,
58
57
  /// PQDecoderGeneric) and as fallback for PQDecoder8 at NONE/NEON.
59
- template <typename PQDecoderT>
58
+ // SL keeps each SIMD-level TU's instantiation a distinct symbol. Without it
59
+ // the linker merges them and may keep one compiled with -mavx512*, which
60
+ // then runs on the AVX2 path and raises SIGILL on CPUs without AVX512.
61
+ // The default keeps callers outside faiss that name only the decoder (e.g.
62
+ // unicorn/features/encoders/PQFSTable.h) compiling; faiss passes SL itself.
63
+ template <typename PQDecoderT, SIMDLevel SL = SIMDLevel::NONE>
60
64
  struct PQCodeDistanceScalar {
61
65
  using PQDecoder = PQDecoderT;
62
66
 
@@ -160,7 +164,7 @@ struct PQCodeDistance {
160
164
  if constexpr (std::is_same_v<PQDecoderT, PQDecoder8>) {
161
165
  return pq_code_distance_single_impl<SL>(M, nbits, sim_table, code);
162
166
  } else {
163
- return PQCodeDistanceScalar<PQDecoderT>::distance_single_code(
167
+ return PQCodeDistanceScalar<PQDecoderT, SL>::distance_single_code(
164
168
  M, nbits, sim_table, code);
165
169
  }
166
170
  }
@@ -191,7 +195,7 @@ struct PQCodeDistance {
191
195
  result2,
192
196
  result3);
193
197
  } else {
194
- PQCodeDistanceScalar<PQDecoderT>::distance_four_codes(
198
+ PQCodeDistanceScalar<PQDecoderT, SL>::distance_four_codes(
195
199
  M,
196
200
  nbits,
197
201
  sim_table,
@@ -25,34 +25,9 @@ inline void prefetch_L3(const void* address) {
25
25
  _mm_prefetch((const char*)address, _MM_HINT_T2);
26
26
  }
27
27
 
28
- #elif defined(__aarch64__)
29
-
30
- // ARM64
31
-
32
- #ifdef _MSC_VER
33
-
34
- // todo: arm on MSVC
35
- inline void prefetch_L1(const void* address) {}
36
- inline void prefetch_L2(const void* address) {}
37
- inline void prefetch_L3(const void* address) {}
38
-
39
- #else
40
- // arm on non-MSVC
41
-
42
- inline void prefetch_L1(const void* address) {
43
- __builtin_prefetch(address, 0, 3);
44
- }
45
- inline void prefetch_L2(const void* address) {
46
- __builtin_prefetch(address, 0, 2);
47
- }
48
- inline void prefetch_L3(const void* address) {
49
- __builtin_prefetch(address, 0, 1);
50
- }
51
- #endif
52
-
53
28
  #else
54
29
 
55
- // a generic platform
30
+ // other platforms, including ARM64
56
31
 
57
32
  #ifdef _MSC_VER
58
33
 
@@ -60,6 +60,19 @@ void round_tab(const float* tab, size_t n, float a, float bi, T* tab_out) {
60
60
 
61
61
  } // anonymous namespace
62
62
 
63
+ float fastscan_lut_scale(
64
+ float max_column_span,
65
+ float max_sum_span,
66
+ size_t n_rounded_terms) {
67
+ const float headroom = 0.5f * float(n_rounded_terms);
68
+ const float sum_budget = 65535.0f - headroom;
69
+ const float a = std::min(
70
+ max_column_span > 0 ? 255.0f / max_column_span : HUGE_VALF,
71
+ (max_sum_span > 0 && sum_budget > 0) ? sum_budget / max_sum_span
72
+ : HUGE_VALF);
73
+ return std::isfinite(a) ? a : 0.0f;
74
+ }
75
+
63
76
  void round_uint8_per_column(
64
77
  float* tab,
65
78
  size_t n,
@@ -67,6 +80,7 @@ void round_uint8_per_column(
67
80
  float* a_out,
68
81
  float* b_out) {
69
82
  float max_span = 0;
83
+ float total_span = 0;
70
84
  std::vector<float> mins(n);
71
85
  for (size_t i = 0; i < n; i++) {
72
86
  mins[i] = tab_min(tab + i * d, d);
@@ -74,8 +88,9 @@ void round_uint8_per_column(
74
88
  if (span > max_span) {
75
89
  max_span = span;
76
90
  }
91
+ total_span += span;
77
92
  }
78
- float a = max_span > 0 ? 255.0f / max_span : 0.0f;
93
+ float a = fastscan_lut_scale(max_span, total_span, n);
79
94
  float b = 0;
80
95
  for (size_t i = 0; i < n; i++) {
81
96
  b += mins[i];
@@ -97,6 +112,7 @@ void round_uint8_per_column_multi(
97
112
  float* a_out,
98
113
  float* b_out) {
99
114
  float max_span = 0;
115
+ float total_span = 0;
100
116
  std::vector<float> mins(n);
101
117
  for (size_t i = 0; i < n; i++) {
102
118
  float min_i = HUGE_VAL;
@@ -110,8 +126,9 @@ void round_uint8_per_column_multi(
110
126
  if (span > max_span) {
111
127
  max_span = span;
112
128
  }
129
+ total_span += span;
113
130
  }
114
- float a = max_span > 0 ? 255.0f / max_span : 0.0f;
131
+ float a = fastscan_lut_scale(max_span, total_span, n);
115
132
  float b = 0;
116
133
  for (size_t i = 0; i < n; i++) {
117
134
  b += mins[i];
@@ -155,12 +172,7 @@ void quantize_LUT_and_bias(
155
172
  max_span_dis += span;
156
173
  b += mins[i];
157
174
  }
158
- a = std::min(
159
- max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
160
- max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
161
- if (!std::isfinite(a)) {
162
- a = 0.0f;
163
- }
175
+ a = fastscan_lut_scale(max_span_LUT, max_span_dis, M);
164
176
 
165
177
  for (size_t i = 0; i < M; i++) {
166
178
  round_tab(LUT + i * ksub, ksub, a, mins[i], LUTq + i * ksub);
@@ -180,12 +192,7 @@ void quantize_LUT_and_bias(
180
192
  max_span_dis += span;
181
193
  b += mins[i];
182
194
  }
183
- a = std::min(
184
- max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
185
- max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
186
- if (!std::isfinite(a)) {
187
- a = 0.0f;
188
- }
195
+ a = fastscan_lut_scale(max_span_LUT, max_span_dis, M);
189
196
  b += bias_min;
190
197
 
191
198
  for (size_t i = 0; i < M; i++) {
@@ -219,12 +226,7 @@ void quantize_LUT_and_bias(
219
226
  b = std::min(b, b2j);
220
227
  }
221
228
 
222
- a = std::min(
223
- max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
224
- max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
225
- if (!std::isfinite(a)) {
226
- a = 0.0f;
227
- }
229
+ a = fastscan_lut_scale(max_span_LUT, max_span_dis, M);
228
230
 
229
231
  ij = 0;
230
232
  size_t ij_2 = 0;
@@ -266,13 +268,15 @@ void quantize_LUT_and_bias(
266
268
  }
267
269
 
268
270
  float max_span = -HUGE_VAL;
271
+ float total_span = 0;
269
272
  b = 0;
270
273
  for (size_t i = 0; i < M; i++) {
271
274
  float span = maxs[i] - mins[i];
272
275
  max_span = std::max(max_span, span);
276
+ total_span += span;
273
277
  b += mins[i];
274
278
  }
275
- a = max_span > 0 ? 255.0f / max_span : 0.0f;
279
+ a = fastscan_lut_scale(max_span, total_span, M);
276
280
  ij = 0;
277
281
  size_t ij_2 = 0;
278
282
  for (size_t j = 0; j < nprobe; j++) {
@@ -321,12 +325,7 @@ void aq_quantize_LUT_and_bias(
321
325
  max_span_dis += (i >= M - M_norm ? span * norm_scale : span);
322
326
  b += mins[i];
323
327
  }
324
- a = std::min(
325
- max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
326
- max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
327
- if (!std::isfinite(a)) {
328
- a = 0.0f;
329
- }
328
+ a = fastscan_lut_scale(max_span_LUT, max_span_dis, M);
330
329
  b += bias_min;
331
330
 
332
331
  for (size_t i = 0; i < M; i++) {
@@ -7,6 +7,8 @@
7
7
 
8
8
  #pragma once
9
9
 
10
+ #include <cstddef>
11
+
10
12
  #include <cstdint>
11
13
  #include <cstdio>
12
14
 
@@ -25,6 +27,15 @@ namespace faiss {
25
27
 
26
28
  namespace quantize_lut {
27
29
 
30
+ /** Scale for a fast scan LUT, bounding both the uint8 entry and the uint16
31
+ * sum the kernel accumulates. `n_rounded_terms` is how many rounded values
32
+ * land in one accumulator: the columns, plus one for a rounded bias term.
33
+ */
34
+ float fastscan_lut_scale(
35
+ float max_column_span,
36
+ float max_sum_span,
37
+ size_t n_rounded_terms);
38
+
28
39
  /* affine quantizer, a and b are the affine coefficients, marginalize over d
29
40
  *
30
41
  * @param tab input/output, size (n, d)
@@ -53,6 +53,28 @@ BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount(
53
53
  size_t size,
54
54
  size_t qb);
55
55
 
56
+ /// Four independent AND-dot-product/popcount pairs for a four-plane query.
57
+ /// Query contains 4 * size bytes; each data pointer contains `size` bytes.
58
+ /// Byte-aligned buffers and arbitrary byte counts are supported.
59
+ template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
60
+ inline void bitwise_q4_batch_4(
61
+ const uint8_t* query,
62
+ const uint8_t* const* data,
63
+ size_t size,
64
+ BitwiseAndDotProductResult* results) {
65
+ for (size_t i = 0; i < 4; ++i) {
66
+ results[i] = bitwise_and_dot_product_with_popcount<SL>(
67
+ query, data[i], size, 4);
68
+ }
69
+ }
70
+
71
+ template <>
72
+ void bitwise_q4_batch_4<SIMDLevel::AVX512_VPOPCNT>(
73
+ const uint8_t* query,
74
+ const uint8_t* const* data,
75
+ size_t size,
76
+ BitwiseAndDotProductResult* results);
77
+
56
78
  /**
57
79
  * Compute dot product between query and binary data using popcount on XOR.
58
80
  *
@@ -140,9 +162,11 @@ inline uint64_t bitwise_and_dot_product<SIMDLevel::NONE>(
140
162
  uint64_t sum = 0;
141
163
  size_t offset = 0;
142
164
  for (size_t step = 64 / 8; offset + step <= size; offset += step) {
143
- const auto yv = *(const uint64_t*)(data + offset);
165
+ uint64_t yv;
166
+ std::memcpy(&yv, data + offset, sizeof(yv));
144
167
  for (int j = 0; j < qb; j++) {
145
- const auto qv = *(const uint64_t*)(query + j * size + offset);
168
+ uint64_t qv;
169
+ std::memcpy(&qv, query + j * size + offset, sizeof(qv));
146
170
  sum += popcount64(qv & yv) << j;
147
171
  }
148
172
  }
@@ -167,10 +191,12 @@ inline BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
167
191
  uint64_t popcount_sum = 0;
168
192
  size_t offset = 0;
169
193
  for (size_t step = 64 / 8; offset + step <= size; offset += step) {
170
- const auto yv = *(const uint64_t*)(data + offset);
194
+ uint64_t yv;
195
+ std::memcpy(&yv, data + offset, sizeof(yv));
171
196
  popcount_sum += popcount64(yv);
172
197
  for (int j = 0; j < qb; j++) {
173
- const auto qv = *(const uint64_t*)(query + j * size + offset);
198
+ uint64_t qv;
199
+ std::memcpy(&qv, query + j * size + offset, sizeof(qv));
174
200
  dot_product += popcount64(qv & yv) << j;
175
201
  }
176
202
  }
@@ -194,9 +220,11 @@ inline uint64_t bitwise_xor_dot_product<SIMDLevel::NONE>(
194
220
  uint64_t sum = 0;
195
221
  size_t offset = 0;
196
222
  for (size_t step = 64 / 8; offset + step <= size; offset += step) {
197
- const auto yv = *(const uint64_t*)(data + offset);
223
+ uint64_t yv;
224
+ std::memcpy(&yv, data + offset, sizeof(yv));
198
225
  for (int j = 0; j < qb; j++) {
199
- const auto qv = *(const uint64_t*)(query + j * size + offset);
226
+ uint64_t qv;
227
+ std::memcpy(&qv, query + j * size + offset, sizeof(qv));
200
228
  sum += popcount64(qv ^ yv) << j;
201
229
  }
202
230
  }
@@ -215,7 +243,8 @@ inline uint64_t popcount<SIMDLevel::NONE>(const uint8_t* data, size_t size) {
215
243
  uint64_t sum = 0;
216
244
  size_t offset = 0;
217
245
  for (size_t step = 64 / 8; offset + step <= size; offset += step) {
218
- const auto yv = *(const uint64_t*)(data + offset);
246
+ uint64_t yv;
247
+ std::memcpy(&yv, data + offset, sizeof(yv));
219
248
  sum += popcount64(yv);
220
249
  }
221
250
  for (; offset < size; ++offset) {
@@ -332,16 +361,12 @@ inline void quantize_query_values<SIMDLevel::NONE>(
332
361
  /*********************************************************
333
362
  * Multi-bit RaBitQ inner product kernels.
334
363
  *
335
- * Compute: sum_i rotated_q[i] * ((sign_bit_i << ex_bits) + ex_code_val_i + cb)
364
+ * Score = sum_i rotated_q[i] * ((sign_i << ex_bits) + ex_i + cb)
336
365
  *
337
- * Strategy:
338
- * ex_bits == 1: Specialized kernel — both sign_bits and ex_code are
339
- * 1-bit-per-dim packed, enabling direct bit→mask→float
340
- * conversion with zero per-element extraction.
341
- * ex_bits >= 2: Bit-plane decomposition (BMI2 required) — PEXT extracts
342
- * each bit plane in one instruction, then the same
343
- * bit→mask→float kernel computes each plane's dot product.
344
- * Fallback: Scalar extraction via 64-bit window read + shift + mask.
366
+ * ex_bits == 1: bits map straight to floats. No extraction.
367
+ * ex_bits 2..7: BMI2 PEXT extracts each bit plane.
368
+ * ex_bits == 8: whole bytes. No extraction and no BMI2.
369
+ * Fallback: scalar math reads one code at a time.
345
370
  *********************************************************/
346
371
  namespace faiss::rabitq::multibit {
347
372
 
@@ -357,6 +382,16 @@ inline float ip_scalar(
357
382
  size_t ex_bits,
358
383
  float cb) {
359
384
  float result = 0.0f;
385
+ if (ex_bits == 8) {
386
+ // RBQ9 is byte-aligned, including the last dimension. Do not require
387
+ // trailing factor bytes for the scalar reference or SIMD tail.
388
+ for (size_t i = start; i < d; ++i) {
389
+ const int sb = (sign_bits[i / 8] >> (i % 8)) & 1;
390
+ result += rotated_q[i] *
391
+ (static_cast<float>((sb << 8) + ex_code[i]) + cb);
392
+ }
393
+ return result;
394
+ }
360
395
  const int sign_shift = static_cast<int>(ex_bits);
361
396
  const uint64_t code_mask = (1ULL << ex_bits) - 1;
362
397
  for (size_t i = start; i < d; i++) {
@@ -6,8 +6,7 @@
6
6
  */
7
7
 
8
8
  #include <faiss/utils/distances.h>
9
-
10
- #ifdef __aarch64__
9
+ #include <faiss/utils/simd_impl/masked_sum.h>
11
10
 
12
11
  #include <arm_neon.h>
13
12
  #include <limits>
@@ -41,6 +40,14 @@ void fvec_madd<SIMDLevel::ARM_NEON>(
41
40
  c[i] = a[i] + bf * b[i];
42
41
  }
43
42
 
43
+ template <>
44
+ float fvec_masked_sum<SIMDLevel::ARM_NEON>(
45
+ const float* x,
46
+ const uint8_t* bits,
47
+ size_t d) {
48
+ return masked_sum<SIMDLevel::ARM_NEON>(x, bits, d);
49
+ }
50
+
44
51
  template <>
45
52
  void fvec_L2sqr_ny_transposed<SIMDLevel::ARM_NEON>(
46
53
  float* dis,
@@ -150,5 +157,3 @@ int fvec_madd_and_argmin<SIMDLevel::ARM_NEON>(
150
157
  }
151
158
 
152
159
  } // namespace faiss
153
-
154
- #endif // __aarch64__
@@ -758,9 +758,11 @@ size_t fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::ARM_SVE>(
758
758
  return current_min_idx;
759
759
  }
760
760
 
761
- template <>
762
- void exhaustive_L2sqr_blas_cmax<SIMDLevel::ARM_SVE>(
763
- const float* x,
761
+ namespace {
762
+
763
+ template <class QueryTiles>
764
+ void exhaustive_L2sqr_blas_cmax_sve(
765
+ QueryTiles& queries,
764
766
  const float* y,
765
767
  size_t d,
766
768
  size_t nx,
@@ -779,7 +781,7 @@ void exhaustive_L2sqr_blas_cmax<SIMDLevel::ARM_SVE>(
779
781
  std::unique_ptr<float[]> x_norms(new float[nx]);
780
782
  std::unique_ptr<float[]> del2;
781
783
 
782
- fvec_norms_L2sqr(x_norms.get(), x, d, nx);
784
+ queries.prepare_norms(nx, x_norms.get());
783
785
 
784
786
  const size_t lanes = svcntw();
785
787
 
@@ -795,6 +797,8 @@ void exhaustive_L2sqr_blas_cmax<SIMDLevel::ARM_SVE>(
795
797
  if (i1 > nx)
796
798
  i1 = nx;
797
799
 
800
+ const float* xt = queries.tile(i0, i1, x_norms.get());
801
+
798
802
  res.begin_multiple(i0, i1);
799
803
 
800
804
  for (size_t j0 = 0; j0 < ny; j0 += bs_y) {
@@ -813,7 +817,7 @@ void exhaustive_L2sqr_blas_cmax<SIMDLevel::ARM_SVE>(
813
817
  &one,
814
818
  y + j0 * d,
815
819
  &di,
816
- x + i0 * d,
820
+ xt,
817
821
  &di,
818
822
  &zero,
819
823
  ip_block.get(),
@@ -938,4 +942,32 @@ void exhaustive_L2sqr_blas_cmax<SIMDLevel::ARM_SVE>(
938
942
  }
939
943
  }
940
944
 
945
+ } // namespace
946
+
947
+ template <>
948
+ void exhaustive_L2sqr_blas_cmax<SIMDLevel::ARM_SVE>(
949
+ const float* x,
950
+ const float* y,
951
+ size_t d,
952
+ size_t nx,
953
+ size_t ny,
954
+ Top1BlockResultHandler<CMax<float, int64_t>>& res,
955
+ const float* y_norms) {
956
+ Fp32QueryTiles queries{x, d};
957
+ exhaustive_L2sqr_blas_cmax_sve(queries, y, d, nx, ny, res, y_norms);
958
+ }
959
+
960
+ template <>
961
+ void exhaustive_L2sqr_blas_cmax_fp16<SIMDLevel::ARM_SVE>(
962
+ const uint16_t* x,
963
+ const float* y,
964
+ size_t d,
965
+ size_t nx,
966
+ size_t ny,
967
+ Top1BlockResultHandler<CMax<float, int64_t>>& res,
968
+ const float* y_norms) {
969
+ Fp16QueryTiles queries(x, d, nx);
970
+ exhaustive_L2sqr_blas_cmax_sve(queries, y, d, nx, ny, res, y_norms);
971
+ }
972
+
941
973
  } // namespace faiss