faiss 0.6.2 → 0.6.4

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/lib/faiss/version.rb +1 -1
  4. data/vendor/faiss/faiss/AutoTune.cpp +3 -1
  5. data/vendor/faiss/faiss/Clustering.cpp +9 -1
  6. data/vendor/faiss/faiss/Clustering.h +8 -0
  7. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  8. data/vendor/faiss/faiss/Index.h +2 -2
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  10. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  11. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
  12. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
  13. data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
  14. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  15. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
  16. data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
  17. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  18. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  19. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  20. data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
  21. data/vendor/faiss/faiss/IndexFlat.h +2 -2
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
  23. data/vendor/faiss/faiss/IndexHNSW.h +31 -7
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
  25. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
  27. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  28. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  29. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  30. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  31. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  32. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  33. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  34. data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
  35. data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
  36. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  37. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  38. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  39. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  40. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  41. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  42. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  43. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  44. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  45. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  46. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  47. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  48. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  49. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  50. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  51. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  52. data/vendor/faiss/faiss/IndexShards.cpp +5 -5
  53. data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
  54. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  55. data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
  56. data/vendor/faiss/faiss/SuperKMeans.h +33 -2
  57. data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
  58. data/vendor/faiss/faiss/VectorTransform.h +3 -0
  59. data/vendor/faiss/faiss/clone_index.cpp +8 -0
  60. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
  63. data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
  64. data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
  65. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
  66. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  67. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  68. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  69. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  70. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  72. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  73. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  74. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
  75. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
  76. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  77. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  78. data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
  79. data/vendor/faiss/faiss/impl/HNSW.h +46 -7
  80. data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
  81. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  82. data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
  83. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  84. data/vendor/faiss/faiss/impl/Panorama.h +20 -9
  85. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  86. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
  87. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  88. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  89. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
  90. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
  91. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
  92. data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
  95. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  96. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  97. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  98. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  100. data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
  101. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
  102. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  103. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  104. data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
  105. data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
  106. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  107. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  108. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  109. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  110. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
  111. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  112. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  113. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  114. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
  115. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  116. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  117. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  118. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  119. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  120. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
  121. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
  122. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  123. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
  124. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  125. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  126. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  127. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
  128. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
  129. data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
  130. data/vendor/faiss/faiss/index_factory.cpp +40 -7
  131. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  132. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
  133. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
  134. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  135. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  136. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  137. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  138. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  139. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  140. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
  141. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
  142. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
  143. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  144. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
  145. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
  146. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  147. data/vendor/faiss/faiss/utils/distances.cpp +30 -11
  148. data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
  149. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
  150. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  151. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  152. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  153. data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
  154. data/vendor/faiss/faiss/utils/hamming.h +10 -1
  155. data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
  156. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
  157. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
  158. data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
  159. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
  160. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  161. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  162. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
  163. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  164. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  165. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
  166. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  167. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
  168. data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
  169. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  170. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  171. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
  172. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
  173. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
  174. data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
  175. data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
  176. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  177. metadata +21 -5
  178. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
@@ -36,7 +36,8 @@ struct IndexSVSVamanaLeanVec : IndexSVSVamana {
36
36
  MetricType metric = METRIC_L2,
37
37
  size_t leanvec_dims = 0,
38
38
  SVSStorageKind storage = SVSStorageKind::SVS_LeanVec4x4,
39
- bool is_static = false);
39
+ bool is_static = false,
40
+ bool store_vectors = true);
40
41
 
41
42
  ~IndexSVSVamanaLeanVec() override;
42
43
 
@@ -118,7 +118,7 @@ struct HeapWithBucketsForHamming32<
118
118
  }
119
119
  }
120
120
 
