usearch 2.21.3 → 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 +235 -52
  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
@@ -0,0 +1,2721 @@
1
+ //! Elementwise operations and trigonometry.
2
+ //!
3
+ //! This module provides:
4
+ //!
5
+ //! - [`EachSin`], [`EachCos`], [`EachATan`]: Trigonometric functions
6
+ //! - [`EachScale`]: Linear scaling (alpha * x + beta)
7
+ //! - [`EachSum`]: Elementwise addition of two vectors
8
+ //! - [`EachBlend`]: Weighted blend of two vectors
9
+ //! - [`EachFMA`]: Fused multiply-add (a * alpha + b * beta)
10
+ //! - [`Trigonometry`]: Blanket trait combining `EachSin + EachCos + EachATan`
11
+ //!
12
+ //! # In-Place vs Allocating Semantics
13
+ //!
14
+ //! Every operation in this module is **allocation-free**: the caller provides both
15
+ //! the input slices and a pre-sized output buffer. The kernels never grow a `Vec`
16
+ //! internally, never return a new allocation, and never call into the allocator —
17
+ //! perfect for warm inner loops and `no_std` contexts.
18
+ //!
19
+ //! Because the output buffer is always a separate `&mut [Self]`, a caller who
20
+ //! wants in-place update must explicitly alias the output to one of the inputs
21
+ //! (for example by passing the same slot for both):
22
+ //!
23
+ //! ```ignore
24
+ //! // Functionally equivalent to `x *= 2.0`.
25
+ //! f32::each_scale(&x.clone(), 2.0, 0.0, &mut x).unwrap();
26
+ //! ```
27
+ //!
28
+ //! # Stride Support
29
+ //!
30
+ //! Inputs are read contiguously in memory. For strided access, `slice::chunks_by`,
31
+ //! `step_by`, or a caller-side reshape is the right tool — this module keeps the
32
+ //! fast-path API simple and lets the SIMD kernels assume packed layout. See the
33
+ //! strided variants in [`reduce`](crate::reduce) when non-unit stride is needed.
34
+ //!
35
+ //! # Example
36
+ //!
37
+ //! ```
38
+ //! use numkong::EachScale;
39
+ //! let input = [1.0_f32, 2.0, 3.0, 4.0];
40
+ //! let mut output = [0.0_f32; 4];
41
+ //! // Compute output[i] = 2.0 * input[i] + 0.5
42
+ //! f32::each_scale(&input, 2.0, 0.5, &mut output).unwrap();
43
+ //! assert_eq!(output, [2.5, 4.5, 6.5, 8.5]);
44
+ //! ```
45
+
46
+ use crate::types::{bf16, bf16c, e2m3, e3m2, e4m3, e5m2, f16, f16c, f32c, f64c, StorageElement};
47
+
48
+ #[link(name = "numkong")]
49
+ extern "C" {
50
+ // Trigonometry
51
+ fn nk_each_sin_f32(inputs: *const f32, n: usize, outputs: *mut f32);
52
+ fn nk_each_sin_f64(inputs: *const f64, n: usize, outputs: *mut f64);
53
+ fn nk_each_sin_f16(inputs: *const u16, n: usize, outputs: *mut u16);
54
+ fn nk_each_cos_f32(inputs: *const f32, n: usize, outputs: *mut f32);
55
+ fn nk_each_cos_f64(inputs: *const f64, n: usize, outputs: *mut f64);
56
+ fn nk_each_cos_f16(inputs: *const u16, n: usize, outputs: *mut u16);
57
+ fn nk_each_atan_f32(inputs: *const f32, n: usize, outputs: *mut f32);
58
+ fn nk_each_atan_f64(inputs: *const f64, n: usize, outputs: *mut f64);
59
+ fn nk_each_atan_f16(inputs: *const u16, n: usize, outputs: *mut u16);
60
+
61
+ // Elementwise operations
62
+ fn nk_each_scale_f64(
63
+ a: *const f64,
64
+ n: usize,
65
+ alpha: *const f64,
66
+ beta: *const f64,
67
+ result: *mut f64,
68
+ );
69
+ fn nk_each_scale_f32(
70
+ a: *const f32,
71
+ n: usize,
72
+ alpha: *const f32,
73
+ beta: *const f32,
74
+ result: *mut f32,
75
+ );
76
+ fn nk_each_scale_f16(
77
+ a: *const u16,
78
+ n: usize,
79
+ alpha: *const f32,
80
+ beta: *const f32,
81
+ result: *mut u16,
82
+ );
83
+ fn nk_each_scale_bf16(
84
+ a: *const u16,
85
+ n: usize,
86
+ alpha: *const f32,
87
+ beta: *const f32,
88
+ result: *mut u16,
89
+ );
90
+ fn nk_each_scale_i8(
91
+ a: *const i8,
92
+ n: usize,
93
+ alpha: *const f32,
94
+ beta: *const f32,
95
+ result: *mut i8,
96
+ );
97
+ fn nk_each_scale_u8(
98
+ a: *const u8,
99
+ n: usize,
100
+ alpha: *const f32,
101
+ beta: *const f32,
102
+ result: *mut u8,
103
+ );
104
+ fn nk_each_scale_i16(
105
+ a: *const i16,
106
+ n: usize,
107
+ alpha: *const f32,
108
+ beta: *const f32,
109
+ result: *mut i16,
110
+ );
111
+ fn nk_each_scale_u16(
112
+ a: *const u16,
113
+ n: usize,
114
+ alpha: *const f32,
115
+ beta: *const f32,
116
+ result: *mut u16,
117
+ );
118
+ fn nk_each_scale_i32(
119
+ a: *const i32,
120
+ n: usize,
121
+ alpha: *const f64,
122
+ beta: *const f64,
123
+ result: *mut i32,
124
+ );
125
+ fn nk_each_scale_u32(
126
+ a: *const u32,
127
+ n: usize,
128
+ alpha: *const f64,
129
+ beta: *const f64,
130
+ result: *mut u32,
131
+ );
132
+ fn nk_each_scale_i64(
133
+ a: *const i64,
134
+ n: usize,
135
+ alpha: *const f64,
136
+ beta: *const f64,
137
+ result: *mut i64,
138
+ );
139
+ fn nk_each_scale_u64(
140
+ a: *const u64,
141
+ n: usize,
142
+ alpha: *const f64,
143
+ beta: *const f64,
144
+ result: *mut u64,
145
+ );
146
+ fn nk_each_scale_e4m3(
147
+ a: *const u8,
148
+ n: usize,
149
+ alpha: *const f32,
150
+ beta: *const f32,
151
+ result: *mut u8,
152
+ );
153
+ fn nk_each_scale_e5m2(
154
+ a: *const u8,
155
+ n: usize,
156
+ alpha: *const f32,
157
+ beta: *const f32,
158
+ result: *mut u8,
159
+ );
160
+ fn nk_each_scale_e2m3(
161
+ a: *const u8,
162
+ n: usize,
163
+ alpha: *const f32,
164
+ beta: *const f32,
165
+ result: *mut u8,
166
+ );
167
+ fn nk_each_scale_e3m2(
168
+ a: *const u8,
169
+ n: usize,
170
+ alpha: *const f32,
171
+ beta: *const f32,
172
+ result: *mut u8,
173
+ );
174
+
175
+ fn nk_each_sum_f64(a: *const f64, b: *const f64, n: usize, result: *mut f64);
176
+ fn nk_each_sum_f32(a: *const f32, b: *const f32, n: usize, result: *mut f32);
177
+ fn nk_each_sum_f16(a: *const u16, b: *const u16, n: usize, result: *mut u16);
178
+ fn nk_each_sum_bf16(a: *const u16, b: *const u16, n: usize, result: *mut u16);
179
+ fn nk_each_sum_i8(a: *const i8, b: *const i8, n: usize, result: *mut i8);
180
+ fn nk_each_sum_u8(a: *const u8, b: *const u8, n: usize, result: *mut u8);
181
+ fn nk_each_sum_i16(a: *const i16, b: *const i16, n: usize, result: *mut i16);
182
+ fn nk_each_sum_u16(a: *const u16, b: *const u16, n: usize, result: *mut u16);
183
+ fn nk_each_sum_i32(a: *const i32, b: *const i32, n: usize, result: *mut i32);
184
+ fn nk_each_sum_u32(a: *const u32, b: *const u32, n: usize, result: *mut u32);
185
+ fn nk_each_sum_i64(a: *const i64, b: *const i64, n: usize, result: *mut i64);
186
+ fn nk_each_sum_u64(a: *const u64, b: *const u64, n: usize, result: *mut u64);
187
+ fn nk_each_sum_e4m3(a: *const u8, b: *const u8, n: usize, result: *mut u8);
188
+ fn nk_each_sum_e5m2(a: *const u8, b: *const u8, n: usize, result: *mut u8);
189
+ fn nk_each_sum_e2m3(a: *const u8, b: *const u8, n: usize, result: *mut u8);
190
+ fn nk_each_sum_e3m2(a: *const u8, b: *const u8, n: usize, result: *mut u8);
191
+
192
+ fn nk_each_blend_f64(
193
+ a: *const f64,
194
+ b: *const f64,
195
+ n: usize,
196
+ alpha: *const f64,
197
+ beta: *const f64,
198
+ result: *mut f64,
199
+ );
200
+ fn nk_each_blend_f32(
201
+ a: *const f32,
202
+ b: *const f32,
203
+ n: usize,
204
+ alpha: *const f32,
205
+ beta: *const f32,
206
+ result: *mut f32,
207
+ );
208
+ fn nk_each_blend_f16(
209
+ a: *const u16,
210
+ b: *const u16,
211
+ n: usize,
212
+ alpha: *const f32,
213
+ beta: *const f32,
214
+ result: *mut u16,
215
+ );
216
+ fn nk_each_blend_bf16(
217
+ a: *const u16,
218
+ b: *const u16,
219
+ n: usize,
220
+ alpha: *const f32,
221
+ beta: *const f32,
222
+ result: *mut u16,
223
+ );
224
+ fn nk_each_blend_i8(
225
+ a: *const i8,
226
+ b: *const i8,
227
+ n: usize,
228
+ alpha: *const f32,
229
+ beta: *const f32,
230
+ result: *mut i8,
231
+ );
232
+ fn nk_each_blend_u8(
233
+ a: *const u8,
234
+ b: *const u8,
235
+ n: usize,
236
+ alpha: *const f32,
237
+ beta: *const f32,
238
+ result: *mut u8,
239
+ );
240
+ fn nk_each_blend_i16(
241
+ a: *const i16,
242
+ b: *const i16,
243
+ n: usize,
244
+ alpha: *const f32,
245
+ beta: *const f32,
246
+ result: *mut i16,
247
+ );
248
+ fn nk_each_blend_u16(
249
+ a: *const u16,
250
+ b: *const u16,
251
+ n: usize,
252
+ alpha: *const f32,
253
+ beta: *const f32,
254
+ result: *mut u16,
255
+ );
256
+ fn nk_each_blend_i32(
257
+ a: *const i32,
258
+ b: *const i32,
259
+ n: usize,
260
+ alpha: *const f64,
261
+ beta: *const f64,
262
+ result: *mut i32,
263
+ );
264
+ fn nk_each_blend_u32(
265
+ a: *const u32,
266
+ b: *const u32,
267
+ n: usize,
268
+ alpha: *const f64,
269
+ beta: *const f64,
270
+ result: *mut u32,
271
+ );
272
+ fn nk_each_blend_i64(
273
+ a: *const i64,
274
+ b: *const i64,
275
+ n: usize,
276
+ alpha: *const f64,
277
+ beta: *const f64,
278
+ result: *mut i64,
279
+ );
280
+ fn nk_each_blend_u64(
281
+ a: *const u64,
282
+ b: *const u64,
283
+ n: usize,
284
+ alpha: *const f64,
285
+ beta: *const f64,
286
+ result: *mut u64,
287
+ );
288
+ fn nk_each_blend_e4m3(
289
+ a: *const u8,
290
+ b: *const u8,
291
+ n: usize,
292
+ alpha: *const f32,
293
+ beta: *const f32,
294
+ result: *mut u8,
295
+ );
296
+ fn nk_each_blend_e5m2(
297
+ a: *const u8,
298
+ b: *const u8,
299
+ n: usize,
300
+ alpha: *const f32,
301
+ beta: *const f32,
302
+ result: *mut u8,
303
+ );
304
+ fn nk_each_blend_e2m3(
305
+ a: *const u8,
306
+ b: *const u8,
307
+ n: usize,
308
+ alpha: *const f32,
309
+ beta: *const f32,
310
+ result: *mut u8,
311
+ );
312
+ fn nk_each_blend_e3m2(
313
+ a: *const u8,
314
+ b: *const u8,
315
+ n: usize,
316
+ alpha: *const f32,
317
+ beta: *const f32,
318
+ result: *mut u8,
319
+ );
320
+
321
+ fn nk_each_fma_f64(
322
+ a: *const f64,
323
+ b: *const f64,
324
+ c: *const f64,
325
+ n: usize,
326
+ alpha: *const f64,
327
+ beta: *const f64,
328
+ result: *mut f64,
329
+ );
330
+ fn nk_each_fma_f32(
331
+ a: *const f32,
332
+ b: *const f32,
333
+ c: *const f32,
334
+ n: usize,
335
+ alpha: *const f32,
336
+ beta: *const f32,
337
+ result: *mut f32,
338
+ );
339
+ fn nk_each_fma_f16(
340
+ a: *const u16,
341
+ b: *const u16,
342
+ c: *const u16,
343
+ n: usize,
344
+ alpha: *const f32,
345
+ beta: *const f32,
346
+ result: *mut u16,
347
+ );
348
+ fn nk_each_fma_bf16(
349
+ a: *const u16,
350
+ b: *const u16,
351
+ c: *const u16,
352
+ n: usize,
353
+ alpha: *const f32,
354
+ beta: *const f32,
355
+ result: *mut u16,
356
+ );
357
+ fn nk_each_fma_i8(
358
+ a: *const i8,
359
+ b: *const i8,
360
+ c: *const i8,
361
+ n: usize,
362
+ alpha: *const f32,
363
+ beta: *const f32,
364
+ result: *mut i8,
365
+ );
366
+ fn nk_each_fma_u8(
367
+ a: *const u8,
368
+ b: *const u8,
369
+ c: *const u8,
370
+ n: usize,
371
+ alpha: *const f32,
372
+ beta: *const f32,
373
+ result: *mut u8,
374
+ );
375
+ fn nk_each_fma_e4m3(
376
+ a: *const u8,
377
+ b: *const u8,
378
+ c: *const u8,
379
+ n: usize,
380
+ alpha: *const f32,
381
+ beta: *const f32,
382
+ result: *mut u8,
383
+ );
384
+ fn nk_each_fma_e5m2(
385
+ a: *const u8,
386
+ b: *const u8,
387
+ c: *const u8,
388
+ n: usize,
389
+ alpha: *const f32,
390
+ beta: *const f32,
391
+ result: *mut u8,
392
+ );
393
+ fn nk_each_fma_e2m3(
394
+ a: *const u8,
395
+ b: *const u8,
396
+ c: *const u8,
397
+ n: usize,
398
+ alpha: *const f32,
399
+ beta: *const f32,
400
+ result: *mut u8,
401
+ );
402
+ fn nk_each_fma_e3m2(
403
+ a: *const u8,
404
+ b: *const u8,
405
+ c: *const u8,
406
+ n: usize,
407
+ alpha: *const f32,
408
+ beta: *const f32,
409
+ result: *mut u8,
410
+ );
411
+ fn nk_each_fma_i16(
412
+ a: *const i16,
413
+ b: *const i16,
414
+ c: *const i16,
415
+ n: usize,
416
+ alpha: *const f32,
417
+ beta: *const f32,
418
+ r: *mut i16,
419
+ );
420
+ fn nk_each_fma_u16(
421
+ a: *const u16,
422
+ b: *const u16,
423
+ c: *const u16,
424
+ n: usize,
425
+ alpha: *const f32,
426
+ beta: *const f32,
427
+ r: *mut u16,
428
+ );
429
+ fn nk_each_fma_i32(
430
+ a: *const i32,
431
+ b: *const i32,
432
+ c: *const i32,
433
+ n: usize,
434
+ alpha: *const f64,
435
+ beta: *const f64,
436
+ r: *mut i32,
437
+ );
438
+ fn nk_each_fma_u32(
439
+ a: *const u32,
440
+ b: *const u32,
441
+ c: *const u32,
442
+ n: usize,
443
+ alpha: *const f64,
444
+ beta: *const f64,
445
+ r: *mut u32,
446
+ );
447
+ fn nk_each_fma_i64(
448
+ a: *const i64,
449
+ b: *const i64,
450
+ c: *const i64,
451
+ n: usize,
452
+ alpha: *const f64,
453
+ beta: *const f64,
454
+ r: *mut i64,
455
+ );
456
+ fn nk_each_fma_u64(
457
+ a: *const u64,
458
+ b: *const u64,
459
+ c: *const u64,
460
+ n: usize,
461
+ alpha: *const f64,
462
+ beta: *const f64,
463
+ r: *mut u64,
464
+ );
465
+
466
+ // Complex elementwise operations (interleaved real/imag layout, n = number of complex pairs)
467
+ fn nk_each_sum_f32c(a: *const f32, b: *const f32, n: usize, result: *mut f32);
468
+ fn nk_each_sum_f64c(a: *const f64, b: *const f64, n: usize, result: *mut f64);
469
+ fn nk_each_scale_f32c(
470
+ a: *const f32,
471
+ n: usize,
472
+ alpha: *const f32,
473
+ beta: *const f32,
474
+ result: *mut f32,
475
+ );
476
+ fn nk_each_scale_f64c(
477
+ a: *const f64,
478
+ n: usize,
479
+ alpha: *const f64,
480
+ beta: *const f64,
481
+ result: *mut f64,
482
+ );
483
+ fn nk_each_blend_f32c(
484
+ a: *const f32,
485
+ b: *const f32,
486
+ n: usize,
487
+ alpha: *const f32,
488
+ beta: *const f32,
489
+ result: *mut f32,
490
+ );
491
+ fn nk_each_blend_f64c(
492
+ a: *const f64,
493
+ b: *const f64,
494
+ n: usize,
495
+ alpha: *const f64,
496
+ beta: *const f64,
497
+ result: *mut f64,
498
+ );
499
+ fn nk_each_fma_f32c(
500
+ a: *const f32,
501
+ b: *const f32,
502
+ c: *const f32,
503
+ n: usize,
504
+ alpha: *const f32,
505
+ beta: *const f32,
506
+ result: *mut f32,
507
+ );
508
+ fn nk_each_fma_f64c(
509
+ a: *const f64,
510
+ b: *const f64,
511
+ c: *const f64,
512
+ n: usize,
513
+ alpha: *const f64,
514
+ beta: *const f64,
515
+ result: *mut f64,
516
+ );
517
+ }
518
+
519
+ // Complex fallback helpers
520
+
521
+ fn complex_each_sum_fallback<Scalar>(
522
+ a: &[Scalar],
523
+ b: &[Scalar],
524
+ result: &mut [Scalar],
525
+ ) -> Option<()>
526
+ where
527
+ Scalar: Copy + core::ops::Add<Output = Scalar>,
528
+ {
529
+ if a.len() != b.len() || a.len() != result.len() {
530
+ return None;
531
+ }
532
+ for ((left, right), out) in a.iter().zip(b.iter()).zip(result.iter_mut()) {
533
+ *out = *left + *right;
534
+ }
535
+ Some(())
536
+ }
537
+
538
+ fn complex_each_scale_fallback<Scalar>(
539
+ a: &[Scalar],
540
+ alpha: Scalar,
541
+ beta: Scalar,
542
+ result: &mut [Scalar],
543
+ ) -> Option<()>
544
+ where
545
+ Scalar: Copy + core::ops::Add<Output = Scalar> + core::ops::Mul<Output = Scalar>,
546
+ {
547
+ if a.len() != result.len() {
548
+ return None;
549
+ }
550
+ for (value, out) in a.iter().zip(result.iter_mut()) {
551
+ *out = alpha * *value + beta;
552
+ }
553
+ Some(())
554
+ }
555
+
556
+ fn complex_each_blend_fallback<Scalar>(
557
+ a: &[Scalar],
558
+ b: &[Scalar],
559
+ alpha: Scalar,
560
+ beta: Scalar,
561
+ result: &mut [Scalar],
562
+ ) -> Option<()>
563
+ where
564
+ Scalar: Copy + core::ops::Add<Output = Scalar> + core::ops::Mul<Output = Scalar>,
565
+ {
566
+ if a.len() != b.len() || a.len() != result.len() {
567
+ return None;
568
+ }
569
+ for ((left, right), out) in a.iter().zip(b.iter()).zip(result.iter_mut()) {
570
+ *out = alpha * *left + beta * *right;
571
+ }
572
+ Some(())
573
+ }
574
+
575
+ fn complex_each_fma_fallback<Scalar>(
576
+ a: &[Scalar],
577
+ b: &[Scalar],
578
+ c: &[Scalar],
579
+ alpha: Scalar,
580
+ beta: Scalar,
581
+ result: &mut [Scalar],
582
+ ) -> Option<()>
583
+ where
584
+ Scalar: Copy + core::ops::Add<Output = Scalar> + core::ops::Mul<Output = Scalar>,
585
+ {
586
+ if a.len() != b.len() || a.len() != c.len() || a.len() != result.len() {
587
+ return None;
588
+ }
589
+ for (((left, right), third), out) in a.iter().zip(b.iter()).zip(c.iter()).zip(result.iter_mut())
590
+ {
591
+ *out = alpha * *left * *right + beta * *third;
592
+ }
593
+ Some(())
594
+ }
595
+
596
+ // region: EachSin
597
+
598
+ /// Computes **element-wise sine** of a vector.
599
+ pub trait EachSin: Sized + StorageElement {
600
+ fn sin(inputs: &[Self], outputs: &mut [Self]) -> Option<()>;
601
+ }
602
+
603
+ impl EachSin for f64 {
604
+ fn sin(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
605
+ if inputs.len() != outputs.len() {
606
+ return None;
607
+ }
608
+ unsafe { nk_each_sin_f64(inputs.as_ptr(), inputs.len(), outputs.as_mut_ptr()) };
609
+ Some(())
610
+ }
611
+ }
612
+
613
+ impl EachSin for f32 {
614
+ fn sin(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
615
+ if inputs.len() != outputs.len() {
616
+ return None;
617
+ }
618
+ unsafe { nk_each_sin_f32(inputs.as_ptr(), inputs.len(), outputs.as_mut_ptr()) };
619
+ Some(())
620
+ }
621
+ }
622
+
623
+ impl EachSin for f16 {
624
+ fn sin(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
625
+ if inputs.len() != outputs.len() {
626
+ return None;
627
+ }
628
+ unsafe {
629
+ nk_each_sin_f16(
630
+ inputs.as_ptr() as *const u16,
631
+ inputs.len(),
632
+ outputs.as_mut_ptr() as *mut u16,
633
+ )
634
+ };
635
+ Some(())
636
+ }
637
+ }
638
+
639
+ // endregion: EachSin
640
+
641
+ // region: EachCos
642
+
643
+ /// Computes **element-wise cosine** of a vector.
644
+ pub trait EachCos: Sized + StorageElement {
645
+ fn cos(inputs: &[Self], outputs: &mut [Self]) -> Option<()>;
646
+ }
647
+
648
+ impl EachCos for f64 {
649
+ fn cos(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
650
+ if inputs.len() != outputs.len() {
651
+ return None;
652
+ }
653
+ unsafe { nk_each_cos_f64(inputs.as_ptr(), inputs.len(), outputs.as_mut_ptr()) };
654
+ Some(())
655
+ }
656
+ }
657
+
658
+ impl EachCos for f32 {
659
+ fn cos(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
660
+ if inputs.len() != outputs.len() {
661
+ return None;
662
+ }
663
+ unsafe { nk_each_cos_f32(inputs.as_ptr(), inputs.len(), outputs.as_mut_ptr()) };
664
+ Some(())
665
+ }
666
+ }
667
+
668
+ impl EachCos for f16 {
669
+ fn cos(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
670
+ if inputs.len() != outputs.len() {
671
+ return None;
672
+ }
673
+ unsafe {
674
+ nk_each_cos_f16(
675
+ inputs.as_ptr() as *const u16,
676
+ inputs.len(),
677
+ outputs.as_mut_ptr() as *mut u16,
678
+ )
679
+ };
680
+ Some(())
681
+ }
682
+ }
683
+
684
+ // endregion: EachCos
685
+
686
+ // region: EachATan
687
+
688
+ /// Computes **element-wise arctangent** of a vector.
689
+ pub trait EachATan: Sized + StorageElement {
690
+ fn atan(inputs: &[Self], outputs: &mut [Self]) -> Option<()>;
691
+ }
692
+
693
+ impl EachATan for f64 {
694
+ fn atan(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
695
+ if inputs.len() != outputs.len() {
696
+ return None;
697
+ }
698
+ unsafe { nk_each_atan_f64(inputs.as_ptr(), inputs.len(), outputs.as_mut_ptr()) };
699
+ Some(())
700
+ }
701
+ }
702
+
703
+ impl EachATan for f32 {
704
+ fn atan(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
705
+ if inputs.len() != outputs.len() {
706
+ return None;
707
+ }
708
+ unsafe { nk_each_atan_f32(inputs.as_ptr(), inputs.len(), outputs.as_mut_ptr()) };
709
+ Some(())
710
+ }
711
+ }
712
+
713
+ impl EachATan for f16 {
714
+ fn atan(inputs: &[Self], outputs: &mut [Self]) -> Option<()> {
715
+ if inputs.len() != outputs.len() {
716
+ return None;
717
+ }
718
+ unsafe {
719
+ nk_each_atan_f16(
720
+ inputs.as_ptr() as *const u16,
721
+ inputs.len(),
722
+ outputs.as_mut_ptr() as *mut u16,
723
+ )
724
+ };
725
+ Some(())
726
+ }
727
+ }
728
+
729
+ // endregion: EachATan
730
+
731
+ // region: Scale
732
+
733
+ /// Applies an **element-wise affine transform** (scale and shift).
734
+ ///
735
+ /// rᵢ = α × aᵢ + β
736
+ ///
737
+ /// Returns `None` if `a` and `result` lengths differ.
738
+ ///
739
+ /// Implemented for: `f64`, `f32`, `f16`, `bf16`, `i8`, `u8`,
740
+ /// `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `e4m3`, `e5m2`, `e2m3`, `e3m2`.
741
+ pub trait EachScale: Sized + StorageElement {
742
+ type Scalar;
743
+
744
+ /// Writes `result[i] = alpha * a[i] + beta` into the pre-sized output slice.
745
+ ///
746
+ /// All three slices (`a`, `result`) must have identical length — the kernel
747
+ /// does not allocate. Returns `None` on length mismatch.
748
+ ///
749
+ /// # Examples
750
+ ///
751
+ /// ```
752
+ /// use numkong::EachScale;
753
+ /// let input = [1.0_f32, 2.0, 3.0];
754
+ /// let mut output = [0.0_f32; 3];
755
+ /// // Rescale to [-1, 1]: alpha = 2/(max-min) = 1.0, beta = -1 - 1*min = -2.0
756
+ /// f32::each_scale(&input, 1.0, -2.0, &mut output).unwrap();
757
+ /// assert_eq!(output, [-1.0, 0.0, 1.0]);
758
+ /// ```
759
+ fn each_scale(
760
+ a: &[Self],
761
+ alpha: Self::Scalar,
762
+ beta: Self::Scalar,
763
+ result: &mut [Self],
764
+ ) -> Option<()>;
765
+ }
766
+
767
+ impl EachScale for f64 {
768
+ type Scalar = f64;
769
+ fn each_scale(a: &[Self], alpha: f64, beta: f64, result: &mut [Self]) -> Option<()> {
770
+ if a.len() != result.len() {
771
+ return None;
772
+ }
773
+ unsafe { nk_each_scale_f64(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
774
+ Some(())
775
+ }
776
+ }
777
+
778
+ impl EachScale for f32 {
779
+ type Scalar = f32;
780
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
781
+ if a.len() != result.len() {
782
+ return None;
783
+ }
784
+ unsafe { nk_each_scale_f32(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
785
+ Some(())
786
+ }
787
+ }
788
+
789
+ impl EachScale for f16 {
790
+ type Scalar = f32;
791
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
792
+ if a.len() != result.len() {
793
+ return None;
794
+ }
795
+ unsafe {
796
+ nk_each_scale_f16(
797
+ a.as_ptr() as *const u16,
798
+ a.len(),
799
+ &alpha,
800
+ &beta,
801
+ result.as_mut_ptr() as *mut u16,
802
+ )
803
+ };
804
+ Some(())
805
+ }
806
+ }
807
+
808
+ impl EachScale for bf16 {
809
+ type Scalar = f32;
810
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
811
+ if a.len() != result.len() {
812
+ return None;
813
+ }
814
+ unsafe {
815
+ nk_each_scale_bf16(
816
+ a.as_ptr() as *const u16,
817
+ a.len(),
818
+ &alpha,
819
+ &beta,
820
+ result.as_mut_ptr() as *mut u16,
821
+ )
822
+ };
823
+ Some(())
824
+ }
825
+ }
826
+
827
+ impl EachScale for i8 {
828
+ type Scalar = f32;
829
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
830
+ if a.len() != result.len() {
831
+ return None;
832
+ }
833
+ unsafe { nk_each_scale_i8(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
834
+ Some(())
835
+ }
836
+ }
837
+
838
+ impl EachScale for u8 {
839
+ type Scalar = f32;
840
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
841
+ if a.len() != result.len() {
842
+ return None;
843
+ }
844
+ unsafe { nk_each_scale_u8(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
845
+ Some(())
846
+ }
847
+ }
848
+
849
+ impl EachScale for i16 {
850
+ type Scalar = f32;
851
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
852
+ if a.len() != result.len() {
853
+ return None;
854
+ }
855
+ unsafe { nk_each_scale_i16(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
856
+ Some(())
857
+ }
858
+ }
859
+
860
+ impl EachScale for u16 {
861
+ type Scalar = f32;
862
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
863
+ if a.len() != result.len() {
864
+ return None;
865
+ }
866
+ unsafe { nk_each_scale_u16(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
867
+ Some(())
868
+ }
869
+ }
870
+
871
+ impl EachScale for i32 {
872
+ type Scalar = f64;
873
+ fn each_scale(a: &[Self], alpha: f64, beta: f64, result: &mut [Self]) -> Option<()> {
874
+ if a.len() != result.len() {
875
+ return None;
876
+ }
877
+ unsafe { nk_each_scale_i32(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
878
+ Some(())
879
+ }
880
+ }
881
+
882
+ impl EachScale for u32 {
883
+ type Scalar = f64;
884
+ fn each_scale(a: &[Self], alpha: f64, beta: f64, result: &mut [Self]) -> Option<()> {
885
+ if a.len() != result.len() {
886
+ return None;
887
+ }
888
+ unsafe { nk_each_scale_u32(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
889
+ Some(())
890
+ }
891
+ }
892
+
893
+ impl EachScale for i64 {
894
+ type Scalar = f64;
895
+ fn each_scale(a: &[Self], alpha: f64, beta: f64, result: &mut [Self]) -> Option<()> {
896
+ if a.len() != result.len() {
897
+ return None;
898
+ }
899
+ unsafe { nk_each_scale_i64(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
900
+ Some(())
901
+ }
902
+ }
903
+
904
+ impl EachScale for u64 {
905
+ type Scalar = f64;
906
+ fn each_scale(a: &[Self], alpha: f64, beta: f64, result: &mut [Self]) -> Option<()> {
907
+ if a.len() != result.len() {
908
+ return None;
909
+ }
910
+ unsafe { nk_each_scale_u64(a.as_ptr(), a.len(), &alpha, &beta, result.as_mut_ptr()) };
911
+ Some(())
912
+ }
913
+ }
914
+
915
+ impl EachScale for e4m3 {
916
+ type Scalar = f32;
917
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
918
+ if a.len() != result.len() {
919
+ return None;
920
+ }
921
+ unsafe {
922
+ nk_each_scale_e4m3(
923
+ a.as_ptr() as *const u8,
924
+ a.len(),
925
+ &alpha,
926
+ &beta,
927
+ result.as_mut_ptr() as *mut u8,
928
+ )
929
+ };
930
+ Some(())
931
+ }
932
+ }
933
+
934
+ impl EachScale for e5m2 {
935
+ type Scalar = f32;
936
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
937
+ if a.len() != result.len() {
938
+ return None;
939
+ }
940
+ unsafe {
941
+ nk_each_scale_e5m2(
942
+ a.as_ptr() as *const u8,
943
+ a.len(),
944
+ &alpha,
945
+ &beta,
946
+ result.as_mut_ptr() as *mut u8,
947
+ )
948
+ };
949
+ Some(())
950
+ }
951
+ }
952
+
953
+ impl EachScale for e2m3 {
954
+ type Scalar = f32;
955
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
956
+ if a.len() != result.len() {
957
+ return None;
958
+ }
959
+ unsafe {
960
+ nk_each_scale_e2m3(
961
+ a.as_ptr() as *const u8,
962
+ a.len(),
963
+ &alpha,
964
+ &beta,
965
+ result.as_mut_ptr() as *mut u8,
966
+ )
967
+ };
968
+ Some(())
969
+ }
970
+ }
971
+
972
+ impl EachScale for e3m2 {
973
+ type Scalar = f32;
974
+ fn each_scale(a: &[Self], alpha: f32, beta: f32, result: &mut [Self]) -> Option<()> {
975
+ if a.len() != result.len() {
976
+ return None;
977
+ }
978
+ unsafe {
979
+ nk_each_scale_e3m2(
980
+ a.as_ptr() as *const u8,
981
+ a.len(),
982
+ &alpha,
983
+ &beta,
984
+ result.as_mut_ptr() as *mut u8,
985
+ )
986
+ };
987
+ Some(())
988
+ }
989
+ }
990
+
991
+ impl EachScale for f64c {
992
+ type Scalar = f64c;
993
+ fn each_scale(
994
+ a: &[Self],
995
+ alpha: Self::Scalar,
996
+ beta: Self::Scalar,
997
+ result: &mut [Self],
998
+ ) -> Option<()> {
999
+ if a.len() != result.len() {
1000
+ return None;
1001
+ }
1002
+ unsafe {
1003
+ nk_each_scale_f64c(
1004
+ a.as_ptr() as *const f64,
1005
+ a.len(),
1006
+ &alpha.re,
1007
+ &beta.re,
1008
+ result.as_mut_ptr() as *mut f64,
1009
+ )
1010
+ };
1011
+ Some(())
1012
+ }
1013
+ }
1014
+
1015
+ impl EachScale for f32c {
1016
+ type Scalar = f32c;
1017
+ fn each_scale(
1018
+ a: &[Self],
1019
+ alpha: Self::Scalar,
1020
+ beta: Self::Scalar,
1021
+ result: &mut [Self],
1022
+ ) -> Option<()> {
1023
+ if a.len() != result.len() {
1024
+ return None;
1025
+ }
1026
+ unsafe {
1027
+ nk_each_scale_f32c(
1028
+ a.as_ptr() as *const f32,
1029
+ a.len(),
1030
+ &alpha.re,
1031
+ &beta.re,
1032
+ result.as_mut_ptr() as *mut f32,
1033
+ )
1034
+ };
1035
+ Some(())
1036
+ }
1037
+ }
1038
+
1039
+ impl EachScale for f16c {
1040
+ type Scalar = f16c;
1041
+ fn each_scale(
1042
+ a: &[Self],
1043
+ alpha: Self::Scalar,
1044
+ beta: Self::Scalar,
1045
+ result: &mut [Self],
1046
+ ) -> Option<()> {
1047
+ complex_each_scale_fallback(a, alpha, beta, result)
1048
+ }
1049
+ }
1050
+
1051
+ impl EachScale for bf16c {
1052
+ type Scalar = bf16c;
1053
+ fn each_scale(
1054
+ a: &[Self],
1055
+ alpha: Self::Scalar,
1056
+ beta: Self::Scalar,
1057
+ result: &mut [Self],
1058
+ ) -> Option<()> {
1059
+ complex_each_scale_fallback(a, alpha, beta, result)
1060
+ }
1061
+ }
1062
+
1063
+ // endregion: Scale
1064
+
1065
+ // region: Sum
1066
+
1067
+ /// Applies **element-wise addition** of two vectors.
1068
+ ///
1069
+ /// rᵢ = aᵢ + bᵢ
1070
+ ///
1071
+ /// Returns `None` if lengths differ.
1072
+ ///
1073
+ /// Implemented for: `f64`, `f32`, `f16`, `bf16`, `i8`, `u8`,
1074
+ /// `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `e4m3`, `e5m2`, `e2m3`, `e3m2`.
1075
+ pub trait EachSum: Sized + StorageElement {
1076
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()>;
1077
+ }
1078
+
1079
+ impl EachSum for f64 {
1080
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1081
+ if a.len() != b.len() || a.len() != result.len() {
1082
+ return None;
1083
+ }
1084
+ unsafe { nk_each_sum_f64(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1085
+ Some(())
1086
+ }
1087
+ }
1088
+
1089
+ impl EachSum for f32 {
1090
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1091
+ if a.len() != b.len() || a.len() != result.len() {
1092
+ return None;
1093
+ }
1094
+ unsafe { nk_each_sum_f32(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1095
+ Some(())
1096
+ }
1097
+ }
1098
+
1099
+ impl EachSum for f16 {
1100
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1101
+ if a.len() != b.len() || a.len() != result.len() {
1102
+ return None;
1103
+ }
1104
+ unsafe {
1105
+ nk_each_sum_f16(
1106
+ a.as_ptr() as *const u16,
1107
+ b.as_ptr() as *const u16,
1108
+ a.len(),
1109
+ result.as_mut_ptr() as *mut u16,
1110
+ )
1111
+ };
1112
+ Some(())
1113
+ }
1114
+ }
1115
+
1116
+ impl EachSum for bf16 {
1117
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1118
+ if a.len() != b.len() || a.len() != result.len() {
1119
+ return None;
1120
+ }
1121
+ unsafe {
1122
+ nk_each_sum_bf16(
1123
+ a.as_ptr() as *const u16,
1124
+ b.as_ptr() as *const u16,
1125
+ a.len(),
1126
+ result.as_mut_ptr() as *mut u16,
1127
+ )
1128
+ };
1129
+ Some(())
1130
+ }
1131
+ }
1132
+
1133
+ impl EachSum for i8 {
1134
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1135
+ if a.len() != b.len() || a.len() != result.len() {
1136
+ return None;
1137
+ }
1138
+ unsafe { nk_each_sum_i8(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1139
+ Some(())
1140
+ }
1141
+ }
1142
+
1143
+ impl EachSum for u8 {
1144
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1145
+ if a.len() != b.len() || a.len() != result.len() {
1146
+ return None;
1147
+ }
1148
+ unsafe { nk_each_sum_u8(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1149
+ Some(())
1150
+ }
1151
+ }
1152
+
1153
+ impl EachSum for i16 {
1154
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1155
+ if a.len() != b.len() || a.len() != result.len() {
1156
+ return None;
1157
+ }
1158
+ unsafe { nk_each_sum_i16(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1159
+ Some(())
1160
+ }
1161
+ }
1162
+
1163
+ impl EachSum for u16 {
1164
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1165
+ if a.len() != b.len() || a.len() != result.len() {
1166
+ return None;
1167
+ }
1168
+ unsafe { nk_each_sum_u16(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1169
+ Some(())
1170
+ }
1171
+ }
1172
+
1173
+ impl EachSum for i32 {
1174
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1175
+ if a.len() != b.len() || a.len() != result.len() {
1176
+ return None;
1177
+ }
1178
+ unsafe { nk_each_sum_i32(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1179
+ Some(())
1180
+ }
1181
+ }
1182
+
1183
+ impl EachSum for u32 {
1184
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1185
+ if a.len() != b.len() || a.len() != result.len() {
1186
+ return None;
1187
+ }
1188
+ unsafe { nk_each_sum_u32(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1189
+ Some(())
1190
+ }
1191
+ }
1192
+
1193
+ impl EachSum for i64 {
1194
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1195
+ if a.len() != b.len() || a.len() != result.len() {
1196
+ return None;
1197
+ }
1198
+ unsafe { nk_each_sum_i64(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1199
+ Some(())
1200
+ }
1201
+ }
1202
+
1203
+ impl EachSum for u64 {
1204
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1205
+ if a.len() != b.len() || a.len() != result.len() {
1206
+ return None;
1207
+ }
1208
+ unsafe { nk_each_sum_u64(a.as_ptr(), b.as_ptr(), a.len(), result.as_mut_ptr()) };
1209
+ Some(())
1210
+ }
1211
+ }
1212
+
1213
+ impl EachSum for e4m3 {
1214
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1215
+ if a.len() != b.len() || a.len() != result.len() {
1216
+ return None;
1217
+ }
1218
+ unsafe {
1219
+ nk_each_sum_e4m3(
1220
+ a.as_ptr() as *const u8,
1221
+ b.as_ptr() as *const u8,
1222
+ a.len(),
1223
+ result.as_mut_ptr() as *mut u8,
1224
+ )
1225
+ };
1226
+ Some(())
1227
+ }
1228
+ }
1229
+
1230
+ impl EachSum for e5m2 {
1231
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1232
+ if a.len() != b.len() || a.len() != result.len() {
1233
+ return None;
1234
+ }
1235
+ unsafe {
1236
+ nk_each_sum_e5m2(
1237
+ a.as_ptr() as *const u8,
1238
+ b.as_ptr() as *const u8,
1239
+ a.len(),
1240
+ result.as_mut_ptr() as *mut u8,
1241
+ )
1242
+ };
1243
+ Some(())
1244
+ }
1245
+ }
1246
+
1247
+ impl EachSum for e2m3 {
1248
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1249
+ if a.len() != b.len() || a.len() != result.len() {
1250
+ return None;
1251
+ }
1252
+ unsafe {
1253
+ nk_each_sum_e2m3(
1254
+ a.as_ptr() as *const u8,
1255
+ b.as_ptr() as *const u8,
1256
+ a.len(),
1257
+ result.as_mut_ptr() as *mut u8,
1258
+ )
1259
+ };
1260
+ Some(())
1261
+ }
1262
+ }
1263
+
1264
+ impl EachSum for e3m2 {
1265
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1266
+ if a.len() != b.len() || a.len() != result.len() {
1267
+ return None;
1268
+ }
1269
+ unsafe {
1270
+ nk_each_sum_e3m2(
1271
+ a.as_ptr() as *const u8,
1272
+ b.as_ptr() as *const u8,
1273
+ a.len(),
1274
+ result.as_mut_ptr() as *mut u8,
1275
+ )
1276
+ };
1277
+ Some(())
1278
+ }
1279
+ }
1280
+
1281
+ impl EachSum for f64c {
1282
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1283
+ if a.len() != b.len() || a.len() != result.len() {
1284
+ return None;
1285
+ }
1286
+ unsafe {
1287
+ nk_each_sum_f64c(
1288
+ a.as_ptr() as *const f64,
1289
+ b.as_ptr() as *const f64,
1290
+ a.len(),
1291
+ result.as_mut_ptr() as *mut f64,
1292
+ )
1293
+ };
1294
+ Some(())
1295
+ }
1296
+ }
1297
+
1298
+ impl EachSum for f32c {
1299
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1300
+ if a.len() != b.len() || a.len() != result.len() {
1301
+ return None;
1302
+ }
1303
+ unsafe {
1304
+ nk_each_sum_f32c(
1305
+ a.as_ptr() as *const f32,
1306
+ b.as_ptr() as *const f32,
1307
+ a.len(),
1308
+ result.as_mut_ptr() as *mut f32,
1309
+ )
1310
+ };
1311
+ Some(())
1312
+ }
1313
+ }
1314
+
1315
+ impl EachSum for f16c {
1316
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1317
+ complex_each_sum_fallback(a, b, result)
1318
+ }
1319
+ }
1320
+
1321
+ impl EachSum for bf16c {
1322
+ fn each_sum(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<()> {
1323
+ complex_each_sum_fallback(a, b, result)
1324
+ }
1325
+ }
1326
+
1327
+ // endregion: Sum
1328
+
1329
+ // region: WSum
1330
+
1331
+ /// Applies **element-wise weighted sum** (blend) of two vectors.
1332
+ ///
1333
+ /// rᵢ = α × aᵢ + β × bᵢ
1334
+ ///
1335
+ /// Returns `None` if lengths differ.
1336
+ ///
1337
+ /// Implemented for: `f64`, `f32`, `f16`, `bf16`, `i8`, `u8`,
1338
+ /// `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `e4m3`, `e5m2`, `e2m3`, `e3m2`.
1339
+ pub trait EachBlend: Sized + StorageElement {
1340
+ type Scalar;
1341
+ fn each_blend(
1342
+ a: &[Self],
1343
+ b: &[Self],
1344
+ alpha: Self::Scalar,
1345
+ beta: Self::Scalar,
1346
+ result: &mut [Self],
1347
+ ) -> Option<()>;
1348
+ }
1349
+
1350
+ impl EachBlend for f64 {
1351
+ type Scalar = f64;
1352
+ fn each_blend(
1353
+ a: &[Self],
1354
+ b: &[Self],
1355
+ alpha: f64,
1356
+ beta: f64,
1357
+ result: &mut [Self],
1358
+ ) -> Option<()> {
1359
+ if a.len() != b.len() || a.len() != result.len() {
1360
+ return None;
1361
+ }
1362
+ unsafe {
1363
+ nk_each_blend_f64(
1364
+ a.as_ptr(),
1365
+ b.as_ptr(),
1366
+ a.len(),
1367
+ &alpha,
1368
+ &beta,
1369
+ result.as_mut_ptr(),
1370
+ )
1371
+ };
1372
+ Some(())
1373
+ }
1374
+ }
1375
+
1376
+ impl EachBlend for f32 {
1377
+ type Scalar = f32;
1378
+ fn each_blend(
1379
+ a: &[Self],
1380
+ b: &[Self],
1381
+ alpha: f32,
1382
+ beta: f32,
1383
+ result: &mut [Self],
1384
+ ) -> Option<()> {
1385
+ if a.len() != b.len() || a.len() != result.len() {
1386
+ return None;
1387
+ }
1388
+ unsafe {
1389
+ nk_each_blend_f32(
1390
+ a.as_ptr(),
1391
+ b.as_ptr(),
1392
+ a.len(),
1393
+ &alpha,
1394
+ &beta,
1395
+ result.as_mut_ptr(),
1396
+ )
1397
+ };
1398
+ Some(())
1399
+ }
1400
+ }
1401
+
1402
+ impl EachBlend for f16 {
1403
+ type Scalar = f32;
1404
+ fn each_blend(
1405
+ a: &[Self],
1406
+ b: &[Self],
1407
+ alpha: f32,
1408
+ beta: f32,
1409
+ result: &mut [Self],
1410
+ ) -> Option<()> {
1411
+ if a.len() != b.len() || a.len() != result.len() {
1412
+ return None;
1413
+ }
1414
+ unsafe {
1415
+ nk_each_blend_f16(
1416
+ a.as_ptr() as *const u16,
1417
+ b.as_ptr() as *const u16,
1418
+ a.len(),
1419
+ &alpha,
1420
+ &beta,
1421
+ result.as_mut_ptr() as *mut u16,
1422
+ )
1423
+ };
1424
+ Some(())
1425
+ }
1426
+ }
1427
+
1428
+ impl EachBlend for bf16 {
1429
+ type Scalar = f32;
1430
+ fn each_blend(
1431
+ a: &[Self],
1432
+ b: &[Self],
1433
+ alpha: f32,
1434
+ beta: f32,
1435
+ result: &mut [Self],
1436
+ ) -> Option<()> {
1437
+ if a.len() != b.len() || a.len() != result.len() {
1438
+ return None;
1439
+ }
1440
+ unsafe {
1441
+ nk_each_blend_bf16(
1442
+ a.as_ptr() as *const u16,
1443
+ b.as_ptr() as *const u16,
1444
+ a.len(),
1445
+ &alpha,
1446
+ &beta,
1447
+ result.as_mut_ptr() as *mut u16,
1448
+ )
1449
+ };
1450
+ Some(())
1451
+ }
1452
+ }
1453
+
1454
+ impl EachBlend for i8 {
1455
+ type Scalar = f32;
1456
+ fn each_blend(
1457
+ a: &[Self],
1458
+ b: &[Self],
1459
+ alpha: f32,
1460
+ beta: f32,
1461
+ result: &mut [Self],
1462
+ ) -> Option<()> {
1463
+ if a.len() != b.len() || a.len() != result.len() {
1464
+ return None;
1465
+ }
1466
+ unsafe {
1467
+ nk_each_blend_i8(
1468
+ a.as_ptr(),
1469
+ b.as_ptr(),
1470
+ a.len(),
1471
+ &alpha,
1472
+ &beta,
1473
+ result.as_mut_ptr(),
1474
+ )
1475
+ };
1476
+ Some(())
1477
+ }
1478
+ }
1479
+
1480
+ impl EachBlend for u8 {
1481
+ type Scalar = f32;
1482
+ fn each_blend(
1483
+ a: &[Self],
1484
+ b: &[Self],
1485
+ alpha: f32,
1486
+ beta: f32,
1487
+ result: &mut [Self],
1488
+ ) -> Option<()> {
1489
+ if a.len() != b.len() || a.len() != result.len() {
1490
+ return None;
1491
+ }
1492
+ unsafe {
1493
+ nk_each_blend_u8(
1494
+ a.as_ptr(),
1495
+ b.as_ptr(),
1496
+ a.len(),
1497
+ &alpha,
1498
+ &beta,
1499
+ result.as_mut_ptr(),
1500
+ )
1501
+ };
1502
+ Some(())
1503
+ }
1504
+ }
1505
+
1506
+ impl EachBlend for i16 {
1507
+ type Scalar = f32;
1508
+ fn each_blend(
1509
+ a: &[Self],
1510
+ b: &[Self],
1511
+ alpha: f32,
1512
+ beta: f32,
1513
+ result: &mut [Self],
1514
+ ) -> Option<()> {
1515
+ if a.len() != b.len() || a.len() != result.len() {
1516
+ return None;
1517
+ }
1518
+ unsafe {
1519
+ nk_each_blend_i16(
1520
+ a.as_ptr(),
1521
+ b.as_ptr(),
1522
+ a.len(),
1523
+ &alpha,
1524
+ &beta,
1525
+ result.as_mut_ptr(),
1526
+ )
1527
+ };
1528
+ Some(())
1529
+ }
1530
+ }
1531
+
1532
+ impl EachBlend for u16 {
1533
+ type Scalar = f32;
1534
+ fn each_blend(
1535
+ a: &[Self],
1536
+ b: &[Self],
1537
+ alpha: f32,
1538
+ beta: f32,
1539
+ result: &mut [Self],
1540
+ ) -> Option<()> {
1541
+ if a.len() != b.len() || a.len() != result.len() {
1542
+ return None;
1543
+ }
1544
+ unsafe {
1545
+ nk_each_blend_u16(
1546
+ a.as_ptr(),
1547
+ b.as_ptr(),
1548
+ a.len(),
1549
+ &alpha,
1550
+ &beta,
1551
+ result.as_mut_ptr(),
1552
+ )
1553
+ };
1554
+ Some(())
1555
+ }
1556
+ }
1557
+
1558
+ impl EachBlend for i32 {
1559
+ type Scalar = f64;
1560
+ fn each_blend(
1561
+ a: &[Self],
1562
+ b: &[Self],
1563
+ alpha: f64,
1564
+ beta: f64,
1565
+ result: &mut [Self],
1566
+ ) -> Option<()> {
1567
+ if a.len() != b.len() || a.len() != result.len() {
1568
+ return None;
1569
+ }
1570
+ unsafe {
1571
+ nk_each_blend_i32(
1572
+ a.as_ptr(),
1573
+ b.as_ptr(),
1574
+ a.len(),
1575
+ &alpha,
1576
+ &beta,
1577
+ result.as_mut_ptr(),
1578
+ )
1579
+ };
1580
+ Some(())
1581
+ }
1582
+ }
1583
+
1584
+ impl EachBlend for u32 {
1585
+ type Scalar = f64;
1586
+ fn each_blend(
1587
+ a: &[Self],
1588
+ b: &[Self],
1589
+ alpha: f64,
1590
+ beta: f64,
1591
+ result: &mut [Self],
1592
+ ) -> Option<()> {
1593
+ if a.len() != b.len() || a.len() != result.len() {
1594
+ return None;
1595
+ }
1596
+ unsafe {
1597
+ nk_each_blend_u32(
1598
+ a.as_ptr(),
1599
+ b.as_ptr(),
1600
+ a.len(),
1601
+ &alpha,
1602
+ &beta,
1603
+ result.as_mut_ptr(),
1604
+ )
1605
+ };
1606
+ Some(())
1607
+ }
1608
+ }
1609
+
1610
+ impl EachBlend for i64 {
1611
+ type Scalar = f64;
1612
+ fn each_blend(
1613
+ a: &[Self],
1614
+ b: &[Self],
1615
+ alpha: f64,
1616
+ beta: f64,
1617
+ result: &mut [Self],
1618
+ ) -> Option<()> {
1619
+ if a.len() != b.len() || a.len() != result.len() {
1620
+ return None;
1621
+ }
1622
+ unsafe {
1623
+ nk_each_blend_i64(
1624
+ a.as_ptr(),
1625
+ b.as_ptr(),
1626
+ a.len(),
1627
+ &alpha,
1628
+ &beta,
1629
+ result.as_mut_ptr(),
1630
+ )
1631
+ };
1632
+ Some(())
1633
+ }
1634
+ }
1635
+
1636
+ impl EachBlend for u64 {
1637
+ type Scalar = f64;
1638
+ fn each_blend(
1639
+ a: &[Self],
1640
+ b: &[Self],
1641
+ alpha: f64,
1642
+ beta: f64,
1643
+ result: &mut [Self],
1644
+ ) -> Option<()> {
1645
+ if a.len() != b.len() || a.len() != result.len() {
1646
+ return None;
1647
+ }
1648
+ unsafe {
1649
+ nk_each_blend_u64(
1650
+ a.as_ptr(),
1651
+ b.as_ptr(),
1652
+ a.len(),
1653
+ &alpha,
1654
+ &beta,
1655
+ result.as_mut_ptr(),
1656
+ )
1657
+ };
1658
+ Some(())
1659
+ }
1660
+ }
1661
+
1662
+ impl EachBlend for e4m3 {
1663
+ type Scalar = f32;
1664
+ fn each_blend(
1665
+ a: &[Self],
1666
+ b: &[Self],
1667
+ alpha: f32,
1668
+ beta: f32,
1669
+ result: &mut [Self],
1670
+ ) -> Option<()> {
1671
+ if a.len() != b.len() || a.len() != result.len() {
1672
+ return None;
1673
+ }
1674
+ unsafe {
1675
+ nk_each_blend_e4m3(
1676
+ a.as_ptr() as *const u8,
1677
+ b.as_ptr() as *const u8,
1678
+ a.len(),
1679
+ &alpha,
1680
+ &beta,
1681
+ result.as_mut_ptr() as *mut u8,
1682
+ )
1683
+ };
1684
+ Some(())
1685
+ }
1686
+ }
1687
+
1688
+ impl EachBlend for e5m2 {
1689
+ type Scalar = f32;
1690
+ fn each_blend(
1691
+ a: &[Self],
1692
+ b: &[Self],
1693
+ alpha: f32,
1694
+ beta: f32,
1695
+ result: &mut [Self],
1696
+ ) -> Option<()> {
1697
+ if a.len() != b.len() || a.len() != result.len() {
1698
+ return None;
1699
+ }
1700
+ unsafe {
1701
+ nk_each_blend_e5m2(
1702
+ a.as_ptr() as *const u8,
1703
+ b.as_ptr() as *const u8,
1704
+ a.len(),
1705
+ &alpha,
1706
+ &beta,
1707
+ result.as_mut_ptr() as *mut u8,
1708
+ )
1709
+ };
1710
+ Some(())
1711
+ }
1712
+ }
1713
+
1714
+ impl EachBlend for e2m3 {
1715
+ type Scalar = f32;
1716
+ fn each_blend(
1717
+ a: &[Self],
1718
+ b: &[Self],
1719
+ alpha: f32,
1720
+ beta: f32,
1721
+ result: &mut [Self],
1722
+ ) -> Option<()> {
1723
+ if a.len() != b.len() || a.len() != result.len() {
1724
+ return None;
1725
+ }
1726
+ unsafe {
1727
+ nk_each_blend_e2m3(
1728
+ a.as_ptr() as *const u8,
1729
+ b.as_ptr() as *const u8,
1730
+ a.len(),
1731
+ &alpha,
1732
+ &beta,
1733
+ result.as_mut_ptr() as *mut u8,
1734
+ )
1735
+ };
1736
+ Some(())
1737
+ }
1738
+ }
1739
+
1740
+ impl EachBlend for e3m2 {
1741
+ type Scalar = f32;
1742
+ fn each_blend(
1743
+ a: &[Self],
1744
+ b: &[Self],
1745
+ alpha: f32,
1746
+ beta: f32,
1747
+ result: &mut [Self],
1748
+ ) -> Option<()> {
1749
+ if a.len() != b.len() || a.len() != result.len() {
1750
+ return None;
1751
+ }
1752
+ unsafe {
1753
+ nk_each_blend_e3m2(
1754
+ a.as_ptr() as *const u8,
1755
+ b.as_ptr() as *const u8,
1756
+ a.len(),
1757
+ &alpha,
1758
+ &beta,
1759
+ result.as_mut_ptr() as *mut u8,
1760
+ )
1761
+ };
1762
+ Some(())
1763
+ }
1764
+ }
1765
+
1766
+ impl EachBlend for f64c {
1767
+ type Scalar = f64c;
1768
+ fn each_blend(
1769
+ a: &[Self],
1770
+ b: &[Self],
1771
+ alpha: Self::Scalar,
1772
+ beta: Self::Scalar,
1773
+ result: &mut [Self],
1774
+ ) -> Option<()> {
1775
+ if a.len() != b.len() || a.len() != result.len() {
1776
+ return None;
1777
+ }
1778
+ unsafe {
1779
+ nk_each_blend_f64c(
1780
+ a.as_ptr() as *const f64,
1781
+ b.as_ptr() as *const f64,
1782
+ a.len(),
1783
+ &alpha.re,
1784
+ &beta.re,
1785
+ result.as_mut_ptr() as *mut f64,
1786
+ )
1787
+ };
1788
+ Some(())
1789
+ }
1790
+ }
1791
+
1792
+ impl EachBlend for f32c {
1793
+ type Scalar = f32c;
1794
+ fn each_blend(
1795
+ a: &[Self],
1796
+ b: &[Self],
1797
+ alpha: Self::Scalar,
1798
+ beta: Self::Scalar,
1799
+ result: &mut [Self],
1800
+ ) -> Option<()> {
1801
+ if a.len() != b.len() || a.len() != result.len() {
1802
+ return None;
1803
+ }
1804
+ unsafe {
1805
+ nk_each_blend_f32c(
1806
+ a.as_ptr() as *const f32,
1807
+ b.as_ptr() as *const f32,
1808
+ a.len(),
1809
+ &alpha.re,
1810
+ &beta.re,
1811
+ result.as_mut_ptr() as *mut f32,
1812
+ )
1813
+ };
1814
+ Some(())
1815
+ }
1816
+ }
1817
+
1818
+ impl EachBlend for f16c {
1819
+ type Scalar = f16c;
1820
+ fn each_blend(
1821
+ a: &[Self],
1822
+ b: &[Self],
1823
+ alpha: Self::Scalar,
1824
+ beta: Self::Scalar,
1825
+ result: &mut [Self],
1826
+ ) -> Option<()> {
1827
+ complex_each_blend_fallback(a, b, alpha, beta, result)
1828
+ }
1829
+ }
1830
+
1831
+ impl EachBlend for bf16c {
1832
+ type Scalar = bf16c;
1833
+ fn each_blend(
1834
+ a: &[Self],
1835
+ b: &[Self],
1836
+ alpha: Self::Scalar,
1837
+ beta: Self::Scalar,
1838
+ result: &mut [Self],
1839
+ ) -> Option<()> {
1840
+ complex_each_blend_fallback(a, b, alpha, beta, result)
1841
+ }
1842
+ }
1843
+
1844
+ // endregion: WSum
1845
+
1846
+ // region: FMA
1847
+
1848
+ /// Applies **fused multiply-add** element-wise across three vectors.
1849
+ ///
1850
+ /// rᵢ = α × aᵢ × bᵢ + β × cᵢ
1851
+ ///
1852
+ /// Returns `None` if lengths differ.
1853
+ ///
1854
+ /// Implemented for: `f64`, `f32`, `f16`, `bf16`, `i8`, `u8`,
1855
+ /// `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `e4m3`, `e5m2`, `e2m3`, `e3m2`.
1856
+ pub trait EachFMA: Sized + StorageElement {
1857
+ type Scalar;
1858
+ fn each_fma(
1859
+ a: &[Self],
1860
+ b: &[Self],
1861
+ c: &[Self],
1862
+ alpha: Self::Scalar,
1863
+ beta: Self::Scalar,
1864
+ result: &mut [Self],
1865
+ ) -> Option<()>;
1866
+ }
1867
+
1868
+ impl EachFMA for f64 {
1869
+ type Scalar = f64;
1870
+ fn each_fma(
1871
+ a: &[Self],
1872
+ b: &[Self],
1873
+ c: &[Self],
1874
+ alpha: f64,
1875
+ beta: f64,
1876
+ result: &mut [Self],
1877
+ ) -> Option<()> {
1878
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
1879
+ return None;
1880
+ }
1881
+ unsafe {
1882
+ nk_each_fma_f64(
1883
+ a.as_ptr(),
1884
+ b.as_ptr(),
1885
+ c.as_ptr(),
1886
+ a.len(),
1887
+ &alpha,
1888
+ &beta,
1889
+ result.as_mut_ptr(),
1890
+ )
1891
+ };
1892
+ Some(())
1893
+ }
1894
+ }
1895
+
1896
+ impl EachFMA for f32 {
1897
+ type Scalar = f32;
1898
+ fn each_fma(
1899
+ a: &[Self],
1900
+ b: &[Self],
1901
+ c: &[Self],
1902
+ alpha: f32,
1903
+ beta: f32,
1904
+ result: &mut [Self],
1905
+ ) -> Option<()> {
1906
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
1907
+ return None;
1908
+ }
1909
+ unsafe {
1910
+ nk_each_fma_f32(
1911
+ a.as_ptr(),
1912
+ b.as_ptr(),
1913
+ c.as_ptr(),
1914
+ a.len(),
1915
+ &alpha,
1916
+ &beta,
1917
+ result.as_mut_ptr(),
1918
+ )
1919
+ };
1920
+ Some(())
1921
+ }
1922
+ }
1923
+
1924
+ impl EachFMA for f16 {
1925
+ type Scalar = f32;
1926
+ fn each_fma(
1927
+ a: &[Self],
1928
+ b: &[Self],
1929
+ c: &[Self],
1930
+ alpha: f32,
1931
+ beta: f32,
1932
+ result: &mut [Self],
1933
+ ) -> Option<()> {
1934
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
1935
+ return None;
1936
+ }
1937
+ unsafe {
1938
+ nk_each_fma_f16(
1939
+ a.as_ptr() as *const u16,
1940
+ b.as_ptr() as *const u16,
1941
+ c.as_ptr() as *const u16,
1942
+ a.len(),
1943
+ &alpha,
1944
+ &beta,
1945
+ result.as_mut_ptr() as *mut u16,
1946
+ )
1947
+ };
1948
+ Some(())
1949
+ }
1950
+ }
1951
+
1952
+ impl EachFMA for bf16 {
1953
+ type Scalar = f32;
1954
+ fn each_fma(
1955
+ a: &[Self],
1956
+ b: &[Self],
1957
+ c: &[Self],
1958
+ alpha: f32,
1959
+ beta: f32,
1960
+ result: &mut [Self],
1961
+ ) -> Option<()> {
1962
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
1963
+ return None;
1964
+ }
1965
+ unsafe {
1966
+ nk_each_fma_bf16(
1967
+ a.as_ptr() as *const u16,
1968
+ b.as_ptr() as *const u16,
1969
+ c.as_ptr() as *const u16,
1970
+ a.len(),
1971
+ &alpha,
1972
+ &beta,
1973
+ result.as_mut_ptr() as *mut u16,
1974
+ )
1975
+ };
1976
+ Some(())
1977
+ }
1978
+ }
1979
+
1980
+ impl EachFMA for i8 {
1981
+ type Scalar = f32;
1982
+ fn each_fma(
1983
+ a: &[Self],
1984
+ b: &[Self],
1985
+ c: &[Self],
1986
+ alpha: f32,
1987
+ beta: f32,
1988
+ result: &mut [Self],
1989
+ ) -> Option<()> {
1990
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
1991
+ return None;
1992
+ }
1993
+ unsafe {
1994
+ nk_each_fma_i8(
1995
+ a.as_ptr(),
1996
+ b.as_ptr(),
1997
+ c.as_ptr(),
1998
+ a.len(),
1999
+ &alpha,
2000
+ &beta,
2001
+ result.as_mut_ptr(),
2002
+ )
2003
+ };
2004
+ Some(())
2005
+ }
2006
+ }
2007
+
2008
+ impl EachFMA for u8 {
2009
+ type Scalar = f32;
2010
+ fn each_fma(
2011
+ a: &[Self],
2012
+ b: &[Self],
2013
+ c: &[Self],
2014
+ alpha: f32,
2015
+ beta: f32,
2016
+ result: &mut [Self],
2017
+ ) -> Option<()> {
2018
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2019
+ return None;
2020
+ }
2021
+ unsafe {
2022
+ nk_each_fma_u8(
2023
+ a.as_ptr(),
2024
+ b.as_ptr(),
2025
+ c.as_ptr(),
2026
+ a.len(),
2027
+ &alpha,
2028
+ &beta,
2029
+ result.as_mut_ptr(),
2030
+ )
2031
+ };
2032
+ Some(())
2033
+ }
2034
+ }
2035
+
2036
+ impl EachFMA for e4m3 {
2037
+ type Scalar = f32;
2038
+ fn each_fma(
2039
+ a: &[Self],
2040
+ b: &[Self],
2041
+ c: &[Self],
2042
+ alpha: f32,
2043
+ beta: f32,
2044
+ result: &mut [Self],
2045
+ ) -> Option<()> {
2046
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2047
+ return None;
2048
+ }
2049
+ unsafe {
2050
+ nk_each_fma_e4m3(
2051
+ a.as_ptr() as *const u8,
2052
+ b.as_ptr() as *const u8,
2053
+ c.as_ptr() as *const u8,
2054
+ a.len(),
2055
+ &alpha,
2056
+ &beta,
2057
+ result.as_mut_ptr() as *mut u8,
2058
+ )
2059
+ };
2060
+ Some(())
2061
+ }
2062
+ }
2063
+
2064
+ impl EachFMA for e5m2 {
2065
+ type Scalar = f32;
2066
+ fn each_fma(
2067
+ a: &[Self],
2068
+ b: &[Self],
2069
+ c: &[Self],
2070
+ alpha: f32,
2071
+ beta: f32,
2072
+ result: &mut [Self],
2073
+ ) -> Option<()> {
2074
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2075
+ return None;
2076
+ }
2077
+ unsafe {
2078
+ nk_each_fma_e5m2(
2079
+ a.as_ptr() as *const u8,
2080
+ b.as_ptr() as *const u8,
2081
+ c.as_ptr() as *const u8,
2082
+ a.len(),
2083
+ &alpha,
2084
+ &beta,
2085
+ result.as_mut_ptr() as *mut u8,
2086
+ )
2087
+ };
2088
+ Some(())
2089
+ }
2090
+ }
2091
+
2092
+ impl EachFMA for e2m3 {
2093
+ type Scalar = f32;
2094
+ fn each_fma(
2095
+ a: &[Self],
2096
+ b: &[Self],
2097
+ c: &[Self],
2098
+ alpha: f32,
2099
+ beta: f32,
2100
+ result: &mut [Self],
2101
+ ) -> Option<()> {
2102
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2103
+ return None;
2104
+ }
2105
+ unsafe {
2106
+ nk_each_fma_e2m3(
2107
+ a.as_ptr() as *const u8,
2108
+ b.as_ptr() as *const u8,
2109
+ c.as_ptr() as *const u8,
2110
+ a.len(),
2111
+ &alpha,
2112
+ &beta,
2113
+ result.as_mut_ptr() as *mut u8,
2114
+ )
2115
+ };
2116
+ Some(())
2117
+ }
2118
+ }
2119
+
2120
+ impl EachFMA for e3m2 {
2121
+ type Scalar = f32;
2122
+ fn each_fma(
2123
+ a: &[Self],
2124
+ b: &[Self],
2125
+ c: &[Self],
2126
+ alpha: f32,
2127
+ beta: f32,
2128
+ result: &mut [Self],
2129
+ ) -> Option<()> {
2130
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2131
+ return None;
2132
+ }
2133
+ unsafe {
2134
+ nk_each_fma_e3m2(
2135
+ a.as_ptr() as *const u8,
2136
+ b.as_ptr() as *const u8,
2137
+ c.as_ptr() as *const u8,
2138
+ a.len(),
2139
+ &alpha,
2140
+ &beta,
2141
+ result.as_mut_ptr() as *mut u8,
2142
+ )
2143
+ };
2144
+ Some(())
2145
+ }
2146
+ }
2147
+
2148
+ impl EachFMA for i16 {
2149
+ type Scalar = f32;
2150
+ fn each_fma(
2151
+ a: &[Self],
2152
+ b: &[Self],
2153
+ c: &[Self],
2154
+ alpha: f32,
2155
+ beta: f32,
2156
+ result: &mut [Self],
2157
+ ) -> Option<()> {
2158
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2159
+ return None;
2160
+ }
2161
+ unsafe {
2162
+ nk_each_fma_i16(
2163
+ a.as_ptr(),
2164
+ b.as_ptr(),
2165
+ c.as_ptr(),
2166
+ a.len(),
2167
+ &alpha,
2168
+ &beta,
2169
+ result.as_mut_ptr(),
2170
+ )
2171
+ };
2172
+ Some(())
2173
+ }
2174
+ }
2175
+
2176
+ impl EachFMA for u16 {
2177
+ type Scalar = f32;
2178
+ fn each_fma(
2179
+ a: &[Self],
2180
+ b: &[Self],
2181
+ c: &[Self],
2182
+ alpha: f32,
2183
+ beta: f32,
2184
+ result: &mut [Self],
2185
+ ) -> Option<()> {
2186
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2187
+ return None;
2188
+ }
2189
+ unsafe {
2190
+ nk_each_fma_u16(
2191
+ a.as_ptr(),
2192
+ b.as_ptr(),
2193
+ c.as_ptr(),
2194
+ a.len(),
2195
+ &alpha,
2196
+ &beta,
2197
+ result.as_mut_ptr(),
2198
+ )
2199
+ };
2200
+ Some(())
2201
+ }
2202
+ }
2203
+
2204
+ impl EachFMA for i32 {
2205
+ type Scalar = f64;
2206
+ fn each_fma(
2207
+ a: &[Self],
2208
+ b: &[Self],
2209
+ c: &[Self],
2210
+ alpha: f64,
2211
+ beta: f64,
2212
+ result: &mut [Self],
2213
+ ) -> Option<()> {
2214
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2215
+ return None;
2216
+ }
2217
+ unsafe {
2218
+ nk_each_fma_i32(
2219
+ a.as_ptr(),
2220
+ b.as_ptr(),
2221
+ c.as_ptr(),
2222
+ a.len(),
2223
+ &alpha,
2224
+ &beta,
2225
+ result.as_mut_ptr(),
2226
+ )
2227
+ };
2228
+ Some(())
2229
+ }
2230
+ }
2231
+
2232
+ impl EachFMA for u32 {
2233
+ type Scalar = f64;
2234
+ fn each_fma(
2235
+ a: &[Self],
2236
+ b: &[Self],
2237
+ c: &[Self],
2238
+ alpha: f64,
2239
+ beta: f64,
2240
+ result: &mut [Self],
2241
+ ) -> Option<()> {
2242
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2243
+ return None;
2244
+ }
2245
+ unsafe {
2246
+ nk_each_fma_u32(
2247
+ a.as_ptr(),
2248
+ b.as_ptr(),
2249
+ c.as_ptr(),
2250
+ a.len(),
2251
+ &alpha,
2252
+ &beta,
2253
+ result.as_mut_ptr(),
2254
+ )
2255
+ };
2256
+ Some(())
2257
+ }
2258
+ }
2259
+
2260
+ impl EachFMA for i64 {
2261
+ type Scalar = f64;
2262
+ fn each_fma(
2263
+ a: &[Self],
2264
+ b: &[Self],
2265
+ c: &[Self],
2266
+ alpha: f64,
2267
+ beta: f64,
2268
+ result: &mut [Self],
2269
+ ) -> Option<()> {
2270
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2271
+ return None;
2272
+ }
2273
+ unsafe {
2274
+ nk_each_fma_i64(
2275
+ a.as_ptr(),
2276
+ b.as_ptr(),
2277
+ c.as_ptr(),
2278
+ a.len(),
2279
+ &alpha,
2280
+ &beta,
2281
+ result.as_mut_ptr(),
2282
+ )
2283
+ };
2284
+ Some(())
2285
+ }
2286
+ }
2287
+
2288
+ impl EachFMA for u64 {
2289
+ type Scalar = f64;
2290
+ fn each_fma(
2291
+ a: &[Self],
2292
+ b: &[Self],
2293
+ c: &[Self],
2294
+ alpha: f64,
2295
+ beta: f64,
2296
+ result: &mut [Self],
2297
+ ) -> Option<()> {
2298
+ if a.len() != b.len() || b.len() != c.len() || a.len() != result.len() {
2299
+ return None;
2300
+ }
2301
+ unsafe {
2302
+ nk_each_fma_u64(
2303
+ a.as_ptr(),
2304
+ b.as_ptr(),
2305
+ c.as_ptr(),
2306
+ a.len(),
2307
+ &alpha,
2308
+ &beta,
2309
+ result.as_mut_ptr(),
2310
+ )
2311
+ };
2312
+ Some(())
2313
+ }
2314
+ }
2315
+
2316
+ impl EachFMA for f64c {
2317
+ type Scalar = f64c;
2318
+ fn each_fma(
2319
+ a: &[Self],
2320
+ b: &[Self],
2321
+ c: &[Self],
2322
+ alpha: Self::Scalar,
2323
+ beta: Self::Scalar,
2324
+ result: &mut [Self],
2325
+ ) -> Option<()> {
2326
+ if a.len() != b.len() || a.len() != c.len() || a.len() != result.len() {
2327
+ return None;
2328
+ }
2329
+ unsafe {
2330
+ nk_each_fma_f64c(
2331
+ a.as_ptr() as *const f64,
2332
+ b.as_ptr() as *const f64,
2333
+ c.as_ptr() as *const f64,
2334
+ a.len(),
2335
+ &alpha.re,
2336
+ &beta.re,
2337
+ result.as_mut_ptr() as *mut f64,
2338
+ )
2339
+ };
2340
+ Some(())
2341
+ }
2342
+ }
2343
+
2344
+ impl EachFMA for f32c {
2345
+ type Scalar = f32c;
2346
+ fn each_fma(
2347
+ a: &[Self],
2348
+ b: &[Self],
2349
+ c: &[Self],
2350
+ alpha: Self::Scalar,
2351
+ beta: Self::Scalar,
2352
+ result: &mut [Self],
2353
+ ) -> Option<()> {
2354
+ if a.len() != b.len() || a.len() != c.len() || a.len() != result.len() {
2355
+ return None;
2356
+ }
2357
+ unsafe {
2358
+ nk_each_fma_f32c(
2359
+ a.as_ptr() as *const f32,
2360
+ b.as_ptr() as *const f32,
2361
+ c.as_ptr() as *const f32,
2362
+ a.len(),
2363
+ &alpha.re,
2364
+ &beta.re,
2365
+ result.as_mut_ptr() as *mut f32,
2366
+ )
2367
+ };
2368
+ Some(())
2369
+ }
2370
+ }
2371
+
2372
+ impl EachFMA for f16c {
2373
+ type Scalar = f16c;
2374
+ fn each_fma(
2375
+ a: &[Self],
2376
+ b: &[Self],
2377
+ c: &[Self],
2378
+ alpha: Self::Scalar,
2379
+ beta: Self::Scalar,
2380
+ result: &mut [Self],
2381
+ ) -> Option<()> {
2382
+ complex_each_fma_fallback(a, b, c, alpha, beta, result)
2383
+ }
2384
+ }
2385
+
2386
+ impl EachFMA for bf16c {
2387
+ type Scalar = bf16c;
2388
+ fn each_fma(
2389
+ a: &[Self],
2390
+ b: &[Self],
2391
+ c: &[Self],
2392
+ alpha: Self::Scalar,
2393
+ beta: Self::Scalar,
2394
+ result: &mut [Self],
2395
+ ) -> Option<()> {
2396
+ complex_each_fma_fallback(a, b, c, alpha, beta, result)
2397
+ }
2398
+ }
2399
+
2400
+ // endregion: FMA
2401
+
2402
+ /// `Trigonometry` bundles trigonometric functions: EachSin, EachCos, and EachATan.
2403
+ pub trait Trigonometry: EachSin + EachCos + EachATan {}
2404
+ impl<Scalar: EachSin + EachCos + EachATan> Trigonometry for Scalar {}
2405
+
2406
+ #[cfg(test)]
2407
+ mod tests {
2408
+ use super::*;
2409
+ use crate::types::{
2410
+ assert_close, bf16, e2m3, e3m2, e4m3, e5m2, f16, FloatLike, NumberLike, TestableType,
2411
+ };
2412
+ /// Test a binary elementwise op: convert inputs, apply `op`, compare element-wise.
2413
+ pub(crate) fn check_each_binary<Scalar, F>(
2414
+ a_vals: &[f32],
2415
+ b_vals: &[f32],
2416
+ op: F,
2417
+ expected_fn: fn(f64, f64) -> f64,
2418
+ label: &str,
2419
+ ) where
2420
+ Scalar: FloatLike + TestableType,
2421
+ F: FnOnce(&[Scalar], &[Scalar], &mut [Scalar]) -> Option<()>,
2422
+ {
2423
+ let a: Vec<Scalar> = a_vals.iter().map(|&v| Scalar::from_f32(v)).collect();
2424
+ let b: Vec<Scalar> = b_vals.iter().map(|&v| Scalar::from_f32(v)).collect();
2425
+ let mut result = vec![Scalar::zero(); a.len()];
2426
+ op(&a, &b, &mut result).unwrap();
2427
+ for (i, &r) in result.iter().enumerate() {
2428
+ let expected = expected_fn(a_vals[i] as f64, b_vals[i] as f64);
2429
+ assert_close(
2430
+ r.to_f64(),
2431
+ expected,
2432
+ Scalar::atol(),
2433
+ Scalar::rtol(),
2434
+ &format!("{}<{}>[{i}]", label, core::any::type_name::<Scalar>()),
2435
+ );
2436
+ }
2437
+ }
2438
+
2439
+ /// Test a unary elementwise op over generated values.
2440
+ pub(crate) fn check_each_unary<Scalar, F>(
2441
+ count: usize,
2442
+ gen_fn: fn(usize, usize) -> f64,
2443
+ op: F,
2444
+ ref_fn: fn(f64) -> f64,
2445
+ label: &str,
2446
+ ) where
2447
+ Scalar: FloatLike + TestableType,
2448
+ F: FnOnce(&[Scalar], &mut [Scalar]) -> Option<()>,
2449
+ {
2450
+ let values: Vec<f64> = (0..count).map(|i| gen_fn(i, count)).collect();
2451
+ let a: Vec<Scalar> = values.iter().map(|&v| Scalar::from_f32(v as f32)).collect();
2452
+ let mut result = vec![Scalar::zero(); count];
2453
+ op(&a, &mut result).unwrap();
2454
+ for (i, r) in result.iter().enumerate() {
2455
+ let expected = ref_fn(values[i]);
2456
+ assert_close(
2457
+ r.to_f64(),
2458
+ expected,
2459
+ Scalar::atol() * 10000.0,
2460
+ Scalar::rtol() * 10000.0,
2461
+ &format!("{}<{}>[{}]", label, core::any::type_name::<Scalar>(), i),
2462
+ );
2463
+ }
2464
+ }
2465
+
2466
+ // region: Elementwise Operations
2467
+
2468
+ fn check_each_scale<Scalar>(values: &[f32], alpha: f32, beta: f32)
2469
+ where
2470
+ Scalar: FloatLike + TestableType + EachScale,
2471
+ <Scalar as EachScale>::Scalar: FloatLike,
2472
+ {
2473
+ let a: Vec<Scalar> = values.iter().map(|&v| Scalar::from_f32(v)).collect();
2474
+ let mut result = vec![Scalar::zero(); a.len()];
2475
+ let alpha_s = <<Scalar as EachScale>::Scalar>::from_f32(alpha);
2476
+ let beta_s = <<Scalar as EachScale>::Scalar>::from_f32(beta);
2477
+ Scalar::each_scale(&a, alpha_s, beta_s, &mut result).unwrap();
2478
+ for (i, r) in result.iter().enumerate() {
2479
+ let expected = alpha as f64 * values[i] as f64 + beta as f64;
2480
+ assert_close(
2481
+ r.to_f64(),
2482
+ expected,
2483
+ Scalar::atol(),
2484
+ Scalar::rtol(),
2485
+ &format!("each_scale<{}>[{i}]", core::any::type_name::<Scalar>()),
2486
+ );
2487
+ }
2488
+ }
2489
+
2490
+ fn check_each_sum<Scalar>(values_a: &[f32], values_b: &[f32])
2491
+ where
2492
+ Scalar: FloatLike + TestableType + EachSum,
2493
+ {
2494
+ check_each_binary::<Scalar, _>(
2495
+ values_a,
2496
+ values_b,
2497
+ Scalar::each_sum,
2498
+ |a, b| a + b,
2499
+ "each_sum",
2500
+ );
2501
+ }
2502
+
2503
+ fn check_each_blend<Scalar>(values_a: &[f32], values_b: &[f32], alpha: f32, beta: f32)
2504
+ where
2505
+ Scalar: FloatLike + TestableType + EachBlend,
2506
+ <Scalar as EachBlend>::Scalar: FloatLike,
2507
+ {
2508
+ let a: Vec<Scalar> = values_a.iter().map(|&v| Scalar::from_f32(v)).collect();
2509
+ let b: Vec<Scalar> = values_b.iter().map(|&v| Scalar::from_f32(v)).collect();
2510
+ let mut result = vec![Scalar::zero(); a.len()];
2511
+ let alpha_s = <<Scalar as EachBlend>::Scalar>::from_f32(alpha);
2512
+ let beta_s = <<Scalar as EachBlend>::Scalar>::from_f32(beta);
2513
+ Scalar::each_blend(&a, &b, alpha_s, beta_s, &mut result).unwrap();
2514
+ for (i, r) in result.iter().enumerate() {
2515
+ let expected = alpha as f64 * values_a[i] as f64 + beta as f64 * values_b[i] as f64;
2516
+ assert_close(
2517
+ r.to_f64(),
2518
+ expected,
2519
+ Scalar::atol(),
2520
+ Scalar::rtol(),
2521
+ &format!("each_blend<{}>[{i}]", core::any::type_name::<Scalar>()),
2522
+ );
2523
+ }
2524
+ }
2525
+
2526
+ fn check_each_fma<Scalar>(
2527
+ values_a: &[f32],
2528
+ values_b: &[f32],
2529
+ values_c: &[f32],
2530
+ alpha: f32,
2531
+ beta: f32,
2532
+ ) where
2533
+ Scalar: FloatLike + TestableType + EachFMA,
2534
+ <Scalar as EachFMA>::Scalar: FloatLike,
2535
+ {
2536
+ let a: Vec<Scalar> = values_a.iter().map(|&v| Scalar::from_f32(v)).collect();
2537
+ let b: Vec<Scalar> = values_b.iter().map(|&v| Scalar::from_f32(v)).collect();
2538
+ let c: Vec<Scalar> = values_c.iter().map(|&v| Scalar::from_f32(v)).collect();
2539
+ let mut result = vec![Scalar::zero(); a.len()];
2540
+ let alpha_s = <<Scalar as EachFMA>::Scalar>::from_f32(alpha);
2541
+ let beta_s = <<Scalar as EachFMA>::Scalar>::from_f32(beta);
2542
+ Scalar::each_fma(&a, &b, &c, alpha_s, beta_s, &mut result).unwrap();
2543
+ for (i, r) in result.iter().enumerate() {
2544
+ let expected = alpha as f64 * values_a[i] as f64 * values_b[i] as f64
2545
+ + beta as f64 * values_c[i] as f64;
2546
+ assert_close(
2547
+ r.to_f64(),
2548
+ expected,
2549
+ Scalar::atol(),
2550
+ Scalar::rtol(),
2551
+ &format!("each_fma<{}>[{i}]", core::any::type_name::<Scalar>()),
2552
+ );
2553
+ }
2554
+ }
2555
+
2556
+ #[test]
2557
+ fn scale_elementwise() {
2558
+ check_each_scale::<f32>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2559
+ check_each_scale::<f64>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2560
+ check_each_scale::<f16>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2561
+ check_each_scale::<bf16>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2562
+ check_each_scale::<e2m3>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2563
+ check_each_scale::<e4m3>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2564
+ check_each_scale::<e5m2>(&[1.0, 2.0], 2.0, 0.0);
2565
+ check_each_scale::<e3m2>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2566
+ check_each_scale::<i8>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2567
+ check_each_scale::<u8>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2568
+ check_each_scale::<i32>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2569
+ check_each_scale::<u32>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2570
+ check_each_scale::<i16>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2571
+ check_each_scale::<u16>(&[1.0, 2.0, 3.0], 2.0, 0.0);
2572
+ check_each_scale::<i64>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2573
+ check_each_scale::<u64>(&[1.0, 2.0, 3.0, 4.0, 5.0], 2.0, 1.0);
2574
+ }
2575
+
2576
+ #[test]
2577
+ fn sum_elementwise() {
2578
+ check_each_sum::<f32>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2579
+ check_each_sum::<f64>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2580
+ check_each_sum::<f16>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2581
+ check_each_sum::<bf16>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2582
+ check_each_sum::<e2m3>(&[1.0, 2.0, 3.0], &[1.0, 1.0, 1.0]);
2583
+ check_each_sum::<e4m3>(&[1.0, 2.0, 3.0], &[1.0, 1.0, 1.0]);
2584
+ check_each_sum::<e5m2>(&[1.0, 2.0], &[1.0, 1.0]);
2585
+ check_each_sum::<e3m2>(&[1.0, 2.0, 3.0], &[1.0, 1.0, 1.0]);
2586
+ check_each_sum::<i8>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2587
+ check_each_sum::<u8>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2588
+ check_each_sum::<i32>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2589
+ check_each_sum::<u32>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2590
+ check_each_sum::<i16>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2591
+ check_each_sum::<u16>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2592
+ check_each_sum::<i64>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2593
+ check_each_sum::<u64>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]);
2594
+ }
2595
+
2596
+ #[test]
2597
+ fn sum_elementwise_length_mismatch() {
2598
+ let a: Vec<f32> = vec![1.0, 2.0, 3.0];
2599
+ let b: Vec<f32> = vec![4.0, 5.0];
2600
+ let mut result = vec![0.0f32; a.len()];
2601
+ assert!(f32::each_sum(&a, &b, &mut result).is_none());
2602
+ }
2603
+
2604
+ #[test]
2605
+ fn blend_elementwise() {
2606
+ check_each_blend::<f32>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0], 0.5, 0.5);
2607
+ check_each_blend::<f64>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0], 0.5, 0.5);
2608
+ check_each_blend::<f16>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0], 0.5, 0.5);
2609
+ check_each_blend::<bf16>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0], 0.5, 0.5);
2610
+ check_each_blend::<e2m3>(&[1.0, 2.0, 3.0], &[1.0, 1.0, 1.0], 0.5, 0.5);
2611
+ check_each_blend::<e4m3>(&[1.0, 2.0, 3.0], &[1.0, 1.0, 1.0], 0.5, 0.5);
2612
+ check_each_blend::<e5m2>(&[1.0, 2.0], &[1.0, 1.0], 0.5, 0.5);
2613
+ check_each_blend::<e3m2>(&[1.0, 2.0, 3.0], &[1.0, 1.0, 1.0], 0.5, 0.5);
2614
+ check_each_blend::<i8>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0], 0.5, 0.5);
2615
+ check_each_blend::<u8>(&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0], 0.5, 0.5);
2616
+ }
2617
+
2618
+ #[test]
2619
+ fn fma_elementwise() {
2620
+ let a = &[1.0, 2.0, 3.0];
2621
+ let b = &[2.0, 3.0, 4.0];
2622
+ let c = &[1.0, 1.0, 1.0];
2623
+ check_each_fma::<f32>(a, b, c, 1.0, 1.0);
2624
+ check_each_fma::<f64>(a, b, c, 1.0, 1.0);
2625
+ check_each_fma::<f16>(a, b, c, 1.0, 1.0);
2626
+ check_each_fma::<bf16>(a, b, c, 1.0, 1.0);
2627
+ // e2m3 max is 7.5, so use small inputs that stay in range: 1*1+1=2
2628
+ check_each_fma::<e2m3>(&[1.0, 1.0, 1.0], &[1.0, 1.0, 1.0], c, 1.0, 1.0);
2629
+ check_each_fma::<e4m3>(a, b, c, 1.0, 1.0);
2630
+ let a2 = &[1.0, 2.0];
2631
+ let b2 = &[2.0, 3.0];
2632
+ let c2 = &[1.0, 1.0];
2633
+ check_each_fma::<e5m2>(a2, b2, c2, 1.0, 1.0);
2634
+ check_each_fma::<e3m2>(a, b, c, 1.0, 1.0);
2635
+ check_each_fma::<i8>(a, b, c, 1.0, 1.0);
2636
+ check_each_fma::<u8>(a, b, c, 1.0, 1.0);
2637
+ check_each_fma::<i32>(a, b, c, 1.0, 1.0);
2638
+ check_each_fma::<u32>(a, b, c, 1.0, 1.0);
2639
+ check_each_fma::<i16>(a, b, c, 1.0, 1.0);
2640
+ check_each_fma::<u16>(a, b, c, 1.0, 1.0);
2641
+ check_each_fma::<i64>(a, b, c, 1.0, 1.0);
2642
+ check_each_fma::<u64>(a, b, c, 1.0, 1.0);
2643
+ }
2644
+
2645
+ #[test]
2646
+ fn large_elementwise() {
2647
+ let values: Vec<f32> = (0..1536).map(|i| i as f32).collect();
2648
+ check_each_scale::<f32>(&values, 2.0, 0.5);
2649
+
2650
+ let b: Vec<f32> = (0..1536).map(|i| (i as f32) * 2.0).collect();
2651
+ check_each_sum::<f32>(&values, &b);
2652
+ }
2653
+
2654
+ // endregion
2655
+
2656
+ // region: Trigonometry
2657
+
2658
+ fn check_each_sin<Scalar>(count: usize)
2659
+ where
2660
+ Scalar: FloatLike + TestableType + EachSin,
2661
+ {
2662
+ use core::f64::consts::PI;
2663
+ check_each_unary::<Scalar, _>(
2664
+ count,
2665
+ |i, n| (i as f64) * 2.0 * PI / (n as f64),
2666
+ Scalar::sin,
2667
+ f64::sin,
2668
+ "sin",
2669
+ );
2670
+ }
2671
+
2672
+ fn check_each_cos<Scalar>(count: usize)
2673
+ where
2674
+ Scalar: FloatLike + TestableType + EachCos,
2675
+ {
2676
+ use core::f64::consts::PI;
2677
+ check_each_unary::<Scalar, _>(
2678
+ count,
2679
+ |i, n| (i as f64) * 2.0 * PI / (n as f64),
2680
+ Scalar::cos,
2681
+ f64::cos,
2682
+ "cos",
2683
+ );
2684
+ }
2685
+
2686
+ fn check_each_atan<Scalar>(count: usize)
2687
+ where
2688
+ Scalar: FloatLike + TestableType + EachATan,
2689
+ {
2690
+ check_each_unary::<Scalar, _>(
2691
+ count,
2692
+ |i, n| -5.0 + 10.0 * (i as f64) / (n as f64),
2693
+ Scalar::atan,
2694
+ f64::atan,
2695
+ "atan",
2696
+ );
2697
+ }
2698
+
2699
+ #[test]
2700
+ fn sin_elementwise() {
2701
+ check_each_sin::<f32>(97);
2702
+ check_each_sin::<f64>(97);
2703
+ check_each_sin::<f16>(97);
2704
+ }
2705
+
2706
+ #[test]
2707
+ fn cos_elementwise() {
2708
+ check_each_cos::<f32>(97);
2709
+ check_each_cos::<f64>(97);
2710
+ check_each_cos::<f16>(97);
2711
+ }
2712
+
2713
+ #[test]
2714
+ fn atan_elementwise() {
2715
+ check_each_atan::<f32>(100);
2716
+ check_each_atan::<f64>(100);
2717
+ check_each_atan::<f16>(100);
2718
+ }
2719
+
2720
+ // endregion
2721
+ }