usearch 2.21.4 → 2.25.0

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 (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -1,2567 +0,0 @@
1
- /**
2
- * @file simsimd.h
3
- * @brief SIMD-accelerated Similarity Measures and Distance Functions.
4
- * @author Ash Vardanian
5
- * @date March 14, 2023
6
- *
7
- * References:
8
- * x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide
9
- * Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics
10
- * Detecting target CPU features at compile time: https://stackoverflow.com/a/28939692/2766161
11
- *
12
- * @section Choosing x86 Target Generations
13
- *
14
- * It's important to provide fine-grained controls over AVX512 families, as they are very fragmented:
15
- *
16
- * - Intel Skylake servers: F, CD, VL, DQ, BW
17
- * - Intel Cascade Lake workstations: F, CD, VL, DQ, BW, VNNI
18
- * > In other words, it extends Skylake with VNNI support
19
- * - Intel Sunny Cove (Ice Lake) servers:
20
- * F, CD, VL, DQ, BW, VNNI, VPOPCNTDQ, IFMA, VBMI, VAES, GFNI, VBMI2, BITALG, VPCLMULQDQ
21
- * - AMD Zen4 (Genoa):
22
- * F, CD, VL, DQ, BW, VNNI, VPOPCNTDQ, IFMA, VBMI, VAES, GFNI, VBMI2, BITALG, VPCLMULQDQ, BF16
23
- * > In other words, it extends Sunny Cove with BF16 support
24
- * - Intel Golden Cove (Sapphire Rapids): extends Zen4 and Sunny Cove with FP16 support
25
- * - AMD Zen5 (Turin): makes VP2INTERSECT cool again
26
- *
27
- * Intel Palm Cove was an irrelevant intermediate release extending Skylake with IFMA and VBMI.
28
- * Intel Willow Cove was an irrelevant intermediate release extending Sunny Cove with VP2INTERSECT,
29
- * which are not supported by other CPUs to date and are only available in Tiger Lake laptops.
30
- * Intel Cooper Lake was the only intermediary platform, that supported BF16, but not FP16.
31
- * It's mostly used in 4-socket and 8-socket high-memory configurations.
32
- *
33
- * For us, it makes sense to differentiate only these AVX512 generations:
34
- * 1. Intel Skylake (pre 2019): supports single-precision dot-products.
35
- * 2. Intel Ice Lake (2019-2021): advanced integer algorithms.
36
- * 3. AMD Genoa (2023+): brain-floating point support.
37
- * 4. Intel Sapphire Rapids (2023+): advanced mixed-precision float processing.
38
- * 5. AMD Turin (2024+): advanced sparse algorithms.
39
- *
40
- * Beyond those, we support AVX2 for old Haswell generation CPUs, and AVX2+VNNI for modern Sierra generation.
41
- *
42
- * To list all available macros for x86, take a recent compiler, like GCC 12 and run:
43
- * gcc-12 -march=sapphirerapids -dM -E - < /dev/null | egrep "SSE|AVX" | sort
44
- * On Arm machines you may want to check for other flags:
45
- * gcc-12 -march=native -dM -E - < /dev/null | egrep "NEON|SVE|FP16|FMA" | sort
46
- *
47
- * @section Choosing Arm Target Generations
48
- *
49
- * Arm CPUs share design IP, but are produced by different vendors, potentially making the platform
50
- * even more fragmented than x86. There are 2 important families of SIMD extensions - NEON and SVE.
51
- *
52
- * - Armv8-A: +fp, +simd
53
- * - Armv8.1-A: armv8-a, +crc, +lse, +rdma
54
- * - Armv8.2-A: armv8.1-a
55
- * - Armv8.3-A: armv8.2-a, +pauth
56
- * - Armv8.4-A: armv8.3-a, +flagm, +fp16fml, +dotprod
57
- * - Armv8.5-A: armv8.4-a, +sb, +ssbs, +predres
58
- * - Armv8.6-A: armv8.5-a, +bf16, +i8mm
59
- * - Armv8.7-A: armv8.6-a, +ls64
60
- * - Armv8.8-A: armv8.7-a, +mops
61
- * - Armv8.9-A: armv8.8-a
62
- * - Armv9-A: armv8.5-a, +sve, +sve2
63
- * - Armv9.1-A: armv9-a, +bf16, +i8mm
64
- * - Armv9.2-A: armv9.1-a, +ls64
65
- * - Armv9.3-A: armv9.2-a, +mops
66
- * - Armv9.4-A: armv9.3-a
67
- *
68
- * SVE has been optional since Armv8.2-A, but it's a requirement for Armv9.0-A.
69
- * A 512-bit SVE variant has already been implemented on the Fugaku supercomputer.
70
- * A more flexible version, 2x256 SVE, was implemented by the AWS Graviton3 ARM processor.
71
- * Here are the most important recent families of CPU cores designed by Arm:
72
- *
73
- * - Neoverse N1: armv8.2-a, extended with Armv8.4 "dotprod" instructions.
74
- * Used in AWS @b Graviton2 and Ampere @b Altra.
75
- * https://developer.arm.com/Processors/Neoverse%20N1
76
- * - Neoverse V1: armv8.4-a, extended with Armv8.6 bfloat/int8 "matmul" instructions.
77
- * Used in AWS @b Graviton3, which also enables `sve`, `svebf16`, and `svei8mm`.
78
- * https://developer.arm.com/Processors/Neoverse%20V1
79
- * - Neoverse V2: armv9.0 with SVE2 and SVE bit-permutes
80
- * Used in AWS @b Graviton4, NVIDIA @b Grace, Google @b Axion.
81
- * https://developer.arm.com/Processors/Neoverse%20V2
82
- * The N2 core is very similar to V2 and is used by Microsoft @b Cobalt.
83
- * https://developer.arm.com/Processors/Neoverse%20N2
84
- *
85
- * On the consumer side, Apple is the biggest player with mobile @b A chips and desktop @b M chips.
86
- * The M1 implements Armv8.5-A, both M2 and M3 implement Armv8.6-A, and M4 is expected to have Armv9.1-A.
87
- */
88
-
89
- #ifndef SIMSIMD_H
90
- #define SIMSIMD_H
91
-
92
- #define SIMSIMD_VERSION_MAJOR 6
93
- #define SIMSIMD_VERSION_MINOR 5
94
- #define SIMSIMD_VERSION_PATCH 5
95
-
96
- /**
97
- * @brief Removes compile-time dispatching, and replaces it with runtime dispatching.
98
- * So the `simsimd_dot_f32` function will invoke the most advanced backend supported by the CPU,
99
- * that runs the program, rather than the most advanced backend supported by the CPU
100
- * used to compile the library or the downstream application.
101
- */
102
- #if !defined(SIMSIMD_DYNAMIC_DISPATCH)
103
- #define SIMSIMD_DYNAMIC_DISPATCH (0) // true or false
104
- #endif
105
-
106
- #include "binary.h" // Hamming, Jaccard
107
- #include "curved.h" // Mahalanobis, Bilinear Forms
108
- #include "dot.h" // Inner (dot) product, and its conjugate
109
- #include "elementwise.h" // Weighted Sum, Fused-Multiply-Add
110
- #include "geospatial.h" // Haversine and Vincenty
111
- #include "probability.h" // Kullback-Leibler, Jensen–Shannon
112
- #include "sparse.h" // Intersect
113
- #include "spatial.h" // L2, Cosine
114
-
115
- // On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
116
- #if defined(_SIMSIMD_DEFINED_APPLE)
117
- #include <fenv.h> // `fesetenv` - part of C 99 standard
118
- #include <sys/sysctl.h> // `sysctlbyname`
119
- #endif
120
-
121
- // Detect POSIX extensions availability for signal handling.
122
- // POSIX extensions provide `sigaction`, `sigjmp_buf`, and `sigsetjmp` for safe signal handling.
123
- // These are needed on Linux ARM for safely testing `mrs` instruction availability.
124
- #if defined(_SIMSIMD_DEFINED_LINUX) && defined(_POSIX_VERSION)
125
- #include <setjmp.h> // `sigjmp_buf`, `sigsetjmp`, `siglongjmp`
126
- #include <signal.h> // `sigaction`, `SIGILL`
127
- #define _SIMSIMD_HAS_POSIX_EXTENSIONS 1
128
- #else
129
- #define _SIMSIMD_HAS_POSIX_EXTENSIONS 0
130
- #endif
131
-
132
- // On Windows ARM, we use IsProcessorFeaturePresent API for capability detection
133
- #if defined(_SIMSIMD_DEFINED_WINDOWS) && _SIMSIMD_TARGET_ARM
134
- #include <processthreadsapi.h> // `IsProcessorFeaturePresent`
135
- #endif
136
-
137
- #ifdef __cplusplus
138
- extern "C" {
139
- #endif
140
-
141
- /**
142
- * @brief Enumeration of supported metric kinds.
143
- * Some have aliases for convenience.
144
- */
145
- typedef enum {
146
- simsimd_metric_unknown_k = 0, ///< Unknown metric kind
147
-
148
- // Classics:
149
- simsimd_metric_dot_k = 'i', ///< Inner product
150
- simsimd_metric_inner_k = 'i', ///< Inner product alias
151
-
152
- simsimd_metric_vdot_k = 'v', ///< Complex inner product
153
-
154
- simsimd_metric_cos_k = 'c', ///< Cosine similarity
155
- simsimd_metric_cosine_k = 'c', ///< Cosine similarity alias
156
- simsimd_metric_angular_k = 'c', ///< Cosine similarity alias
157
-
158
- simsimd_metric_l2_k = '2', ///< Euclidean distance alias
159
- simsimd_metric_euclidean_k = '2', ///< Euclidean distance alias
160
- simsimd_metric_l2sq_k = 'e', ///< Squared Euclidean distance
161
- simsimd_metric_sqeuclidean_k = 'e', ///< Squared Euclidean distance alias
162
-
163
- // Binary:
164
- simsimd_metric_hamming_k = 'h', ///< Hamming distance
165
- simsimd_metric_manhattan_k = 'h', ///< Manhattan distance is same as Hamming
166
-
167
- simsimd_metric_jaccard_k = 'j', ///< Jaccard coefficient
168
- simsimd_metric_tanimoto_k = 'j', ///< Tanimoto coefficient is same as Jaccard
169
-
170
- // Sets:
171
- simsimd_metric_intersect_k = 'x', ///< Equivalent to unnormalized Jaccard
172
- simsimd_metric_spdot_counts_k = 'y', ///< Sparse sets with integer weights
173
- simsimd_metric_spdot_weights_k = 'z', ///< Sparse sets with brain floating-point weights
174
-
175
- // Curved Spaces:
176
- simsimd_metric_bilinear_k = 'b', ///< Bilinear form
177
- simsimd_metric_mahalanobis_k = 'm', ///< Mahalanobis distance
178
-
179
- // Probability:
180
- simsimd_metric_kl_k = 'k', ///< Kullback-Leibler divergence
181
- simsimd_metric_kullback_leibler_k = 'k', ///< Kullback-Leibler divergence alias
182
-
183
- simsimd_metric_js_k = 's', ///< Jensen-Shannon divergence
184
- simsimd_metric_jensen_shannon_k = 's', ///< Jensen-Shannon divergence alias
185
-
186
- // BLAS-like operations:
187
- simsimd_metric_fma_k = 'f', ///< Fused Multiply-Add
188
- simsimd_metric_wsum_k = 'w', ///< Weighted Sum
189
-
190
- } simsimd_metric_kind_t;
191
-
192
- /**
193
- * @brief Enumeration of SIMD capabilities of the target architecture.
194
- */
195
- typedef enum {
196
- simsimd_cap_serial_k = 1, ///< Serial (non-SIMD) capability
197
- simsimd_cap_any_k = 0x7FFFFFFF, ///< Mask representing any capability with `INT_MAX`
198
-
199
- simsimd_cap_haswell_k = 1 << 10, ///< x86 AVX2 capability with FMA and F16C extensions
200
- simsimd_cap_skylake_k = 1 << 11, ///< x86 AVX512 baseline capability
201
- simsimd_cap_ice_k = 1 << 12, ///< x86 AVX512 capability with advanced integer algos
202
- simsimd_cap_genoa_k = 1 << 13, ///< x86 AVX512 capability with `bf16` support
203
- simsimd_cap_sapphire_k = 1 << 14, ///< x86 AVX512 capability with `f16` support
204
- simsimd_cap_turin_k = 1 << 15, ///< x86 AVX512 capability with conflict detection
205
- simsimd_cap_sierra_k = 1 << 16, ///< x86 AVX2+VNNI capability with `i8` dot-products
206
-
207
- simsimd_cap_neon_k = 1 << 20, ///< ARM NEON baseline capability
208
- simsimd_cap_neon_f16_k = 1 << 21, ///< ARM NEON `f16` capability
209
- simsimd_cap_neon_bf16_k = 1 << 22, ///< ARM NEON `bf16` capability
210
- simsimd_cap_neon_i8_k = 1 << 23, ///< ARM NEON `i8` capability
211
- simsimd_cap_sve_k = 1 << 24, ///< ARM SVE baseline capability
212
- simsimd_cap_sve_f16_k = 1 << 25, ///< ARM SVE `f16` capability
213
- simsimd_cap_sve_bf16_k = 1 << 26, ///< ARM SVE `bf16` capability
214
- simsimd_cap_sve_i8_k = 1 << 27, ///< ARM SVE `i8` capability
215
- simsimd_cap_sve2_k = 1 << 28, ///< ARM SVE2 capability
216
- simsimd_cap_sve2p1_k = 1 << 29, ///< ARM SVE2p1 capability
217
-
218
- } simsimd_capability_t;
219
-
220
- /**
221
- * @brief Enumeration of supported data types.
222
- *
223
- * Includes complex type descriptors which in C code would use the real counterparts,
224
- * but the independent flags contain metadata to be passed between programming language
225
- * interfaces.
226
- */
227
- typedef enum {
228
- simsimd_datatype_unknown_k = 0, ///< Unknown data type
229
- simsimd_datatype_b8_k = 1 << 1, ///< Single-bit values packed into 8-bit words
230
- simsimd_datatype_b1x8_k = simsimd_datatype_b8_k, ///< Single-bit values packed into 8-bit words
231
- simsimd_datatype_i4x2_k = 1 << 19, ///< 4-bit signed integers packed into 8-bit words
232
-
233
- simsimd_datatype_i8_k = 1 << 2, ///< 8-bit signed integer
234
- simsimd_datatype_i16_k = 1 << 3, ///< 16-bit signed integer
235
- simsimd_datatype_i32_k = 1 << 4, ///< 32-bit signed integer
236
- simsimd_datatype_i64_k = 1 << 5, ///< 64-bit signed integer
237
-
238
- simsimd_datatype_u8_k = 1 << 6, ///< 8-bit unsigned integer
239
- simsimd_datatype_u16_k = 1 << 7, ///< 16-bit unsigned integer
240
- simsimd_datatype_u32_k = 1 << 8, ///< 32-bit unsigned integer
241
- simsimd_datatype_u64_k = 1 << 9, ///< 64-bit unsigned integer
242
-
243
- simsimd_datatype_f64_k = 1 << 10, ///< Double precision floating point
244
- simsimd_datatype_f32_k = 1 << 11, ///< Single precision floating point
245
- simsimd_datatype_f16_k = 1 << 12, ///< Half precision floating point
246
- simsimd_datatype_bf16_k = 1 << 13, ///< Brain floating point
247
-
248
- simsimd_datatype_f64c_k = 1 << 20, ///< Complex double precision floating point
249
- simsimd_datatype_f32c_k = 1 << 21, ///< Complex single precision floating point
250
- simsimd_datatype_f16c_k = 1 << 22, ///< Complex half precision floating point
251
- simsimd_datatype_bf16c_k = 1 << 23, ///< Complex brain floating point
252
- } simsimd_datatype_t;
253
-
254
- /**
255
- * @brief Type-punned function pointer for dense vector representations and simplest similarity measures.
256
- *
257
- * @param[in] a Pointer to the first data array.
258
- * @param[in] b Pointer to the second data array.
259
- * @param[in] n Number of scalar words in the input arrays.
260
- * When dealing with sub-byte types, the number of scalar words is the number of bytes.
261
- * When dealing with complex types, the number of scalar words is the sum of real and imaginary parts.
262
- * @param[out] d Output value as a double-precision float.
263
- * In complex dot-products @b two scalars are exported for the real and imaginary parts.
264
- */
265
- typedef void (*simsimd_metric_dense_punned_t)(void const *a, void const *b, simsimd_size_t n, simsimd_distance_t *d);
266
-
267
- /**
268
- * @brief Type-punned function pointer for sparse vector representations and similarity measures.
269
- *
270
- * @param[in] a Pointer to the first data array, generally a sorted array of integers.
271
- * @param[in] b Pointer to the second data array, generally a sorted array of integers.
272
- * @param[in] a_length Number of scalar words in the first input array.
273
- * @param[in] b_length Number of scalar words in the second input array.
274
- * @param[out] d Output value as a double-precision float, generally without decimals.
275
- */
276
- typedef void (*simsimd_metric_sparse_punned_t)( //
277
- void const *a, void const *b, //
278
- simsimd_size_t a_length, simsimd_size_t b_length, //
279
- simsimd_distance_t *d);
280
-
281
- /**
282
- * @brief Type-punned function pointer for curved vector spaces and similarity measures.
283
- *
284
- * @param[in] a Pointer to the first data array.
285
- * @param[in] b Pointer to the second data array.
286
- * @param[in] c Pointer to the metric tensor array or some covariance matrix.
287
- * @param[in] n Number of scalar words in the input arrays.
288
- * @param[out] d Output value as a double-precision float.
289
- */
290
- typedef void (*simsimd_metric_curved_punned_t)( //
291
- void const *a, void const *b, void const *c, //
292
- simsimd_size_t n, simsimd_distance_t *d);
293
-
294
- /**
295
- * @brief Type-punned function pointer for FMA operations on dense vector representations.
296
- * Implements the `y = alpha * a * b + beta * c` operation.
297
- *
298
- * @param[in] a Pointer to the first data array.
299
- * @param[in] b Pointer to the second data array.
300
- * @param[in] c Pointer to the third data array.
301
- * @param[in] n Number of scalar words in the input arrays.
302
- * @param[in] alpha Scaling factor for the first two arrays.
303
- * @param[in] beta Scaling factor for the third array.
304
- * @param[out] y Output value in the same precision as the input arrays.
305
- */
306
- typedef void (*simsimd_kernel_fma_punned_t)( //
307
- void const *a, void const *b, void const *c, //
308
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta, void *y);
309
-
310
- /**
311
- * @brief Type-punned function pointer for Weighted Sum operations on dense vector representations.
312
- * Implements the `y = alpha * a + beta * b` operation.
313
- *
314
- * @param[in] a Pointer to the first data array.
315
- * @param[in] b Pointer to the second data array.
316
- * @param[in] n Number of scalar words in the input arrays.
317
- * @param[in] alpha Scaling factor for the first array.
318
- * @param[in] beta Scaling factor for the second array.
319
- * @param[out] y Output value in the same precision as the input arrays.
320
- */
321
- typedef void (*simsimd_kernel_wsum_punned_t)( //
322
- void const *a, void const *b, //
323
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta, void *y);
324
-
325
- /**
326
- * @brief Type-punned function pointer for a SimSIMD public interface.
327
- *
328
- * Can be a `simsimd_metric_dense_punned_t`, `simsimd_metric_sparse_punned_t`, `simsimd_metric_curved_punned_t`,
329
- * `simsimd_kernel_fma_punned_t`, or `simsimd_kernel_wsum_punned_t`.
330
- */
331
- typedef void (*simsimd_kernel_punned_t)(void *);
332
-
333
- #if SIMSIMD_DYNAMIC_DISPATCH
334
- SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
335
- SIMSIMD_DYNAMIC void simsimd_find_kernel_punned( //
336
- simsimd_metric_kind_t kind, //
337
- simsimd_datatype_t datatype, //
338
- simsimd_capability_t supported, //
339
- simsimd_capability_t allowed, //
340
- simsimd_kernel_punned_t *kernel_output, //
341
- simsimd_capability_t *capability_output);
342
- SIMSIMD_DYNAMIC int simsimd_flush_denormals(void);
343
- #else
344
- SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void);
345
- SIMSIMD_PUBLIC void simsimd_find_kernel_punned( //
346
- simsimd_metric_kind_t kind, //
347
- simsimd_datatype_t datatype, //
348
- simsimd_capability_t supported, //
349
- simsimd_capability_t allowed, //
350
- simsimd_kernel_punned_t *kernel_output, //
351
- simsimd_capability_t *capability_output);
352
- SIMSIMD_PUBLIC int simsimd_flush_denormals(void);
353
- #endif
354
-
355
- #if _SIMSIMD_TARGET_X86
356
-
357
- /**
358
- * @brief Function to flush denormalized numbers to zero on x86 CPUs.
359
- * @note This should be called on each thread before any SIMD operations to avoid performance penalties.
360
- * @return 1 if the operation was successful, 0 otherwise.
361
- */
362
- SIMSIMD_PUBLIC int _simsimd_flush_denormals_x86(void) {
363
- #if defined(_MSC_VER)
364
- unsigned int mxcsr = _mm_getcsr();
365
- mxcsr |= 1 << 15; // bit 15 = Flush-To-Zero (FTZ)
366
- mxcsr |= 1 << 6; // bit 6 = Denormals-Are-Zero (DAZ)
367
- _mm_setcsr(mxcsr);
368
- #else // GCC, Clang, ICC
369
- unsigned int mxcsr;
370
- __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));
371
- mxcsr |= 1 << 15; // bit 15 = Flush-To-Zero (FTZ)
372
- mxcsr |= 1 << 6; // bit 6 = Denormals-Are-Zero (DAZ)
373
- __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
374
- #endif
375
- return 1;
376
- }
377
-
378
- /**
379
- * @brief Function to determine the SIMD capabilities of the current 64-bit x86 machine at @b runtime.
380
- * @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
381
- */
382
- SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_x86(void) {
383
-
384
- /// The states of 4 registers populated for a specific "cpuid" assembly call
385
- union four_registers_t {
386
- int array[4];
387
- struct separate_t {
388
- unsigned eax, ebx, ecx, edx;
389
- } named;
390
- } info1, info7, info7sub1;
391
-
392
- #if defined(_MSC_VER)
393
- __cpuidex(info1.array, 1, 0);
394
- __cpuidex(info7.array, 7, 0);
395
- __cpuidex(info7sub1.array, 7, 1);
396
- #else // GCC, Clang, ICC
397
- __asm__ __volatile__( //
398
- "cpuid"
399
- : "=a"(info1.named.eax), "=b"(info1.named.ebx), "=c"(info1.named.ecx), "=d"(info1.named.edx)
400
- : "a"(1), "c"(0));
401
- __asm__ __volatile__( //
402
- "cpuid"
403
- : "=a"(info7.named.eax), "=b"(info7.named.ebx), "=c"(info7.named.ecx), "=d"(info7.named.edx)
404
- : "a"(7), "c"(0));
405
- __asm__ __volatile__( //
406
- "cpuid"
407
- : "=a"(info7sub1.named.eax), "=b"(info7sub1.named.ebx), "=c"(info7sub1.named.ecx), "=d"(info7sub1.named.edx)
408
- : "a"(7), "c"(1));
409
- #endif
410
-
411
- // Check for AVX2 (Function ID 7, EBX register)
412
- // https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L148
413
- unsigned supports_avx2 = (info7.named.ebx & 0x00000020) != 0;
414
- // Check for F16C (Function ID 1, ECX register)
415
- // https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L107
416
- unsigned supports_f16c = (info1.named.ecx & 0x20000000) != 0;
417
- unsigned supports_fma = (info1.named.ecx & 0x00001000) != 0;
418
- // Check for AVX512F (Function ID 7, EBX register)
419
- // https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L155
420
- unsigned supports_avx512f = (info7.named.ebx & 0x00010000) != 0;
421
- // Check for AVX512FP16 (Function ID 7, EDX register)
422
- // https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L198C9-L198C23
423
- unsigned supports_avx512fp16 = (info7.named.edx & 0x00800000) != 0;
424
- // Check for AVX512VNNI (Function ID 7, ECX register)
425
- unsigned supports_avx512vnni = (info7.named.ecx & 0x00000800) != 0;
426
- // Check for AVX512IFMA (Function ID 7, EBX register)
427
- unsigned supports_avx512ifma = (info7.named.ebx & 0x00200000) != 0;
428
- // Check for AVX512BITALG (Function ID 7, ECX register)
429
- unsigned supports_avx512bitalg = (info7.named.ecx & 0x00001000) != 0;
430
- // Check for AVX512VBMI2 (Function ID 7, ECX register)
431
- unsigned supports_avx512vbmi2 = (info7.named.ecx & 0x00000040) != 0;
432
- // Check for AVX512VPOPCNTDQ (Function ID 7, ECX register)
433
- unsigned supports_avx512vpopcntdq = (info7.named.ecx & 0x00004000) != 0;
434
- // Check for AVX512BF16 (Function ID 7, Sub-leaf 1, EAX register)
435
- // https://github.com/llvm/llvm-project/blob/50598f0ff44f3a4e75706f8c53f3380fe7faa896/clang/lib/Headers/cpuid.h#L205
436
- unsigned supports_avx512bf16 = (info7sub1.named.eax & 0x00000020) != 0;
437
- // Clang doesn't show the VP2INTERSECT flag, but we can get it from QEMU
438
- // https://stackoverflow.com/a/68289220/2766161
439
- unsigned supports_avx512vp2intersect = (info7.named.edx & 0x00000100) != 0;
440
-
441
- // Convert specific features into CPU generations
442
- unsigned supports_haswell = supports_avx2 && supports_f16c && supports_fma;
443
- unsigned supports_skylake = supports_avx512f;
444
- unsigned supports_ice = supports_avx512vnni && supports_avx512ifma && supports_avx512bitalg &&
445
- supports_avx512vbmi2 && supports_avx512vpopcntdq;
446
- unsigned supports_genoa = supports_avx512bf16;
447
- unsigned supports_sapphire = supports_avx512fp16;
448
- // We don't want to accidentally enable AVX512VP2INTERSECT on Intel Tiger Lake CPUs
449
- unsigned supports_turin = supports_avx512vp2intersect && supports_avx512bf16;
450
- unsigned supports_sierra = 0;
451
-
452
- return (simsimd_capability_t)( //
453
- (simsimd_cap_haswell_k * supports_haswell) | //
454
- (simsimd_cap_skylake_k * supports_skylake) | //
455
- (simsimd_cap_ice_k * supports_ice) | //
456
- (simsimd_cap_genoa_k * supports_genoa) | //
457
- (simsimd_cap_sapphire_k * supports_sapphire) | //
458
- (simsimd_cap_turin_k * supports_turin) | //
459
- (simsimd_cap_sierra_k * supports_sierra) | //
460
- (simsimd_cap_serial_k));
461
- }
462
-
463
- #endif // _SIMSIMD_TARGET_X86
464
-
465
- #if _SIMSIMD_TARGET_ARM
466
-
467
- /* Compiling the next section one may get: selected processor does not support system register name 'id_aa64zfr0_el1'.
468
- * Suppressing assembler errors is very complicated, so when dealing with older ARM CPUs it's simpler to compile this
469
- * function targeting newer ones.
470
- */
471
- #pragma GCC push_options
472
- #pragma GCC target("arch=armv8.5-a+sve")
473
- #pragma clang attribute push(__attribute__((target("arch=armv8.5-a+sve"))), apply_to = function)
474
-
475
- #if _SIMSIMD_HAS_POSIX_EXTENSIONS
476
- /** @brief SIGILL handler for `mrs` instruction testing on Linux ARM */
477
- static sigjmp_buf _simsimd_mrs_test_jump_buffer;
478
- static void _simsimd_mrs_test_sigill_handler(int sig) {
479
- (void)sig; // Unused parameter
480
- siglongjmp(_simsimd_mrs_test_jump_buffer, 1);
481
- }
482
- #endif
483
-
484
- /**
485
- * @brief Function to flush denormalized numbers to zero on Arm CPUs.
486
- * @note This should be called on each thread before any SIMD operations to avoid performance penalties.
487
- * @note On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
488
- * @return 1 if the operation was successful, 0 otherwise.
489
- */
490
- SIMSIMD_PUBLIC int _simsimd_flush_denormals_arm(void) {
491
- #if defined(_SIMSIMD_DEFINED_APPLE)
492
- // https://stackoverflow.com/a/19904907/2766161
493
- // https://stackoverflow.com/a/78252076/2766161
494
- int is_success = fesetenv(FE_DFL_DISABLE_DENORMS_ENV) == 0;
495
- return is_success;
496
- #elif defined(_SIMSIMD_DEFINED_LINUX)
497
- // For Linux, we can toggle bits in the Floating-point Control Register (FPCR)
498
- // https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Registers/FPCR--Floating-point-Control-Register
499
- uint64_t fpcr;
500
- __asm__ volatile("mrs %0, fpcr" : "=r"(fpcr));
501
- fpcr |= (1 << 19); // bit 19 = FZ16 (Flush half-precision to zero)
502
- fpcr |= (1 << 24); // bit 24 = FZ (Flush subnormals to zero)
503
- fpcr |= (1 << 25); // bit 25 = DN (Force Default NaN instead of preserving payload)
504
- __asm__ volatile("msr fpcr, %0" : : "r"(fpcr));
505
- return 1;
506
- #else
507
- return 0;
508
- #endif
509
- }
510
-
511
- /**
512
- * @brief Function to determine the SIMD capabilities of the current 64-bit Arm machine at @b runtime.
513
- * @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
514
- */
515
- SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_arm(void) {
516
- #if defined(_SIMSIMD_DEFINED_APPLE)
517
- // On Apple Silicon, `mrs` is not allowed in user-space, so we need to use the `sysctl` API.
518
- unsigned supports_neon = 0, supports_fp16 = 0, supports_bf16 = 0, supports_i8mm = 0;
519
- size_t size = sizeof(supports_neon);
520
- if (sysctlbyname("hw.optional.neon", &supports_neon, &size, NULL, 0) != 0) supports_neon = 0;
521
- if (sysctlbyname("hw.optional.arm.FEAT_FP16", &supports_fp16, &size, NULL, 0) != 0) supports_fp16 = 0;
522
- if (sysctlbyname("hw.optional.arm.FEAT_BF16", &supports_bf16, &size, NULL, 0) != 0) supports_bf16 = 0;
523
- if (sysctlbyname("hw.optional.arm.FEAT_I8MM", &supports_i8mm, &size, NULL, 0) != 0) supports_i8mm = 0;
524
-
525
- return (simsimd_capability_t)( //
526
- (simsimd_cap_neon_k * (supports_neon)) | //
527
- (simsimd_cap_neon_f16_k * (supports_neon && supports_fp16)) | //
528
- (simsimd_cap_neon_bf16_k * (supports_neon && supports_bf16)) | //
529
- (simsimd_cap_neon_i8_k * (supports_neon && supports_i8mm)) | //
530
- (simsimd_cap_serial_k));
531
-
532
- #elif defined(_SIMSIMD_DEFINED_LINUX)
533
-
534
- // Depending on the environment, reading system registers may cause SIGILL.
535
- // One option to avoid the crash is to use `getauxval(AT_HWCAP)` and `getauxval(AT_HWCAP2)`,
536
- // Linux APIs, but those aren't as informative as reading the registers directly.
537
- // So before reading the ID registers, we set up a signal handler to catch SIGILL
538
- // and probe one of the registers, reverting back to the old signal handler afterwards.
539
- //
540
- // This issue was originally observed in: https://github.com/ashvardanian/SimSIMD/issues/279
541
- #if _SIMSIMD_HAS_POSIX_EXTENSIONS
542
- struct sigaction action_new, action_old;
543
- action_new.sa_handler = _simsimd_mrs_test_sigill_handler;
544
- sigemptyset(&action_new.sa_mask);
545
- action_new.sa_flags = 0;
546
-
547
- int mrs_works = 0;
548
- if (sigaction(SIGILL, &action_new, &action_old) == 0) {
549
- if (sigsetjmp(_simsimd_mrs_test_jump_buffer, 1) == 0) {
550
- unsigned long midr_value;
551
- __asm__ __volatile__("mrs %0, MIDR_EL1" : "=r"(midr_value));
552
- mrs_works = 1;
553
- }
554
- sigaction(SIGILL, &action_old, NULL);
555
- }
556
-
557
- // Early exit if `mrs` doesn't work - return conservative NEON-only capabilities
558
- if (!mrs_works) return (simsimd_capability_t)(simsimd_cap_neon_k | simsimd_cap_serial_k);
559
- #else // _SIMSIMD_HAS_POSIX_EXTENSIONS
560
- // Without POSIX signal handlers, fall back to conservative NEON capabilities.
561
- return (simsimd_capability_t)(simsimd_cap_neon_k | simsimd_cap_serial_k);
562
- #endif // _SIMSIMD_HAS_POSIX_EXTENSIONS
563
-
564
- // Read CPUID registers directly
565
- unsigned long id_aa64isar0_el1 = 0, id_aa64isar1_el1 = 0, id_aa64pfr0_el1 = 0, id_aa64zfr0_el1 = 0;
566
-
567
- // Now let's unpack the status flags from ID_AA64ISAR0_EL1
568
- // https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0?lang=en
569
- __asm__ __volatile__("mrs %0, ID_AA64ISAR0_EL1" : "=r"(id_aa64isar0_el1));
570
- // DP, bits [47:44] of ID_AA64ISAR0_EL1
571
- unsigned supports_integer_dot_products = ((id_aa64isar0_el1 >> 44) & 0xF) >= 1;
572
- // Now let's unpack the status flags from ID_AA64ISAR1_EL1
573
- // https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ISAR1-EL1--AArch64-Instruction-Set-Attribute-Register-1?lang=en
574
- __asm__ __volatile__("mrs %0, ID_AA64ISAR1_EL1" : "=r"(id_aa64isar1_el1));
575
- // I8MM, bits [55:52] of ID_AA64ISAR1_EL1
576
- unsigned supports_i8mm = ((id_aa64isar1_el1 >> 52) & 0xF) >= 1;
577
- // BF16, bits [47:44] of ID_AA64ISAR1_EL1
578
- unsigned supports_bf16 = ((id_aa64isar1_el1 >> 44) & 0xF) >= 1;
579
-
580
- // Now let's unpack the status flags from ID_AA64PFR0_EL1
581
- // https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64PFR0-EL1--AArch64-Processor-Feature-Register-0?lang=en
582
- __asm__ __volatile__("mrs %0, ID_AA64PFR0_EL1" : "=r"(id_aa64pfr0_el1));
583
- // SVE, bits [35:32] of ID_AA64PFR0_EL1
584
- unsigned supports_sve = ((id_aa64pfr0_el1 >> 32) & 0xF) >= 1;
585
- // AdvSIMD, bits [23:20] of ID_AA64PFR0_EL1 can be used to check for `fp16` support
586
- // - 0b0000: integers, single, double precision arithmetic
587
- // - 0b0001: includes support for half-precision floating-point arithmetic
588
- // - 0b1111: NEON is not supported?!
589
- // That's a really weird way to encode lack of NEON support, but it's important to
590
- // check in case we are running on R-profile CPUs.
591
- unsigned supports_fp16 = ((id_aa64pfr0_el1 >> 20) & 0xF) == 0x1;
592
- unsigned supports_neon = ((id_aa64pfr0_el1 >> 20) & 0xF) != 0xF;
593
-
594
- // Now let's unpack the status flags from ID_AA64ZFR0_EL1
595
- // https://developer.arm.com/documentation/ddi0601/2024-03/AArch64-Registers/ID-AA64ZFR0-EL1--SVE-Feature-ID-Register-0?lang=en
596
- if (supports_sve) __asm__ __volatile__("mrs %0, ID_AA64ZFR0_EL1" : "=r"(id_aa64zfr0_el1));
597
- // I8MM, bits [47:44] of ID_AA64ZFR0_EL1
598
- unsigned supports_sve_i8mm = ((id_aa64zfr0_el1 >> 44) & 0xF) >= 1;
599
- // BF16, bits [23:20] of ID_AA64ZFR0_EL1
600
- unsigned supports_sve_bf16 = ((id_aa64zfr0_el1 >> 20) & 0xF) >= 1;
601
- // SVEver, bits [3:0] can be used to check for capability levels:
602
- // - 0b0000: SVE is implemented
603
- // - 0b0001: SVE2 is implemented
604
- // - 0b0010: SVE2.1 is implemented
605
- // This value must match the existing indicator obtained from ID_AA64PFR0_EL1:
606
- unsigned supports_sve2 = ((id_aa64zfr0_el1) & 0xF) >= 1;
607
- unsigned supports_sve2p1 = ((id_aa64zfr0_el1) & 0xF) >= 2;
608
-
609
- return (simsimd_capability_t)( //
610
- (simsimd_cap_neon_k * (supports_neon)) | //
611
- (simsimd_cap_neon_f16_k * (supports_neon && supports_fp16)) | //
612
- (simsimd_cap_neon_bf16_k * (supports_neon && supports_bf16)) | //
613
- (simsimd_cap_neon_i8_k * (supports_neon && supports_i8mm && supports_integer_dot_products)) | //
614
- (simsimd_cap_sve_k * (supports_sve)) | //
615
- (simsimd_cap_sve_f16_k * (supports_sve && supports_fp16)) | //
616
- (simsimd_cap_sve_bf16_k * (supports_sve && supports_sve_bf16)) | //
617
- (simsimd_cap_sve_i8_k * (supports_sve && supports_sve_i8mm)) | //
618
- (simsimd_cap_sve2_k * (supports_sve2)) | //
619
- (simsimd_cap_sve2p1_k * (supports_sve2p1)) | //
620
- (simsimd_cap_serial_k));
621
-
622
- #elif defined(_SIMSIMD_DEFINED_WINDOWS)
623
-
624
- unsigned supports_neon = 0, supports_dp = 0;
625
-
626
- // On Windows ARM, use the `IsProcessorFeaturePresent` API for capability detection.
627
- // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
628
- #if defined(PF_ARM_V8_INSTRUCTIONS_AVAILABLE)
629
- supports_neon = IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE);
630
- #endif
631
- #if defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
632
- supports_dp = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE);
633
- #endif
634
-
635
- // Windows API doesn't provide reliable detection for FP16, BF16.
636
- return (simsimd_capability_t)( //
637
- (simsimd_cap_neon_k * (supports_neon)) | //
638
- (simsimd_cap_neon_i8_k * (supports_neon && supports_dp)) | //
639
- (simsimd_cap_serial_k));
640
-
641
- #else // Unknown platform
642
-
643
- // Conservative fallback for unknown platforms: NEON is mandatory in ARMv8-A (ARM64)
644
- return (simsimd_capability_t)(simsimd_cap_neon_k | simsimd_cap_serial_k);
645
-
646
- #endif
647
- }
648
-
649
- #pragma clang attribute pop
650
- #pragma GCC pop_options
651
-
652
- #endif
653
-
654
- /**
655
- * @brief Function to flush @b denormalized numbers to zero to avoid performance penalties.
656
- * @return 1 if the operation was successful, 0 otherwise.
657
- *
658
- * When facing denormalized values Fused-Multiply-Add (FMA) operations can be up to 30x slower,
659
- * as measured on Intel Sapphire Rapids: https://github.com/ashvardanian/ParallelReductionsBenchmark
660
- */
661
- SIMSIMD_PUBLIC int _simsimd_flush_denormals(void) {
662
- #if _SIMSIMD_TARGET_X86
663
- return _simsimd_flush_denormals_x86();
664
- #endif // _SIMSIMD_TARGET_X86
665
- #if _SIMSIMD_TARGET_ARM
666
- return _simsimd_flush_denormals_arm();
667
- #endif // _SIMSIMD_TARGET_ARM
668
- return 0;
669
- }
670
-
671
- /**
672
- * @brief Function to determine the SIMD capabilities of the current 64-bit x86 machine at @b runtime.
673
- * @return A bitmask of the SIMD capabilities represented as a `simsimd_capability_t` enum value.
674
- */
675
- SIMSIMD_PUBLIC simsimd_capability_t _simsimd_capabilities_implementation(void) {
676
- #if _SIMSIMD_TARGET_X86
677
- return _simsimd_capabilities_x86();
678
- #endif // _SIMSIMD_TARGET_X86
679
- #if _SIMSIMD_TARGET_ARM
680
- return _simsimd_capabilities_arm();
681
- #endif // _SIMSIMD_TARGET_ARM
682
- return simsimd_cap_serial_k;
683
- }
684
-
685
- #pragma GCC diagnostic push
686
- #pragma GCC diagnostic ignored "-Wcast-function-type"
687
- #pragma clang diagnostic push
688
- #pragma clang diagnostic ignored "-Wcast-function-type"
689
-
690
- #ifdef __cplusplus //! option "-Wvolatile" is valid for C++/ObjC++ but not for C
691
- #pragma GCC diagnostic ignored "-Wvolatile"
692
- #pragma clang diagnostic ignored "-Wvolatile"
693
- #endif
694
-
695
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f64(simsimd_capability_t v, simsimd_metric_kind_t k,
696
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
697
- typedef simsimd_kernel_punned_t m_t;
698
- #if SIMSIMD_TARGET_SVE
699
- if (v & simsimd_cap_sve_k) switch (k) {
700
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_sve, *c = simsimd_cap_sve_k; return;
701
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_sve, *c = simsimd_cap_sve_k; return;
702
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_sve, *c = simsimd_cap_sve_k; return;
703
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_sve, *c = simsimd_cap_sve_k; return;
704
- default: break;
705
- }
706
- #endif
707
- #if SIMSIMD_TARGET_NEON
708
- if (v & simsimd_cap_neon_k) switch (k) {
709
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_neon, *c = simsimd_cap_neon_k; return;
710
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_neon, *c = simsimd_cap_neon_k; return;
711
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_neon, *c = simsimd_cap_neon_k; return;
712
- default: break;
713
- }
714
- #endif
715
- #if SIMSIMD_TARGET_SKYLAKE
716
- if (v & simsimd_cap_skylake_k) switch (k) {
717
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_skylake, *c = simsimd_cap_skylake_k; return;
718
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_skylake, *c = simsimd_cap_skylake_k; return;
719
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_skylake, *c = simsimd_cap_skylake_k; return;
720
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_skylake, *c = simsimd_cap_skylake_k; return;
721
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f64_skylake, *c = simsimd_cap_skylake_k; return;
722
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f64_skylake, *c = simsimd_cap_skylake_k; return;
723
- default: break;
724
- }
725
- #endif
726
- #if SIMSIMD_TARGET_HASWELL
727
- if (v & simsimd_cap_haswell_k) switch (k) {
728
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_haswell, *c = simsimd_cap_haswell_k; return;
729
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_haswell, *c = simsimd_cap_haswell_k; return;
730
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_haswell, *c = simsimd_cap_haswell_k; return;
731
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f64_haswell, *c = simsimd_cap_haswell_k; return;
732
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f64_haswell, *c = simsimd_cap_haswell_k; return;
733
- default: break;
734
- }
735
- #endif
736
- if (v & simsimd_cap_serial_k) switch (k) {
737
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64_serial, *c = simsimd_cap_serial_k; return;
738
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f64_serial, *c = simsimd_cap_serial_k; return;
739
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f64_serial, *c = simsimd_cap_serial_k; return;
740
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f64_serial, *c = simsimd_cap_serial_k; return;
741
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f64_serial, *c = simsimd_cap_serial_k; return;
742
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f64_serial, *c = simsimd_cap_serial_k; return;
743
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64_serial, *c = simsimd_cap_serial_k; return;
744
- case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f64_serial, *c = simsimd_cap_serial_k; return;
745
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f64_serial, *c = simsimd_cap_serial_k; return;
746
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f64_serial, *c = simsimd_cap_serial_k; return;
747
- default: break;
748
- }
749
- }
750
-
751
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32(simsimd_capability_t v, simsimd_metric_kind_t k,
752
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
753
- typedef simsimd_kernel_punned_t m_t;
754
- #if SIMSIMD_TARGET_SVE
755
- if (v & simsimd_cap_sve_k) switch (k) {
756
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_sve, *c = simsimd_cap_sve_k; return;
757
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_sve, *c = simsimd_cap_sve_k; return;
758
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_sve, *c = simsimd_cap_sve_k; return;
759
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_sve, *c = simsimd_cap_sve_k; return;
760
- default: break;
761
- }
762
- #endif
763
- #if SIMSIMD_TARGET_NEON
764
- if (v & simsimd_cap_neon_k) switch (k) {
765
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_neon, *c = simsimd_cap_neon_k; return;
766
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_neon, *c = simsimd_cap_neon_k; return;
767
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_neon, *c = simsimd_cap_neon_k; return;
768
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_neon, *c = simsimd_cap_neon_k; return;
769
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_neon, *c = simsimd_cap_neon_k; return;
770
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_neon, *c = simsimd_cap_neon_k; return;
771
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_neon, *c = simsimd_cap_neon_k; return;
772
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_neon, *c = simsimd_cap_neon_k; return;
773
- default: break;
774
- }
775
- #endif
776
- #if SIMSIMD_TARGET_SKYLAKE
777
- if (v & simsimd_cap_skylake_k) switch (k) {
778
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_skylake, *c = simsimd_cap_skylake_k; return;
779
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_skylake, *c = simsimd_cap_skylake_k; return;
780
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_skylake, *c = simsimd_cap_skylake_k; return;
781
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_skylake, *c = simsimd_cap_skylake_k; return;
782
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_skylake, *c = simsimd_cap_skylake_k; return;
783
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_skylake, *c = simsimd_cap_skylake_k; return;
784
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32_skylake, *c = simsimd_cap_skylake_k; return;
785
- case simsimd_metric_mahalanobis_k:
786
- *m = (m_t)&simsimd_mahalanobis_f32_skylake, *c = simsimd_cap_skylake_k;
787
- return;
788
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_skylake, *c = simsimd_cap_skylake_k; return;
789
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_skylake, *c = simsimd_cap_skylake_k; return;
790
- default: break;
791
- }
792
- #endif
793
- #if SIMSIMD_TARGET_HASWELL
794
- if (v & simsimd_cap_haswell_k) switch (k) {
795
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_haswell, *c = simsimd_cap_haswell_k; return;
796
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_haswell, *c = simsimd_cap_haswell_k; return;
797
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_haswell, *c = simsimd_cap_haswell_k; return;
798
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_haswell, *c = simsimd_cap_haswell_k; return;
799
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_haswell, *c = simsimd_cap_haswell_k; return;
800
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_haswell, *c = simsimd_cap_haswell_k; return;
801
- default: break;
802
- }
803
- #endif
804
- if (v & simsimd_cap_serial_k) switch (k) {
805
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32_serial, *c = simsimd_cap_serial_k; return;
806
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f32_serial, *c = simsimd_cap_serial_k; return;
807
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f32_serial, *c = simsimd_cap_serial_k; return;
808
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f32_serial, *c = simsimd_cap_serial_k; return;
809
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f32_serial, *c = simsimd_cap_serial_k; return;
810
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f32_serial, *c = simsimd_cap_serial_k; return;
811
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32_serial, *c = simsimd_cap_serial_k; return;
812
- case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f32_serial, *c = simsimd_cap_serial_k; return;
813
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f32_serial, *c = simsimd_cap_serial_k; return;
814
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f32_serial, *c = simsimd_cap_serial_k; return;
815
- default: break;
816
- }
817
- }
818
-
819
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16(simsimd_capability_t v, simsimd_metric_kind_t k,
820
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
821
- typedef simsimd_kernel_punned_t m_t;
822
- #if SIMSIMD_TARGET_SVE_F16
823
- if (v & simsimd_cap_sve_k) switch (k) {
824
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sve, *c = simsimd_cap_sve_f16_k; return;
825
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sve, *c = simsimd_cap_sve_f16_k; return;
826
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sve, *c = simsimd_cap_sve_f16_k; return;
827
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_sve, *c = simsimd_cap_sve_f16_k; return;
828
- default: break;
829
- }
830
- #endif
831
- #if SIMSIMD_TARGET_NEON_F16
832
- if (v & simsimd_cap_neon_f16_k) switch (k) {
833
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_neon, *c = simsimd_cap_neon_f16_k; return;
834
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_neon, *c = simsimd_cap_neon_f16_k; return;
835
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_neon, *c = simsimd_cap_neon_f16_k; return;
836
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_neon, *c = simsimd_cap_neon_f16_k; return;
837
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_neon, *c = simsimd_cap_neon_f16_k; return;
838
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_neon, *c = simsimd_cap_neon_f16_k; return;
839
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_neon, *c = simsimd_cap_neon_f16_k; return;
840
- case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f16_neon, *c = simsimd_cap_neon_f16_k; return;
841
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_neon, *c = simsimd_cap_neon_f16_k; return;
842
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_neon, *c = simsimd_cap_neon_f16_k; return;
843
- default: break;
844
- }
845
- #endif
846
- #if SIMSIMD_TARGET_SAPPHIRE
847
- if (v & simsimd_cap_sapphire_k) switch (k) {
848
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
849
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
850
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
851
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
852
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
853
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
854
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
855
- case simsimd_metric_mahalanobis_k:
856
- *m = (m_t)&simsimd_mahalanobis_f16_sapphire, *c = simsimd_cap_sapphire_k;
857
- return;
858
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
859
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_sapphire, *c = simsimd_cap_sapphire_k; return;
860
- default: break;
861
- }
862
- #endif
863
- #if SIMSIMD_TARGET_HASWELL
864
- if (v & simsimd_cap_haswell_k) switch (k) {
865
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_haswell, *c = simsimd_cap_haswell_k; return;
866
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_haswell, *c = simsimd_cap_haswell_k; return;
867
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_haswell, *c = simsimd_cap_haswell_k; return;
868
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_haswell, *c = simsimd_cap_haswell_k; return;
869
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_haswell, *c = simsimd_cap_haswell_k; return;
870
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_haswell, *c = simsimd_cap_haswell_k; return;
871
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_haswell, *c = simsimd_cap_haswell_k; return;
872
- case simsimd_metric_mahalanobis_k:
873
- *m = (m_t)&simsimd_mahalanobis_f16_haswell, *c = simsimd_cap_haswell_k;
874
- return;
875
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_haswell, *c = simsimd_cap_haswell_k; return;
876
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_haswell, *c = simsimd_cap_haswell_k; return;
877
- default: break;
878
- }
879
- #endif
880
- if (v & simsimd_cap_serial_k) switch (k) {
881
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16_serial, *c = simsimd_cap_serial_k; return;
882
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_f16_serial, *c = simsimd_cap_serial_k; return;
883
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_f16_serial, *c = simsimd_cap_serial_k; return;
884
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_f16_serial, *c = simsimd_cap_serial_k; return;
885
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_f16_serial, *c = simsimd_cap_serial_k; return;
886
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_f16_serial, *c = simsimd_cap_serial_k; return;
887
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16_serial, *c = simsimd_cap_serial_k; return;
888
- case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_f16_serial, *c = simsimd_cap_serial_k; return;
889
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_f16_serial, *c = simsimd_cap_serial_k; return;
890
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_f16_serial, *c = simsimd_cap_serial_k; return;
891
- default: break;
892
- }
893
- }
894
-
895
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_bf16(simsimd_capability_t v, simsimd_metric_kind_t k,
896
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
897
- typedef simsimd_kernel_punned_t m_t;
898
- #if SIMSIMD_TARGET_SVE_BF16
899
- if (v & simsimd_cap_sve_bf16_k) switch (k) {
900
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
901
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
902
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_sve, *c = simsimd_cap_sve_bf16_k; return;
903
- default: break;
904
- }
905
- #endif
906
- #if SIMSIMD_TARGET_NEON_BF16
907
- if (v & simsimd_cap_neon_bf16_k) switch (k) {
908
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
909
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
910
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
911
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
912
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
913
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_neon, *c = simsimd_cap_neon_bf16_k; return;
914
- default: break;
915
- }
916
- #endif
917
- #if SIMSIMD_TARGET_GENOA
918
- if (v & simsimd_cap_genoa_k) switch (k) {
919
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_genoa, *c = simsimd_cap_genoa_k; return;
920
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_genoa, *c = simsimd_cap_genoa_k; return;
921
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_genoa, *c = simsimd_cap_genoa_k; return;
922
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_genoa, *c = simsimd_cap_genoa_k; return;
923
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_genoa, *c = simsimd_cap_genoa_k; return;
924
- case simsimd_metric_mahalanobis_k: *m = (m_t)&simsimd_mahalanobis_bf16_genoa, *c = simsimd_cap_genoa_k; return;
925
- default: break;
926
- }
927
- #endif
928
- #if SIMSIMD_TARGET_SKYLAKE
929
- if (v & simsimd_cap_skylake_k) switch (k) {
930
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_skylake, *c = simsimd_cap_skylake_k; return;
931
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_skylake, *c = simsimd_cap_skylake_k; return;
932
- default: break;
933
- }
934
- #endif
935
- #if SIMSIMD_TARGET_HASWELL
936
- if (v & simsimd_cap_haswell_k) switch (k) {
937
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_haswell, *c = simsimd_cap_haswell_k; return;
938
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_haswell, *c = simsimd_cap_haswell_k; return;
939
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_haswell, *c = simsimd_cap_haswell_k; return;
940
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_haswell, *c = simsimd_cap_haswell_k; return;
941
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_haswell, *c = simsimd_cap_haswell_k; return;
942
- case simsimd_metric_mahalanobis_k:
943
- *m = (m_t)&simsimd_mahalanobis_bf16_haswell, *c = simsimd_cap_haswell_k;
944
- return;
945
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_haswell, *c = simsimd_cap_haswell_k; return;
946
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_haswell, *c = simsimd_cap_haswell_k; return;
947
- default: break;
948
- }
949
- #endif
950
- if (v & simsimd_cap_serial_k) switch (k) {
951
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16_serial, *c = simsimd_cap_serial_k; return;
952
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_bf16_serial, *c = simsimd_cap_serial_k; return;
953
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_bf16_serial, *c = simsimd_cap_serial_k; return;
954
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_bf16_serial, *c = simsimd_cap_serial_k; return;
955
- case simsimd_metric_js_k: *m = (m_t)&simsimd_js_bf16_serial, *c = simsimd_cap_serial_k; return;
956
- case simsimd_metric_kl_k: *m = (m_t)&simsimd_kl_bf16_serial, *c = simsimd_cap_serial_k; return;
957
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16_serial, *c = simsimd_cap_serial_k; return;
958
- case simsimd_metric_mahalanobis_k:
959
- *m = (m_t)&simsimd_mahalanobis_bf16_serial, *c = simsimd_cap_serial_k;
960
- return;
961
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_bf16_serial, *c = simsimd_cap_serial_k; return;
962
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_bf16_serial, *c = simsimd_cap_serial_k; return;
963
- default: break;
964
- }
965
- }
966
-
967
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_i8(simsimd_capability_t v, simsimd_metric_kind_t k,
968
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
969
- typedef simsimd_kernel_punned_t m_t;
970
- #if SIMSIMD_TARGET_NEON_I8
971
- if (v & simsimd_cap_neon_i8_k) switch (k) {
972
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_neon, *c = simsimd_cap_neon_i8_k; return;
973
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_neon, *c = simsimd_cap_neon_i8_k; return;
974
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_neon, *c = simsimd_cap_neon_i8_k; return;
975
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_neon, *c = simsimd_cap_neon_i8_k; return;
976
- default: break;
977
- }
978
- #endif
979
- #if SIMSIMD_TARGET_NEON_F16 //! Scaling of 8-bit integers is performed using 16-bit floats.
980
- if (v & simsimd_cap_neon_f16_k) switch (k) {
981
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_neon, *c = simsimd_cap_neon_f16_k; return;
982
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_neon, *c = simsimd_cap_neon_f16_k; return;
983
- default: break;
984
- }
985
- #endif
986
- #if SIMSIMD_TARGET_SAPPHIRE //! Scaling of 8-bit integers is performed using 16-bit floats.
987
- if (v & simsimd_cap_sapphire_k) switch (k) {
988
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_sapphire, *c = simsimd_cap_sapphire_k; return;
989
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_sapphire, *c = simsimd_cap_sapphire_k; return;
990
- default: break;
991
- }
992
- #endif
993
- #if SIMSIMD_TARGET_ICE
994
- if (v & simsimd_cap_ice_k) switch (k) {
995
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_ice, *c = simsimd_cap_ice_k; return;
996
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_ice, *c = simsimd_cap_ice_k; return;
997
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_ice, *c = simsimd_cap_ice_k; return;
998
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_ice, *c = simsimd_cap_ice_k; return;
999
- default: break;
1000
- }
1001
- #endif
1002
- #if SIMSIMD_TARGET_HASWELL
1003
- if (v & simsimd_cap_haswell_k) switch (k) {
1004
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_haswell, *c = simsimd_cap_haswell_k; return;
1005
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_haswell, *c = simsimd_cap_haswell_k; return;
1006
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_haswell, *c = simsimd_cap_haswell_k; return;
1007
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_haswell, *c = simsimd_cap_haswell_k; return;
1008
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_haswell, *c = simsimd_cap_haswell_k; return;
1009
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_haswell, *c = simsimd_cap_haswell_k; return;
1010
- default: break;
1011
- }
1012
- #endif
1013
- if (v & simsimd_cap_serial_k) switch (k) {
1014
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_i8_serial, *c = simsimd_cap_serial_k; return;
1015
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_i8_serial, *c = simsimd_cap_serial_k; return;
1016
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_i8_serial, *c = simsimd_cap_serial_k; return;
1017
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_i8_serial, *c = simsimd_cap_serial_k; return;
1018
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_i8_serial, *c = simsimd_cap_serial_k; return;
1019
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_i8_serial, *c = simsimd_cap_serial_k; return;
1020
- default: break;
1021
- }
1022
- }
1023
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_u8(simsimd_capability_t v, simsimd_metric_kind_t k,
1024
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1025
- typedef simsimd_kernel_punned_t m_t;
1026
- #if SIMSIMD_TARGET_NEON_I8
1027
- if (v & simsimd_cap_neon_i8_k) switch (k) {
1028
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_neon, *c = simsimd_cap_neon_i8_k; return;
1029
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_neon, *c = simsimd_cap_neon_i8_k; return;
1030
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_neon, *c = simsimd_cap_neon_i8_k; return;
1031
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_neon, *c = simsimd_cap_neon_i8_k; return;
1032
- default: break;
1033
- }
1034
- #endif
1035
- #if SIMSIMD_TARGET_NEON_F16 //! Scaling of 8-bit integers is performed using 16-bit floats.
1036
- if (v & simsimd_cap_neon_f16_k) switch (k) {
1037
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_neon, *c = simsimd_cap_neon_f16_k; return;
1038
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_neon, *c = simsimd_cap_neon_f16_k; return;
1039
- default: break;
1040
- }
1041
- #endif
1042
- #if SIMSIMD_TARGET_SAPPHIRE //! Scaling of 8-bit integers is performed using 16-bit floats.
1043
- if (v & simsimd_cap_sapphire_k) switch (k) {
1044
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_sapphire, *c = simsimd_cap_sapphire_k; return;
1045
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_sapphire, *c = simsimd_cap_sapphire_k; return;
1046
- default: break;
1047
- }
1048
- #endif
1049
- #if SIMSIMD_TARGET_ICE
1050
- if (v & simsimd_cap_ice_k) switch (k) {
1051
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_ice, *c = simsimd_cap_ice_k; return;
1052
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_ice, *c = simsimd_cap_ice_k; return;
1053
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_ice, *c = simsimd_cap_ice_k; return;
1054
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_ice, *c = simsimd_cap_ice_k; return;
1055
- default: break;
1056
- }
1057
- #endif
1058
- #if SIMSIMD_TARGET_HASWELL
1059
- if (v & simsimd_cap_haswell_k) switch (k) {
1060
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_haswell, *c = simsimd_cap_haswell_k; return;
1061
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_haswell, *c = simsimd_cap_haswell_k; return;
1062
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_haswell, *c = simsimd_cap_haswell_k; return;
1063
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_haswell, *c = simsimd_cap_haswell_k; return;
1064
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_haswell, *c = simsimd_cap_haswell_k; return;
1065
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_haswell, *c = simsimd_cap_haswell_k; return;
1066
- default: break;
1067
- }
1068
- #endif
1069
- if (v & simsimd_cap_serial_k) switch (k) {
1070
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_u8_serial, *c = simsimd_cap_serial_k; return;
1071
- case simsimd_metric_cos_k: *m = (m_t)&simsimd_cos_u8_serial, *c = simsimd_cap_serial_k; return;
1072
- case simsimd_metric_l2sq_k: *m = (m_t)&simsimd_l2sq_u8_serial, *c = simsimd_cap_serial_k; return;
1073
- case simsimd_metric_l2_k: *m = (m_t)&simsimd_l2_u8_serial, *c = simsimd_cap_serial_k; return;
1074
- case simsimd_metric_fma_k: *m = (m_t)&simsimd_fma_u8_serial, *c = simsimd_cap_serial_k; return;
1075
- case simsimd_metric_wsum_k: *m = (m_t)&simsimd_wsum_u8_serial, *c = simsimd_cap_serial_k; return;
1076
- default: break;
1077
- }
1078
- }
1079
-
1080
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_b8(simsimd_capability_t v, simsimd_metric_kind_t k,
1081
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1082
- typedef simsimd_kernel_punned_t m_t;
1083
- #if SIMSIMD_TARGET_SVE
1084
- if (v & simsimd_cap_sve_k) switch (k) {
1085
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_sve, *c = simsimd_cap_sve_k; return;
1086
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_sve, *c = simsimd_cap_sve_k; return;
1087
- default: break;
1088
- }
1089
- #endif
1090
- #if SIMSIMD_TARGET_NEON
1091
- if (v & simsimd_cap_neon_k) switch (k) {
1092
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_neon, *c = simsimd_cap_neon_k; return;
1093
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_neon, *c = simsimd_cap_neon_k; return;
1094
- default: break;
1095
- }
1096
- #endif
1097
- #if SIMSIMD_TARGET_ICE
1098
- if (v & simsimd_cap_ice_k) switch (k) {
1099
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_ice, *c = simsimd_cap_ice_k; return;
1100
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_ice, *c = simsimd_cap_ice_k; return;
1101
- default: break;
1102
- }
1103
- #endif
1104
- #if SIMSIMD_TARGET_HASWELL
1105
- if (v & simsimd_cap_haswell_k) switch (k) {
1106
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_haswell, *c = simsimd_cap_haswell_k; return;
1107
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_haswell, *c = simsimd_cap_haswell_k; return;
1108
- default: break;
1109
- }
1110
- #endif
1111
- if (v & simsimd_cap_serial_k) switch (k) {
1112
- case simsimd_metric_hamming_k: *m = (m_t)&simsimd_hamming_b8_serial, *c = simsimd_cap_serial_k; return;
1113
- case simsimd_metric_jaccard_k: *m = (m_t)&simsimd_jaccard_b8_serial, *c = simsimd_cap_serial_k; return;
1114
- default: break;
1115
- }
1116
- }
1117
-
1118
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f64c(simsimd_capability_t v, simsimd_metric_kind_t k,
1119
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1120
- typedef simsimd_kernel_punned_t m_t;
1121
- #if SIMSIMD_TARGET_SVE
1122
- if (v & simsimd_cap_sve_k) switch (k) {
1123
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_sve, *c = simsimd_cap_sve_k; return;
1124
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_sve, *c = simsimd_cap_sve_k; return;
1125
- default: break;
1126
- }
1127
- #endif
1128
- #if SIMSIMD_TARGET_SKYLAKE
1129
- if (v & simsimd_cap_skylake_k) switch (k) {
1130
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
1131
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_skylake, *c = simsimd_cap_skylake_k; return;
1132
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64c_skylake, *c = simsimd_cap_skylake_k; return;
1133
- default: break;
1134
- }
1135
- #endif
1136
- if (v & simsimd_cap_serial_k) switch (k) {
1137
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f64c_serial, *c = simsimd_cap_serial_k; return;
1138
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f64c_serial, *c = simsimd_cap_serial_k; return;
1139
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f64c_serial, *c = simsimd_cap_serial_k; return;
1140
- default: break;
1141
- }
1142
- }
1143
-
1144
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f32c(simsimd_capability_t v, simsimd_metric_kind_t k,
1145
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1146
- typedef simsimd_kernel_punned_t m_t;
1147
- #if SIMSIMD_TARGET_SVE
1148
- if (v & simsimd_cap_sve_k) switch (k) {
1149
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_sve, *c = simsimd_cap_sve_k; return;
1150
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_sve, *c = simsimd_cap_sve_k; return;
1151
- default: break;
1152
- }
1153
- #endif
1154
- #if SIMSIMD_TARGET_NEON
1155
- if (v & simsimd_cap_neon_k) switch (k) {
1156
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_neon, *c = simsimd_cap_neon_k; return;
1157
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_neon, *c = simsimd_cap_neon_k; return;
1158
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32c_neon, *c = simsimd_cap_neon_k; return;
1159
- default: break;
1160
- }
1161
- #endif
1162
- #if SIMSIMD_TARGET_SKYLAKE
1163
- if (v & simsimd_cap_skylake_k) switch (k) {
1164
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
1165
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_skylake, *c = simsimd_cap_skylake_k; return;
1166
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32c_skylake, *c = simsimd_cap_skylake_k; return;
1167
- default: break;
1168
- }
1169
- #endif
1170
- #if SIMSIMD_TARGET_HASWELL
1171
- if (v & simsimd_cap_haswell_k) switch (k) {
1172
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
1173
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_haswell, *c = simsimd_cap_haswell_k; return;
1174
- default: break;
1175
- }
1176
- #endif
1177
- if (v & simsimd_cap_serial_k) switch (k) {
1178
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f32c_serial, *c = simsimd_cap_serial_k; return;
1179
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f32c_serial, *c = simsimd_cap_serial_k; return;
1180
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f32c_serial, *c = simsimd_cap_serial_k; return;
1181
- default: break;
1182
- }
1183
- }
1184
-
1185
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_f16c(simsimd_capability_t v, simsimd_metric_kind_t k,
1186
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1187
- typedef simsimd_kernel_punned_t m_t;
1188
- #if SIMSIMD_TARGET_SVE_F16
1189
- if (v & simsimd_cap_sve_k) switch (k) {
1190
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
1191
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sve, *c = simsimd_cap_sve_f16_k; return;
1192
- default: break;
1193
- }
1194
- #endif
1195
- #if SIMSIMD_TARGET_NEON_F16
1196
- if (v & simsimd_cap_neon_f16_k) switch (k) {
1197
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
1198
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_neon, *c = simsimd_cap_neon_f16_k; return;
1199
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1200
- default: break;
1201
- }
1202
- #endif
1203
- #if SIMSIMD_TARGET_SAPPHIRE
1204
- if (v & simsimd_cap_sapphire_k) switch (k) {
1205
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1206
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1207
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16c_sapphire, *c = simsimd_cap_sapphire_k; return;
1208
- default: break;
1209
- }
1210
- #endif
1211
- #if SIMSIMD_TARGET_HASWELL
1212
- if (v & simsimd_cap_haswell_k) switch (k) {
1213
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
1214
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_haswell, *c = simsimd_cap_haswell_k; return;
1215
- default: break;
1216
- }
1217
- #endif
1218
- if (v & simsimd_cap_serial_k) switch (k) {
1219
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_f16c_serial, *c = simsimd_cap_serial_k; return;
1220
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_f16c_serial, *c = simsimd_cap_serial_k; return;
1221
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_f16c_serial, *c = simsimd_cap_serial_k; return;
1222
- default: break;
1223
- }
1224
- }
1225
-
1226
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_bf16c(simsimd_capability_t v, simsimd_metric_kind_t k,
1227
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1228
- typedef simsimd_kernel_punned_t m_t;
1229
- #if SIMSIMD_TARGET_NEON_BF16
1230
- if (v & simsimd_cap_neon_bf16_k) switch (k) {
1231
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1232
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1233
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16c_neon, *c = simsimd_cap_neon_bf16_k; return;
1234
- default: break;
1235
- }
1236
- #endif
1237
- #if SIMSIMD_TARGET_GENOA
1238
- if (v & simsimd_cap_genoa_k) switch (k) {
1239
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1240
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1241
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16c_genoa, *c = simsimd_cap_genoa_k; return;
1242
- default: break;
1243
- }
1244
- #endif
1245
- if (v & simsimd_cap_serial_k) switch (k) {
1246
- case simsimd_metric_dot_k: *m = (m_t)&simsimd_dot_bf16c_serial, *c = simsimd_cap_serial_k; return;
1247
- case simsimd_metric_vdot_k: *m = (m_t)&simsimd_vdot_bf16c_serial, *c = simsimd_cap_serial_k; return;
1248
- case simsimd_metric_bilinear_k: *m = (m_t)&simsimd_bilinear_bf16c_serial, *c = simsimd_cap_serial_k; return;
1249
- default: break;
1250
- }
1251
- }
1252
-
1253
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_u16(simsimd_capability_t v, simsimd_metric_kind_t k,
1254
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1255
- typedef simsimd_kernel_punned_t m_t;
1256
- #if SIMSIMD_TARGET_SVE2
1257
- if (v & simsimd_cap_sve2_k) switch (k) {
1258
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_sve2, *c = simsimd_cap_sve2_k; return;
1259
- case simsimd_metric_spdot_counts_k: *m = (m_t)&simsimd_spdot_counts_u16_sve2, *c = simsimd_cap_sve2_k; return;
1260
- #if SIMSIMD_TARGET_SVE_BF16 //! We also need `bf16` support for weights
1261
- case simsimd_metric_spdot_weights_k: *m = (m_t)&simsimd_spdot_weights_u16_sve2, *c = simsimd_cap_sve2_k; return;
1262
- #endif
1263
- default: break;
1264
- }
1265
- #endif
1266
- #if SIMSIMD_TARGET_NEON
1267
- if (v & simsimd_cap_neon_k) switch (k) {
1268
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_neon, *c = simsimd_cap_neon_k; return;
1269
- default: break;
1270
- }
1271
- #endif
1272
- #if SIMSIMD_TARGET_TURIN
1273
- if (v & simsimd_cap_turin_k) switch (k) {
1274
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_turin, *c = simsimd_cap_turin_k; return;
1275
- case simsimd_metric_spdot_counts_k: *m = (m_t)&simsimd_spdot_counts_u16_turin, *c = simsimd_cap_turin_k; return;
1276
- case simsimd_metric_spdot_weights_k:
1277
- *m = (m_t)&simsimd_spdot_weights_u16_turin, *c = simsimd_cap_turin_k;
1278
- return;
1279
- default: break;
1280
- }
1281
- #endif
1282
- #if SIMSIMD_TARGET_ICE
1283
- if (v & simsimd_cap_ice_k) switch (k) {
1284
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_ice, *c = simsimd_cap_skylake_k; return;
1285
- default: break;
1286
- }
1287
- #endif
1288
- if (v & simsimd_cap_serial_k) switch (k) {
1289
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u16_serial, *c = simsimd_cap_serial_k; return;
1290
- default: break;
1291
- }
1292
- }
1293
-
1294
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_u32(simsimd_capability_t v, simsimd_metric_kind_t k,
1295
- simsimd_kernel_punned_t *m, simsimd_capability_t *c) {
1296
- typedef simsimd_kernel_punned_t m_t;
1297
- #if SIMSIMD_TARGET_SVE2
1298
- if (v & simsimd_cap_sve2_k) switch (k) {
1299
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_sve2, *c = simsimd_cap_sve2_k; return;
1300
- default: break;
1301
- }
1302
- #endif
1303
- #if SIMSIMD_TARGET_NEON
1304
- if (v & simsimd_cap_neon_k) switch (k) {
1305
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_neon, *c = simsimd_cap_neon_k; return;
1306
- default: break;
1307
- }
1308
- #endif
1309
- #if SIMSIMD_TARGET_TURIN
1310
- if (v & simsimd_cap_turin_k) switch (k) {
1311
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_turin, *c = simsimd_cap_skylake_k; return;
1312
- default: break;
1313
- }
1314
- #endif
1315
- #if SIMSIMD_TARGET_ICE
1316
- if (v & simsimd_cap_ice_k) switch (k) {
1317
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_ice, *c = simsimd_cap_skylake_k; return;
1318
- default: break;
1319
- }
1320
- #endif
1321
- if (v & simsimd_cap_serial_k) switch (k) {
1322
- case simsimd_metric_intersect_k: *m = (m_t)&simsimd_intersect_u32_serial, *c = simsimd_cap_serial_k; return;
1323
- default: break;
1324
- }
1325
- }
1326
-
1327
- /**
1328
- * @brief Determines the best suited metric implementation based on the given datatype,
1329
- * supported and allowed by hardware capabilities.
1330
- *
1331
- * @param kind The kind of metric to be evaluated.
1332
- * @param datatype The data type for which the metric needs to be evaluated.
1333
- * @param supported The hardware capabilities supported by the CPU.
1334
- * @param allowed The hardware capabilities allowed for use.
1335
- * @param kernel_output Output variable for the selected similarity function.
1336
- * @param capability_output Output variable for the utilized hardware capabilities.
1337
- */
1338
- SIMSIMD_INTERNAL void _simsimd_find_kernel_punned_implementation( //
1339
- simsimd_metric_kind_t kind, //
1340
- simsimd_datatype_t datatype, //
1341
- simsimd_capability_t supported, //
1342
- simsimd_capability_t allowed, //
1343
- simsimd_kernel_punned_t *kernel_output, //
1344
- simsimd_capability_t *capability_output) {
1345
-
1346
- // Modern compilers abso-freaking-lutely love optimizing-out my logic!
1347
- // Just marking the variables as `volatile` is not enough, so we have
1348
- // to add inline assembly to further discourage them!
1349
- #if defined(_MSC_VER)
1350
- _ReadWriteBarrier();
1351
- #else
1352
- __asm__ __volatile__("" ::: "memory");
1353
- #endif
1354
-
1355
- simsimd_kernel_punned_t *m = kernel_output;
1356
- simsimd_capability_t *c = capability_output;
1357
- simsimd_capability_t viable = (simsimd_capability_t)(supported & allowed);
1358
-
1359
- switch (datatype) {
1360
-
1361
- case simsimd_datatype_f64_k: _simsimd_find_kernel_punned_f64(viable, kind, m, c); return;
1362
- case simsimd_datatype_f32_k: _simsimd_find_kernel_punned_f32(viable, kind, m, c); return;
1363
- case simsimd_datatype_f16_k: _simsimd_find_kernel_punned_f16(viable, kind, m, c); return;
1364
- case simsimd_datatype_bf16_k: _simsimd_find_kernel_punned_bf16(viable, kind, m, c); return;
1365
- case simsimd_datatype_i8_k: _simsimd_find_kernel_punned_i8(viable, kind, m, c); return;
1366
- case simsimd_datatype_u8_k: _simsimd_find_kernel_punned_u8(viable, kind, m, c); return;
1367
- case simsimd_datatype_b8_k: _simsimd_find_kernel_punned_b8(viable, kind, m, c); return;
1368
- case simsimd_datatype_f32c_k: _simsimd_find_kernel_punned_f32c(viable, kind, m, c); return;
1369
- case simsimd_datatype_f64c_k: _simsimd_find_kernel_punned_f64c(viable, kind, m, c); return;
1370
- case simsimd_datatype_f16c_k: _simsimd_find_kernel_punned_f16c(viable, kind, m, c); return;
1371
- case simsimd_datatype_bf16c_k: _simsimd_find_kernel_punned_bf16c(viable, kind, m, c); return;
1372
- case simsimd_datatype_u16_k: _simsimd_find_kernel_punned_u16(viable, kind, m, c); return;
1373
- case simsimd_datatype_u32_k: _simsimd_find_kernel_punned_u32(viable, kind, m, c); return;
1374
-
1375
- // These data-types are not supported yet
1376
- case simsimd_datatype_i4x2_k: break;
1377
- case simsimd_datatype_i16_k: break;
1378
- case simsimd_datatype_i32_k: break;
1379
- case simsimd_datatype_i64_k: break;
1380
- case simsimd_datatype_u64_k: break;
1381
- case simsimd_datatype_unknown_k: break;
1382
- default: break;
1383
- }
1384
-
1385
- // Replace with zeros if no suitable implementation was found
1386
- *m = (simsimd_kernel_punned_t)0;
1387
- *c = (simsimd_capability_t)0;
1388
-
1389
- // Modern compilers abso-freaking-lutely love optimizing-out my logic!
1390
- // Just marking the variables as `volatile` is not enough, so we have
1391
- // to add inline assembly to further discourage them!
1392
- #if defined(_MSC_VER)
1393
- _ReadWriteBarrier();
1394
- #else
1395
- __asm__ __volatile__("" ::: "memory");
1396
- #endif
1397
- }
1398
-
1399
- #pragma GCC diagnostic pop
1400
- #pragma clang diagnostic pop
1401
-
1402
- /**
1403
- * @brief Selects the most suitable metric implementation based on the given metric kind, datatype,
1404
- * and allowed capabilities. @b Don't call too often and prefer caching the `simsimd_capabilities()`.
1405
- *
1406
- * @param kind The kind of metric to be evaluated.
1407
- * @param datatype The data type for which the metric needs to be evaluated.
1408
- * @param allowed The hardware capabilities allowed for use.
1409
- * @return A function pointer to the selected metric implementation.
1410
- */
1411
- SIMSIMD_PUBLIC simsimd_kernel_punned_t simsimd_metric_punned( //
1412
- simsimd_metric_kind_t kind, //
1413
- simsimd_datatype_t datatype, //
1414
- simsimd_capability_t allowed) {
1415
-
1416
- simsimd_kernel_punned_t result = 0;
1417
- simsimd_capability_t c = simsimd_cap_serial_k;
1418
- simsimd_capability_t supported = simsimd_capabilities();
1419
- simsimd_find_kernel_punned(kind, datatype, supported, allowed, &result, &c);
1420
- return result;
1421
- }
1422
-
1423
- #if SIMSIMD_DYNAMIC_DISPATCH
1424
-
1425
- /* Run-time feature-testing functions
1426
- * - Check if the CPU supports NEON or SVE extensions on Arm
1427
- * - Check if the CPU supports AVX2 and F16C extensions on Haswell x86 CPUs and newer
1428
- * - Check if the CPU supports AVX512F and AVX512BW extensions on Skylake x86 CPUs and newer
1429
- * - Check if the CPU supports AVX512VNNI, AVX512IFMA, AVX512BITALG, AVX512VBMI2, and AVX512VPOPCNTDQ
1430
- * extensions on Ice Lake x86 CPUs and newer
1431
- * - Check if the CPU supports AVX512BF16 extensions on Genoa x86 CPUs and newer
1432
- * - Check if the CPU supports AVX512FP16 extensions on Sapphire Rapids x86 CPUs and newer
1433
- * - Check if the CPU supports AVX2VP2INTERSECT extensions on Turin x86 CPUs and newer
1434
- *
1435
- * @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
1436
- */
1437
- SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void);
1438
- SIMSIMD_DYNAMIC int simsimd_flush_denormals(void);
1439
- SIMSIMD_DYNAMIC int simsimd_uses_dynamic_dispatch(void);
1440
- SIMSIMD_DYNAMIC int simsimd_uses_neon(void);
1441
- SIMSIMD_DYNAMIC int simsimd_uses_neon_f16(void);
1442
- SIMSIMD_DYNAMIC int simsimd_uses_neon_bf16(void);
1443
- SIMSIMD_DYNAMIC int simsimd_uses_neon_i8(void);
1444
- SIMSIMD_DYNAMIC int simsimd_uses_sve(void);
1445
- SIMSIMD_DYNAMIC int simsimd_uses_sve_f16(void);
1446
- SIMSIMD_DYNAMIC int simsimd_uses_sve_bf16(void);
1447
- SIMSIMD_DYNAMIC int simsimd_uses_sve_i8(void);
1448
- SIMSIMD_DYNAMIC int simsimd_uses_sve2(void);
1449
- SIMSIMD_DYNAMIC int simsimd_uses_haswell(void);
1450
- SIMSIMD_DYNAMIC int simsimd_uses_skylake(void);
1451
- SIMSIMD_DYNAMIC int simsimd_uses_ice(void);
1452
- SIMSIMD_DYNAMIC int simsimd_uses_genoa(void);
1453
- SIMSIMD_DYNAMIC int simsimd_uses_sapphire(void);
1454
- SIMSIMD_DYNAMIC int simsimd_uses_turin(void);
1455
- SIMSIMD_DYNAMIC int simsimd_uses_sierra(void);
1456
-
1457
- /* Inner products
1458
- * - Dot product: the sum of the products of the corresponding elements of two vectors.
1459
- * - Complex Dot product: dot product with a conjugate first argument.
1460
- * - Complex Conjugate Dot product: dot product with a conjugate first argument.
1461
- *
1462
- * @param a The first vector.
1463
- * @param b The second vector.
1464
- * @param n The number of elements in the vectors. Even for complex variants (the number of scalars).
1465
- * @param d The output distance value.
1466
- *
1467
- * @note The dot product can be negative, to use as a distance, take `1 - a * b`.
1468
- * @note The dot product is zero if and only if the two vectors are orthogonal.
1469
- * @note Defined only for floating-point and integer data types.
1470
- */
1471
- SIMSIMD_DYNAMIC void simsimd_dot_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1472
- simsimd_distance_t *d);
1473
- SIMSIMD_DYNAMIC void simsimd_dot_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1474
- simsimd_distance_t *d);
1475
- SIMSIMD_DYNAMIC void simsimd_dot_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1476
- simsimd_distance_t *d);
1477
- SIMSIMD_DYNAMIC void simsimd_dot_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1478
- simsimd_distance_t *d);
1479
- SIMSIMD_DYNAMIC void simsimd_dot_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1480
- simsimd_distance_t *d);
1481
- SIMSIMD_DYNAMIC void simsimd_dot_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1482
- simsimd_distance_t *d);
1483
- SIMSIMD_DYNAMIC void simsimd_dot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
1484
- simsimd_distance_t *d);
1485
- SIMSIMD_DYNAMIC void simsimd_dot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
1486
- simsimd_distance_t *d);
1487
- SIMSIMD_DYNAMIC void simsimd_dot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
1488
- simsimd_distance_t *d);
1489
- SIMSIMD_DYNAMIC void simsimd_dot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
1490
- simsimd_distance_t *d);
1491
- SIMSIMD_DYNAMIC void simsimd_vdot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
1492
- simsimd_distance_t *d);
1493
- SIMSIMD_DYNAMIC void simsimd_vdot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
1494
- simsimd_distance_t *d);
1495
- SIMSIMD_DYNAMIC void simsimd_vdot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
1496
- simsimd_distance_t *d);
1497
- SIMSIMD_DYNAMIC void simsimd_vdot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
1498
- simsimd_distance_t *d);
1499
-
1500
- /* Spatial distances
1501
- * - Cosine distance: the cosine of the angle between two vectors.
1502
- * - L2 squared distance: the squared Euclidean distance between two vectors.
1503
- *
1504
- * @param a The first vector.
1505
- * @param b The second vector.
1506
- * @param n The number of elements in the vectors.
1507
- * @param d The output distance value.
1508
- *
1509
- * @note The output distance value is non-negative.
1510
- * @note The output distance value is zero if and only if the two vectors are identical.
1511
- * @note Defined only for floating-point and integer data types.
1512
- */
1513
- SIMSIMD_DYNAMIC void simsimd_cos_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1514
- simsimd_distance_t *d);
1515
- SIMSIMD_DYNAMIC void simsimd_cos_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1516
- simsimd_distance_t *d);
1517
- SIMSIMD_DYNAMIC void simsimd_cos_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1518
- simsimd_distance_t *d);
1519
- SIMSIMD_DYNAMIC void simsimd_cos_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1520
- simsimd_distance_t *d);
1521
- SIMSIMD_DYNAMIC void simsimd_cos_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1522
- simsimd_distance_t *d);
1523
- SIMSIMD_DYNAMIC void simsimd_cos_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1524
- simsimd_distance_t *d);
1525
- SIMSIMD_DYNAMIC void simsimd_l2sq_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1526
- simsimd_distance_t *d);
1527
- SIMSIMD_DYNAMIC void simsimd_l2sq_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1528
- simsimd_distance_t *d);
1529
- SIMSIMD_DYNAMIC void simsimd_l2sq_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1530
- simsimd_distance_t *d);
1531
- SIMSIMD_DYNAMIC void simsimd_l2sq_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1532
- simsimd_distance_t *d);
1533
- SIMSIMD_DYNAMIC void simsimd_l2sq_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1534
- simsimd_distance_t *d);
1535
- SIMSIMD_DYNAMIC void simsimd_l2sq_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1536
- simsimd_distance_t *d);
1537
- SIMSIMD_DYNAMIC void simsimd_l2_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1538
- simsimd_distance_t *d);
1539
- SIMSIMD_DYNAMIC void simsimd_l2_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1540
- simsimd_distance_t *d);
1541
- SIMSIMD_DYNAMIC void simsimd_l2_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1542
- simsimd_distance_t *d);
1543
- SIMSIMD_DYNAMIC void simsimd_l2_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1544
- simsimd_distance_t *d);
1545
- SIMSIMD_DYNAMIC void simsimd_l2_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1546
- simsimd_distance_t *d);
1547
- SIMSIMD_DYNAMIC void simsimd_l2_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1548
- simsimd_distance_t *d);
1549
-
1550
- /* Binary distances
1551
- * - Hamming distance: the number of positions at which the corresponding bits are different.
1552
- * - Jaccard distance: ratio of bit-level matching positions (intersection) to the total number of positions (union).
1553
- *
1554
- * @param a The first binary vector.
1555
- * @param b The second binary vector.
1556
- * @param n The number of 8-bit words in the vectors.
1557
- * @param d The output distance value.
1558
- *
1559
- * @note The output distance value is non-negative.
1560
- * @note The output distance value is zero if and only if the two vectors are identical.
1561
- * @note Defined only for binary data.
1562
- */
1563
- SIMSIMD_DYNAMIC void simsimd_hamming_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
1564
- simsimd_distance_t *d);
1565
- SIMSIMD_DYNAMIC void simsimd_jaccard_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
1566
- simsimd_distance_t *d);
1567
-
1568
- /* Probability distributions
1569
- * - Jensen-Shannon divergence: a measure of similarity between two probability distributions.
1570
- * - Kullback-Leibler divergence: a measure of how one probability distribution diverges from a second.
1571
- *
1572
- * @param a The first discrete probability distribution.
1573
- * @param b The second discrete probability distribution.
1574
- * @param n The number of elements in the discrete distributions.
1575
- * @param d The output divergence value.
1576
- *
1577
- * @note The distributions are assumed to be normalized.
1578
- * @note The output divergence value is non-negative.
1579
- * @note The output divergence value is zero if and only if the two distributions are identical.
1580
- * @note Defined only for floating-point data types.
1581
- */
1582
- SIMSIMD_DYNAMIC void simsimd_kl_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1583
- simsimd_distance_t *d);
1584
- SIMSIMD_DYNAMIC void simsimd_kl_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1585
- simsimd_distance_t *d);
1586
- SIMSIMD_DYNAMIC void simsimd_kl_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1587
- simsimd_distance_t *d);
1588
- SIMSIMD_DYNAMIC void simsimd_kl_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1589
- simsimd_distance_t *d);
1590
- SIMSIMD_DYNAMIC void simsimd_js_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1591
- simsimd_distance_t *d);
1592
- SIMSIMD_DYNAMIC void simsimd_js_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1593
- simsimd_distance_t *d);
1594
- SIMSIMD_DYNAMIC void simsimd_js_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1595
- simsimd_distance_t *d);
1596
- SIMSIMD_DYNAMIC void simsimd_js_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1597
- simsimd_distance_t *d);
1598
-
1599
- #else
1600
-
1601
- /* Compile-time feature-testing functions
1602
- * - Check if the CPU supports NEON or SVE extensions on Arm
1603
- * - Check if the CPU supports AVX2 and F16C extensions on Haswell x86 CPUs and newer
1604
- * - Check if the CPU supports AVX512F and AVX512BW extensions on Skylake x86 CPUs and newer
1605
- * - Check if the CPU supports AVX512VNNI, AVX512IFMA, AVX512BITALG, AVX512VBMI2, and AVX512VPOPCNTDQ
1606
- * extensions on Ice Lake x86 CPUs and newer
1607
- * - Check if the CPU supports AVX512BF16 extensions on Genoa x86 CPUs and newer
1608
- * - Check if the CPU supports AVX512FP16 extensions on Sapphire Rapids x86 CPUs and newer
1609
- *
1610
- * @return 1 if the CPU supports the SIMD instruction set, 0 otherwise.
1611
- */
1612
-
1613
- // clang-format off
1614
- SIMSIMD_PUBLIC int simsimd_uses_neon(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON; }
1615
- SIMSIMD_PUBLIC int simsimd_uses_neon_f16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_F16 ; }
1616
- SIMSIMD_PUBLIC int simsimd_uses_neon_bf16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_BF16; }
1617
- SIMSIMD_PUBLIC int simsimd_uses_neon_i8(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_NEON_I8; }
1618
- SIMSIMD_PUBLIC int simsimd_uses_sve(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE; }
1619
- SIMSIMD_PUBLIC int simsimd_uses_sve_f16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_F16; }
1620
- SIMSIMD_PUBLIC int simsimd_uses_sve_bf16(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_BF16; }
1621
- SIMSIMD_PUBLIC int simsimd_uses_sve_i8(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE_I8; }
1622
- SIMSIMD_PUBLIC int simsimd_uses_sve2(void) { return _SIMSIMD_TARGET_ARM && SIMSIMD_TARGET_SVE2; }
1623
- SIMSIMD_PUBLIC int simsimd_uses_haswell(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_HASWELL; }
1624
- SIMSIMD_PUBLIC int simsimd_uses_skylake(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SKYLAKE; }
1625
- SIMSIMD_PUBLIC int simsimd_uses_ice(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_ICE; }
1626
- SIMSIMD_PUBLIC int simsimd_uses_genoa(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_GENOA; }
1627
- SIMSIMD_PUBLIC int simsimd_uses_sapphire(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SAPPHIRE; }
1628
- SIMSIMD_PUBLIC int simsimd_uses_turin(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_TURIN; }
1629
- SIMSIMD_PUBLIC int simsimd_uses_sierra(void) { return _SIMSIMD_TARGET_X86 && SIMSIMD_TARGET_SIERRA; }
1630
- SIMSIMD_PUBLIC int simsimd_uses_dynamic_dispatch(void) { return 0; }
1631
- SIMSIMD_PUBLIC int simsimd_flush_denormals(void) { return _simsimd_flush_denormals(); }
1632
- SIMSIMD_PUBLIC simsimd_capability_t simsimd_capabilities(void) { return _simsimd_capabilities_implementation(); }
1633
- SIMSIMD_PUBLIC void simsimd_find_kernel_punned( //
1634
- simsimd_metric_kind_t kind, //
1635
- simsimd_datatype_t datatype, //
1636
- simsimd_capability_t supported, //
1637
- simsimd_capability_t allowed, //
1638
- simsimd_kernel_punned_t* kernel_output, //
1639
- simsimd_capability_t* capability_output) {
1640
- _simsimd_find_kernel_punned_implementation(kind, datatype, supported, allowed, kernel_output, capability_output);
1641
- }
1642
- // clang-format on
1643
-
1644
- /* Inner products
1645
- * - Dot product: the sum of the products of the corresponding elements of two vectors.
1646
- * - Complex Dot product: dot product with a conjugate first argument.
1647
- * - Complex Conjugate Dot product: dot product with a conjugate first argument.
1648
- *
1649
- * @param a The first vector.
1650
- * @param b The second vector.
1651
- * @param n The number of elements in the vectors. Even for complex variants (the number of scalars).
1652
- * @param d The output distance value.
1653
- *
1654
- * @note The dot product can be negative, to use as a distance, take `1 - a * b`.
1655
- * @note The dot product is zero if and only if the two vectors are orthogonal.
1656
- * @note Defined only for floating-point and integer data types.
1657
- */
1658
- SIMSIMD_PUBLIC void simsimd_dot_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1659
- simsimd_distance_t *d) {
1660
- #if SIMSIMD_TARGET_NEON_I8
1661
- simsimd_dot_i8_neon(a, b, n, d);
1662
- #elif SIMSIMD_TARGET_ICE
1663
- simsimd_dot_i8_ice(a, b, n, d);
1664
- #elif SIMSIMD_TARGET_HASWELL
1665
- simsimd_dot_i8_haswell(a, b, n, d);
1666
- #else
1667
- simsimd_dot_i8_serial(a, b, n, d);
1668
- #endif
1669
- }
1670
- SIMSIMD_PUBLIC void simsimd_dot_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1671
- simsimd_distance_t *d) {
1672
- #if SIMSIMD_TARGET_NEON_F16
1673
- simsimd_dot_u8_neon(a, b, n, d);
1674
- #elif SIMSIMD_TARGET_ICE
1675
- simsimd_dot_u8_ice(a, b, n, d);
1676
- #elif SIMSIMD_TARGET_HASWELL
1677
- simsimd_dot_u8_haswell(a, b, n, d);
1678
- #else
1679
- simsimd_dot_u8_serial(a, b, n, d);
1680
- #endif
1681
- }
1682
- SIMSIMD_PUBLIC void simsimd_dot_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1683
- simsimd_distance_t *d) {
1684
- #if SIMSIMD_TARGET_SVE_F16
1685
- simsimd_dot_f16_sve(a, b, n, d);
1686
- #elif SIMSIMD_TARGET_NEON_F16
1687
- simsimd_dot_f16_neon(a, b, n, d);
1688
- #elif SIMSIMD_TARGET_SAPPHIRE
1689
- simsimd_dot_f16_sapphire(a, b, n, d);
1690
- #elif SIMSIMD_TARGET_HASWELL
1691
- simsimd_dot_f16_haswell(a, b, n, d);
1692
- #else
1693
- simsimd_dot_f16_serial(a, b, n, d);
1694
- #endif
1695
- }
1696
- SIMSIMD_PUBLIC void simsimd_dot_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1697
- simsimd_distance_t *d) {
1698
- #if SIMSIMD_TARGET_GENOA
1699
- simsimd_dot_bf16_genoa(a, b, n, d);
1700
- #elif SIMSIMD_TARGET_HASWELL
1701
- simsimd_dot_bf16_haswell(a, b, n, d);
1702
- #elif SIMSIMD_TARGET_NEON_BF16
1703
- simsimd_dot_bf16_neon(a, b, n, d);
1704
- #else
1705
- simsimd_dot_bf16_serial(a, b, n, d);
1706
- #endif
1707
- }
1708
- SIMSIMD_PUBLIC void simsimd_dot_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1709
- simsimd_distance_t *d) {
1710
- #if SIMSIMD_TARGET_SVE
1711
- simsimd_dot_f32_sve(a, b, n, d);
1712
- #elif SIMSIMD_TARGET_NEON
1713
- simsimd_dot_f32_neon(a, b, n, d);
1714
- #elif SIMSIMD_TARGET_SKYLAKE
1715
- simsimd_dot_f32_skylake(a, b, n, d);
1716
- #elif SIMSIMD_TARGET_HASWELL
1717
- simsimd_dot_f32_haswell(a, b, n, d);
1718
- #else
1719
- simsimd_dot_f32_serial(a, b, n, d);
1720
- #endif
1721
- }
1722
- SIMSIMD_PUBLIC void simsimd_dot_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1723
- simsimd_distance_t *d) {
1724
- #if SIMSIMD_TARGET_SVE
1725
- simsimd_dot_f64_sve(a, b, n, d);
1726
- #elif SIMSIMD_TARGET_SKYLAKE
1727
- simsimd_dot_f64_skylake(a, b, n, d);
1728
- #else
1729
- simsimd_dot_f64_serial(a, b, n, d);
1730
- #endif
1731
- }
1732
- SIMSIMD_PUBLIC void simsimd_dot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
1733
- simsimd_distance_t *d) {
1734
- #if SIMSIMD_TARGET_SVE_F16
1735
- simsimd_dot_f16c_sve(a, b, n, d);
1736
- #elif SIMSIMD_TARGET_NEON_F16
1737
- simsimd_dot_f16c_neon(a, b, n, d);
1738
- #elif SIMSIMD_TARGET_SAPPHIRE
1739
- simsimd_dot_f16c_sapphire(a, b, n, d);
1740
- #elif SIMSIMD_TARGET_HASWELL
1741
- simsimd_dot_f16c_haswell(a, b, n, d);
1742
- #else
1743
- simsimd_dot_f16c_serial(a, b, n, d);
1744
- #endif
1745
- }
1746
- SIMSIMD_PUBLIC void simsimd_dot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
1747
- simsimd_distance_t *d) {
1748
- #if SIMSIMD_TARGET_GENOA
1749
- simsimd_dot_bf16c_genoa(a, b, n, d);
1750
- #elif SIMSIMD_TARGET_NEON_BF16
1751
- simsimd_dot_bf16c_neon(a, b, n, d);
1752
- #else
1753
- simsimd_dot_bf16c_serial(a, b, n, d);
1754
- #endif
1755
- }
1756
- SIMSIMD_PUBLIC void simsimd_dot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
1757
- simsimd_distance_t *d) {
1758
- #if SIMSIMD_TARGET_SVE
1759
- simsimd_dot_f32c_sve(a, b, n, d);
1760
- #elif SIMSIMD_TARGET_NEON
1761
- simsimd_dot_f32c_neon(a, b, n, d);
1762
- #elif SIMSIMD_TARGET_SKYLAKE
1763
- simsimd_dot_f32c_skylake(a, b, n, d);
1764
- #elif SIMSIMD_TARGET_HASWELL
1765
- simsimd_dot_f32c_haswell(a, b, n, d);
1766
- #else
1767
- simsimd_dot_f32c_serial(a, b, n, d);
1768
- #endif
1769
- }
1770
- SIMSIMD_PUBLIC void simsimd_dot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
1771
- simsimd_distance_t *d) {
1772
- #if SIMSIMD_TARGET_SVE
1773
- simsimd_dot_f64c_sve(a, b, n, d);
1774
- #elif SIMSIMD_TARGET_SKYLAKE
1775
- simsimd_dot_f64c_skylake(a, b, n, d);
1776
- #else
1777
- simsimd_dot_f64c_serial(a, b, n, d);
1778
- #endif
1779
- }
1780
- SIMSIMD_PUBLIC void simsimd_vdot_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_size_t n,
1781
- simsimd_distance_t *d) {
1782
- #if SIMSIMD_TARGET_SVE
1783
- simsimd_vdot_f16c_sve(a, b, n, d);
1784
- #elif SIMSIMD_TARGET_NEON_F16
1785
- simsimd_dot_f16c_neon(a, b, n, d);
1786
- #elif SIMSIMD_TARGET_SAPPHIRE
1787
- simsimd_dot_f16c_sapphire(a, b, n, d);
1788
- #elif SIMSIMD_TARGET_HASWELL
1789
- simsimd_dot_f16c_haswell(a, b, n, d);
1790
- #else
1791
- simsimd_vdot_f16c_serial(a, b, n, d);
1792
- #endif
1793
- }
1794
- SIMSIMD_PUBLIC void simsimd_vdot_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_size_t n,
1795
- simsimd_distance_t *d) {
1796
- #if SIMSIMD_TARGET_GENOA
1797
- simsimd_vdot_bf16c_genoa(a, b, n, d);
1798
- #elif SIMSIMD_TARGET_NEON_BF16
1799
- simsimd_dot_bf16c_neon(a, b, n, d);
1800
- #else
1801
- simsimd_vdot_bf16c_serial(a, b, n, d);
1802
- #endif
1803
- }
1804
- SIMSIMD_PUBLIC void simsimd_vdot_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_size_t n,
1805
- simsimd_distance_t *d) {
1806
- #if SIMSIMD_TARGET_SVE
1807
- simsimd_vdot_f32c_sve(a, b, n, d);
1808
- #elif SIMSIMD_TARGET_NEON
1809
- simsimd_dot_f32c_neon(a, b, n, d);
1810
- #elif SIMSIMD_TARGET_SKYLAKE
1811
- simsimd_dot_f32c_skylake(a, b, n, d);
1812
- #elif SIMSIMD_TARGET_HASWELL
1813
- simsimd_dot_f32c_haswell(a, b, n, d);
1814
- #else
1815
- simsimd_vdot_f32c_serial(a, b, n, d);
1816
- #endif
1817
- }
1818
- SIMSIMD_PUBLIC void simsimd_vdot_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_size_t n,
1819
- simsimd_distance_t *d) {
1820
- #if SIMSIMD_TARGET_SVE
1821
- simsimd_vdot_f64c_sve(a, b, n, d);
1822
- #elif SIMSIMD_TARGET_SKYLAKE
1823
- simsimd_vdot_f64c_skylake(a, b, n, d);
1824
- #else
1825
- simsimd_vdot_f64c_serial(a, b, n, d);
1826
- #endif
1827
- }
1828
-
1829
- /* Spatial distances
1830
- * - Cosine distance: the cosine of the angle between two vectors.
1831
- * - L2 squared distance: the squared Euclidean distance between two vectors.
1832
- *
1833
- * @param a The first vector.
1834
- * @param b The second vector.
1835
- * @param n The number of elements in the vectors.
1836
- * @param d The output distance value.
1837
- *
1838
- * @note The output distance value is non-negative.
1839
- * @note The output distance value is zero if and only if the two vectors are identical.
1840
- * @note Defined only for floating-point and integer data types.
1841
- */
1842
- SIMSIMD_PUBLIC void simsimd_cos_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1843
- simsimd_distance_t *d) {
1844
- #if SIMSIMD_TARGET_NEON_I8
1845
- simsimd_cos_i8_neon(a, b, n, d);
1846
- #elif SIMSIMD_TARGET_ICE
1847
- simsimd_cos_i8_ice(a, b, n, d);
1848
- #elif SIMSIMD_TARGET_HASWELL
1849
- simsimd_cos_i8_haswell(a, b, n, d);
1850
- #else
1851
- simsimd_cos_i8_serial(a, b, n, d);
1852
- #endif
1853
- }
1854
- SIMSIMD_PUBLIC void simsimd_cos_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1855
- simsimd_distance_t *d) {
1856
- #if SIMSIMD_TARGET_NEON_I8
1857
- simsimd_cos_u8_neon(a, b, n, d);
1858
- #elif SIMSIMD_TARGET_ICE
1859
- simsimd_cos_u8_ice(a, b, n, d);
1860
- #elif SIMSIMD_TARGET_HASWELL
1861
- simsimd_cos_u8_haswell(a, b, n, d);
1862
- #else
1863
- simsimd_cos_u8_serial(a, b, n, d);
1864
- #endif
1865
- }
1866
- SIMSIMD_PUBLIC void simsimd_cos_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1867
- simsimd_distance_t *d) {
1868
- #if SIMSIMD_TARGET_SVE_F16
1869
- simsimd_cos_f16_sve(a, b, n, d);
1870
- #elif SIMSIMD_TARGET_NEON_F16
1871
- simsimd_cos_f16_neon(a, b, n, d);
1872
- #elif SIMSIMD_TARGET_SAPPHIRE
1873
- simsimd_cos_f16_sapphire(a, b, n, d);
1874
- #elif SIMSIMD_TARGET_HASWELL
1875
- simsimd_cos_f16_haswell(a, b, n, d);
1876
- #else
1877
- simsimd_cos_f16_serial(a, b, n, d);
1878
- #endif
1879
- }
1880
- SIMSIMD_PUBLIC void simsimd_cos_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1881
- simsimd_distance_t *d) {
1882
- #if SIMSIMD_TARGET_GENOA
1883
- simsimd_cos_bf16_genoa(a, b, n, d);
1884
- #elif SIMSIMD_TARGET_HASWELL
1885
- simsimd_cos_bf16_haswell(a, b, n, d);
1886
- #elif SIMSIMD_TARGET_SVE_BF16
1887
- simsimd_cos_bf16_sve(a, b, n, d);
1888
- #elif SIMSIMD_TARGET_NEON_BF16
1889
- simsimd_cos_bf16_neon(a, b, n, d);
1890
- #else
1891
- simsimd_cos_bf16_serial(a, b, n, d);
1892
- #endif
1893
- }
1894
- SIMSIMD_PUBLIC void simsimd_cos_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1895
- simsimd_distance_t *d) {
1896
- #if SIMSIMD_TARGET_SVE
1897
- simsimd_cos_f32_sve(a, b, n, d);
1898
- #elif SIMSIMD_TARGET_NEON
1899
- simsimd_cos_f32_neon(a, b, n, d);
1900
- #elif SIMSIMD_TARGET_SKYLAKE
1901
- simsimd_cos_f32_skylake(a, b, n, d);
1902
- #elif SIMSIMD_TARGET_HASWELL
1903
- simsimd_cos_f32_haswell(a, b, n, d);
1904
- #else
1905
- simsimd_cos_f32_serial(a, b, n, d);
1906
- #endif
1907
- }
1908
- SIMSIMD_PUBLIC void simsimd_cos_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1909
- simsimd_distance_t *d) {
1910
- #if SIMSIMD_TARGET_SVE
1911
- simsimd_cos_f64_sve(a, b, n, d);
1912
- #elif SIMSIMD_TARGET_NEON
1913
- simsimd_cos_f64_neon(a, b, n, d);
1914
- #elif SIMSIMD_TARGET_SKYLAKE
1915
- simsimd_cos_f64_skylake(a, b, n, d);
1916
- #else
1917
- simsimd_cos_f64_serial(a, b, n, d);
1918
- #endif
1919
- }
1920
- SIMSIMD_PUBLIC void simsimd_l2sq_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1921
- simsimd_distance_t *d) {
1922
- #if SIMSIMD_TARGET_NEON_I8
1923
- simsimd_l2sq_i8_neon(a, b, n, d);
1924
- #elif SIMSIMD_TARGET_ICE
1925
- simsimd_l2sq_i8_ice(a, b, n, d);
1926
- #elif SIMSIMD_TARGET_HASWELL
1927
- simsimd_l2sq_i8_haswell(a, b, n, d);
1928
- #else
1929
- simsimd_l2sq_i8_serial(a, b, n, d);
1930
- #endif
1931
- }
1932
- SIMSIMD_PUBLIC void simsimd_l2sq_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
1933
- simsimd_distance_t *d) {
1934
- #if SIMSIMD_TARGET_NEON_I8
1935
- simsimd_l2sq_u8_neon(a, b, n, d);
1936
- #elif SIMSIMD_TARGET_ICE
1937
- simsimd_l2sq_u8_ice(a, b, n, d);
1938
- #elif SIMSIMD_TARGET_HASWELL
1939
- simsimd_l2sq_u8_haswell(a, b, n, d);
1940
- #else
1941
- simsimd_l2sq_u8_serial(a, b, n, d);
1942
- #endif
1943
- }
1944
- SIMSIMD_PUBLIC void simsimd_l2sq_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
1945
- simsimd_distance_t *d) {
1946
- #if SIMSIMD_TARGET_SVE_F16
1947
- simsimd_l2sq_f16_sve(a, b, n, d);
1948
- #elif SIMSIMD_TARGET_NEON_F16
1949
- simsimd_l2sq_f16_neon(a, b, n, d);
1950
- #elif SIMSIMD_TARGET_SAPPHIRE
1951
- simsimd_l2sq_f16_sapphire(a, b, n, d);
1952
- #elif SIMSIMD_TARGET_HASWELL
1953
- simsimd_l2sq_f16_haswell(a, b, n, d);
1954
- #else
1955
- simsimd_l2sq_f16_serial(a, b, n, d);
1956
- #endif
1957
- }
1958
- SIMSIMD_PUBLIC void simsimd_l2sq_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
1959
- simsimd_distance_t *d) {
1960
- #if SIMSIMD_TARGET_GENOA
1961
- simsimd_l2sq_bf16_genoa(a, b, n, d);
1962
- #elif SIMSIMD_TARGET_HASWELL
1963
- simsimd_l2sq_bf16_haswell(a, b, n, d);
1964
- #elif SIMSIMD_TARGET_SVE_BF16
1965
- simsimd_l2sq_bf16_sve(a, b, n, d);
1966
- #elif SIMSIMD_TARGET_NEON_BF16
1967
- simsimd_l2sq_bf16_neon(a, b, n, d);
1968
- #else
1969
- simsimd_l2sq_bf16_serial(a, b, n, d);
1970
- #endif
1971
- }
1972
- SIMSIMD_PUBLIC void simsimd_l2sq_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
1973
- simsimd_distance_t *d) {
1974
- #if SIMSIMD_TARGET_SVE
1975
- simsimd_l2sq_f32_sve(a, b, n, d);
1976
- #elif SIMSIMD_TARGET_NEON
1977
- simsimd_l2sq_f32_neon(a, b, n, d);
1978
- #elif SIMSIMD_TARGET_SKYLAKE
1979
- simsimd_l2sq_f32_skylake(a, b, n, d);
1980
- #elif SIMSIMD_TARGET_HASWELL
1981
- simsimd_l2sq_f32_haswell(a, b, n, d);
1982
- #else
1983
- simsimd_l2sq_f32_serial(a, b, n, d);
1984
- #endif
1985
- }
1986
- SIMSIMD_PUBLIC void simsimd_l2sq_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
1987
- simsimd_distance_t *d) {
1988
- #if SIMSIMD_TARGET_SVE
1989
- simsimd_l2sq_f64_sve(a, b, n, d);
1990
- #elif SIMSIMD_TARGET_NEON
1991
- simsimd_l2sq_f64_neon(a, b, n, d);
1992
- #elif SIMSIMD_TARGET_SKYLAKE
1993
- simsimd_l2sq_f64_skylake(a, b, n, d);
1994
- #else
1995
- simsimd_l2sq_f64_serial(a, b, n, d);
1996
- #endif
1997
- }
1998
- SIMSIMD_PUBLIC void simsimd_l2_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
1999
- simsimd_distance_t *d) {
2000
- #if SIMSIMD_TARGET_NEON_I8
2001
- simsimd_l2_i8_neon(a, b, n, d);
2002
- #elif SIMSIMD_TARGET_ICE
2003
- simsimd_l2_i8_ice(a, b, n, d);
2004
- #elif SIMSIMD_TARGET_HASWELL
2005
- simsimd_l2_i8_haswell(a, b, n, d);
2006
- #else
2007
- simsimd_l2_i8_serial(a, b, n, d);
2008
- #endif
2009
- }
2010
- SIMSIMD_PUBLIC void simsimd_l2_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
2011
- simsimd_distance_t *d) {
2012
- #if SIMSIMD_TARGET_NEON_I8
2013
- simsimd_l2_u8_neon(a, b, n, d);
2014
- #elif SIMSIMD_TARGET_ICE
2015
- simsimd_l2_u8_ice(a, b, n, d);
2016
- #elif SIMSIMD_TARGET_HASWELL
2017
- simsimd_l2_u8_haswell(a, b, n, d);
2018
- #else
2019
- simsimd_l2_u8_serial(a, b, n, d);
2020
- #endif
2021
- }
2022
- SIMSIMD_PUBLIC void simsimd_l2_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
2023
- simsimd_distance_t *d) {
2024
- #if SIMSIMD_TARGET_SVE_F16
2025
- simsimd_l2_f16_sve(a, b, n, d);
2026
- #elif SIMSIMD_TARGET_NEON_F16
2027
- simsimd_l2_f16_neon(a, b, n, d);
2028
- #elif SIMSIMD_TARGET_SAPPHIRE
2029
- simsimd_l2_f16_sapphire(a, b, n, d);
2030
- #elif SIMSIMD_TARGET_HASWELL
2031
- simsimd_l2_f16_haswell(a, b, n, d);
2032
- #else
2033
- simsimd_l2_f16_serial(a, b, n, d);
2034
- #endif
2035
- }
2036
- SIMSIMD_PUBLIC void simsimd_l2_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
2037
- simsimd_distance_t *d) {
2038
- #if SIMSIMD_TARGET_GENOA
2039
- simsimd_l2_bf16_genoa(a, b, n, d);
2040
- #elif SIMSIMD_TARGET_HASWELL
2041
- simsimd_l2_bf16_haswell(a, b, n, d);
2042
- #elif SIMSIMD_TARGET_SVE_BF16
2043
- simsimd_l2_bf16_sve(a, b, n, d);
2044
- #elif SIMSIMD_TARGET_NEON_BF16
2045
- simsimd_l2_bf16_neon(a, b, n, d);
2046
- #else
2047
- simsimd_l2_bf16_serial(a, b, n, d);
2048
- #endif
2049
- }
2050
- SIMSIMD_PUBLIC void simsimd_l2_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
2051
- simsimd_distance_t *d) {
2052
- #if SIMSIMD_TARGET_SVE
2053
- simsimd_l2_f32_sve(a, b, n, d);
2054
- #elif SIMSIMD_TARGET_NEON
2055
- simsimd_l2_f32_neon(a, b, n, d);
2056
- #elif SIMSIMD_TARGET_SKYLAKE
2057
- simsimd_l2_f32_skylake(a, b, n, d);
2058
- #elif SIMSIMD_TARGET_HASWELL
2059
- simsimd_l2_f32_haswell(a, b, n, d);
2060
- #else
2061
- simsimd_l2_f32_serial(a, b, n, d);
2062
- #endif
2063
- }
2064
- SIMSIMD_PUBLIC void simsimd_l2_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
2065
- simsimd_distance_t *d) {
2066
- #if SIMSIMD_TARGET_SVE
2067
- simsimd_l2_f64_sve(a, b, n, d);
2068
- #elif SIMSIMD_TARGET_NEON
2069
- simsimd_l2_f64_neon(a, b, n, d);
2070
- #elif SIMSIMD_TARGET_SKYLAKE
2071
- simsimd_l2_f64_skylake(a, b, n, d);
2072
- #else
2073
- simsimd_l2_f64_serial(a, b, n, d);
2074
- #endif
2075
- }
2076
-
2077
- /* Binary distances
2078
- * - Hamming distance: the number of positions at which the corresponding bits are different.
2079
- * - Jaccard distance: ratio of bit-level matching positions (intersection) to the total number of positions (union).
2080
- *
2081
- * @param a The first binary vector.
2082
- * @param b The second binary vector.
2083
- * @param n The number of 8-bit words in the vectors.
2084
- * @param d The output distance value.
2085
- *
2086
- * @note The output distance value is non-negative.
2087
- * @note The output distance value is zero if and only if the two vectors are identical.
2088
- * @note Defined only for binary data.
2089
- */
2090
- SIMSIMD_PUBLIC void simsimd_hamming_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
2091
- simsimd_distance_t *d) {
2092
- #if SIMSIMD_TARGET_SVE
2093
- simsimd_hamming_b8_sve(a, b, n, d);
2094
- #elif SIMSIMD_TARGET_NEON
2095
- simsimd_hamming_b8_neon(a, b, n, d);
2096
- #elif SIMSIMD_TARGET_ICE
2097
- simsimd_hamming_b8_ice(a, b, n, d);
2098
- #elif SIMSIMD_TARGET_HASWELL
2099
- simsimd_hamming_b8_haswell(a, b, n, d);
2100
- #else
2101
- simsimd_hamming_b8_serial(a, b, n, d);
2102
- #endif
2103
- }
2104
- SIMSIMD_PUBLIC void simsimd_jaccard_b8(simsimd_b8_t const *a, simsimd_b8_t const *b, simsimd_size_t n,
2105
- simsimd_distance_t *d) {
2106
- #if SIMSIMD_TARGET_SVE
2107
- simsimd_jaccard_b8_sve(a, b, n, d);
2108
- #elif SIMSIMD_TARGET_NEON
2109
- simsimd_jaccard_b8_neon(a, b, n, d);
2110
- #elif SIMSIMD_TARGET_ICE
2111
- simsimd_jaccard_b8_ice(a, b, n, d);
2112
- #elif SIMSIMD_TARGET_HASWELL
2113
- simsimd_jaccard_b8_haswell(a, b, n, d);
2114
- #else
2115
- simsimd_jaccard_b8_serial(a, b, n, d);
2116
- #endif
2117
- }
2118
-
2119
- /* Probability distributions
2120
- * - Jensen-Shannon divergence: a measure of similarity between two probability distributions.
2121
- * - Kullback-Leibler divergence: a measure of how one probability distribution diverges from a second.
2122
- *
2123
- * @param a The first discrete probability distribution.
2124
- * @param b The second discrete probability distribution.
2125
- * @param n The number of elements in the discrete distributions.
2126
- * @param d The output divergence value.
2127
- *
2128
- * @note The distributions are assumed to be normalized.
2129
- * @note The output divergence value is non-negative.
2130
- * @note The output divergence value is zero if and only if the two distributions are identical.
2131
- * @note Defined only for floating-point data types.
2132
- */
2133
- SIMSIMD_PUBLIC void simsimd_kl_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
2134
- simsimd_distance_t *d) {
2135
- #if SIMSIMD_TARGET_NEON_F16
2136
- simsimd_kl_f16_neon(a, b, n, d);
2137
- #elif SIMSIMD_TARGET_HASWELL
2138
- simsimd_kl_f16_haswell(a, b, n, d);
2139
- #else
2140
- simsimd_kl_f16_serial(a, b, n, d);
2141
- #endif
2142
- }
2143
- SIMSIMD_PUBLIC void simsimd_kl_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
2144
- simsimd_distance_t *d) {
2145
- simsimd_kl_bf16_serial(a, b, n, d);
2146
- }
2147
- SIMSIMD_PUBLIC void simsimd_kl_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
2148
- simsimd_distance_t *d) {
2149
- #if SIMSIMD_TARGET_NEON
2150
- simsimd_kl_f32_neon(a, b, n, d);
2151
- #elif SIMSIMD_TARGET_SKYLAKE
2152
- simsimd_kl_f32_skylake(a, b, n, d);
2153
- #else
2154
- simsimd_kl_f32_serial(a, b, n, d);
2155
- #endif
2156
- }
2157
- SIMSIMD_PUBLIC void simsimd_kl_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
2158
- simsimd_distance_t *d) {
2159
- simsimd_kl_f64_serial(a, b, n, d);
2160
- }
2161
- SIMSIMD_PUBLIC void simsimd_js_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
2162
- simsimd_distance_t *d) {
2163
- #if SIMSIMD_TARGET_NEON_F16
2164
- simsimd_js_f16_neon(a, b, n, d);
2165
- #elif SIMSIMD_TARGET_HASWELL
2166
- simsimd_js_f16_haswell(a, b, n, d);
2167
- #else
2168
- simsimd_js_f16_serial(a, b, n, d);
2169
- #endif
2170
- }
2171
- SIMSIMD_PUBLIC void simsimd_js_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
2172
- simsimd_distance_t *d) {
2173
- simsimd_js_bf16_serial(a, b, n, d);
2174
- }
2175
- SIMSIMD_PUBLIC void simsimd_js_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
2176
- simsimd_distance_t *d) {
2177
- #if SIMSIMD_TARGET_NEON
2178
- simsimd_js_f32_neon(a, b, n, d);
2179
- #elif SIMSIMD_TARGET_SKYLAKE
2180
- simsimd_js_f32_skylake(a, b, n, d);
2181
- #else
2182
- simsimd_js_f32_serial(a, b, n, d);
2183
- #endif
2184
- }
2185
- SIMSIMD_PUBLIC void simsimd_js_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
2186
- simsimd_distance_t *d) {
2187
- simsimd_js_f64_serial(a, b, n, d);
2188
- }
2189
-
2190
- /* Set operations
2191
- *
2192
- * @param a The first sorted array of integers.
2193
- * @param b The second sorted array of integers.
2194
- * @param a_length The number of elements in the first array.
2195
- * @param b_length The number of elements in the second array.
2196
- * @param d The output for the number of elements in the intersection.
2197
- */
2198
- SIMSIMD_PUBLIC void simsimd_intersect_u16(simsimd_u16_t const *a, simsimd_u16_t const *b, simsimd_size_t a_length,
2199
- simsimd_size_t b_length, simsimd_distance_t *d) {
2200
- #if SIMSIMD_TARGET_SVE2
2201
- simsimd_intersect_u16_sve2(a, b, a_length, b_length, d);
2202
- #elif SIMSIMD_TARGET_NEON
2203
- simsimd_intersect_u16_neon(a, b, a_length, b_length, d);
2204
- #elif SIMSIMD_TARGET_TURIN
2205
- simsimd_intersect_u16_turin(a, b, a_length, b_length, d);
2206
- #elif SIMSIMD_TARGET_ICE
2207
- simsimd_intersect_u16_ice(a, b, a_length, b_length, d);
2208
- #else
2209
- simsimd_intersect_u16_serial(a, b, a_length, b_length, d);
2210
- #endif
2211
- }
2212
-
2213
- SIMSIMD_PUBLIC void simsimd_intersect_u32(simsimd_u32_t const *a, simsimd_u32_t const *b, simsimd_size_t a_length,
2214
- simsimd_size_t b_length, simsimd_distance_t *d) {
2215
- #if SIMSIMD_TARGET_SVE2
2216
- simsimd_intersect_u32_sve2(a, b, a_length, b_length, d);
2217
- #elif SIMSIMD_TARGET_NEON
2218
- simsimd_intersect_u32_neon(a, b, a_length, b_length, d);
2219
- #elif SIMSIMD_TARGET_TURIN
2220
- simsimd_intersect_u32_turin(a, b, a_length, b_length, d);
2221
- #elif SIMSIMD_TARGET_ICE
2222
- simsimd_intersect_u32_ice(a, b, a_length, b_length, d);
2223
- #else
2224
- simsimd_intersect_u32_serial(a, b, a_length, b_length, d);
2225
- #endif
2226
- }
2227
-
2228
- /* Weighted set operations
2229
- *
2230
- * @param a The first sorted array of integers.
2231
- * @param b The second sorted array of integers.
2232
- * @param a_weights The weights for the first array.
2233
- * @param b_weights The weights for the second array.
2234
- * @param a_length The number of elements in the first array.
2235
- * @param b_length The number of elements in the second array.
2236
- * @param d The output for the number of elements in the intersection.
2237
- */
2238
- SIMSIMD_PUBLIC void simsimd_spdot_counts_u16(simsimd_u16_t const *a, simsimd_u16_t const *b,
2239
- simsimd_i16_t const *a_weights, simsimd_i16_t const *b_weights,
2240
- simsimd_size_t a_length, simsimd_size_t b_length, simsimd_distance_t *d) {
2241
- #if SIMSIMD_TARGET_SVE2
2242
- simsimd_spdot_counts_u16_sve2(a, b, a_weights, b_weights, a_length, b_length, d);
2243
- #elif SIMSIMD_TARGET_TURIN
2244
- simsimd_spdot_counts_u16_turin(a, b, a_weights, b_weights, a_length, b_length, d);
2245
- #else
2246
- simsimd_spdot_counts_u16_serial(a, b, a_weights, b_weights, a_length, b_length, d);
2247
- #endif
2248
- }
2249
-
2250
- SIMSIMD_PUBLIC void simsimd_spdot_weights_u16(simsimd_u16_t const *a, simsimd_u16_t const *b,
2251
- simsimd_bf16_t const *a_weights, simsimd_bf16_t const *b_weights,
2252
- simsimd_size_t a_length, simsimd_size_t b_length, simsimd_distance_t *d) {
2253
- #if SIMSIMD_TARGET_SVE2
2254
- simsimd_spdot_weights_u16_sve2(a, b, a_weights, b_weights, a_length, b_length, d);
2255
- #elif SIMSIMD_TARGET_TURIN
2256
- simsimd_spdot_weights_u16_turin(a, b, a_weights, b_weights, a_length, b_length, d);
2257
- #else
2258
- simsimd_spdot_weights_u16_serial(a, b, a_weights, b_weights, a_length, b_length, d);
2259
- #endif
2260
- }
2261
-
2262
- /* Curved space distances
2263
- *
2264
- * @param a The first vector of floating point values.
2265
- * @param b The second vector of floating point values.
2266
- * @param c The metric tensor or covariance matrix.
2267
- * @param n The number of dimensions in the vectors.
2268
- * @param d The output for the number of elements in the intersection.
2269
- */
2270
- SIMSIMD_PUBLIC void simsimd_bilinear_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
2271
- simsimd_size_t n, simsimd_distance_t *d) {
2272
- #if SIMSIMD_TARGET_SKYLAKE
2273
- simsimd_bilinear_f64_skylake(a, b, c, n, d);
2274
- #else
2275
- simsimd_bilinear_f64_serial(a, b, c, n, d);
2276
- #endif
2277
- }
2278
- SIMSIMD_PUBLIC void simsimd_bilinear_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
2279
- simsimd_size_t n, simsimd_distance_t *d) {
2280
- #if SIMSIMD_TARGET_SKYLAKE
2281
- simsimd_bilinear_f32_skylake(a, b, c, n, d);
2282
- #elif SIMSIMD_TARGET_NEON
2283
- simsimd_bilinear_f32_neon(a, b, c, n, d);
2284
- #else
2285
- simsimd_bilinear_f32_serial(a, b, c, n, d);
2286
- #endif
2287
- }
2288
- SIMSIMD_PUBLIC void simsimd_bilinear_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
2289
- simsimd_size_t n, simsimd_distance_t *d) {
2290
- #if SIMSIMD_TARGET_SAPPHIRE
2291
- simsimd_bilinear_f16_sapphire(a, b, c, n, d);
2292
- #elif SIMSIMD_TARGET_HASWELL
2293
- simsimd_bilinear_f16_haswell(a, b, c, n, d);
2294
- #elif SIMSIMD_TARGET_NEON_F16
2295
- simsimd_bilinear_f16_neon(a, b, c, n, d);
2296
- #else
2297
- simsimd_bilinear_f16_serial(a, b, c, n, d);
2298
- #endif
2299
- }
2300
- SIMSIMD_PUBLIC void simsimd_bilinear_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
2301
- simsimd_size_t n, simsimd_distance_t *d) {
2302
- #if SIMSIMD_TARGET_GENOA
2303
- simsimd_bilinear_bf16_genoa(a, b, c, n, d);
2304
- #elif SIMSIMD_TARGET_HASWELL
2305
- simsimd_bilinear_bf16_haswell(a, b, c, n, d);
2306
- #elif SIMSIMD_TARGET_NEON_BF16
2307
- simsimd_bilinear_bf16_neon(a, b, c, n, d);
2308
- #else
2309
- simsimd_bilinear_bf16_serial(a, b, c, n, d);
2310
- #endif
2311
- }
2312
- SIMSIMD_PUBLIC void simsimd_bilinear_f64c(simsimd_f64c_t const *a, simsimd_f64c_t const *b, simsimd_f64c_t const *c,
2313
- simsimd_size_t n, simsimd_distance_t *d) {
2314
- #if SIMSIMD_TARGET_SKYLAKE
2315
- simsimd_bilinear_f64c_skylake(a, b, c, n, d);
2316
- #else
2317
- simsimd_bilinear_f64c_serial(a, b, c, n, d);
2318
- #endif
2319
- }
2320
- SIMSIMD_PUBLIC void simsimd_bilinear_f32c(simsimd_f32c_t const *a, simsimd_f32c_t const *b, simsimd_f32c_t const *c,
2321
- simsimd_size_t n, simsimd_distance_t *d) {
2322
- #if SIMSIMD_TARGET_SKYLAKE
2323
- simsimd_bilinear_f32c_skylake(a, b, c, n, d);
2324
- #elif SIMSIMD_TARGET_NEON
2325
- simsimd_bilinear_f32c_neon(a, b, c, n, d);
2326
- #else
2327
- simsimd_bilinear_f32c_serial(a, b, c, n, d);
2328
- #endif
2329
- }
2330
- SIMSIMD_PUBLIC void simsimd_bilinear_f16c(simsimd_f16c_t const *a, simsimd_f16c_t const *b, simsimd_f16c_t const *c,
2331
- simsimd_size_t n, simsimd_distance_t *d) {
2332
- #if SIMSIMD_TARGET_SAPPHIRE
2333
- simsimd_bilinear_f16c_sapphire(a, b, c, n, d);
2334
- #elif SIMSIMD_TARGET_NEON_F16
2335
- simsimd_bilinear_f16c_neon(a, b, c, n, d);
2336
- #else
2337
- simsimd_bilinear_f16c_serial(a, b, c, n, d);
2338
- #endif
2339
- }
2340
- SIMSIMD_PUBLIC void simsimd_bilinear_bf16c(simsimd_bf16c_t const *a, simsimd_bf16c_t const *b, simsimd_bf16c_t const *c,
2341
- simsimd_size_t n, simsimd_distance_t *d) {
2342
- #if SIMSIMD_TARGET_GENOA
2343
- simsimd_bilinear_bf16c_genoa(a, b, c, n, d);
2344
- #elif SIMSIMD_TARGET_NEON_BF16
2345
- simsimd_bilinear_bf16c_neon(a, b, c, n, d);
2346
- #else
2347
- simsimd_bilinear_bf16c_serial(a, b, c, n, d);
2348
- #endif
2349
- }
2350
- SIMSIMD_PUBLIC void simsimd_mahalanobis_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
2351
- simsimd_size_t n, simsimd_distance_t *d) {
2352
- #if SIMSIMD_TARGET_SKYLAKE
2353
- simsimd_mahalanobis_f64_skylake(a, b, c, n, d);
2354
- #else
2355
- simsimd_mahalanobis_f64_serial(a, b, c, n, d);
2356
- #endif
2357
- }
2358
- SIMSIMD_PUBLIC void simsimd_mahalanobis_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
2359
- simsimd_size_t n, simsimd_distance_t *d) {
2360
- #if SIMSIMD_TARGET_SKYLAKE
2361
- simsimd_mahalanobis_f32_skylake(a, b, c, n, d);
2362
- #elif SIMSIMD_TARGET_NEON
2363
- simsimd_mahalanobis_f32_neon(a, b, c, n, d);
2364
- #else
2365
- simsimd_mahalanobis_f32_serial(a, b, c, n, d);
2366
- #endif
2367
- }
2368
- SIMSIMD_PUBLIC void simsimd_mahalanobis_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
2369
- simsimd_size_t n, simsimd_distance_t *d) {
2370
- #if SIMSIMD_TARGET_SAPPHIRE
2371
- simsimd_mahalanobis_f16_sapphire(a, b, c, n, d);
2372
- #elif SIMSIMD_TARGET_HASWELL
2373
- simsimd_mahalanobis_f16_haswell(a, b, c, n, d);
2374
- #elif SIMSIMD_TARGET_NEON_F16
2375
- simsimd_mahalanobis_f16_neon(a, b, c, n, d);
2376
- #else
2377
- simsimd_mahalanobis_f16_serial(a, b, c, n, d);
2378
- #endif
2379
- }
2380
- SIMSIMD_PUBLIC void simsimd_mahalanobis_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
2381
- simsimd_size_t n, simsimd_distance_t *d) {
2382
- #if SIMSIMD_TARGET_GENOA
2383
- simsimd_mahalanobis_bf16_genoa(a, b, c, n, d);
2384
- #elif SIMSIMD_TARGET_HASWELL
2385
- simsimd_mahalanobis_bf16_haswell(a, b, c, n, d);
2386
- #elif SIMSIMD_TARGET_NEON_BF16
2387
- simsimd_mahalanobis_bf16_neon(a, b, c, n, d);
2388
- #else
2389
- simsimd_mahalanobis_bf16_serial(a, b, c, n, d);
2390
- #endif
2391
- }
2392
-
2393
- /* Elementwise operations
2394
- *
2395
- * @param a The first vector of integral or floating point values.
2396
- * @param b The second vector of integral or floating point values.
2397
- * @param c The third vector of integral or floating point values.
2398
- * @param n The number of dimensions in the vectors.
2399
- * @param alpha The first scaling factor.
2400
- * @param beta The first scaling factor.
2401
- * @param r The output vector or integral or floating point values.
2402
- */
2403
- SIMSIMD_PUBLIC void simsimd_wsum_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_size_t n,
2404
- simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_f64_t *r) {
2405
- #if SIMSIMD_TARGET_SKYLAKE
2406
- simsimd_wsum_f64_skylake(a, b, n, alpha, beta, r);
2407
- #elif SIMSIMD_TARGET_HASWELL
2408
- simsimd_wsum_f64_haswell(a, b, n, alpha, beta, r);
2409
- #else
2410
- simsimd_wsum_f64_serial(a, b, n, alpha, beta, r);
2411
- #endif
2412
- }
2413
-
2414
- SIMSIMD_PUBLIC void simsimd_wsum_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_size_t n,
2415
- simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_f32_t *r) {
2416
- #if SIMSIMD_TARGET_SKYLAKE
2417
- simsimd_wsum_f32_skylake(a, b, n, alpha, beta, r);
2418
- #elif SIMSIMD_TARGET_HASWELL
2419
- simsimd_wsum_f32_haswell(a, b, n, alpha, beta, r);
2420
- #elif SIMSIMD_TARGET_NEON
2421
- simsimd_wsum_f32_neon(a, b, n, alpha, beta, r);
2422
- #else
2423
- simsimd_wsum_f32_serial(a, b, n, alpha, beta, r);
2424
- #endif
2425
- }
2426
-
2427
- SIMSIMD_PUBLIC void simsimd_wsum_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_size_t n,
2428
- simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_bf16_t *r) {
2429
- #if SIMSIMD_TARGET_SKYLAKE
2430
- simsimd_wsum_bf16_skylake(a, b, n, alpha, beta, r);
2431
- #elif SIMSIMD_TARGET_HASWELL
2432
- simsimd_wsum_bf16_haswell(a, b, n, alpha, beta, r);
2433
- #elif SIMSIMD_TARGET_NEON_BF16
2434
- simsimd_wsum_bf16_neon(a, b, n, alpha, beta, r);
2435
- #else
2436
- simsimd_wsum_bf16_serial(a, b, n, alpha, beta, r);
2437
- #endif
2438
- }
2439
-
2440
- SIMSIMD_PUBLIC void simsimd_wsum_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_size_t n,
2441
- simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_f16_t *r) {
2442
- #if SIMSIMD_TARGET_SAPPHIRE
2443
- simsimd_wsum_f16_sapphire(a, b, n, alpha, beta, r);
2444
- #elif SIMSIMD_TARGET_HASWELL
2445
- simsimd_wsum_f16_haswell(a, b, n, alpha, beta, r);
2446
- #elif SIMSIMD_TARGET_NEON_F16
2447
- simsimd_wsum_f16_neon(a, b, n, alpha, beta, r);
2448
- #else
2449
- simsimd_wsum_f16_serial(a, b, n, alpha, beta, r);
2450
- #endif
2451
- }
2452
-
2453
- SIMSIMD_PUBLIC void simsimd_wsum_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_size_t n,
2454
- simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_i8_t *r) {
2455
- #if SIMSIMD_TARGET_SAPPHIRE
2456
- simsimd_wsum_i8_sapphire(a, b, n, alpha, beta, r);
2457
- #elif SIMSIMD_TARGET_HASWELL
2458
- simsimd_wsum_i8_haswell(a, b, n, alpha, beta, r);
2459
- #elif SIMSIMD_TARGET_NEON_F16
2460
- simsimd_wsum_i8_neon(a, b, n, alpha, beta, r);
2461
- #else
2462
- simsimd_wsum_i8_serial(a, b, n, alpha, beta, r);
2463
- #endif
2464
- }
2465
-
2466
- SIMSIMD_PUBLIC void simsimd_wsum_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_size_t n,
2467
- simsimd_distance_t alpha, simsimd_distance_t beta, simsimd_u8_t *r) {
2468
- #if SIMSIMD_TARGET_SAPPHIRE
2469
- simsimd_wsum_u8_sapphire(a, b, n, alpha, beta, r);
2470
- #elif SIMSIMD_TARGET_HASWELL
2471
- simsimd_wsum_u8_haswell(a, b, n, alpha, beta, r);
2472
- #elif SIMSIMD_TARGET_NEON_F16
2473
- simsimd_wsum_u8_neon(a, b, n, alpha, beta, r);
2474
- #else
2475
- simsimd_wsum_u8_serial(a, b, n, alpha, beta, r);
2476
- #endif
2477
- }
2478
-
2479
- SIMSIMD_PUBLIC void simsimd_fma_f64(simsimd_f64_t const *a, simsimd_f64_t const *b, simsimd_f64_t const *c,
2480
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2481
- simsimd_f64_t *r) {
2482
- #if SIMSIMD_TARGET_SKYLAKE
2483
- simsimd_fma_f64_skylake(a, b, c, n, alpha, beta, r);
2484
- #elif SIMSIMD_TARGET_HASWELL
2485
- simsimd_fma_f64_haswell(a, b, c, n, alpha, beta, r);
2486
- #else
2487
- simsimd_fma_f64_serial(a, b, c, n, alpha, beta, r);
2488
- #endif
2489
- }
2490
-
2491
- SIMSIMD_PUBLIC void simsimd_fma_f32(simsimd_f32_t const *a, simsimd_f32_t const *b, simsimd_f32_t const *c,
2492
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2493
- simsimd_f32_t *r) {
2494
- #if SIMSIMD_TARGET_SKYLAKE
2495
- simsimd_fma_f32_skylake(a, b, c, n, alpha, beta, r);
2496
- #elif SIMSIMD_TARGET_HASWELL
2497
- simsimd_fma_f32_haswell(a, b, c, n, alpha, beta, r);
2498
- #elif SIMSIMD_TARGET_NEON
2499
- simsimd_fma_f32_neon(a, b, c, n, alpha, beta, r);
2500
- #else
2501
- simsimd_fma_f32_serial(a, b, c, n, alpha, beta, r);
2502
- #endif
2503
- }
2504
-
2505
- SIMSIMD_PUBLIC void simsimd_fma_bf16(simsimd_bf16_t const *a, simsimd_bf16_t const *b, simsimd_bf16_t const *c,
2506
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2507
- simsimd_bf16_t *r) {
2508
- #if SIMSIMD_TARGET_SKYLAKE
2509
- simsimd_fma_bf16_skylake(a, b, c, n, alpha, beta, r);
2510
- #elif SIMSIMD_TARGET_HASWELL
2511
- simsimd_fma_bf16_haswell(a, b, c, n, alpha, beta, r);
2512
- #elif SIMSIMD_TARGET_NEON_BF16
2513
- simsimd_fma_bf16_neon(a, b, c, n, alpha, beta, r);
2514
- #else
2515
- simsimd_fma_bf16_serial(a, b, c, n, alpha, beta, r);
2516
- #endif
2517
- }
2518
-
2519
- SIMSIMD_PUBLIC void simsimd_fma_f16(simsimd_f16_t const *a, simsimd_f16_t const *b, simsimd_f16_t const *c,
2520
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2521
- simsimd_f16_t *r) {
2522
- #if SIMSIMD_TARGET_SAPPHIRE
2523
- simsimd_fma_f16_sapphire(a, b, c, n, alpha, beta, r);
2524
- #elif SIMSIMD_TARGET_HASWELL
2525
- simsimd_fma_f16_haswell(a, b, c, n, alpha, beta, r);
2526
- #elif SIMSIMD_TARGET_NEON_F16
2527
- simsimd_fma_f16_neon(a, b, c, n, alpha, beta, r);
2528
- #else
2529
- simsimd_fma_f16_serial(a, b, c, n, alpha, beta, r);
2530
- #endif
2531
- }
2532
-
2533
- SIMSIMD_PUBLIC void simsimd_fma_i8(simsimd_i8_t const *a, simsimd_i8_t const *b, simsimd_i8_t const *c,
2534
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2535
- simsimd_i8_t *r) {
2536
- #if SIMSIMD_TARGET_SAPPHIRE
2537
- simsimd_fma_i8_sapphire(a, b, c, n, alpha, beta, r);
2538
- #elif SIMSIMD_TARGET_HASWELL
2539
- simsimd_fma_i8_haswell(a, b, c, n, alpha, beta, r);
2540
- #elif SIMSIMD_TARGET_NEON_F16
2541
- simsimd_fma_i8_neon(a, b, c, n, alpha, beta, r);
2542
- #else
2543
- simsimd_fma_i8_serial(a, b, c, n, alpha, beta, r);
2544
- #endif
2545
- }
2546
-
2547
- SIMSIMD_PUBLIC void simsimd_fma_u8(simsimd_u8_t const *a, simsimd_u8_t const *b, simsimd_u8_t const *c,
2548
- simsimd_size_t n, simsimd_distance_t alpha, simsimd_distance_t beta,
2549
- simsimd_u8_t *r) {
2550
- #if SIMSIMD_TARGET_SAPPHIRE
2551
- simsimd_fma_u8_sapphire(a, b, c, n, alpha, beta, r);
2552
- #elif SIMSIMD_TARGET_HASWELL
2553
- simsimd_fma_u8_haswell(a, b, c, n, alpha, beta, r);
2554
- #elif SIMSIMD_TARGET_NEON_F16
2555
- simsimd_fma_u8_neon(a, b, c, n, alpha, beta, r);
2556
- #else
2557
- simsimd_fma_u8_serial(a, b, c, n, alpha, beta, r);
2558
- #endif
2559
- }
2560
-
2561
- #endif
2562
-
2563
- #ifdef __cplusplus
2564
- }
2565
- #endif
2566
-
2567
- #endif // SIMSIMD_H