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
@@ -41,17 +41,7 @@ struct DistanceComputer {
41
41
  float& dis0,
42
42
  float& dis1,
43
43
  float& dis2,
44
- float& dis3) {
45
- // compute first, assign next
46
- const float d0 = this->operator()(idx0);
47
- const float d1 = this->operator()(idx1);
48
- const float d2 = this->operator()(idx2);
49
- const float d3 = this->operator()(idx3);
50
- dis0 = d0;
51
- dis1 = d1;
52
- dis2 = d2;
53
- dis3 = d3;
54
- }
44
+ float& dis3);
55
45
 
56
46
  /// compute distance between two stored vectors
57
47
  virtual float symmetric_dis(idx_t i, idx_t j) = 0;
@@ -181,9 +171,7 @@ struct FlatCodesDistanceComputer : DistanceComputer {
181
171
  virtual float partial_dot_product(
182
172
  const idx_t /* i */,
183
173
  const uint32_t /* offset */,
184
- const uint32_t /* num_components */) {
185
- FAISS_THROW_MSG("partial_dot_product not implemented");
186
- }
174
+ const uint32_t /* num_components */);
187
175
 
188
176
  /// compute distance of current query to an encoded vector
189
177
  virtual float distance_to_code(const uint8_t* code) = 0;
@@ -214,21 +202,7 @@ struct FlatCodesDistanceComputer : DistanceComputer {
214
202
  float& dp2,
215
203
  float& dp3,
216
204
  const uint32_t offset,
217
- const uint32_t num_components) {
218
- // default implementation for correctness
219
- const float d0 =
220
- this->partial_dot_product(idx0, offset, num_components);
221
- const float d1 =
222
- this->partial_dot_product(idx1, offset, num_components);
223
- const float d2 =
224
- this->partial_dot_product(idx2, offset, num_components);
225
- const float d3 =
226
- this->partial_dot_product(idx3, offset, num_components);
227
- dp0 = d0;
228
- dp1 = d1;
229
- dp2 = d2;
230
- dp3 = d3;
231
- }
205
+ const uint32_t num_components);
232
206
 
233
207
  virtual ~FlatCodesDistanceComputer() override {}
234
208
  };
