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
@@ -39,17 +39,50 @@ namespace faiss {
39
39
 
40
40
  namespace {
41
41
 
42
+ // Whether the computer can measure a whole batch of codes in one call.
42
43
  template <class HammingComputer>
43
- struct IVFBinaryScannerL2 : BinaryInvertedListScanner {
44
+ constexpr bool has_hamming_batch =
45
+ requires(const uint8_t* tile, const uint8_t* codes, int32_t* dis) {
46
+ HammingComputer::batch_size;
47
+ HammingComputer::get_code_size();
48
+ HammingComputer::build_batch_query(tile, nullptr);
49
+ HammingComputer::hamming_batch(tile, codes, dis);
50
+ };
51
+
52
+ // The query repeated batch_size times, which is what hamming_batch() XORs
53
+ // against. Empty for a computer that does not batch, so those scanners carry
54
+ // neither the buffer nor its alignment.
55
+ template <class HammingComputer>
56
+ struct BatchQueryTile {};
57
+
58
+ template <class HammingComputer>
59
+ requires has_hamming_batch<HammingComputer>
60
+ struct BatchQueryTile<HammingComputer> {
61
+ alignas(64) uint8_t batch_query
62
+ [HammingComputer::batch_size * HammingComputer::get_code_size()];
63
+ };
64
+
65
+ template <class HammingComputer>
66
+ struct IVFBinaryScannerL2 : BinaryInvertedListScanner,
67
+ BatchQueryTile<HammingComputer> {
44
68
  HammingComputer hc;
45
69
  size_t code_size;
46
70
  bool store_pairs;
47
71
 
48
72
  IVFBinaryScannerL2(size_t code_size_, bool store_pairs_)
49
- : code_size(code_size_), store_pairs(store_pairs_) {}
73
+ : code_size(code_size_), store_pairs(store_pairs_) {
74
+ if constexpr (has_hamming_batch<HammingComputer>) {
75
+ // The batch kernel reads a fixed stride, so a caller that pairs
76
+ // this computer with another code size would read past the codes.
77
+ FAISS_THROW_IF_NOT(code_size == HammingComputer::get_code_size());
78
+ }
79
+ }
50
80
 
51
81
  void set_query(const uint8_t* query_vector) override {
52
82
  hc.set(query_vector, code_size);
83
+ if constexpr (has_hamming_batch<HammingComputer>) {
84
+ HammingComputer::build_batch_query(query_vector, this->batch_query);
85
+ }
53
86
  }
54
87
 
55
88
  idx_t list_no = 0;
@@ -61,6 +94,31 @@ struct IVFBinaryScannerL2 : BinaryInvertedListScanner {
61
94
  return hc.hamming(code);
62
95
  }
63
96
 
97
+ // Measures whole batches while at least batch_size codes remain, then
98
+ // leaves codes and j on the first code the caller must measure singly.
99
+ // bound is read per lane, so a caller that raises its heap top inside
100
+ // accept prunes the rest of the batch.
101
+ template <class Accept>
102
+ void scan_batch_prefix(
103
+ size_t n,
104
+ const uint8_t* __restrict& codes,
105
+ size_t& j,
106
+ const uint32_t& bound,
107
+ Accept&& accept) const {
108
+ if constexpr (has_hamming_batch<HammingComputer>) {
109
+ constexpr size_t B = HammingComputer::batch_size;
110
+ int32_t batch[B];
111
+ for (; j + B <= n; j += B, codes += B * code_size) {
112
+ HammingComputer::hamming_batch(this->batch_query, codes, batch);
113
+ for (size_t t = 0; t < B; t++) {
114
+ if (static_cast<uint32_t>(batch[t]) < bound) {
115
+ accept(batch[t], j + t);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+
64
122
  size_t scan_codes(
65
123
  size_t n,
66
124
  const uint8_t* __restrict codes,
@@ -70,15 +128,25 @@ struct IVFBinaryScannerL2 : BinaryInvertedListScanner {
70
128
  size_t k) const override {
71
129
  using C = CMax<int32_t, idx_t>;
72
130
 
131
+ uint32_t bound = static_cast<uint32_t>(simi[0]);
132
+
73
133
  size_t nup = 0;
74
- for (size_t j = 0; j < n; j++) {
134
+ size_t j = 0;
135
+
136
+ auto accept = [&](int32_t dis, size_t at) {
137
+ idx_t id = store_pairs ? lo_build(list_no, at) : ids[at];
138
+ heap_replace_top<C>(k, simi, idxi, dis, id);
139
+ bound = static_cast<uint32_t>(simi[0]);
140
+ nup++;
141
+ };
142
+
143
+ scan_batch_prefix(n, codes, j, bound, accept);
144
+
145
+ for (; j < n; j++, codes += code_size) {
75
146
  uint32_t dis = hc.hamming(codes);
76
- if (dis < static_cast<uint32_t>(simi[0])) {
77
- idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
78
- heap_replace_top<C>(k, simi, idxi, dis, id);
79
- nup++;
147
+ if (dis < bound) {
148
+ accept(static_cast<int32_t>(dis), j);
80
149
  }
81
- codes += code_size;
82
150
  }
83
151
  return nup;
84
152
  }
@@ -89,13 +157,21 @@ struct IVFBinaryScannerL2 : BinaryInvertedListScanner {
89
157
  const idx_t* __restrict ids,
90
158
  int radius,
91
159
  RangeQueryResult& result) const override {
92
- for (size_t j = 0; j < n; j++) {
160
+ const uint32_t bound = static_cast<uint32_t>(radius);
161
+ size_t j = 0;
162
+
163
+ auto accept = [&](int32_t dis, size_t at) {
164
+ int64_t id = store_pairs ? lo_build(list_no, at) : ids[at];
165
+ result.add(static_cast<uint32_t>(dis), id);
166
+ };
167
+
168
+ scan_batch_prefix(n, codes, j, bound, accept);
169
+
170
+ for (; j < n; j++, codes += code_size) {
93
171
  uint32_t dis = hc.hamming(codes);
94
- if (dis < static_cast<uint32_t>(radius)) {
95
- int64_t id = store_pairs ? lo_build(list_no, j) : ids[j];
96
- result.add(dis, id);
172
+ if (dis < bound) {
173
+ accept(static_cast<int32_t>(dis), j);
97
174
  }
98
- codes += code_size;
99
175
  }
100
176
  }
101
177
  };
@@ -292,7 +368,7 @@ void search_knn_hamming_per_invlist(
292
368
  nprobe = std::min((idx_t)ivf->nlist, nprobe);
293
369
  idx_t max_codes = params ? params->max_codes : ivf->max_codes;
294
370
  FAISS_THROW_IF_NOT(max_codes == 0);
295
- FAISS_THROW_IF_NOT(!store_pairs);
371
+ FAISS_THROW_IF_MSG(store_pairs, "store_pairs is not supported here");
296
372
 
297
373
  // reorder buckets
298
374
  std::vector<int64_t> lims(n + 1);
@@ -9,17 +9,17 @@
9
9
 
10
10
  #define THE_SIMD_LEVEL SIMDLevel::AVX2
11
11
 
12
- // NOLINTNEXTLINE(facebook-hte-InlineHeader)
12
+ // NOLINTNEXTLINE(facebook-hte-InlineHeader,facebook-unused-include-check)
13
13
  #include <faiss/utils/hamming_distance/hamming_computer-avx2.h>
14
14
 
15
15
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
16
- #include <faiss/impl/binary_hamming/IndexBinaryHNSW_impl.h>
16
+ #include <faiss/impl/binary_hamming/IndexBinaryHNSW_impl.h> // IWYU pragma: keep
17
17
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
18
- #include <faiss/impl/binary_hamming/IndexBinaryHash_impl.h>
18
+ #include <faiss/impl/binary_hamming/IndexBinaryHash_impl.h> // IWYU pragma: keep
19
19
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
20
20
  #include <faiss/impl/binary_hamming/IndexBinaryIVF_impl.h>
21
21
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
22
- #include <faiss/impl/binary_hamming/IndexIVFSpectralHash_impl.h>
22
+ #include <faiss/impl/binary_hamming/IndexIVFSpectralHash_impl.h> // IWYU pragma: keep
23
23
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
24
24
  #include <faiss/impl/binary_hamming/IndexPQ_impl.h>
25
25
 
@@ -35,12 +35,16 @@ size_t run_scan_codes1(
35
35
  size_t list_no = scanner.list_no;
36
36
  size_t code_size = scanner.code_size;
37
37
  const IDSelector* sel = scanner.sel;
38
+ // If the selector implements IDSelectorWithContext, hand it the scan
39
+ // context (ids, list_size, j) so it can exploit scan-order locality; the
40
+ // dispatch caches the once-per-list RTTI detection.
41
+ const IDSelectorContextDispatch sel_dispatch(sel, store_pairs);
38
42
  float threshold = handler.threshold;
39
43
  for (size_t j = 0; j < list_size; j++) {
40
44
  if (use_sel) {
41
45
  int64_t id = store_pairs ? lo_build(list_no, j) : ids[j];
42
46
  // skip code without computing distance
43
- if (!sel->is_member(id)) {
47
+ if (!sel_dispatch.is_member(id, IDScanContext{ids, list_size, j})) {
44
48
  codes += code_size;
45
49
  continue;
46
50
  }
@@ -40,6 +40,7 @@ void kernel_accumulate_block(
40
40
  #ifdef __AVX512F__
41
41
  if constexpr (
42
42
  KernelSL == SIMDLevel::AVX512 ||
43
+ KernelSL == SIMDLevel::AVX512_VPOPCNT ||
43
44
  KernelSL == SIMDLevel::AVX512_SPR) {
44
45
  pq4_kernel_qbs_512<NQ>(nsq, codes, LUT, res, scaler);
45
46
  } else {
@@ -33,6 +33,7 @@
33
33
 
34
34
  #include <faiss/impl/fast_scan/accumulate_loops.h>
35
35
  #include <faiss/impl/fast_scan/fast_scan.h>
36
+ #include <faiss/utils/simd_levels.h>
36
37
 
37
38
  #if defined(COMPILE_SIMD_AVX512) && defined(__AVX512F__)
38
39
  #include <faiss/impl/fast_scan/accumulate_loops_512.h>
@@ -114,8 +115,40 @@ struct ScannerMixIn : FastScanCodeScanner {
114
115
  constexpr bool use_avx512_qbs = false;
115
116
  #endif
116
117
  if constexpr (use_avx512_qbs) {
117
- // Use 512-bit QBS kernels with properly-leveled scalers.
118
- if (pq2x4_scale) {
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
+ if (SIMDConfig::avx512_split) {
127
+ if (pq2x4_scale) {
128
+ NormTableScaler<SIMDLevel::AVX2> scaler(pq2x4_scale);
129
+ pq4_accumulate_loop_qbs_fixed_scaler_256<SIMDLevel::AVX2>(
130
+ qbs,
131
+ nb,
132
+ nsq,
133
+ codes,
134
+ LUT,
135
+ handler_,
136
+ scaler,
137
+ block_stride);
138
+ } else {
139
+ DummyScaler<SIMDLevel::AVX2> dummy;
140
+ pq4_accumulate_loop_qbs_fixed_scaler_256<SIMDLevel::AVX2>(
141
+ qbs,
142
+ nb,
143
+ nsq,
144
+ codes,
145
+ LUT,
146
+ handler_,
147
+ dummy,
148
+ block_stride);
149
+ }
150
+ } else if (pq2x4_scale) {
151
+ // Use 512-bit QBS kernels with properly-leveled scalers.
119
152
  NormTableScaler<THE_LEVEL_TO_DISPATCH> scaler(pq2x4_scale);
120
153
  pq4_accumulate_loop_qbs_fixed_scaler_512(
121
154
  qbs,
@@ -30,7 +30,7 @@ void LockVector::prepare(size_t new_size) {
30
30
  // Just destroy old and init fresh; omp_lock_t is not copyable.
31
31
  clear();
32
32
  data_ = static_cast<omp_lock_t*>(malloc(new_cap * sizeof(omp_lock_t)));
33
- FAISS_THROW_IF_NOT(data_ != nullptr);
33
+ FAISS_THROW_IF_NOT(data_);
34
34
  capacity_ = new_cap;
35
35
  }
36
36
  for (size_t i = size_; i < new_size; i++) {