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
@@ -26,6 +26,7 @@
26
26
  #include <faiss/utils/distances_dispatch.h>
27
27
  #include <faiss/utils/distances_fused/distances_fused.h>
28
28
  #include <faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h>
29
+ #include <faiss/utils/utils.h>
29
30
 
30
31
  #ifndef FINTEGER
31
32
  #define FINTEGER long
@@ -361,10 +362,11 @@ void exhaustive_L2sqr_seq(
361
362
  }
362
363
  }
363
364
 
364
- /** Find the nearest neighbors for nx queries in a set of ny vectors */
365
- template <class BlockResultHandler>
366
- void exhaustive_inner_product_blas(
367
- const float* x,
365
+ /** Find the nearest neighbors for nx queries (see Fp32QueryTiles) in a set
366
+ * of ny vectors */
367
+ template <class BlockResultHandler, class QueryTiles>
368
+ void exhaustive_inner_product_blas_tiles(
369
+ QueryTiles& queries,
368
370
  const float* y,
369
371
  size_t d,
370
372
  size_t nx,
@@ -386,6 +388,8 @@ void exhaustive_inner_product_blas(
386
388
  i1 = nx;
387
389
  }
388
390
 
391
+ const float* xt = queries.tile(i0, i1, nullptr);
392
+
389
393
  res.begin_multiple(i0, i1);
390
394
 
391
395
  for (size_t j0 = 0; j0 < ny; j0 += bs_y) {
@@ -405,7 +409,7 @@ void exhaustive_inner_product_blas(
405
409
  &one,
406
410
  y + j0 * d,
407
411
  &di,
408
- x + i0 * d,
412
+ xt,
409
413
  &di,
410
414
  &zero,
411
415
  ip_block.get(),
@@ -421,9 +425,9 @@ void exhaustive_inner_product_blas(
421
425
 
422
426
  // distance correction is an operator that can be applied to transform
423
427
  // the distances
424
- template <class BlockResultHandler>
425
- void exhaustive_L2sqr_blas_default_impl(
426
- const float* x,
428
+ template <class BlockResultHandler, class QueryTiles>
429
+ void exhaustive_L2sqr_blas_tiles(
430
+ QueryTiles& queries,
427
431
  const float* y,
428
432
  size_t d,
429
433
  size_t nx,
@@ -443,7 +447,7 @@ void exhaustive_L2sqr_blas_default_impl(
443
447
  std::unique_ptr<float[]> x_norms(new float[nx]);
444
448
  std::unique_ptr<float[]> del2;
445
449
 
446
- fvec_norms_L2sqr(x_norms.get(), x, d, nx);
450
+ queries.prepare_norms(nx, x_norms.get());
447
451
 
448
452
  if (!y_norms) {
449
453
  float* y_norms2 = new float[ny];
@@ -458,6 +462,8 @@ void exhaustive_L2sqr_blas_default_impl(
458
462
  i1 = nx;
459
463
  }
460
464
 
465
+ const float* xt = queries.tile(i0, i1, x_norms.get());
466
+
461
467
  res.begin_multiple(i0, i1);
462
468
 
463
469
  for (size_t j0 = 0; j0 < ny; j0 += bs_y) {
@@ -477,7 +483,7 @@ void exhaustive_L2sqr_blas_default_impl(
477
483
  &one,
478
484
  y + j0 * d,
479
485
  &di,
480
- x + i0 * d,
486
+ xt,
481
487
  &di,
482
488
  &zero,
483
489
  ip_block.get(),
@@ -510,6 +516,31 @@ void exhaustive_L2sqr_blas_default_impl(
510
516
  }
511
517
  }
512
518
 
519
+ template <class BlockResultHandler>
520
+ void exhaustive_inner_product_blas(
521
+ const float* x,
522
+ const float* y,
523
+ size_t d,
524
+ size_t nx,
525
+ size_t ny,
526
+ BlockResultHandler& res) {
527
+ Fp32QueryTiles queries{x, d};
528
+ exhaustive_inner_product_blas_tiles(queries, y, d, nx, ny, res);
529
+ }
530
+
531
+ template <class BlockResultHandler>
532
+ void exhaustive_L2sqr_blas_default_impl(
533
+ const float* x,
534
+ const float* y,
535
+ size_t d,
536
+ size_t nx,
537
+ size_t ny,
538
+ BlockResultHandler& res,
539
+ const float* y_norms = nullptr) {
540
+ Fp32QueryTiles queries{x, d};
541
+ exhaustive_L2sqr_blas_tiles(queries, y, d, nx, ny, res, y_norms);
542
+ }
543
+
513
544
  template <class BlockResultHandler>
514
545
  void exhaustive_L2sqr_blas(
515
546
  const float* x,
@@ -556,6 +587,44 @@ void exhaustive_L2sqr_blas<Top1BlockResultHandler<CMax<float, int64_t>>>(
556
587
  });
557
588
  }
558
589
 
590
+ /// exhaustive_L2sqr_blas for packed IEEE binary16 queries
591
+ template <class BlockResultHandler>
592
+ void exhaustive_L2sqr_blas_fp16(
593
+ const uint16_t* x,
594
+ const float* y,
595
+ size_t d,
596
+ size_t nx,
597
+ size_t ny,
598
+ BlockResultHandler& res,
599
+ const float* y_norms) {
600
+ Fp16QueryTiles queries(x, d, nx);
601
+ exhaustive_L2sqr_blas_tiles(queries, y, d, nx, ny, res, y_norms);
602
+ }
603
+
604
+ template <>
605
+ void exhaustive_L2sqr_blas_fp16<Top1BlockResultHandler<CMax<float, int64_t>>>(
606
+ const uint16_t* x,
607
+ const float* y,
608
+ size_t d,
609
+ size_t nx,
610
+ size_t ny,
611
+ Top1BlockResultHandler<CMax<float, int64_t>>& res,
612
+ const float* y_norms) {
613
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
614
+ [&]<SIMDLevel SL>() {
615
+ if constexpr (
616
+ SL == SIMDLevel::AVX2 || SL == SIMDLevel::AVX512 ||
617
+ SL == SIMDLevel::ARM_SVE) {
618
+ exhaustive_L2sqr_blas_cmax_fp16<SL>(
619
+ x, y, d, nx, ny, res, y_norms);
620
+ } else {
621
+ Fp16QueryTiles queries(x, d, nx);
622
+ exhaustive_L2sqr_blas_tiles(
623
+ queries, y, d, nx, ny, res, y_norms);
624
+ }
625
+ });
626
+ }
627
+
559
628
  struct Run_search_inner_product {
560
629
  using T = void;
561
630
  template <class BlockResultHandler>
@@ -598,6 +667,35 @@ struct Run_search_L2sqr {
598
667
  }
599
668
  };
600
669
 
670
+ // fp16 consumers only run the BLAS kernels, see use_fp16_blas_kernels
671
+ struct Run_search_inner_product_fp16 {
672
+ using T = void;
673
+ template <class BlockResultHandler>
674
+ void f(BlockResultHandler& res,
675
+ const uint16_t* x,
676
+ const float* y,
677
+ size_t d,
678
+ size_t nx,
679
+ size_t ny) {
680
+ Fp16QueryTiles queries(x, d, nx);
681
+ exhaustive_inner_product_blas_tiles(queries, y, d, nx, ny, res);
682
+ }
683
+ };
684
+
685
+ struct Run_search_L2sqr_fp16 {
686
+ using T = void;
687
+ template <class BlockResultHandler>
688
+ void f(BlockResultHandler& res,
689
+ const uint16_t* x,
690
+ const float* y,
691
+ size_t d,
692
+ size_t nx,
693
+ size_t ny,
694
+ const float* y_norm2) {
695
+ exhaustive_L2sqr_blas_fp16(x, y, d, nx, ny, res, y_norm2);
696
+ }
697
+ };
698
+
601
699
  } // anonymous namespace
602
700
 
603
701
  /*******************************************************
@@ -630,7 +728,7 @@ static void knn_db_parallel_impl(
630
728
  int nt = omp_get_max_threads();
631
729
  const size_t bs_y = distance_compute_blas_database_bs;
632
730
 
633
- // Per-thread result heaps: nt threads x nx queries x k results
731
+ // Result heaps: nt segments x nx queries x k results
634
732
  std::vector<T> all_dis(static_cast<size_t>(nt) * nx * k);
635
733
  std::vector<TI> all_ids(static_cast<size_t>(nt) * nx * k);
636
734
 
@@ -649,9 +747,8 @@ static void knn_db_parallel_impl(
649
747
  }
650
748
  }
651
749
 
652
- #pragma omp parallel num_threads(nt)
653
- {
654
- int tid = omp_get_thread_num();
750
+ #pragma omp parallel for
751
+ for (int tid = 0; tid < nt; tid++) {
655
752
  size_t j_begin = static_cast<size_t>(tid) * ny / nt;
656
753
  size_t j_end = static_cast<size_t>(tid + 1) * ny / nt;
657
754
  size_t local_ny = j_end - j_begin;
@@ -734,7 +831,7 @@ static void knn_db_parallel_impl(
734
831
  }
735
832
  }
736
833
 
737
- // Merge per-thread heaps into output, parallelized over queries
834
+ // Merge per-segment heaps into output, parallelized over queries
738
835
  #pragma omp parallel for
739
836
  for (int64_t i = 0; i < static_cast<int64_t>(nx); i++) {
740
837
  heap_heapify<C>(k, vals + i * k, ids + i * k);
@@ -894,6 +991,120 @@ void knn_L2sqr(
894
991
  knn_L2sqr(x, y, d, nx, ny, res->k, res->val, res->ids, y_norm2, sel);
895
992
  }
896
993
 
994
+ namespace {
995
+
996
+ /** Whether fp16 queries go to the BLAS kernels directly.
997
+ *
998
+ * Other cases widen chunks of queries and run the fp32 search: selectors,
999
+ * sequential and database-parallel searches, and small d, where the fused
1000
+ * top-1 kernels need fp32 rows.
1001
+ */
1002
+ bool use_fp16_blas_kernels(
1003
+ size_t d,
1004
+ size_t nx,
1005
+ size_t ny,
1006
+ const IDSelector* sel) {
1007
+ return !sel && ny > 0 && d > 32 &&
1008
+ nx * d >= static_cast<size_t>(distance_compute_blas_threshold) &&
1009
+ !should_use_db_parallel(nx, ny, sel);
1010
+ }
1011
+
1012
+ /// widens chunks of queries and calls search(x_chunk, n_chunk, i0) on them
1013
+ template <class Fp32Search>
1014
+ void search_fp16_by_chunks(
1015
+ const uint16_t* x,
1016
+ size_t d,
1017
+ size_t nx,
1018
+ const Fp32Search& search) {
1019
+ // a multiple of the query tile, so the fp32 kernels see the same tiles
1020
+ const size_t bs_x = std::max(distance_compute_blas_query_bs, 1);
1021
+ const size_t chunk = bs_x *
1022
+ std::max<size_t>(1, (size_t(8) << 20) / (bs_x * d * sizeof(float)));
1023
+ std::vector<float> buffer(std::min(nx, chunk) * d);
1024
+ for (size_t i0 = 0; i0 < nx; i0 += chunk) {
1025
+ const size_t i1 = std::min(nx, i0 + chunk);
1026
+ fp16_to_fp32((i1 - i0) * d, x + i0 * d, buffer.data());
1027
+ search(buffer.data(), i1 - i0, i0);
1028
+ }
1029
+ }
1030
+
1031
+ } // namespace
1032
+
1033
+ void knn_inner_product_fp16(
1034
+ const uint16_t* x,
1035
+ const float* y,
1036
+ size_t d,
1037
+ size_t nx,
1038
+ size_t ny,
1039
+ size_t k,
1040
+ float* vals,
1041
+ int64_t* ids,
1042
+ const IDSelector* sel) {
1043
+ if (!use_fp16_blas_kernels(d, nx, ny, sel)) {
1044
+ search_fp16_by_chunks(
1045
+ x, d, nx, [&](const float* xc, size_t nc, size_t i0) {
1046
+ knn_inner_product(
1047
+ xc,
1048
+ y,
1049
+ d,
1050
+ nc,
1051
+ ny,
1052
+ k,
1053
+ vals + i0 * k,
1054
+ ids + i0 * k,
1055
+ sel);
1056
+ });
1057
+ return;
1058
+ }
1059
+ Run_search_inner_product_fp16 r;
1060
+ dispatch_knn_ResultHandler(
1061
+ nx,
1062
+ vals,
1063
+ ids,
1064
+ k,
1065
+ METRIC_INNER_PRODUCT,
1066
+ nullptr,
1067
+ r,
1068
+ x,
1069
+ y,
1070
+ d,
1071
+ nx,
1072
+ ny);
1073
+ }
1074
+
1075
+ void knn_L2sqr_fp16(
1076
+ const uint16_t* x,
1077
+ const float* y,
1078
+ size_t d,
1079
+ size_t nx,
1080
+ size_t ny,
1081
+ size_t k,
1082
+ float* vals,
1083
+ int64_t* ids,
1084
+ const float* y_norm2,
1085
+ const IDSelector* sel) {
1086
+ if (!use_fp16_blas_kernels(d, nx, ny, sel)) {
1087
+ search_fp16_by_chunks(
1088
+ x, d, nx, [&](const float* xc, size_t nc, size_t i0) {
1089
+ knn_L2sqr(
1090
+ xc,
1091
+ y,
1092
+ d,
1093
+ nc,
1094
+ ny,
1095
+ k,
1096
+ vals + i0 * k,
1097
+ ids + i0 * k,
1098
+ y_norm2,
1099
+ sel);
1100
+ });
1101
+ return;
1102
+ }
1103
+ Run_search_L2sqr_fp16 r;
1104
+ dispatch_knn_ResultHandler(
1105
+ nx, vals, ids, k, METRIC_L2, nullptr, r, x, y, d, nx, ny, y_norm2);
1106
+ }
1107
+
897
1108
  /***************************************************************************
898
1109
  * Range search
899
1110
  ***************************************************************************/
@@ -455,6 +455,36 @@ void knn_L2sqr(
455
455
  const float* y_norm2 = nullptr,
456
456
  const IDSelector* sel = nullptr);
457
457
 
458
+ /** knn_inner_product for packed IEEE binary16 queries (x: nx * d uint16_t).
459
+ *
460
+ * The BLAS kernels widen each query tile once and reuse it for all database
461
+ * tiles, so there is no fp32 copy of the queries. Results are the same as
462
+ * knn_inner_product on the widened queries.
463
+ */
464
+ void knn_inner_product_fp16(
465
+ const uint16_t* x,
466
+ const float* y,
467
+ size_t d,
468
+ size_t nx,
469
+ size_t ny,
470
+ size_t k,
471
+ float* distances,
472
+ int64_t* indexes,
473
+ const IDSelector* sel = nullptr);
474
+
475
+ /// knn_L2sqr for packed IEEE binary16 queries, see knn_inner_product_fp16
476
+ void knn_L2sqr_fp16(
477
+ const uint16_t* x,
478
+ const float* y,
479
+ size_t d,
480
+ size_t nx,
481
+ size_t ny,
482
+ size_t k,
483
+ float* distances,
484
+ int64_t* indexes,
485
+ const float* y_norm2 = nullptr,
486
+ const IDSelector* sel = nullptr);
487
+
458
488
  /** Find the max inner product neighbors for nx queries in a set of ny vectors
459
489
  * indexed by ids. May be useful for re-ranking a pre-selected vector list
460
490
  *
@@ -600,4 +630,8 @@ int fvec_madd_and_argmin(
600
630
  const float* b,
601
631
  float* c);
602
632
 
633
+ /// sum of x[j] for every j < d whose bit is set in bits (LSB-first per byte)
634
+ template <SIMDLevel>
635
+ float fvec_masked_sum(const float* x, const uint8_t* bits, size_t d);
636
+
603
637
  } // namespace faiss
@@ -184,7 +184,7 @@ inline void fvec_sub_dispatch(
184
184
  const float* a,
185
185
  const float* b,
186
186
  float* c) {
187
- with_simd_level_256bit(
187
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_NO_AVX512>(
188
188
  [&]<SIMDLevel level>() { fvec_sub<level>(d, a, b, c); });
189
189
  }
190
190
 
@@ -193,7 +193,7 @@ inline void fvec_add_dispatch(
193
193
  const float* a,
194
194
  const float* b,
195
195
  float* c) {
196
- with_simd_level_256bit(
196
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_NO_AVX512>(
197
197
  [&]<SIMDLevel level>() { fvec_add<level>(d, a, b, c); });
198
198
  }
199
199
 
@@ -202,7 +202,7 @@ inline void fvec_add_scalar_dispatch(
202
202
  const float* a,
203
203
  float b,
204
204
  float* c) {
205
- with_simd_level_256bit(
205
+ with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_NO_AVX512>(
206
206
  [&]<SIMDLevel level>() { fvec_add<level>(d, a, b, c); });
207
207
  }
208
208
 
@@ -214,7 +214,9 @@ inline void compute_PQ_dis_tables_dsub2_dispatch(
214
214
  const float* x,
215
215
  bool is_inner_product,
216
216
  float* dis_tables) {
217
- with_simd_level_256bit([&]<SIMDLevel level>() {
217
+ constexpr int dsub2_mask =
218
+ AVAILABLE_SIMD_LEVELS_AVX2_NEON | (1 << int(SIMDLevel::RISCV_RVV));
219
+ with_selected_simd_levels<dsub2_mask>([&]<SIMDLevel level>() {
218
220
  compute_PQ_dis_tables_dsub2<level>(
219
221
  d, ksub, centroids, nx, x, is_inner_product, dis_tables);
220
222
  });
@@ -7,10 +7,9 @@
7
7
 
8
8
  // -*- c++ -*-
9
9
 
10
+ #include <faiss/impl/platform_macros.h>
10
11
  #include <faiss/utils/distances_fused/distances_fused.h>
11
12
 
12
- #ifdef COMPILE_SIMD_AVX512
13
-
14
13
  #include <immintrin.h>
15
14
 
16
15
  namespace faiss {
@@ -264,7 +263,7 @@ void exhaustive_L2sqr_fused_cmax(
264
263
 
265
264
  const idx_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
266
265
  // the main loop.
267
- #pragma omp parallel for schedule(dynamic)
266
+ #pragma omp parallel for schedule(FAISS_OMP_DYNAMIC)
268
267
  for (idx_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
269
268
  kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
270
269
  x, y, y_transposed.data(), ny, res, y_norms, i);
@@ -343,5 +342,3 @@ bool exhaustive_L2sqr_fused_cmax<SIMDLevel::AVX512>(
343
342
  }
344
343
 
345
344
  } // namespace faiss
346
-
347
- #endif // COMPILE_SIMD_AVX512
@@ -24,20 +24,6 @@ bool exhaustive_L2sqr_fused_cmax<SIMDLevel::NONE>(
24
24
  return false;
25
25
  }
26
26
 
27
- #ifdef COMPILE_SIMD_RISCV_RVV
28
- template <>
29
- bool exhaustive_L2sqr_fused_cmax<SIMDLevel::RISCV_RVV>(
30
- const float*,
31
- const float*,
32
- size_t,
33
- size_t,
34
- size_t,
35
- Top1BlockResultHandler<CMax<float, int64_t>>&,
36
- const float*) {
37
- return false;
38
- }
39
- #endif // COMPILE_SIMD_RISCV_RVV
40
-
41
27
  bool exhaustive_L2sqr_fused_cmax(
42
28
  const float* x,
43
29
  const float* y,
@@ -0,0 +1,25 @@
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
+ #include <faiss/utils/distances_fused/distances_fused.h>
9
+
10
+ namespace faiss {
11
+
12
+ // Scalar fallback: no fused kernel available.
13
+ template <>
14
+ bool exhaustive_L2sqr_fused_cmax<SIMDLevel::RISCV_RVV>(
15
+ const float*,
16
+ const float*,
17
+ size_t,
18
+ size_t,
19
+ size_t,
20
+ Top1BlockResultHandler<CMax<float, int64_t>>&,
21
+ const float*) {
22
+ return false;
23
+ }
24
+
25
+ } // namespace faiss
@@ -7,8 +7,6 @@
7
7
 
8
8
  // AVX2 compilation unit for the simdlib-based fused distance kernel.
9
9
 
10
- #ifdef COMPILE_SIMD_AVX2
11
-
12
10
  #include <faiss/impl/simdlib/simdlib_avx2.h>
13
11
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
14
12
  #include <faiss/utils/distances_fused/simdlib_kernel-inl.h>
@@ -71,5 +69,3 @@ bool exhaustive_L2sqr_fused_cmax<SIMDLevel::AVX2>(
71
69
  }
72
70
 
73
71
  } // namespace faiss
74
-
75
- #endif // COMPILE_SIMD_AVX2
@@ -7,8 +7,6 @@
7
7
 
8
8
  // ARM NEON compilation unit for the simdlib-based fused distance kernel.
9
9
 
10
- #ifdef COMPILE_SIMD_ARM_NEON
11
-
12
10
  #include <faiss/impl/simdlib/simdlib_neon.h>
13
11
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
14
12
  #include <faiss/utils/distances_fused/simdlib_kernel-inl.h>
@@ -53,5 +51,3 @@ bool exhaustive_L2sqr_fused_cmax<SIMDLevel::ARM_NEON>(
53
51
  }
54
52
 
55
53
  } // namespace faiss
56
-
57
- #endif // COMPILE_SIMD_ARM_NEON
@@ -14,6 +14,7 @@
14
14
 
15
15
  #pragma once
16
16
 
17
+ #include <faiss/impl/platform_macros.h>
17
18
  #include <faiss/utils/distances_fused/distances_fused.h>
18
19
 
19
20
  namespace faiss {
@@ -267,7 +268,7 @@ void exhaustive_L2sqr_fused_cmax(
267
268
 
268
269
  const size_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
269
270
  // the main loop.
270
- #pragma omp parallel for schedule(dynamic)
271
+ #pragma omp parallel for schedule(FAISS_OMP_DYNAMIC)
271
272
  for (int64_t i = 0; i < static_cast<int64_t>(nx_p);
272
273
  i += NX_POINTS_PER_LOOP) {
273
274
  kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP, SL>(
@@ -8,6 +8,7 @@
8
8
  // -*- c++ -*-
9
9
 
10
10
  #include <faiss/utils/distances.h>
11
+ #include <faiss/utils/simd_impl/masked_sum.h>
11
12
 
12
13
  #include <cmath>
13
14
  #include <cstring>
@@ -42,6 +43,14 @@ void fvec_madd<SIMDLevel::NONE>(
42
43
  }
43
44
  }
44
45
 
46
+ template <>
47
+ float fvec_masked_sum<SIMDLevel::NONE>(
48
+ const float* x,
49
+ const uint8_t* bits,
50
+ size_t d) {
51
+ return masked_sum<SIMDLevel::NONE>(x, bits, d);
52
+ }
53
+
45
54
  template <>
46
55
  void fvec_L2sqr_ny_transposed<SIMDLevel::NONE>(
47
56
  float* dis,
@@ -12,6 +12,8 @@
12
12
 
13
13
  namespace faiss {
14
14
 
15
+ namespace {
16
+
15
17
  inline uint16_t encode_fp16(float x) {
16
18
  __m128 xf = _mm_set1_ps(x);
17
19
  __m128i xi =
@@ -25,4 +27,6 @@ inline float decode_fp16(uint16_t x) {
25
27
  return _mm_cvtss_f32(xf);
26
28
  }
27
29
 
30
+ } // namespace
31
+
28
32
  } // namespace faiss
@@ -27,63 +27,35 @@ inline uint32_t intbits(float f) {
27
27
  return *(uint32_t*)fptr;
28
28
  }
29
29
 
30
- } // namespace
31
-
32
30
  inline uint16_t encode_fp16(float f) {
33
- // via Fabian "ryg" Giesen.
34
- // https://gist.github.com/2156668
35
- uint32_t sign_mask = 0x80000000u;
36
- int32_t o;
31
+ // Rounds to nearest even, as the F16C and Arm conversions do, so that
32
+ // every SIMD level encodes the same bits. Via Fabian "ryg" Giesen
33
+ // (float_to_half_fast3_rtne): https://gist.github.com/2156668
34
+ const uint32_t f32infty = 255u << 23;
35
+ const uint32_t f16max = (127u + 16u) << 23;
36
+ const uint32_t denorm_magic = ((127u - 15u) + (23u - 10u) + 1u) << 23;
37
+ const uint32_t sign_mask = 0x80000000u;
37
38
 
38
39
  uint32_t fint = intbits(f);
39
- uint32_t sign = fint & sign_mask;
40
+ const uint32_t sign = fint & sign_mask;
40
41
  fint ^= sign;
41
42
 
42
- // NOTE all the integer compares in this function can be safely
43
- // compiled into signed compares since all operands are below
44
- // 0x80000000. Important if you want fast straight SSE2 code (since
45
- // there's no unsigned PCMPGTD).
46
-
47
- // Inf or NaN (all exponent bits set)
48
- // NaN->qNaN and Inf->Inf
49
- // unconditional assignment here, will override with right value for
50
- // the regular case below.
51
- uint32_t f32infty = 255u << 23;
52
- o = (fint > f32infty) ? 0x7e00u : 0x7c00u;
53
-
54
- // (De)normalized number or zero
55
- // update fint unconditionally to save the blending; we don't need it
56
- // anymore for the Inf/NaN case anyway.
57
-
58
- const uint32_t round_mask = ~0xfffu;
59
- const uint32_t magic = 15u << 23;
60
-
61
- // Shift exponent down, denormalize if necessary.
62
- // NOTE This represents half-float denormals using single
63
- // precision denormals. The main reason to do this is that
64
- // there's no shift with per-lane variable shifts in SSE*, which
65
- // we'd otherwise need. It has some funky side effects though:
66
- // - This conversion will actually respect the FTZ (Flush To Zero)
67
- // flag in MXCSR - if it's set, no half-float denormals will be
68
- // generated. I'm honestly not sure whether this is good or
69
- // bad. It's definitely interesting.
70
- // - If the underlying HW doesn't support denormals (not an issue
71
- // with Intel CPUs, but might be a problem on GPUs or PS3 SPUs),
72
- // you will always get flush-to-zero behavior. This is bad,
73
- // unless you're on a CPU where you don't care.
74
- // - Denormals tend to be slow. FP32 denormals are rare in
75
- // practice outside of things like recursive filters in DSP -
76
- // not a typical half-float application. Whether FP16 denormals
77
- // are rare in practice, I don't know. Whatever slow path your
78
- // HW may or may not have for denormals, this may well hit it.
79
- float fscale = floatbits(fint & round_mask) * floatbits(magic);
80
- fscale = std::min(fscale, floatbits((31u << 23) - 0x1000u));
81
- int32_t fint2 = intbits(fscale) - round_mask;
82
-
83
- if (fint < f32infty)
84
- o = fint2 >> 13; // Take the bits!
85
-
86
- return (o | (sign >> 16));
43
+ uint32_t o;
44
+ if (fint >= f16max) {
45
+ // Inf->Inf. NaN->qNaN with the top bits of the payload, as F16C.
46
+ o = (fint > f32infty) ? 0x7e00u | ((fint >> 13) & 0x3ffu) : 0x7c00u;
47
+ } else if (fint < (113u << 23)) {
48
+ // The result is subnormal or zero. Adding a magic value aligns the 10
49
+ // mantissa bits at the bottom of the float, and the float addition
50
+ // rounds to nearest even.
51
+ o = intbits(floatbits(fint) + floatbits(denorm_magic)) - denorm_magic;
52
+ } else {
53
+ const uint32_t mant_odd = (fint >> 13) & 1;
54
+ // rebias the exponent, and round to nearest even
55
+ fint += ((15u - 127u) << 23) + 0xfffu + mant_odd;
56
+ o = fint >> 13;
57
+ }
58
+ return static_cast<uint16_t>(o | (sign >> 16));
87
59
  }
88
60
 
89
61
  inline float decode_fp16(uint16_t h) {
@@ -105,4 +77,6 @@ inline float decode_fp16(uint16_t h) {
105
77
  return floatbits(((exp == shifted_exp) ? infnan_val : reg_val) | sign_bit);
106
78
  }
107
79
 
80
+ } // namespace
81
+
108
82
  } // namespace faiss