121
- if (valid_counter == 8) {
121
+ if (valid_counter == 0) {
122
122
  continue; // Skip if all vectors are filtered out
123
123
  }
124
124
 
@@ -291,6 +291,11 @@ void exhaustive_inner_product_seq(
291
291
  BlockResultHandler& res) {
292
292
  using SingleResultHandler =
293
293
  typename BlockResultHandler::SingleResultHandler;
294
+
295
+ if (nx == 0) {
296
+ return;
297
+ }
298
+
294
299
  [[maybe_unused]] int nt = std::min(int(nx), omp_get_max_threads());
295
300
 
296
301
  #pragma omp parallel num_threads(nt)
@@ -327,6 +332,11 @@ void exhaustive_L2sqr_seq(
327
332
  BlockResultHandler& res) {
328
333
  using SingleResultHandler =
329
334
  typename BlockResultHandler::SingleResultHandler;
335
+
336
+ if (nx == 0) {
337
+ return;
338
+ }
339
+
330
340
  [[maybe_unused]] int nt = std::min(int(nx), omp_get_max_threads());
331
341
 
332
342
  #pragma omp parallel num_threads(nt)
@@ -531,15 +541,19 @@ void exhaustive_L2sqr_blas<Top1BlockResultHandler<CMax<float, int64_t>>>(
531
541
  return;
532
542
  }
533
543
 
534
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A2>([&]<SIMDLevel SL>() {
535
- if constexpr (SL == SIMDLevel::AVX2 || SL == SIMDLevel::ARM_SVE) {
536
- exhaustive_L2sqr_blas_cmax<SL>(x, y, d, nx, ny, res, y_norms);
537
- } else {
538
- exhaustive_L2sqr_blas_default_impl<
539
- Top1BlockResultHandler<CMax<float, int64_t>>>(
540
- x, y, d, nx, ny, res, y_norms);
541
- }
542
- });
544
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
545
+ [&]<SIMDLevel SL>() {
546
+ if constexpr (
547
+ SL == SIMDLevel::AVX2 || SL == SIMDLevel::AVX512 ||
548
+ SL == SIMDLevel::ARM_SVE) {
549
+ exhaustive_L2sqr_blas_cmax<SL>(
550
+ x, y, d, nx, ny, res, y_norms);
551
+ } else {
552
+ exhaustive_L2sqr_blas_default_impl<
553
+ Top1BlockResultHandler<CMax<float, int64_t>>>(
554
+ x, y, d, nx, ny, res, y_norms);
555
+ }
556
+ });
543
557
  }
544
558
 
545
559
  struct Run_search_inner_product {
@@ -551,7 +565,11 @@ struct Run_search_inner_product {
551
565
  size_t d,
552
566
  size_t nx,
553
567
  size_t ny) {
554
- if (res.sel ||
568
+ // ny == 0 goes to the sequential path: it guards only on nx, so its
569
+ // per-query begin()/end() still runs and each handler writes its own
570
+ // neutral distance and -1 label. The BLAS path instead returns early
571
+ // on ny == 0, before the handler is initialized.
572
+ if (res.sel || ny == 0 ||
555
573
  nx * d < static_cast<size_t>(distance_compute_blas_threshold)) {
556
574
  exhaustive_inner_product_seq(x, y, d, nx, ny, res);
557
575
  } else {
@@ -570,7 +588,8 @@ struct Run_search_L2sqr {
570
588
  size_t nx,
571
589
  size_t ny,
572
590
  const float* y_norm2) {
573
- if (res.sel ||
591
+ // See the note on ny == 0 in Run_search_inner_product.
592
+ if (res.sel || ny == 0 ||
574
593
  nx * d < static_cast<size_t>(distance_compute_blas_threshold)) {
575
594
  exhaustive_L2sqr_seq(x, y, d, nx, ny, res);
576
595
  } else {
@@ -29,22 +29,22 @@
29
29
  namespace faiss {
30
30
 
31
31
  inline float fvec_L1_dispatch(const float* x, const float* y, size_t d) {
32
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
32
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
33
33
  [&]<SIMDLevel SL>() { return fvec_L1<SL>(x, y, d); });
34
34
  }
35
35
 
36
36
  inline float fvec_Linf_dispatch(const float* x, const float* y, size_t d) {
37
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
37
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
38
38
  [&]<SIMDLevel SL>() { return fvec_Linf<SL>(x, y, d); });
39
39
  }
40
40
 
41
41
  inline float fvec_norm_L2sqr_dispatch(const float* x, size_t d) {
42
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
42
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
43
43
  [&]<SIMDLevel SL>() { return fvec_norm_L2sqr<SL>(x, d); });
44
44
  }
45
45
 
46
46
  inline float fvec_L2sqr_dispatch(const float* x, const float* y, size_t d) {
47
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
47
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
48
48
  [&]<SIMDLevel SL>() { return fvec_L2sqr<SL>(x, y, d); });
49
49
  }
50
50
 
@@ -52,7 +52,7 @@ inline float fvec_inner_product_dispatch(
52
52
  const float* x,
53
53
  const float* y,
54
54
  size_t d) {
55
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
55
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
56
56
  [&]<SIMDLevel SL>() { return fvec_inner_product<SL>(x, y, d); });
57
57
  }
58
58
 
@@ -67,10 +67,11 @@ inline void fvec_inner_product_batch_4_dispatch(
67
67
  float& dis1,
68
68
  float& dis2,
69
69
  float& dis3) {
70
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>([&]<SIMDLevel SL>() {
71
- fvec_inner_product_batch_4<SL>(
72
- x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
73
- });
70
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
71
+ [&]<SIMDLevel SL>() {
72
+ fvec_inner_product_batch_4<SL>(
73
+ x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
74
+ });
74
75
  }
75
76
 
76
77
  inline void fvec_L2sqr_batch_4_dispatch(
@@ -84,9 +85,11 @@ inline void fvec_L2sqr_batch_4_dispatch(
84
85
  float& dis1,
85
86
  float& dis2,
86
87
  float& dis3) {
87
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>([&]<SIMDLevel SL>() {
88
- fvec_L2sqr_batch_4<SL>(x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
89
- });
88
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
89
+ [&]<SIMDLevel SL>() {
90
+ fvec_L2sqr_batch_4<SL>(
91
+ x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
92
+ });
90
93
  }
91
94
 
92
95
  inline void fvec_L2sqr_ny_transposed_dispatch(
@@ -97,9 +100,11 @@ inline void fvec_L2sqr_ny_transposed_dispatch(
97
100
  size_t d,
98
101
  size_t d_offset,
99
102
  size_t ny) {
100
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>([&]<SIMDLevel SL>() {
101
- fvec_L2sqr_ny_transposed<SL>(dis, x, y, y_sqlen, d, d_offset, ny);
102
- });
103
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
104
+ [&]<SIMDLevel SL>() {
105
+ fvec_L2sqr_ny_transposed<SL>(
106
+ dis, x, y, y_sqlen, d, d_offset, ny);
107
+ });
103
108
  }
104
109
 
105
110
  inline void fvec_inner_products_ny_dispatch(
@@ -108,9 +113,10 @@ inline void fvec_inner_products_ny_dispatch(
108
113
  const float* y,
109
114
  size_t d,
110
115
  size_t ny) {
111
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>([&]<SIMDLevel SL>() {
112
- fvec_inner_products_ny<SL>(ip, x, y, d, ny);
113
- });
116
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
117
+ [&]<SIMDLevel SL>() {
118
+ fvec_inner_products_ny<SL>(ip, x, y, d, ny);
119
+ });
114
120
  }
115
121
 
116
122
  inline void fvec_L2sqr_ny_dispatch(
@@ -119,7 +125,7 @@ inline void fvec_L2sqr_ny_dispatch(
119
125
  const float* y,
120
126
  size_t d,
121
127
  size_t ny) {
122
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
128
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
123
129
  [&]<SIMDLevel SL>() { fvec_L2sqr_ny<SL>(dis, x, y, d, ny); });
124
130
  }
125
131
 
@@ -129,7 +135,7 @@ inline size_t fvec_L2sqr_ny_nearest_dispatch(
129
135
  const float* y,
130
136
  size_t d,
131
137
  size_t ny) {
132
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
138
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
133
139
  [&]<SIMDLevel SL>() {
134
140
  return fvec_L2sqr_ny_nearest<SL>(
135
141
  distances_tmp_buffer, x, y, d, ny);
@@ -144,7 +150,7 @@ inline size_t fvec_L2sqr_ny_nearest_y_transposed_dispatch(
144
150
  size_t d,
145
151
  size_t d_offset,
146
152
  size_t ny) {
147
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
153
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
148
154
  [&]<SIMDLevel SL>() {
149
155
  return fvec_L2sqr_ny_nearest_y_transposed<SL>(
150
156
  distances_tmp_buffer, x, y, y_sqlen, d, d_offset, ny);
@@ -157,7 +163,7 @@ inline void fvec_madd_dispatch(
157
163
  float bf,
158
164
  const float* b,
159
165
  float* c) {
160
- with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
166
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
161
167
  [&]<SIMDLevel SL>() { fvec_madd<SL>(n, a, bf, b, c); });
162
168
  }
163
169
 
@@ -167,7 +173,7 @@ inline int fvec_madd_and_argmin_dispatch(
167
173
  float bf,
168
174
  const float* b,
169
175
  float* c) {
170
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A1>(
176
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
171
177
  [&]<SIMDLevel SL>() {
172
178
  return fvec_madd_and_argmin<SL>(n, a, bf, b, c);
173
179
  });
@@ -241,7 +247,7 @@ auto with_VectorDistance(
241
247
  if constexpr (!has_simd) {
242
248
  return call.template operator()<SIMDLevel::NONE>();
243
249
  } else {
244
- return with_simd_level(call);
250
+ return with_simd_level_with_sve(call);
245
251
  }
246
252
  };
247
253
  return with_metric_type(metric, dispatch_metric);
@@ -51,7 +51,7 @@ bool exhaustive_L2sqr_fused_cmax(
51
51
  return true;
52
52
  }
53
53
 
54
- return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A0>(
54
+ return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE>(
55
55
  [&]<SIMDLevel SL>() {
56
56
  return exhaustive_L2sqr_fused_cmax<SL>(
57
57
  x, y, d, nx, ny, res, y_norms);
@@ -10,18 +10,19 @@
10
10
  #include <faiss/utils/distances.h>
11
11
 
12
12
  #include <cmath>
13
- #include <cstdio>
14
13
  #include <cstring>
15
14
 
16
- #include <faiss/impl/FaissAssert.h>
17
15
  #include <faiss/impl/simdlib/simdlib_dispatch.h>
18
16
 
19
17
  #define THE_SIMD_LEVEL SIMDLevel::NONE
20
18
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
21
19
  #include <faiss/utils/simd_impl/distances_autovec-inl.h>
22
20
 
21
+ // This TU is the SIMDLevel::NONE build of the specializations that
22
+ // distances_simdlib256.h emits, so the include is required despite no symbol
23
+ // being named directly here.
23
24
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
24
- #include <faiss/utils/simd_impl/distances_simdlib256.h>
25
+ #include <faiss/utils/simd_impl/distances_simdlib256.h> // IWYU pragma: keep
25
26
 
26
27
  namespace faiss {
27
28
 
@@ -29,11 +29,9 @@ namespace {
29
29
  template <class VD>
30
30
  struct ExtraDistanceComputer : FlatCodesDistanceComputer {
31
31
  VD vd;
32
- idx_t nb;
33
- const float* q;
34
- const float* b;
35
32
 
36
33
  float symmetric_dis(idx_t i, idx_t j) final {
34
+ const float* b = (const float*)codes;
37
35
  return vd(b + j * vd.d, b + i * vd.d);
38
36
  }
39
37
 
@@ -41,16 +39,9 @@ struct ExtraDistanceComputer : FlatCodesDistanceComputer {
41
39
  return vd(q, (float*)code);
42
40
  }
43
41
 
44
- ExtraDistanceComputer(
45
- const VD& vd_in,
46
- const float* xb,
47
- size_t nb_in,
48
- const float* q_in = nullptr)
42
+ ExtraDistanceComputer(const VD& vd_in, const float* xb)
49
43
  : FlatCodesDistanceComputer((uint8_t*)xb, vd_in.d * sizeof(float)),
50
- vd(vd_in),
51
- nb(nb_in),
52
- q(q_in),
53
- b(xb) {}
44
+ vd(vd_in) {}
54
45
 
55
46
  void set_query(const float* x) override {
56
47
  q = x;
@@ -149,11 +140,10 @@ FlatCodesDistanceComputer* get_extra_distance_computer(
149
140
  size_t d,
150
141
  MetricType mt,
151
142
  float metric_arg,
152
- size_t nb,
153
143
  const float* xb) {
154
144
  return with_VectorDistance(
155
145
  d, mt, metric_arg, [&](auto vd) -> FlatCodesDistanceComputer* {
156
- return new ExtraDistanceComputer<decltype(vd)>(vd, xb, nb);
146
+ return new ExtraDistanceComputer<decltype(vd)>(vd, xb);
157
147
  });
158
148
  }
159
149
 
@@ -49,12 +49,11 @@ void knn_extra_metrics(
49
49
  const IDSelector* sel = nullptr);
50
50
 
51
51
  /** get a DistanceComputer that refers to this type of distance and
52
- * indexes a flat array of size nb */
52
+ * indexes a flat array */
53
53
  FlatCodesDistanceComputer* get_extra_distance_computer(
54
54
  size_t d,
55
55
  MetricType mt,
56
56
  float metric_arg,
57
- size_t nb,
58
57
  const float* xb);
59
58
 
60
59
  /// Dispatch to a lambda with MetricType as a compile-time constant.
@@ -33,7 +33,7 @@
33
33
  // Scalar (NONE) fallback — only needs the generic specializations.
34
34
  #define THE_SIMD_LEVEL SIMDLevel::NONE
35
35
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
36
- #include <faiss/utils/hamming_distance/hamming_computer-generic.h>
36
+ #include <faiss/utils/hamming_distance/hamming_computer-generic.h> // IWYU pragma: keep
37
37
  #include <faiss/utils/hamming_distance/hamming_impl.h>
38
38
  #undef THE_SIMD_LEVEL
39
39
 
@@ -146,8 +146,14 @@ void hammings(
146
146
  size_t nb,
147
147
  size_t ncodes,
148
148
  hamdis_t* __restrict dis) {
149
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
150
- hammings_fixSL<SL>(a, b, na, nb, ncodes, dis);
149
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
150
+ // Ragged sizes have their own kernel; keeping it out of
151
+ // hammings_fixSL() leaves the word-level paths untouched.
152
+ if (ncodes % 8 != 0) {
153
+ hammings_ragged_fixSL<SL>(a, b, na, nb, ncodes, dis);
154
+ } else {
155
+ hammings_fixSL<SL>(a, b, na, nb, ncodes, dis);
156
+ }
151
157
  });
152
158
  }
153
159
 
@@ -170,7 +176,7 @@ void hammings_knn_hc(
170
176
  int order,
171
177
  ApproxTopK_mode_t approx_topk_mode,
172
178
  const faiss::IDSelector* sel) {
173
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
179
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
174
180
  hammings_knn_hc_fixSL<SL>(
175
181
  ha, a, b, nb, ncodes, order, approx_topk_mode, sel);
176
182
  });
@@ -186,7 +192,7 @@ void hammings_knn_mc(
186
192
  int32_t* __restrict distances,
187
193
  int64_t* __restrict labels,
188
194
  const faiss::IDSelector* sel) {
189
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
195
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
190
196
  hammings_knn_mc_fixSL<SL>(
191
197
  a, b, na, nb, k, ncodes, distances, labels, sel);
192
198
  });
@@ -201,7 +207,7 @@ void hamming_range_search(
201
207
  size_t code_size,
202
208
  RangeSearchResult* result,
203
209
  const faiss::IDSelector* sel) {
204
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
210
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
205
211
  hamming_range_search_fixSL<SL>(
206
212
  a, b, na, nb, radius, code_size, result, sel);
207
213
  });
@@ -215,7 +221,7 @@ void hamming_count_thres(
215
221
  hamdis_t ht,
216
222
  size_t ncodes,
217
223
  size_t* nptr) {
218
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
224
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
219
225
  hamming_count_thres_fixSL<SL>(bs1, bs2, n1, n2, ht, ncodes, nptr);
220
226
  });
221
227
  }
@@ -226,7 +232,7 @@ void crosshamming_count_thres(
226
232
  hamdis_t ht,
227
233
  size_t ncodes,
228
234
  size_t* nptr) {
229
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
235
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
230
236
  crosshamming_count_thres_fixSL<SL>(dbs, n, ht, ncodes, nptr);
231
237
  });
232
238
  }
@@ -240,7 +246,7 @@ size_t match_hamming_thres(
240
246
  size_t ncodes,
241
247
  int64_t* idx,
242
248
  hamdis_t* dis) {
243
- return with_simd_level_a0_spr([&]<SIMDLevel SL>() -> size_t {
249
+ return with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() -> size_t {
244
250
  return match_hamming_thres_fixSL<SL>(
245
251
  bs1, bs2, n1, n2, ht, ncodes, idx, dis);
246
252
  });
@@ -253,7 +259,7 @@ void generalized_hammings_knn_hc(
253
259
  size_t nb,
254
260
  size_t code_size,
255
261
  int ordered) {
256
- with_simd_level_a0_spr([&]<SIMDLevel SL>() {
262
+ with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
257
263
  generalized_hammings_knn_hc_fixSL<SL>(ha, a, b, nb, code_size, ordered);
258
264
  });
259
265
  }
@@ -111,7 +111,7 @@ FAISS_API extern size_t hamming_batch_size;
111
111
  *
112
112
  * @param a size na * nbytespercode
113
113
  * @param b size nb * nbytespercode
114
- * @param nbytespercode should be multiple of 8
114
+ * @param nbytespercode any size; multiples of 8 take a faster kernel
115
115
  * @param dis output distances, size na * nb
116
116
  */
117
117
  void hammings(
@@ -327,6 +327,15 @@ void hamming_range_search_fixSL(
327
327
  RangeSearchResult* result,
328
328
  const IDSelector* sel);
329
329
 
330
+ template <SIMDLevel SL>
331
+ void hammings_ragged_fixSL(
332
+ const uint8_t* a,
333
+ const uint8_t* b,
334
+ size_t na,
335
+ size_t nb,
336
+ size_t ncodes,
337
+ hamdis_t* dis);
338
+
330
339
  template <SIMDLevel SL>
331
340
  void hammings_fixSL(
332
341
  const uint8_t* a,
@@ -210,12 +210,23 @@ inline void hammings_impl(
210
210
  size_t n2,
211
211
  hamdis_t* __restrict dis) {
212
212
  size_t i, j;
213
- const size_t nwords = nbits / 64;
213
+ constexpr size_t nwords = nbits / 64;
214
214
  for (i = 0; i < n1; i++) {
215
215
  const uint64_t* __restrict bs1_ = bs1 + i * nwords;
216
216
  hamdis_t* __restrict dis_ = dis + i * n2;
217
- for (j = 0; j < n2; j++) {
218
- dis_[j] = hamming<nbits>(bs1_, bs2 + j * nwords);
217
+ if constexpr (nwords >= 4) {
218
+ // Wide codes are quicker one candidate at a time; otherwise the
219
+ // compiler batches candidates and must gather scattered bytes.
220
+ #if defined(__clang__)
221
+ #pragma clang loop vectorize(disable)
222
+ #endif
223
+ for (j = 0; j < n2; j++) {
224
+ dis_[j] = hamming<nbits>(bs1_, bs2 + j * nwords);
225
+ }
226
+ } else {
227
+ for (j = 0; j < n2; j++) {
228
+ dis_[j] = hamming<nbits>(bs1_, bs2 + j * nwords);
229
+ }
219
230
  }
220
231
  }
221
232
  }
@@ -0,0 +1,24 @@
1
+ /*
2
+ * 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
+ #ifdef COMPILE_SIMD_AVX512_VPOPCNT
9
+
10
+ #define THE_SIMD_LEVEL SIMDLevel::AVX512_VPOPCNT
11
+ #include <faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h>
12
+ #include <faiss/utils/hamming_distance/hamming_impl.h>
13
+
14
+ // Must follow the computer specializations above.
15
+ // clang-format off
16
+ // NOLINTNEXTLINE(facebook-hte-InlineHeader)
17
+ #include <faiss/impl/binary_hamming/IndexBinaryIVF_impl.h>
18
+ // clang-format on
19
+
20
+ // Fails the build if the batch path stops being selected for this computer.
21
+ static_assert(faiss::has_hamming_batch<
22
+ faiss::HammingComputer20_tpl<faiss::SIMDLevel::AVX512_VPOPCNT>>);
23
+
24
+ #endif // COMPILE_SIMD_AVX512_VPOPCNT
@@ -12,7 +12,7 @@
12
12
  // Types without custom AVX512 code inherit from the NONE specializations
13
13
  // in hamming_computer-generic.h. HammingComputer64 and
14
14
  // HammingComputerDefault use scalar popcount here; the VPOPCNTDQ fast
15
- // path lives in hamming_computer-avx512_spr.h (AVX512_SPR level).
15
+ // path lives in hamming_computer-avx512_vpopcnt.h (AVX512_VPOPCNT level).
16
16
  // GenHammingComputer classes leverage SSE/AVX2 intrinsics.
17
17
 
18
18
  #include <cassert>
@@ -5,17 +5,19 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- #ifndef HAMMING_COMPUTER_AVX512_SPR_H
9
- #define HAMMING_COMPUTER_AVX512_SPR_H
8
+ #ifndef HAMMING_COMPUTER_AVX512_VPOPCNT_H
9
+ #define HAMMING_COMPUTER_AVX512_VPOPCNT_H
10
10
 
11
- // AVX512_SPR HammingComputer specializations using VPOPCNTDQ.
12
- // On Sapphire Rapids+, _mm512_popcnt_epi64 (and _mm256_popcnt_epi64 with VL)
13
- // are unconditionally available. This gives a faster path than the scalar
14
- // popcount fallback used in the base AVX512 specializations when compiled
15
- // without -mavx512vpopcntdq.
11
+ // AVX512_VPOPCNT HammingComputer specializations. The 32/64/Default kernels
12
+ // use VPOPCNTDQ; the batched 20-byte kernel uses AVX512_BITALG. This gives
13
+ // a faster path than the scalar popcount fallback used in the base AVX512
14
+ // specializations when compiled without -mavx512vpopcntdq.
16
15
 
17
16
  #include <cassert>
18
17
  #include <cstdint>
18
+ #include <cstring>
19
+
20
+ #include <faiss/utils/popcount.h>
19
21
 
20
22
  #include <faiss/impl/platform_macros.h>
21
23
  #include <faiss/utils/hamming_distance/hamming_computer-avx512.h>
@@ -25,31 +27,90 @@
25
27
  namespace faiss {
26
28
 
27
29
  /***************************************************************************
28
- * AVX512_SPR inheriting specializations for types without custom SPR code.
30
+ * AVX512_VPOPCNT inheriting specializations without custom VPOPCNT code.
29
31
  ***************************************************************************/
30
32
 
31
- #define FAISS_INHERIT_HAMMING_SPR(Class) \
32
- template <> \
33
- struct Class## \
34
- _tpl<SIMDLevel::AVX512_SPR> : Class##_tpl<SIMDLevel::AVX512> { \
35
- using Class##_tpl<SIMDLevel::AVX512>::Class##_tpl; \
33
+ #define FAISS_INHERIT_HAMMING_VPOPCNT(Class) \
34
+ template <> \
35
+ struct Class## \
36
+ _tpl<SIMDLevel::AVX512_VPOPCNT> : Class##_tpl<SIMDLevel::AVX512> { \
37
+ using Class##_tpl<SIMDLevel::AVX512>::Class##_tpl; \
36
38
  }
37
39
 
38
- FAISS_INHERIT_HAMMING_SPR(HammingComputer16);
39
- FAISS_INHERIT_HAMMING_SPR(HammingComputer20);
40
- FAISS_INHERIT_HAMMING_SPR(GenHammingComputer8);
41
- FAISS_INHERIT_HAMMING_SPR(GenHammingComputer16);
42
- FAISS_INHERIT_HAMMING_SPR(GenHammingComputer32);
43
- FAISS_INHERIT_HAMMING_SPR(GenHammingComputerM8);
40
+ FAISS_INHERIT_HAMMING_VPOPCNT(HammingComputer16);
41
+ FAISS_INHERIT_HAMMING_VPOPCNT(GenHammingComputer8);
42
+ FAISS_INHERIT_HAMMING_VPOPCNT(GenHammingComputer16);
43
+ FAISS_INHERIT_HAMMING_VPOPCNT(GenHammingComputer32);
44
+ FAISS_INHERIT_HAMMING_VPOPCNT(GenHammingComputerM8);
44
45
 
45
- #undef FAISS_INHERIT_HAMMING_SPR
46
+ #undef FAISS_INHERIT_HAMMING_VPOPCNT
46
47
 
47
48
  /***************************************************************************
48
- * Custom AVX512_SPR specializations using VPOPCNTDQ.
49
+ * Custom AVX512_VPOPCNT specializations using VPOPCNTDQ.
49
50
  ***************************************************************************/
50
51
 
51
52
  template <>
52
- struct HammingComputer32_tpl<SIMDLevel::AVX512_SPR> {
53
+ struct HammingComputer20_tpl<SIMDLevel::AVX512_VPOPCNT>
54
+ : HammingComputer20_tpl<SIMDLevel::AVX512> {
55
+ using HammingComputer20_tpl<SIMDLevel::AVX512>::HammingComputer20_tpl;
56
+
57
+ static constexpr size_t batch_size = 8;
58
+ static constexpr size_t kStride = get_code_size();
59
+ // 160 bytes is what the three loads in hamming_batch() cover, and the
60
+ // 16+4 or 4+16 split it applies per lane is written out for 20 bytes:
61
+ // the literal offsets and the two group indices are not derived from
62
+ // kStride, so another width needs the body reworked, not just retuned.
63
+ static_assert(batch_size * kStride == 160);
64
+ static_assert(kStride == 20, "hamming_batch() hardcodes the 16+4 split");
65
+ static constexpr __mmask64 kTailMask = 0xFFFFFFFFull;
66
+
67
+ /// Writes the query repeated batch_size times. The caller owns the buffer,
68
+ /// so a computer used only through hamming() carries no batch state.
69
+ static void build_batch_query(const uint8_t* a8, uint8_t* tile) {
70
+ for (size_t k = 0; k < batch_size; k++) {
71
+ memcpy(tile + k * kStride, a8, kStride);
72
+ }
73
+ }
74
+
75
+ static void hamming_batch(
76
+ const uint8_t* tile,
77
+ const uint8_t* codes,
78
+ int32_t* dis) {
79
+ const __m512i zero = _mm512_setzero_si512();
80
+ const __m512i p0 = _mm512_popcnt_epi8(_mm512_xor_si512(
81
+ _mm512_loadu_si512(codes), _mm512_loadu_si512(tile)));
82
+ const __m512i p1 = _mm512_popcnt_epi8(_mm512_xor_si512(
83
+ _mm512_loadu_si512(codes + 64), _mm512_loadu_si512(tile + 64)));
84
+ const __m512i p2 = _mm512_popcnt_epi8(_mm512_xor_si512(
85
+ _mm512_maskz_loadu_epi8(kTailMask, codes + 128),
86
+ _mm512_maskz_loadu_epi8(kTailMask, tile + 128)));
87
+
88
+ alignas(64) uint64_t grp[24];
89
+ _mm512_store_si512(grp, _mm512_sad_epu8(p0, zero));
90
+ _mm512_store_si512(grp + 8, _mm512_sad_epu8(p1, zero));
91
+ _mm512_store_si512(grp + 16, _mm512_sad_epu8(p2, zero));
92
+
93
+ for (size_t k = 0; k < batch_size; k++) {
94
+ const size_t s = k * kStride;
95
+ const size_t g = s / 8;
96
+ uint32_t xh, qh;
97
+ if (s % 8 == 0) {
98
+ memcpy(&xh, codes + s + 16, 4);
99
+ memcpy(&qh, tile + s + 16, 4);
100
+ dis[k] = static_cast<int32_t>(
101
+ grp[g] + grp[g + 1] + popcount32(xh ^ qh));
102
+ } else {
103
+ memcpy(&xh, codes + s, 4);
104
+ memcpy(&qh, tile + s, 4);
105
+ dis[k] = static_cast<int32_t>(
106
+ popcount32(xh ^ qh) + grp[g + 1] + grp[g + 2]);
107
+ }
108
+ }
109
+ }
110
+ };
111
+
112
+ template <>
113
+ struct HammingComputer32_tpl<SIMDLevel::AVX512_VPOPCNT> {
53
114
  const uint8_t* a8;
54
115
 
55
116
  HammingComputer32_tpl() {}
@@ -81,7 +142,7 @@ struct HammingComputer32_tpl<SIMDLevel::AVX512_SPR> {
81
142
  };
82
143
 
83
144
  template <>
84
- struct HammingComputer64_tpl<SIMDLevel::AVX512_SPR> {
145
+ struct HammingComputer64_tpl<SIMDLevel::AVX512_VPOPCNT> {
85
146
  const uint8_t* a8;
86
147
 
87
148
  HammingComputer64_tpl() {}
@@ -108,7 +169,7 @@ struct HammingComputer64_tpl<SIMDLevel::AVX512_SPR> {
108
169
  };
109
170
 
110
171
  template <>
111
- struct HammingComputerDefault_tpl<SIMDLevel::AVX512_SPR> {
172
+ struct HammingComputerDefault_tpl<SIMDLevel::AVX512_VPOPCNT> {
112
173
  const uint8_t* a8;
113
174
  int quotient8;
114
175
  int remainder8;