@@ -1568,6 +1568,8 @@ void reservePriorityQueue(
1568
1568
  /// Templated body of `search_from_candidate_unbounded`. The choice of
1569
1569
  /// max-heap vs min-heap for both `top_candidates` and `candidates` is
1570
1570
  /// derived from C via `TopCandidatesQueue` / `CandidatesQueue`.
1571
+ /// `sel` filters the results only. The traversal still visits the rejected
1572
+ /// nodes.
1571
1573
  template <typename VTType, class C>
1572
1574
  TopCandidatesQueue<C> search_from_candidate_unbounded_fixVT(
1573
1575
  const HNSW& hnsw,
@@ -1575,16 +1577,48 @@ TopCandidatesQueue<C> search_from_candidate_unbounded_fixVT(
1575
1577
  DistanceComputer& qdis,
1576
1578
  int ef,
1577
1579
  VTType& vt,
1578
- HNSWStats& stats) {
1580
+ HNSWStats& stats,
1581
+ const IDSelector* sel) {
1582
+ const auto max_size = static_cast<size_t>(ef);
1583
+
1579
1584
  int ndis = 0;
1585
+ // `top_candidates` bounds the traversal and keeps the nodes that `sel`
1586
+ // rejects, because a rejected node is still a valid hop towards an
1587
+ // accepted one.
1580
1588
  TopCandidatesQueue<C> top_candidates;
1581
1589
  reservePriorityQueue(top_candidates, ef);
1582
1590
 
1591
+ // `selected_candidates` keeps only the accepted nodes, and
1592
+ // the function returns it instead when `sel` is set.
1593
+ TopCandidatesQueue<C> selected_candidates;
1594
+ if (sel) {
1595
+ reservePriorityQueue(selected_candidates, ef);
1596
+ }
1597
+
1583
1598
  CandidatesQueue<C> candidates;
1584
1599
  reservePriorityQueue(candidates, ef);
1585
1600
 
1601
+ // Adds a node to a queue of the best `max_size` nodes. The size test
1602
+ // comes first because `top()` needs a queue that is not empty.
1603
+ auto push_bounded = [max_size](
1604
+ TopCandidatesQueue<C>& queue,
1605
+ const float dis,
1606
+ const size_t idx) {
1607
+ if (queue.size() >= max_size && !C::cmp(queue.top().first, dis)) {
1608
+ return false;
1609
+ }
1610
+ queue.emplace(dis, idx);
1611
+ if (queue.size() > max_size) {
1612
+ queue.pop();
1613
+ }
1614
+ return true;
1615
+ };
1616
+
1586
1617
  top_candidates.push(node);
1587
1618
  candidates.push(node);
1619
+ if (sel && sel->is_member(node.second)) {
1620
+ selected_candidates.push(node);
1621
+ }
1588
1622
 
1589
1623
  vt.set(node.second);
1590
1624
 
@@ -1619,14 +1653,11 @@ TopCandidatesQueue<C> search_from_candidate_unbounded_fixVT(
1619
1653
  size_t saved_j[4];
1620
1654
 
1621
1655
  auto add_to_heap = [&](const size_t idx, const float dis) {
1622
- if (C::cmp(top_candidates.top().first, dis) ||
1623
- top_candidates.size() < static_cast<size_t>(ef)) {
1656
+ if (sel && sel->is_member(idx)) {
1657
+ push_bounded(selected_candidates, dis, idx);
1658
+ }
1659
+ if (push_bounded(top_candidates, dis, idx)) {
1624
1660
  candidates.emplace(dis, idx);
1625
- top_candidates.emplace(dis, idx);
1626
-
1627
- if (top_candidates.size() > static_cast<size_t>(ef)) {
1628
- top_candidates.pop();
1629
- }
1630
1661
  }
1631
1662
  };
1632
1663
 
@@ -1674,6 +1705,9 @@ TopCandidatesQueue<C> search_from_candidate_unbounded_fixVT(
1674
1705
  }
1675
1706
  stats.ndis += ndis;
1676
1707
 
1708
+ if (sel) {
1709
+ return selected_candidates;
1710
+ }
1677
1711
  return top_candidates;
1678
1712
  }
1679
1713
 
@@ -1693,7 +1727,7 @@ std::priority_queue<HNSW::Node> hnsw_detail::search_from_candidate_unbounded(
1693
1727
  using C = HNSW::C_distance;
1694
1728
  auto call = [&]<typename VTType>(VTType& vt_concrete) {
1695
1729
  return search_from_candidate_unbounded_fixVT<VTType, C>(
1696
- hnsw, node, qdis, ef, vt_concrete, stats);
1730
+ hnsw, node, qdis, ef, vt_concrete, stats, nullptr);
1697
1731
  };
1698
1732
  if (VisitedTableVector* vtv = dynamic_cast<VisitedTableVector*>(vt)) {
1699
1733
  return call(*vtv);
@@ -1792,6 +1826,7 @@ HNSWStats search_impl(
1792
1826
  hnsw.search_method == HNSW::SM_DEFAULT ||
1793
1827
  hnsw.search_method == HNSW::SM_PANORAMA,
1794
1828
  "invalid HNSW search method");
1829
+ const IDSelector* sel = params ? params->sel : nullptr;
1795
1830
  auto call = [&]<typename VTType>(VTType& vt_concrete) {
1796
1831
  return search_from_candidate_unbounded_fixVT<VTType, C>(
1797
1832
  hnsw,
@@ -1799,7 +1834,8 @@ HNSWStats search_impl(
1799
1834
  qdis,
1800
1835
  ef,
1801
1836
  vt_concrete,
1802
- stats);
1837
+ stats,
1838
+ sel);
1803
1839
  };
1804
1840
  TopCandidatesQueue<C> top_candidates;
1805
1841
  if (VisitedTableVector* vtv = dynamic_cast<VisitedTableVector*>(&vt)) {
@@ -296,6 +296,76 @@ void hnsw_add_vertices_deterministic(
296
296
  const std::function<void(DistanceComputer&, HNSW::storage_idx_t)>&
297
297
  set_query);
298
298
 
299
+ /// Parameters of add_level_0_links_from_sample() of IndexHNSW and
300
+ /// IndexBinaryHNSW.
301
+ struct HNSWLevel0LinkParameters {
302
+ /// The search that the new links are for. nullptr: the search settings
303
+ /// of the index, which the IVF assignment with a coarse quantizer uses.
304
+ const SearchParametersHNSW* search_params = nullptr;
305
+ /// A sink receives at least this factor times the mean number of
306
+ /// vectors per node.
307
+ float min_mean_factor = 3.0f;
308
+ /// For at least this fraction of the vectors that the search sends to a
309
+ /// sink, an exact search finds a nearer node.
310
+ float min_closer_fraction = 0.5f;
311
+ /// Maximum number of level-0 links added to one sink in one round.
312
+ int max_links_per_sink = 32;
313
+ /// Maximum number of rounds that find sinks and add links.
314
+ int max_rounds = 3;
315
+ };
316
+
317
+ struct HNSWLevel0LinkStats {
318
+ /// Sinks found in the first round.
319
+ size_t n_sinks_found = 0;
320
+ /// Sinks found after the last round.
321
+ size_t n_sinks_remaining = 0;
322
+ /// Level-0 links written into free slots.
323
+ size_t n_links_added = 0;
324
+ /// Level-0 links that replaced a link.
325
+ size_t n_links_replaced = 0;
326
+ /// Rounds that changed links.
327
+ int n_rounds = 0;
328
+ /// Exact searches with the storage, in all rounds.
329
+ size_t n_exact_searches = 0;
330
+ };
331
+
332
+ /** The two searches of the sample vectors that
333
+ * hnsw_add_level_0_links_from_sample() compares. IndexHNSW and IndexBinaryHNSW
334
+ * implement them for their vector types. */
335
+ struct HNSWLinkSampleSearch {
336
+ /// number of sample vectors
337
+ idx_t n = 0;
338
+
339
+ virtual ~HNSWLinkSampleSearch() = default;
340
+
341
+ /// HNSW search (k = 1) of the m sample vectors `ids` (null: the first m).
342
+ virtual void search(
343
+ const SearchParametersHNSW* params,
344
+ size_t m,
345
+ const idx_t* ids,
346
+ idx_t* labels) const = 0;
347
+
348
+ /** Exact search (k = 1) of the m sample vectors `ids`. nearer[j] is 1 when
349
+ * exact[j] is nearer than found[j] by more than rounding differences. */
350
+ virtual void search_exact(
351
+ size_t m,
352
+ const idx_t* ids,
353
+ const idx_t* found,
354
+ idx_t* exact,
355
+ uint8_t* nearer) const = 0;
356
+ };
357
+
358
+ /** add_level_0_links_from_sample() of IndexHNSW and IndexBinaryHNSW.
359
+ * `dis` computes distances between nodes. `similarity` is true when a larger
360
+ * distance is nearer. */
361
+ HNSWLevel0LinkStats hnsw_add_level_0_links_from_sample(
362
+ HNSW& hnsw,
363
+ size_t ntotal,
364
+ DistanceComputer& dis,
365
+ bool similarity,
366
+ const HNSWLinkSampleSearch& sample,
367
+ const HNSWLevel0LinkParameters& params);
368
+
299
369
  struct HNSWStats {
300
370
  size_t n1 = 0; /// number of vectors searched
301
371
  size_t n2 =
@@ -315,6 +385,8 @@ struct HNSWStats {
315
385
  ndis += other.ndis;
316
386
  nhops += other.nhops;
317
387
  }
388
+
389
+ void combine_atomic(const HNSWStats& other);
318
390
  };
319
391
 
320
392
  // global var that collects them all
@@ -23,12 +23,9 @@
23
23
  #include <faiss/utils/utils.h>
24
24
 
25
25
  #include <faiss/impl/approx_topk/approx_topk.h>
26
+ #include <faiss/impl/platform_macros.h>
26
27
 
27
- // this is needed for prefetching
28
-
29
- #ifdef COMPILE_SIMD_AVX2
30
- #include <xmmintrin.h>
31
- #endif
28
+ #include <faiss/utils/prefetch.h>
32
29
 
33
30
  extern "C" {
34
31
  // LU decomposition of a general matrix
@@ -602,7 +599,7 @@ void LocalSearchQuantizer::icm_encode_step(
602
599
 
603
600
  // Resolve SIMD level once, not per iteration of the n × n_iters × M loop.
604
601
  with_simd_level_256bit([&]<SIMDLevel SL>() {
605
- #pragma omp parallel for schedule(dynamic)
602
+ #pragma omp parallel for schedule(FAISS_OMP_DYNAMIC)
606
603
  for (int64_t i = 0; i < static_cast<int64_t>(n); i++) {
607
604
  std::vector<float> objs(K);
608
605
 
@@ -622,23 +619,13 @@ void LocalSearchQuantizer::icm_encode_step(
622
619
  continue;
623
620
  }
624
621
 
625
- #ifdef COMPILE_SIMD_AVX2
626
- // TODO: add platform-independent compiler-independent
627
- // prefetch utilities.
628
622
  if (other_m + 1 < M) {
629
623
  // do a single prefetch
630
624
  int32_t code2 = codes[i * M + other_m + 1];
631
- // for (int32_t code = 0; code < K; code += 64) {
632
- int32_t code = 0;
633
- {
634
- size_t binary_idx = (other_m + 1) * M * K * K +
635
- m * K * K + code2 * K + code;
636
- _mm_prefetch(
637
- (const char*)(binaries + binary_idx),
638
- _MM_HINT_T0);
639
- }
625
+ size_t binary_idx = (other_m + 1) * M * K * K +
626
+ m * K * K + code2 * K;
627
+ prefetch_L1(binaries + binary_idx);
640
628
  }
641
- #endif
642
629
 
643
630
  for (size_t code = 0; code < K; code++) {
644
631
  int32_t code2 = codes[i * M + other_m];
@@ -14,6 +14,7 @@
14
14
  #include <faiss/impl/AuxIndexStructures.h>
15
15
  #include <faiss/impl/DistanceComputer.h>
16
16
  #include <faiss/impl/VisitedTable.h>
17
+ #include <faiss/impl/platform_macros.h>
17
18
 
18
19
  namespace faiss {
19
20
 
@@ -200,7 +201,7 @@ void NNDescent::join(DistanceComputer& qdis) {
200
201
  idx_t check_period = InterruptCallback::get_period_hint(d * search_L);
201
202
  for (idx_t i0 = 0; i0 < (idx_t)ntotal; i0 += check_period) {
202
203
  idx_t i1 = std::min(i0 + check_period, (idx_t)ntotal);
203
- #pragma omp parallel for default(shared) schedule(dynamic, 100)
204
+ #pragma omp parallel for default(shared) schedule(FAISS_OMP_DYNAMIC, 100)
204
205
  for (idx_t n = i0; n < i1; n++) {
205
206
  graph[n].join([&](int i, int j) {
206
207
  if (i != j) {
@@ -15,6 +15,7 @@
15
15
 
16
16
  #include <faiss/impl/DistanceComputer.h>
17
17
  #include <faiss/impl/VisitedTable.h>
18
+ #include <faiss/impl/platform_macros.h>
18
19
 
19
20
  namespace faiss {
20
21
 
@@ -352,7 +353,7 @@ void NSG::link(
352
353
  std::unique_ptr<DistanceComputer> dis(
353
354
  storage_distance_computer(storage));
354
355
 
355
- #pragma omp for schedule(dynamic, 100)
356
+ #pragma omp for schedule(FAISS_OMP_DYNAMIC, 100)
356
357
  for (int i = 0; i < ntotal; i++) {
357
358
  storage->reconstruct(i, vec.get());
358
359
  dis->set_query(vec.get());
@@ -375,7 +376,7 @@ void NSG::link(
375
376
  std::unique_ptr<DistanceComputer> dis(
376
377
  storage_distance_computer(storage));
377
378
 
378
- #pragma omp for schedule(dynamic, 100)
379
+ #pragma omp for schedule(FAISS_OMP_DYNAMIC, 100)
379
380
  for (int i = 0; i < ntotal; ++i) {
380
381
  add_reverse_links(i, locks, *dis, graph);
381
382
  }
@@ -14,6 +14,7 @@
14
14
  #include <faiss/impl/IDSelector.h>
15
15
  #include <faiss/impl/PanoramaStats.h>
16
16
  #include <faiss/utils/distances.h>
17
+ #include <faiss/utils/simd_levels.h>
17
18
 
18
19
  #include <algorithm>
19
20
  #include <cstddef>
@@ -21,7 +22,7 @@
21
22
  #include <cstring>
22
23
  #include <vector>
23
24
 
24
- #if defined(COMPILE_SIMD_AVX2) && defined(__AVX2__) && defined(__BMI2__)
25
+ #if FAISS_SIMD_TU(AVX2) && defined(__BMI2__)
25
26
  #include <immintrin.h>
26
27
  #endif
27
28
 
@@ -154,7 +155,7 @@ inline size_t compact_active_kernel(
154
155
  size_t next_active = 0;
155
156
  size_t i = 0;
156
157
 
157
- #if defined(COMPILE_SIMD_AVX2) && defined(__AVX2__) && defined(__BMI2__)
158
+ #if FAISS_SIMD_TU(AVX2) && defined(__BMI2__)
158
159
  for (; i + 8 <= num_active; i += 8) {
159
160
  uint64_t bytes;
160
161
  memcpy(&bytes, &active_byteset[i], 8);