usearch 2.21.4 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,874 @@
1
+ /**
2
+ * @brief SWAR-accelerated Dot Products for SIMD-free CPUs.
3
+ * @file include/numkong/dot/serial.h
4
+ * @author Ash Vardanian
5
+ * @date December 27, 2025
6
+ *
7
+ * @sa include/numkong/dot.h
8
+ *
9
+ * @section dot_serial_instructions Serial Fallback Implementation
10
+ *
11
+ * The serial backend provides portable scalar implementations for all numeric types without requiring
12
+ * any SIMD extensions. While significantly slower than vectorized implementations, these serve as:
13
+ *
14
+ * - Reference implementations for correctness validation
15
+ * - Fallbacks for platforms without SIMD support (WASM, older CPUs)
16
+ * - Baseline for benchmarking vectorized speedups
17
+ *
18
+ * For f64 dot products, compensated (Kahan-style) summation is used to minimize floating-point
19
+ * accumulation errors. For smaller types (f16, bf16, FP8), values are upcast to f32 for accumulation.
20
+ *
21
+ * @section dot_serial_stateful Stateful Streaming Logic
22
+ *
23
+ * To build memory-optimal tiled algorithms, this file defines following structures and force-inlined
24
+ * `NK_INTERNAL` functions:
25
+ *
26
+ * - nk_dot_f64x2 state with compensated summation for numerical stability,
27
+ * - nk_dot_f32x4 state with simple f32 accumulation,
28
+ * - nk_dot_f16x8 state for f16 inputs via f32 upcasting,
29
+ * - nk_dot_bf16x8 state for bf16 inputs via f32 upcasting,
30
+ * - nk_dot_i8x16 for 8-bit signed integer inputs,
31
+ * - nk_dot_u8x16 for 8-bit unsigned integer inputs,
32
+ * - nk_dot_e4m3x16, nk_dot_e5m2x16, nk_dot_e2m3x16, nk_dot_e3m2x16 for FP8/FP6 inputs,
33
+ * - nk_dot_i4x16, nk_dot_u4x16 for 4-bit integer inputs.
34
+ *
35
+ * @code{c}
36
+ * nk_dot_f64x2_state_serial_t state_first, state_second, state_third, state_fourth;
37
+ * nk_b128_vec_t query_f64x2, target_first_f64x2, target_second_f64x2, target_third_f64x2, target_fourth_f64x2;
38
+ * nk_dot_f64x2_init_serial(&state_first);
39
+ * nk_dot_f64x2_init_serial(&state_second);
40
+ * nk_dot_f64x2_init_serial(&state_third);
41
+ * nk_dot_f64x2_init_serial(&state_fourth);
42
+ * for (nk_size_t idx = 0; idx + 2 <= depth; idx += 2) {
43
+ * query_f64x2.f64s[0] = query_ptr[idx], query_f64x2.f64s[1] = query_ptr[idx + 1];
44
+ * target_first_f64x2.f64s[0] = target_first_ptr[idx], target_first_f64x2.f64s[1] = target_first_ptr[idx + 1];
45
+ * target_second_f64x2.f64s[0] = target_second_ptr[idx], target_second_f64x2.f64s[1] = target_second_ptr[idx + 1];
46
+ * target_third_f64x2.f64s[0] = target_third_ptr[idx], target_third_f64x2.f64s[1] = target_third_ptr[idx + 1];
47
+ * target_fourth_f64x2.f64s[0] = target_fourth_ptr[idx], target_fourth_f64x2.f64s[1] = target_fourth_ptr[idx + 1];
48
+ * nk_dot_f64x2_update_serial(&state_first, query_f64x2, target_first_f64x2, idx, 2);
49
+ * nk_dot_f64x2_update_serial(&state_second, query_f64x2, target_second_f64x2, idx, 2);
50
+ * nk_dot_f64x2_update_serial(&state_third, query_f64x2, target_third_f64x2, idx, 2);
51
+ * nk_dot_f64x2_update_serial(&state_fourth, query_f64x2, target_fourth_f64x2, idx, 2);
52
+ * }
53
+ * nk_b256_vec_t results_f64x4;
54
+ * nk_dot_f64x2_finalize_serial(&state_first, &state_second, &state_third, &state_fourth, depth, &results_f64x4);
55
+ * @endcode
56
+ *
57
+ * Integer types follow a similar pattern with appropriate type changes:
58
+ *
59
+ * @code{c}
60
+ * nk_dot_i8x16_state_serial_t state_first, state_second, state_third, state_fourth;
61
+ * nk_b128_vec_t query_i8x16, target_first_i8x16, target_second_i8x16, target_third_i8x16, target_fourth_i8x16;
62
+ * nk_dot_i8x16_init_serial(&state_first);
63
+ * nk_dot_i8x16_init_serial(&state_second);
64
+ * nk_dot_i8x16_init_serial(&state_third);
65
+ * nk_dot_i8x16_init_serial(&state_fourth);
66
+ * for (nk_size_t idx = 0; idx + 16 <= depth; idx += 16) {
67
+ * memcpy(query_i8x16.i8s, query_ptr + idx, 16);
68
+ * memcpy(target_first_i8x16.i8s, target_first_ptr + idx, 16);
69
+ * memcpy(target_second_i8x16.i8s, target_second_ptr + idx, 16);
70
+ * memcpy(target_third_i8x16.i8s, target_third_ptr + idx, 16);
71
+ * memcpy(target_fourth_i8x16.i8s, target_fourth_ptr + idx, 16);
72
+ * nk_dot_i8x16_update_serial(&state_first, query_i8x16, target_first_i8x16, idx, 16);
73
+ * nk_dot_i8x16_update_serial(&state_second, query_i8x16, target_second_i8x16, idx, 16);
74
+ * nk_dot_i8x16_update_serial(&state_third, query_i8x16, target_third_i8x16, idx, 16);
75
+ * nk_dot_i8x16_update_serial(&state_fourth, query_i8x16, target_fourth_i8x16, idx, 16);
76
+ * }
77
+ * nk_b128_vec_t results_i32x4;
78
+ * nk_dot_i8x16_finalize_serial(&state_first, &state_second, &state_third, &state_fourth, depth, &results_i32x4);
79
+ * @endcode
80
+ */
81
+ #ifndef NK_DOT_SERIAL_H
82
+ #define NK_DOT_SERIAL_H
83
+
84
+ #include "numkong/types.h"
85
+ #include "numkong/reduce/serial.h" // `nk_f64_abs_`
86
+
87
+ #if defined(__cplusplus)
88
+ extern "C" {
89
+ #endif
90
+
91
+ /**
92
+ * @brief Macro for dot product with simple accumulation.
93
+ */
94
+ #define nk_define_dot_(input_type, accumulator_type, output_type, load_and_convert) \
95
+ NK_PUBLIC void nk_dot_##input_type##_serial(nk_##input_type##_t const *a, nk_##input_type##_t const *b, \
96
+ nk_size_t n, nk_##output_type##_t *result) { \
97
+ nk_##accumulator_type##_t sum = 0, a_value, b_value; \
98
+ for (nk_size_t i = 0; i != n; ++i) { \
99
+ load_and_convert(a + i, &a_value); \
100
+ load_and_convert(b + i, &b_value); \
101
+ sum += a_value * b_value; \
102
+ } \
103
+ *result = (nk_##output_type##_t)sum; \
104
+ }
105
+
106
+ #define nk_define_dot_complex_(input_type, accumulator_type, output_complex_type, load_and_convert) \
107
+ NK_PUBLIC void nk_dot_##input_type##_serial(nk_##input_type##_t const *a_pairs, \
108
+ nk_##input_type##_t const *b_pairs, nk_size_t count_pairs, \
109
+ nk_##output_complex_type##_t *result) { \
110
+ nk_##accumulator_type##_t sum_real = 0, sum_imag = 0; \
111
+ nk_##accumulator_type##_t a_real, b_real, a_imag, b_imag; \
112
+ for (nk_size_t i = 0; i != count_pairs; ++i) { \
113
+ load_and_convert(&(a_pairs + i)->real, &a_real); \
114
+ load_and_convert(&(b_pairs + i)->real, &b_real); \
115
+ load_and_convert(&(a_pairs + i)->imag, &a_imag); \
116
+ load_and_convert(&(b_pairs + i)->imag, &b_imag); \
117
+ sum_real += a_real * b_real - a_imag * b_imag; \
118
+ sum_imag += a_real * b_imag + a_imag * b_real; \
119
+ } \
120
+ result->real = sum_real; \
121
+ result->imag = sum_imag; \
122
+ }
123
+
124
+ #define nk_define_vdot_complex_(input_type, accumulator_type, output_complex_type, load_and_convert) \
125
+ NK_PUBLIC void nk_vdot_##input_type##_serial(nk_##input_type##_t const *a_pairs, \
126
+ nk_##input_type##_t const *b_pairs, nk_size_t count_pairs, \
127
+ nk_##output_complex_type##_t *result) { \
128
+ nk_##accumulator_type##_t sum_real = 0, sum_imag = 0; \
129
+ nk_##accumulator_type##_t a_real, b_real, a_imag, b_imag; \
130
+ for (nk_size_t i = 0; i != count_pairs; ++i) { \
131
+ load_and_convert(&(a_pairs + i)->real, &a_real); \
132
+ load_and_convert(&(b_pairs + i)->real, &b_real); \
133
+ load_and_convert(&(a_pairs + i)->imag, &a_imag); \
134
+ load_and_convert(&(b_pairs + i)->imag, &b_imag); \
135
+ sum_real += a_real * b_real + a_imag * b_imag; \
136
+ sum_imag += a_real * b_imag - a_imag * b_real; \
137
+ } \
138
+ result->real = sum_real; \
139
+ result->imag = sum_imag; \
140
+ }
141
+
142
+ #pragma region F32 and F64 Floats
143
+
144
+ nk_define_dot_(f32, f64, f64, nk_assign_from_to_) // nk_dot_f32_serial
145
+ nk_define_dot_complex_(f32c, f64, f64c, nk_assign_from_to_) // nk_dot_f32c_serial
146
+ nk_define_vdot_complex_(f32c, f64, f64c, nk_assign_from_to_) // nk_vdot_f32c_serial
147
+
148
+ #pragma endregion F32 and F64 Floats
149
+
150
+ #pragma region F16 and BF16 Floats
151
+
152
+ nk_define_dot_(f16, f32, f32, nk_f16_to_f32_serial) // nk_dot_f16_serial
153
+ nk_define_dot_complex_(f16c, f32, f32c, nk_f16_to_f32_serial) // nk_dot_f16c_serial
154
+ nk_define_vdot_complex_(f16c, f32, f32c, nk_f16_to_f32_serial) // nk_vdot_f16c_serial
155
+
156
+ nk_define_dot_(bf16, f32, f32, nk_bf16_to_f32_serial) // nk_dot_bf16_serial
157
+ nk_define_dot_complex_(bf16c, f32, f32c, nk_bf16_to_f32_serial) // nk_dot_bf16c_serial
158
+ nk_define_vdot_complex_(bf16c, f32, f32c, nk_bf16_to_f32_serial) // nk_vdot_bf16c_serial
159
+
160
+ nk_define_dot_(e4m3, f32, f32, nk_e4m3_to_f32_serial) // nk_dot_e4m3_serial
161
+ nk_define_dot_(e5m2, f32, f32, nk_e5m2_to_f32_serial) // nk_dot_e5m2_serial
162
+ nk_define_dot_(e2m3, f32, f32, nk_e2m3_to_f32_serial) // nk_dot_e2m3_serial
163
+ nk_define_dot_(e3m2, f32, f32, nk_e3m2_to_f32_serial) // nk_dot_e3m2_serial
164
+
165
+ #pragma endregion F16 and BF16 Floats
166
+
167
+ #pragma region I8 and U8 Integers
168
+
169
+ nk_define_dot_(i8, i32, i32, nk_assign_from_to_) // nk_dot_i8_serial
170
+ nk_define_dot_(u8, u32, u32, nk_assign_from_to_) // nk_dot_u8_serial
171
+
172
+ #undef nk_define_dot_
173
+ #undef nk_define_dot_complex_
174
+ #undef nk_define_vdot_complex_
175
+
176
+ NK_PUBLIC void nk_dot_i4_serial(nk_i4x2_t const *a, nk_i4x2_t const *b, nk_size_t n, nk_i32_t *result) {
177
+ // i4 values are packed as nibbles: two 4-bit signed values per byte.
178
+ // Parameter `n` is the number of 4-bit values (dimensions), not bytes.
179
+ // Sign extension: (nibble ^ 8) - 8 maps [0,15] to [-8,7]
180
+ n = nk_size_round_up_to_multiple_(n, 2);
181
+ nk_size_t n_bytes = n / 2;
182
+ nk_i32_t sum = 0;
183
+ for (nk_size_t i = 0; i < n_bytes; ++i) {
184
+ nk_i32_t a_low = (nk_i32_t)nk_i4x2_low_(a[i]);
185
+ nk_i32_t b_low = (nk_i32_t)nk_i4x2_low_(b[i]);
186
+ nk_i32_t a_high = (nk_i32_t)nk_i4x2_high_(a[i]);
187
+ nk_i32_t b_high = (nk_i32_t)nk_i4x2_high_(b[i]);
188
+ sum += a_low * b_low + a_high * b_high;
189
+ }
190
+ *result = sum;
191
+ }
192
+
193
+ NK_PUBLIC void nk_dot_u4_serial(nk_u4x2_t const *a, nk_u4x2_t const *b, nk_size_t n, nk_u32_t *result) {
194
+ // u4 values are packed as nibbles: two 4-bit unsigned values per byte.
195
+ // Parameter `n` is the number of 4-bit values (dimensions), not bytes.
196
+ // No sign extension needed - values are ∈ [0,15].
197
+ n = nk_size_round_up_to_multiple_(n, 2);
198
+ nk_size_t n_bytes = n / 2;
199
+ nk_u32_t sum = 0;
200
+ for (nk_size_t i = 0; i < n_bytes; ++i) {
201
+ nk_u32_t a_low = (nk_u32_t)nk_u4x2_low_(a[i]);
202
+ nk_u32_t b_low = (nk_u32_t)nk_u4x2_low_(b[i]);
203
+ nk_u32_t a_high = (nk_u32_t)nk_u4x2_high_(a[i]);
204
+ nk_u32_t b_high = (nk_u32_t)nk_u4x2_high_(b[i]);
205
+ sum += a_low * b_low + a_high * b_high;
206
+ }
207
+ *result = sum;
208
+ }
209
+
210
+ #pragma endregion I8 and U8 Integers
211
+
212
+ #pragma region F32 and F64 Floats
213
+
214
+ /* Double-precision dot-produce variants
215
+ *
216
+ * Implements Neumaier's Kahan-Babuška variant to minimize floating-point rounding errors.
217
+ * Unlike Kahan, Neumaier handles the case where the term being added is larger than the
218
+ * running sum. Achieves O(1) error growth regardless of vector dimension.
219
+ *
220
+ * Algorithm: For each term, compute t = sum + term, then:
221
+ * - If ‖sum‖ ≥ ‖term‖: c += (sum - t) + term (lost low-order bits of term)
222
+ * - Else: c += (term - t) + sum (lost low-order bits of sum)
223
+ *
224
+ * @see Neumaier, A. (1974). "Rundungsfehleranalyse einiger Verfahren zur Summation endlicher Summen"
225
+ */
226
+ NK_PUBLIC void nk_dot_f64_serial(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
227
+ nk_f64_t sum = 0, compensation = 0;
228
+ for (nk_size_t i = 0; i != n; ++i) nk_f64_dot2_(&sum, &compensation, a[i], b[i]);
229
+ *result = sum + compensation;
230
+ }
231
+
232
+ NK_PUBLIC void nk_dot_f64c_serial(nk_f64c_t const *a_pairs, nk_f64c_t const *b_pairs, nk_size_t count_pairs,
233
+ nk_f64c_t *result) {
234
+ nk_f64_t sum_real = 0, sum_imag = 0, compensation_real = 0, compensation_imag = 0;
235
+ for (nk_size_t i = 0; i != count_pairs; ++i) {
236
+ nk_f64_t a_real = a_pairs[i].real, b_real = b_pairs[i].real;
237
+ nk_f64_t a_imag = a_pairs[i].imag, b_imag = b_pairs[i].imag;
238
+ nk_f64_dot2_(&sum_real, &compensation_real, a_real, b_real);
239
+ nk_f64_dot2_(&sum_real, &compensation_real, -a_imag, b_imag);
240
+ nk_f64_dot2_(&sum_imag, &compensation_imag, a_real, b_imag);
241
+ nk_f64_dot2_(&sum_imag, &compensation_imag, a_imag, b_real);
242
+ }
243
+ result->real = sum_real + compensation_real;
244
+ result->imag = sum_imag + compensation_imag;
245
+ }
246
+
247
+ NK_PUBLIC void nk_vdot_f64c_serial(nk_f64c_t const *a_pairs, nk_f64c_t const *b_pairs, nk_size_t count_pairs,
248
+ nk_f64c_t *result) {
249
+ nk_f64_t sum_real = 0, sum_imag = 0, compensation_real = 0, compensation_imag = 0;
250
+ for (nk_size_t i = 0; i != count_pairs; ++i) {
251
+ nk_f64_t a_real = a_pairs[i].real, b_real = b_pairs[i].real;
252
+ nk_f64_t a_imag = a_pairs[i].imag, b_imag = b_pairs[i].imag;
253
+ nk_f64_dot2_(&sum_real, &compensation_real, a_real, b_real);
254
+ nk_f64_dot2_(&sum_real, &compensation_real, a_imag, b_imag);
255
+ nk_f64_dot2_(&sum_imag, &compensation_imag, a_real, b_imag);
256
+ nk_f64_dot2_(&sum_imag, &compensation_imag, -a_imag, b_real);
257
+ }
258
+ result->real = sum_real + compensation_real;
259
+ result->imag = sum_imag + compensation_imag;
260
+ }
261
+
262
+ typedef struct nk_dot_f64x2_state_serial_t {
263
+ nk_f64_t sums[2];
264
+ nk_f64_t compensations[2];
265
+ } nk_dot_f64x2_state_serial_t;
266
+
267
+ NK_INTERNAL void nk_dot_f64x2_init_serial(nk_dot_f64x2_state_serial_t *state) {
268
+ state->sums[0] = 0, state->sums[1] = 0;
269
+ state->compensations[0] = 0, state->compensations[1] = 0;
270
+ }
271
+
272
+ NK_INTERNAL void nk_dot_f64x2_update_serial(nk_dot_f64x2_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
273
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
274
+ nk_unused_(depth_offset);
275
+ nk_unused_(active_dimensions);
276
+ nk_f64_t sum0 = state->sums[0], compensation0 = state->compensations[0];
277
+ nk_f64_t sum1 = state->sums[1], compensation1 = state->compensations[1];
278
+ nk_f64_dot2_(&sum0, &compensation0, a.f64s[0], b.f64s[0]);
279
+ nk_f64_dot2_(&sum1, &compensation1, a.f64s[1], b.f64s[1]);
280
+
281
+ state->sums[0] = sum0, state->sums[1] = sum1;
282
+ state->compensations[0] = compensation0, state->compensations[1] = compensation1;
283
+ }
284
+
285
+ NK_INTERNAL void nk_dot_f64x2_finalize_serial( //
286
+ nk_dot_f64x2_state_serial_t const *state_a, nk_dot_f64x2_state_serial_t const *state_b, //
287
+ nk_dot_f64x2_state_serial_t const *state_c, nk_dot_f64x2_state_serial_t const *state_d, //
288
+ nk_size_t total_dimensions, nk_b256_vec_t *result) {
289
+ nk_unused_(total_dimensions);
290
+ result->f64s[0] = nk_reduce_sum_f64_serial_(state_a->sums, state_a->compensations, 2);
291
+ result->f64s[1] = nk_reduce_sum_f64_serial_(state_b->sums, state_b->compensations, 2);
292
+ result->f64s[2] = nk_reduce_sum_f64_serial_(state_c->sums, state_c->compensations, 2);
293
+ result->f64s[3] = nk_reduce_sum_f64_serial_(state_d->sums, state_d->compensations, 2);
294
+ }
295
+
296
+ typedef struct nk_dot_f32x4_state_serial_t {
297
+ nk_f64_t sums[4];
298
+ } nk_dot_f32x4_state_serial_t;
299
+
300
+ NK_INTERNAL void nk_dot_f32x4_init_serial(nk_dot_f32x4_state_serial_t *state) {
301
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
302
+ }
303
+
304
+ NK_INTERNAL void nk_dot_f32x4_update_serial(nk_dot_f32x4_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
305
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
306
+ nk_unused_(depth_offset);
307
+ nk_unused_(active_dimensions);
308
+ nk_f64_t sum0 = state->sums[0];
309
+ nk_f64_t sum1 = state->sums[1];
310
+ nk_f64_t sum2 = state->sums[2];
311
+ nk_f64_t sum3 = state->sums[3];
312
+ sum0 += (nk_f64_t)a.f32s[0] * b.f32s[0], sum1 += (nk_f64_t)a.f32s[1] * b.f32s[1];
313
+ sum2 += (nk_f64_t)a.f32s[2] * b.f32s[2], sum3 += (nk_f64_t)a.f32s[3] * b.f32s[3];
314
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
315
+ }
316
+
317
+ NK_INTERNAL void nk_dot_f32x4_finalize_serial( //
318
+ nk_dot_f32x4_state_serial_t const *state_a, nk_dot_f32x4_state_serial_t const *state_b, //
319
+ nk_dot_f32x4_state_serial_t const *state_c, nk_dot_f32x4_state_serial_t const *state_d, //
320
+ nk_size_t total_dimensions, nk_b256_vec_t *result) {
321
+ nk_unused_(total_dimensions);
322
+ result->f64s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
323
+ result->f64s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
324
+ result->f64s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
325
+ result->f64s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
326
+ }
327
+
328
+ #pragma endregion F32 and F64 Floats
329
+
330
+ #pragma region F16 and BF16 Floats
331
+
332
+ typedef struct nk_dot_f16x8_state_serial_t {
333
+ nk_f32_t sums[4];
334
+ } nk_dot_f16x8_state_serial_t;
335
+
336
+ NK_INTERNAL void nk_dot_f16x8_init_serial(nk_dot_f16x8_state_serial_t *state) {
337
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
338
+ }
339
+
340
+ NK_INTERNAL void nk_dot_f16x8_update_serial(nk_dot_f16x8_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
341
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
342
+ nk_unused_(depth_offset);
343
+ nk_unused_(active_dimensions);
344
+ nk_f32_t sum0 = state->sums[0], sum1 = state->sums[1], sum2 = state->sums[2], sum3 = state->sums[3];
345
+ for (nk_size_t i = 0; i < 8; i += 4) {
346
+ nk_f32_t a0, a1, a2, a3, b0, b1, b2, b3;
347
+ nk_f16_to_f32_serial(a.f16s + i + 0, &a0), nk_f16_to_f32_serial(a.f16s + i + 1, &a1);
348
+ nk_f16_to_f32_serial(a.f16s + i + 2, &a2), nk_f16_to_f32_serial(a.f16s + i + 3, &a3);
349
+ nk_f16_to_f32_serial(b.f16s + i + 0, &b0), nk_f16_to_f32_serial(b.f16s + i + 1, &b1);
350
+ nk_f16_to_f32_serial(b.f16s + i + 2, &b2), nk_f16_to_f32_serial(b.f16s + i + 3, &b3);
351
+ sum0 += a0 * b0, sum1 += a1 * b1, sum2 += a2 * b2, sum3 += a3 * b3;
352
+ }
353
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
354
+ }
355
+
356
+ NK_INTERNAL void nk_dot_f16x8_finalize_serial( //
357
+ nk_dot_f16x8_state_serial_t const *state_a, nk_dot_f16x8_state_serial_t const *state_b, //
358
+ nk_dot_f16x8_state_serial_t const *state_c, nk_dot_f16x8_state_serial_t const *state_d, //
359
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
360
+ nk_unused_(total_dimensions);
361
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
362
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
363
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
364
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
365
+ }
366
+
367
+ typedef struct nk_dot_through_f32x4_state_serial_t {
368
+ nk_f32_t sums[4];
369
+ } nk_dot_through_f32x4_state_serial_t;
370
+
371
+ NK_INTERNAL void nk_dot_through_f32x4_init_serial(nk_dot_through_f32x4_state_serial_t *state) {
372
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
373
+ }
374
+
375
+ NK_INTERNAL void nk_dot_through_f32x4_update_serial(nk_dot_through_f32x4_state_serial_t *state, nk_b128_vec_t a,
376
+ nk_b128_vec_t b, nk_size_t depth_offset,
377
+ nk_size_t active_dimensions) {
378
+ nk_unused_(depth_offset);
379
+ nk_unused_(active_dimensions);
380
+ state->sums[0] += a.f32s[0] * b.f32s[0];
381
+ state->sums[1] += a.f32s[1] * b.f32s[1];
382
+ state->sums[2] += a.f32s[2] * b.f32s[2];
383
+ state->sums[3] += a.f32s[3] * b.f32s[3];
384
+ }
385
+
386
+ NK_INTERNAL void nk_dot_through_f32x4_finalize_serial( //
387
+ nk_dot_through_f32x4_state_serial_t const *state_a, nk_dot_through_f32x4_state_serial_t const *state_b, //
388
+ nk_dot_through_f32x4_state_serial_t const *state_c, nk_dot_through_f32x4_state_serial_t const *state_d, //
389
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
390
+ nk_unused_(total_dimensions);
391
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
392
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
393
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
394
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
395
+ }
396
+
397
+ typedef struct nk_dot_bf16x8_state_serial_t {
398
+ nk_f32_t sums[4];
399
+ } nk_dot_bf16x8_state_serial_t;
400
+
401
+ NK_INTERNAL void nk_dot_bf16x8_init_serial(nk_dot_bf16x8_state_serial_t *state) {
402
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
403
+ }
404
+
405
+ NK_INTERNAL void nk_dot_bf16x8_update_serial(nk_dot_bf16x8_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
406
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
407
+ nk_unused_(depth_offset);
408
+ nk_unused_(active_dimensions);
409
+ nk_f32_t sum0 = state->sums[0], sum1 = state->sums[1], sum2 = state->sums[2], sum3 = state->sums[3];
410
+ for (nk_size_t i = 0; i < 8; i += 4) {
411
+ nk_f32_t a0, a1, a2, a3, b0, b1, b2, b3;
412
+ nk_bf16_to_f32_serial(a.bf16s + i + 0, &a0), nk_bf16_to_f32_serial(a.bf16s + i + 1, &a1);
413
+ nk_bf16_to_f32_serial(a.bf16s + i + 2, &a2), nk_bf16_to_f32_serial(a.bf16s + i + 3, &a3);
414
+ nk_bf16_to_f32_serial(b.bf16s + i + 0, &b0), nk_bf16_to_f32_serial(b.bf16s + i + 1, &b1);
415
+ nk_bf16_to_f32_serial(b.bf16s + i + 2, &b2), nk_bf16_to_f32_serial(b.bf16s + i + 3, &b3);
416
+ sum0 += a0 * b0, sum1 += a1 * b1, sum2 += a2 * b2, sum3 += a3 * b3;
417
+ }
418
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
419
+ }
420
+
421
+ NK_INTERNAL void nk_dot_bf16x8_finalize_serial( //
422
+ nk_dot_bf16x8_state_serial_t const *state_a, nk_dot_bf16x8_state_serial_t const *state_b, //
423
+ nk_dot_bf16x8_state_serial_t const *state_c, nk_dot_bf16x8_state_serial_t const *state_d, //
424
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
425
+ nk_unused_(total_dimensions);
426
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
427
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
428
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
429
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
430
+ }
431
+
432
+ #pragma endregion F16 and BF16 Floats
433
+
434
+ #pragma region I8 and U8 Integers
435
+
436
+ typedef struct nk_dot_i8x16_state_serial_t {
437
+ nk_i64_t sums[2];
438
+ } nk_dot_i8x16_state_serial_t;
439
+
440
+ NK_INTERNAL void nk_dot_i8x16_init_serial(nk_dot_i8x16_state_serial_t *state) {
441
+ state->sums[0] = 0, state->sums[1] = 0;
442
+ }
443
+
444
+ NK_INTERNAL void nk_dot_i8x16_update_serial(nk_dot_i8x16_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
445
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
446
+ nk_unused_(depth_offset);
447
+ nk_unused_(active_dimensions);
448
+ nk_i64_t sum0 = state->sums[0];
449
+ nk_i64_t sum1 = state->sums[1];
450
+ sum0 += (nk_i16_t)a.i8s[0] * (nk_i16_t)b.i8s[0], sum1 += (nk_i16_t)a.i8s[1] * (nk_i16_t)b.i8s[1];
451
+ sum0 += (nk_i16_t)a.i8s[2] * (nk_i16_t)b.i8s[2], sum1 += (nk_i16_t)a.i8s[3] * (nk_i16_t)b.i8s[3];
452
+ sum0 += (nk_i16_t)a.i8s[4] * (nk_i16_t)b.i8s[4], sum1 += (nk_i16_t)a.i8s[5] * (nk_i16_t)b.i8s[5];
453
+ sum0 += (nk_i16_t)a.i8s[6] * (nk_i16_t)b.i8s[6], sum1 += (nk_i16_t)a.i8s[7] * (nk_i16_t)b.i8s[7];
454
+ sum0 += (nk_i16_t)a.i8s[8] * (nk_i16_t)b.i8s[8], sum1 += (nk_i16_t)a.i8s[9] * (nk_i16_t)b.i8s[9];
455
+ sum0 += (nk_i16_t)a.i8s[10] * (nk_i16_t)b.i8s[10], sum1 += (nk_i16_t)a.i8s[11] * (nk_i16_t)b.i8s[11];
456
+ sum0 += (nk_i16_t)a.i8s[12] * (nk_i16_t)b.i8s[12], sum1 += (nk_i16_t)a.i8s[13] * (nk_i16_t)b.i8s[13];
457
+ sum0 += (nk_i16_t)a.i8s[14] * (nk_i16_t)b.i8s[14], sum1 += (nk_i16_t)a.i8s[15] * (nk_i16_t)b.i8s[15];
458
+ state->sums[0] = sum0, state->sums[1] = sum1;
459
+ }
460
+
461
+ NK_INTERNAL void nk_dot_i8x16_finalize_serial( //
462
+ nk_dot_i8x16_state_serial_t const *state_a, nk_dot_i8x16_state_serial_t const *state_b, //
463
+ nk_dot_i8x16_state_serial_t const *state_c, nk_dot_i8x16_state_serial_t const *state_d, //
464
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
465
+ nk_unused_(total_dimensions);
466
+ result->i32s[0] = (nk_i32_t)(state_a->sums[0] + state_a->sums[1]);
467
+ result->i32s[1] = (nk_i32_t)(state_b->sums[0] + state_b->sums[1]);
468
+ result->i32s[2] = (nk_i32_t)(state_c->sums[0] + state_c->sums[1]);
469
+ result->i32s[3] = (nk_i32_t)(state_d->sums[0] + state_d->sums[1]);
470
+ }
471
+
472
+ typedef struct nk_dot_u8x16_state_serial_t {
473
+ nk_u64_t sums[2];
474
+ } nk_dot_u8x16_state_serial_t;
475
+
476
+ NK_INTERNAL void nk_dot_u8x16_init_serial(nk_dot_u8x16_state_serial_t *state) {
477
+ state->sums[0] = 0, state->sums[1] = 0;
478
+ }
479
+
480
+ NK_INTERNAL void nk_dot_u8x16_update_serial(nk_dot_u8x16_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
481
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
482
+ nk_unused_(depth_offset);
483
+ nk_unused_(active_dimensions);
484
+ nk_u64_t sum0 = state->sums[0];
485
+ nk_u64_t sum1 = state->sums[1];
486
+
487
+ sum0 += (nk_u16_t)a.u8s[0] * (nk_u16_t)b.u8s[0], sum1 += (nk_u16_t)a.u8s[1] * (nk_u16_t)b.u8s[1];
488
+ sum0 += (nk_u16_t)a.u8s[2] * (nk_u16_t)b.u8s[2], sum1 += (nk_u16_t)a.u8s[3] * (nk_u16_t)b.u8s[3];
489
+ sum0 += (nk_u16_t)a.u8s[4] * (nk_u16_t)b.u8s[4], sum1 += (nk_u16_t)a.u8s[5] * (nk_u16_t)b.u8s[5];
490
+ sum0 += (nk_u16_t)a.u8s[6] * (nk_u16_t)b.u8s[6], sum1 += (nk_u16_t)a.u8s[7] * (nk_u16_t)b.u8s[7];
491
+ sum0 += (nk_u16_t)a.u8s[8] * (nk_u16_t)b.u8s[8], sum1 += (nk_u16_t)a.u8s[9] * (nk_u16_t)b.u8s[9];
492
+ sum0 += (nk_u16_t)a.u8s[10] * (nk_u16_t)b.u8s[10], sum1 += (nk_u16_t)a.u8s[11] * (nk_u16_t)b.u8s[11];
493
+ sum0 += (nk_u16_t)a.u8s[12] * (nk_u16_t)b.u8s[12], sum1 += (nk_u16_t)a.u8s[13] * (nk_u16_t)b.u8s[13];
494
+ sum0 += (nk_u16_t)a.u8s[14] * (nk_u16_t)b.u8s[14], sum1 += (nk_u16_t)a.u8s[15] * (nk_u16_t)b.u8s[15];
495
+ state->sums[0] = sum0, state->sums[1] = sum1;
496
+ }
497
+
498
+ NK_INTERNAL void nk_dot_u8x16_finalize_serial( //
499
+ nk_dot_u8x16_state_serial_t const *state_a, nk_dot_u8x16_state_serial_t const *state_b, //
500
+ nk_dot_u8x16_state_serial_t const *state_c, nk_dot_u8x16_state_serial_t const *state_d, //
501
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
502
+ nk_unused_(total_dimensions);
503
+ result->u32s[0] = (nk_u32_t)(state_a->sums[0] + state_a->sums[1]);
504
+ result->u32s[1] = (nk_u32_t)(state_b->sums[0] + state_b->sums[1]);
505
+ result->u32s[2] = (nk_u32_t)(state_c->sums[0] + state_c->sums[1]);
506
+ result->u32s[3] = (nk_u32_t)(state_d->sums[0] + state_d->sums[1]);
507
+ }
508
+
509
+ #pragma endregion I8 and U8 Integers
510
+
511
+ #pragma region F16 and BF16 Floats
512
+
513
+ typedef struct nk_dot_e4m3x16_state_serial_t {
514
+ nk_f32_t sums[4];
515
+ } nk_dot_e4m3x16_state_serial_t;
516
+
517
+ NK_INTERNAL void nk_dot_e4m3x16_init_serial(nk_dot_e4m3x16_state_serial_t *state) {
518
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
519
+ }
520
+
521
+ NK_INTERNAL void nk_dot_e4m3x16_update_serial(nk_dot_e4m3x16_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
522
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
523
+ nk_unused_(depth_offset);
524
+ nk_unused_(active_dimensions);
525
+ nk_f32_t sum0 = state->sums[0];
526
+ nk_f32_t sum1 = state->sums[1];
527
+ nk_f32_t sum2 = state->sums[2];
528
+ nk_f32_t sum3 = state->sums[3];
529
+ nk_f32_t ai0, ai1, ai2, ai3;
530
+ nk_f32_t bi0, bi1, bi2, bi3;
531
+ for (nk_size_t i = 0; i != 16; i += 4) {
532
+ nk_e4m3_to_f32_serial(a.e4m3s + i, &ai0), nk_e4m3_to_f32_serial(b.e4m3s + i, &bi0);
533
+ nk_e4m3_to_f32_serial(a.e4m3s + i + 1, &ai1), nk_e4m3_to_f32_serial(b.e4m3s + i + 1, &bi1);
534
+ nk_e4m3_to_f32_serial(a.e4m3s + i + 2, &ai2), nk_e4m3_to_f32_serial(b.e4m3s + i + 2, &bi2);
535
+ nk_e4m3_to_f32_serial(a.e4m3s + i + 3, &ai3), nk_e4m3_to_f32_serial(b.e4m3s + i + 3, &bi3);
536
+ sum0 += ai0 * bi0, sum1 += ai1 * bi1, sum2 += ai2 * bi2, sum3 += ai3 * bi3;
537
+ }
538
+
539
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
540
+ }
541
+
542
+ NK_INTERNAL void nk_dot_e4m3x16_finalize_serial( //
543
+ nk_dot_e4m3x16_state_serial_t const *state_a, nk_dot_e4m3x16_state_serial_t const *state_b, //
544
+ nk_dot_e4m3x16_state_serial_t const *state_c, nk_dot_e4m3x16_state_serial_t const *state_d, //
545
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
546
+ nk_unused_(total_dimensions);
547
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
548
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
549
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
550
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
551
+ }
552
+
553
+ typedef struct nk_dot_e5m2x16_state_serial_t {
554
+ nk_f32_t sums[4];
555
+ } nk_dot_e5m2x16_state_serial_t;
556
+
557
+ NK_INTERNAL void nk_dot_e5m2x16_init_serial(nk_dot_e5m2x16_state_serial_t *state) {
558
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
559
+ }
560
+
561
+ NK_INTERNAL void nk_dot_e5m2x16_update_serial(nk_dot_e5m2x16_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
562
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
563
+ nk_unused_(depth_offset);
564
+ nk_unused_(active_dimensions);
565
+ nk_f32_t sum0 = state->sums[0];
566
+ nk_f32_t sum1 = state->sums[1];
567
+ nk_f32_t sum2 = state->sums[2];
568
+ nk_f32_t sum3 = state->sums[3];
569
+ nk_f32_t ai0, ai1, ai2, ai3;
570
+ nk_f32_t bi0, bi1, bi2, bi3;
571
+ for (nk_size_t i = 0; i != 16; i += 4) {
572
+ nk_e5m2_to_f32_serial(a.e5m2s + i, &ai0), nk_e5m2_to_f32_serial(b.e5m2s + i, &bi0);
573
+ nk_e5m2_to_f32_serial(a.e5m2s + i + 1, &ai1), nk_e5m2_to_f32_serial(b.e5m2s + i + 1, &bi1);
574
+ nk_e5m2_to_f32_serial(a.e5m2s + i + 2, &ai2), nk_e5m2_to_f32_serial(b.e5m2s + i + 2, &bi2);
575
+ nk_e5m2_to_f32_serial(a.e5m2s + i + 3, &ai3), nk_e5m2_to_f32_serial(b.e5m2s + i + 3, &bi3);
576
+ sum0 += ai0 * bi0, sum1 += ai1 * bi1, sum2 += ai2 * bi2, sum3 += ai3 * bi3;
577
+ }
578
+
579
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
580
+ }
581
+
582
+ NK_INTERNAL void nk_dot_e5m2x16_finalize_serial( //
583
+ nk_dot_e5m2x16_state_serial_t const *state_a, nk_dot_e5m2x16_state_serial_t const *state_b, //
584
+ nk_dot_e5m2x16_state_serial_t const *state_c, nk_dot_e5m2x16_state_serial_t const *state_d, //
585
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
586
+ nk_unused_(total_dimensions);
587
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
588
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
589
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
590
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
591
+ }
592
+
593
+ typedef struct nk_dot_e2m3x16_state_serial_t {
594
+ nk_f32_t sums[4];
595
+ } nk_dot_e2m3x16_state_serial_t;
596
+
597
+ NK_INTERNAL void nk_dot_e2m3x16_init_serial(nk_dot_e2m3x16_state_serial_t *state) {
598
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
599
+ }
600
+
601
+ NK_INTERNAL void nk_dot_e2m3x16_update_serial(nk_dot_e2m3x16_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
602
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
603
+ nk_unused_(depth_offset);
604
+ nk_unused_(active_dimensions);
605
+ nk_f32_t sum0 = state->sums[0];
606
+ nk_f32_t sum1 = state->sums[1];
607
+ nk_f32_t sum2 = state->sums[2];
608
+ nk_f32_t sum3 = state->sums[3];
609
+ nk_f32_t ai0, ai1, ai2, ai3;
610
+ nk_f32_t bi0, bi1, bi2, bi3;
611
+ for (nk_size_t i = 0; i != 16; i += 4) {
612
+ nk_e2m3_to_f32_serial(a.e2m3s + i, &ai0), nk_e2m3_to_f32_serial(b.e2m3s + i, &bi0);
613
+ nk_e2m3_to_f32_serial(a.e2m3s + i + 1, &ai1), nk_e2m3_to_f32_serial(b.e2m3s + i + 1, &bi1);
614
+ nk_e2m3_to_f32_serial(a.e2m3s + i + 2, &ai2), nk_e2m3_to_f32_serial(b.e2m3s + i + 2, &bi2);
615
+ nk_e2m3_to_f32_serial(a.e2m3s + i + 3, &ai3), nk_e2m3_to_f32_serial(b.e2m3s + i + 3, &bi3);
616
+ sum0 += ai0 * bi0, sum1 += ai1 * bi1, sum2 += ai2 * bi2, sum3 += ai3 * bi3;
617
+ }
618
+
619
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
620
+ }
621
+
622
+ NK_INTERNAL void nk_dot_e2m3x16_finalize_serial( //
623
+ nk_dot_e2m3x16_state_serial_t const *state_a, nk_dot_e2m3x16_state_serial_t const *state_b, //
624
+ nk_dot_e2m3x16_state_serial_t const *state_c, nk_dot_e2m3x16_state_serial_t const *state_d, //
625
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
626
+ nk_unused_(total_dimensions);
627
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
628
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
629
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
630
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
631
+ }
632
+
633
+ typedef struct nk_dot_e3m2x16_state_serial_t {
634
+ nk_f32_t sums[4];
635
+ } nk_dot_e3m2x16_state_serial_t;
636
+
637
+ NK_INTERNAL void nk_dot_e3m2x16_init_serial(nk_dot_e3m2x16_state_serial_t *state) {
638
+ state->sums[0] = 0, state->sums[1] = 0, state->sums[2] = 0, state->sums[3] = 0;
639
+ }
640
+
641
+ NK_INTERNAL void nk_dot_e3m2x16_update_serial(nk_dot_e3m2x16_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
642
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
643
+ nk_unused_(depth_offset);
644
+ nk_unused_(active_dimensions);
645
+ nk_f32_t sum0 = state->sums[0];
646
+ nk_f32_t sum1 = state->sums[1];
647
+ nk_f32_t sum2 = state->sums[2];
648
+ nk_f32_t sum3 = state->sums[3];
649
+ nk_f32_t ai0, ai1, ai2, ai3;
650
+ nk_f32_t bi0, bi1, bi2, bi3;
651
+ for (nk_size_t i = 0; i != 16; i += 4) {
652
+ nk_e3m2_to_f32_serial(a.e3m2s + i, &ai0), nk_e3m2_to_f32_serial(b.e3m2s + i, &bi0);
653
+ nk_e3m2_to_f32_serial(a.e3m2s + i + 1, &ai1), nk_e3m2_to_f32_serial(b.e3m2s + i + 1, &bi1);
654
+ nk_e3m2_to_f32_serial(a.e3m2s + i + 2, &ai2), nk_e3m2_to_f32_serial(b.e3m2s + i + 2, &bi2);
655
+ nk_e3m2_to_f32_serial(a.e3m2s + i + 3, &ai3), nk_e3m2_to_f32_serial(b.e3m2s + i + 3, &bi3);
656
+ sum0 += ai0 * bi0, sum1 += ai1 * bi1, sum2 += ai2 * bi2, sum3 += ai3 * bi3;
657
+ }
658
+
659
+ state->sums[0] = sum0, state->sums[1] = sum1, state->sums[2] = sum2, state->sums[3] = sum3;
660
+ }
661
+
662
+ NK_INTERNAL void nk_dot_e3m2x16_finalize_serial( //
663
+ nk_dot_e3m2x16_state_serial_t const *state_a, nk_dot_e3m2x16_state_serial_t const *state_b, //
664
+ nk_dot_e3m2x16_state_serial_t const *state_c, nk_dot_e3m2x16_state_serial_t const *state_d, //
665
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
666
+ nk_unused_(total_dimensions);
667
+ result->f32s[0] = state_a->sums[0] + state_a->sums[1] + state_a->sums[2] + state_a->sums[3];
668
+ result->f32s[1] = state_b->sums[0] + state_b->sums[1] + state_b->sums[2] + state_b->sums[3];
669
+ result->f32s[2] = state_c->sums[0] + state_c->sums[1] + state_c->sums[2] + state_c->sums[3];
670
+ result->f32s[3] = state_d->sums[0] + state_d->sums[1] + state_d->sums[2] + state_d->sums[3];
671
+ }
672
+
673
+ #pragma endregion F16 and BF16 Floats
674
+
675
+ #pragma region I8 and U8 Integers
676
+
677
+ // U4x2 state: processes 16 nibbles (8 bytes = 64 bits) per update
678
+ typedef struct nk_dot_u4x16_state_serial_t {
679
+ nk_u64_t sums[2]; // sums[0]: low nibbles, sums[1]: high nibbles
680
+ } nk_dot_u4x16_state_serial_t;
681
+
682
+ NK_INTERNAL void nk_dot_u4x16_init_serial(nk_dot_u4x16_state_serial_t *state) {
683
+ state->sums[0] = 0, state->sums[1] = 0;
684
+ }
685
+
686
+ NK_INTERNAL void nk_dot_u4x16_update_serial(nk_dot_u4x16_state_serial_t *state, nk_b64_vec_t a, nk_b64_vec_t b,
687
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
688
+ nk_unused_(depth_offset);
689
+ nk_unused_(active_dimensions);
690
+ // Process 8 bytes (16 nibbles total) using SWAR
691
+ // Separate accumulators for low and high nibbles
692
+ nk_u64_t sum_low = state->sums[0];
693
+ nk_u64_t sum_high = state->sums[1];
694
+
695
+ // Process all 8 bytes, extracting and multiplying nibbles
696
+ for (nk_size_t i = 0; i < 8; i++) {
697
+ nk_u8_t a_byte = a.u8s[i];
698
+ nk_u8_t b_byte = b.u8s[i];
699
+
700
+ // Extract low and high nibbles using SWAR masks
701
+ nk_u8_t a_low = a_byte & 0x0F;
702
+ nk_u8_t b_low = b_byte & 0x0F;
703
+ nk_u8_t a_high = (a_byte >> 4) & 0x0F;
704
+ nk_u8_t b_high = (b_byte >> 4) & 0x0F;
705
+
706
+ // Accumulate products into separate accumulators
707
+ sum_low += (nk_u32_t)a_low * (nk_u32_t)b_low;
708
+ sum_high += (nk_u32_t)a_high * (nk_u32_t)b_high;
709
+ }
710
+
711
+ state->sums[0] = sum_low, state->sums[1] = sum_high;
712
+ }
713
+
714
+ NK_INTERNAL void nk_dot_u4x16_finalize_serial(nk_dot_u4x16_state_serial_t const *state_a,
715
+ nk_dot_u4x16_state_serial_t const *state_b,
716
+ nk_dot_u4x16_state_serial_t const *state_c,
717
+ nk_dot_u4x16_state_serial_t const *state_d, nk_size_t total_dimensions,
718
+ nk_b128_vec_t *result) {
719
+ nk_unused_(total_dimensions);
720
+ result->u32s[0] = (nk_u32_t)(state_a->sums[0] + state_a->sums[1]);
721
+ result->u32s[1] = (nk_u32_t)(state_b->sums[0] + state_b->sums[1]);
722
+ result->u32s[2] = (nk_u32_t)(state_c->sums[0] + state_c->sums[1]);
723
+ result->u32s[3] = (nk_u32_t)(state_d->sums[0] + state_d->sums[1]);
724
+ }
725
+
726
+ NK_INTERNAL void nk_load_i4x16_to_i8x16_serial_(void const *src, nk_b128_vec_t *dst) {
727
+ nk_i4x2_t const *pairs = (nk_i4x2_t const *)src;
728
+ for (nk_size_t i = 0; i < 8; ++i) nk_i4x2_to_i8x2_serial(&pairs[i], &dst->i8s[i * 2]);
729
+ }
730
+
731
+ NK_INTERNAL void nk_partial_load_i4x16_to_i8x16_serial_(void const *src, nk_b128_vec_t *dst, nk_size_t n) {
732
+ nk_i4x2_t const *pairs = (nk_i4x2_t const *)src;
733
+ nk_size_t count_pairs = n / 2;
734
+ for (nk_size_t i = 0; i < count_pairs; ++i) nk_i4x2_to_i8x2_serial(&pairs[i], &dst->i8s[i * 2]);
735
+ for (nk_size_t i = n; i < 16; ++i) dst->i8s[i] = 0;
736
+ }
737
+
738
+ NK_INTERNAL void nk_load_u4x16_to_u8x16_serial_(void const *src, nk_b128_vec_t *dst) {
739
+ nk_u4x2_t const *pairs = (nk_u4x2_t const *)src;
740
+ for (nk_size_t i = 0; i < 8; ++i) nk_u4x2_to_u8x2_serial(&pairs[i], &dst->u8s[i * 2]);
741
+ }
742
+
743
+ NK_INTERNAL void nk_partial_load_u4x16_to_u8x16_serial_(void const *src, nk_b128_vec_t *dst, nk_size_t n) {
744
+ nk_u4x2_t const *pairs = (nk_u4x2_t const *)src;
745
+ nk_size_t count_pairs = n / 2;
746
+ for (nk_size_t i = 0; i < count_pairs; ++i) nk_u4x2_to_u8x2_serial(&pairs[i], &dst->u8s[i * 2]);
747
+ for (nk_size_t i = n; i < 16; ++i) dst->u8s[i] = 0;
748
+ }
749
+
750
+ typedef struct nk_dot_i4x16_state_serial_t {
751
+ nk_i64_t sums[2]; // sums[0]: low nibbles, sums[1]: high nibbles
752
+ } nk_dot_i4x16_state_serial_t;
753
+
754
+ NK_INTERNAL void nk_dot_i4x16_init_serial(nk_dot_i4x16_state_serial_t *state) {
755
+ state->sums[0] = 0, state->sums[1] = 0;
756
+ }
757
+
758
+ NK_INTERNAL void nk_dot_i4x16_update_serial(nk_dot_i4x16_state_serial_t *state, nk_b64_vec_t a, nk_b64_vec_t b,
759
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
760
+ nk_unused_(depth_offset);
761
+ nk_unused_(active_dimensions);
762
+ // Process 8 bytes (16 nibbles total) using SWAR with sign extension
763
+ // Separate accumulators for low and high nibbles
764
+ nk_i64_t sum_low = state->sums[0];
765
+ nk_i64_t sum_high = state->sums[1];
766
+
767
+ // Process all 8 bytes, extracting and multiplying signed nibbles
768
+ for (nk_size_t i = 0; i < 8; i++) {
769
+ nk_u8_t a_byte = a.u8s[i];
770
+ nk_u8_t b_byte = b.u8s[i];
771
+
772
+ // Extract nibbles and sign extend: (nibble ^ 8) - 8 maps [0,15] → [-8,7]
773
+ nk_i8_t a_low = (nk_i8_t)(((a_byte & 0x0F) ^ 8) - 8);
774
+ nk_i8_t b_low = (nk_i8_t)(((b_byte & 0x0F) ^ 8) - 8);
775
+ nk_i8_t a_high = (nk_i8_t)((((a_byte >> 4) & 0x0F) ^ 8) - 8);
776
+ nk_i8_t b_high = (nk_i8_t)((((b_byte >> 4) & 0x0F) ^ 8) - 8);
777
+
778
+ // Accumulate products into separate accumulators
779
+ sum_low += (nk_i32_t)a_low * (nk_i32_t)b_low;
780
+ sum_high += (nk_i32_t)a_high * (nk_i32_t)b_high;
781
+ }
782
+
783
+ state->sums[0] = sum_low, state->sums[1] = sum_high;
784
+ }
785
+
786
+ NK_INTERNAL void nk_dot_i4x16_finalize_serial(nk_dot_i4x16_state_serial_t const *state_a,
787
+ nk_dot_i4x16_state_serial_t const *state_b,
788
+ nk_dot_i4x16_state_serial_t const *state_c,
789
+ nk_dot_i4x16_state_serial_t const *state_d, nk_size_t total_dimensions,
790
+ nk_b128_vec_t *result) {
791
+ nk_unused_(total_dimensions);
792
+ result->i32s[0] = (nk_i32_t)(state_a->sums[0] + state_a->sums[1]);
793
+ result->i32s[1] = (nk_i32_t)(state_b->sums[0] + state_b->sums[1]);
794
+ result->i32s[2] = (nk_i32_t)(state_c->sums[0] + state_c->sums[1]);
795
+ result->i32s[3] = (nk_i32_t)(state_d->sums[0] + state_d->sums[1]);
796
+ }
797
+
798
+ #pragma endregion I8 and U8 Integers
799
+
800
+ #pragma region Binary
801
+
802
+ NK_PUBLIC void nk_dot_u1_serial(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n_bits, nk_u32_t *result) {
803
+ nk_u32_t dot = 0;
804
+ nk_size_t bytes = nk_size_divide_round_up_(n_bits, NK_BITS_PER_BYTE);
805
+ for (nk_size_t i = 0; i < bytes; ++i) dot += nk_u1x8_popcount_(((nk_u8_t const *)a)[i] & ((nk_u8_t const *)b)[i]);
806
+ *result = dot;
807
+ }
808
+
809
+ typedef struct nk_dot_u1x128_state_serial_t {
810
+ nk_u32_t dot_count;
811
+ } nk_dot_u1x128_state_serial_t;
812
+
813
+ NK_INTERNAL void nk_dot_u1x128_init_serial(nk_dot_u1x128_state_serial_t *state) { state->dot_count = 0; }
814
+
815
+ NK_INTERNAL void nk_dot_u1x128_update_serial(nk_dot_u1x128_state_serial_t *state, nk_b128_vec_t a, nk_b128_vec_t b,
816
+ nk_size_t depth_offset, nk_size_t active_dimensions) {
817
+ nk_unused_(depth_offset);
818
+ nk_unused_(active_dimensions);
819
+ nk_u64_t and_low = a.u64s[0] & b.u64s[0];
820
+ nk_u64_t and_high = a.u64s[1] & b.u64s[1];
821
+ state->dot_count += (nk_u32_t)nk_u64_popcount_(and_low);
822
+ state->dot_count += (nk_u32_t)nk_u64_popcount_(and_high);
823
+ }
824
+
825
+ NK_INTERNAL void nk_dot_u1x128_finalize_serial(nk_dot_u1x128_state_serial_t const *state_a,
826
+ nk_dot_u1x128_state_serial_t const *state_b,
827
+ nk_dot_u1x128_state_serial_t const *state_c,
828
+ nk_dot_u1x128_state_serial_t const *state_d, nk_size_t total_dimensions,
829
+ nk_b128_vec_t *result) {
830
+ nk_unused_(total_dimensions);
831
+ result->u32s[0] = state_a->dot_count;
832
+ result->u32s[1] = state_b->dot_count;
833
+ result->u32s[2] = state_c->dot_count;
834
+ result->u32s[3] = state_d->dot_count;
835
+ }
836
+
837
+ #pragma endregion Binary
838
+
839
+ /**
840
+ * Serial fallback sum helpers for progressive element-sum accumulation.
841
+ * Used by the compensated symmetric GEMM macro to piggyback sum computation
842
+ * on the depth loop's already-loaded vectors, avoiding a separate sum pass.
843
+ */
844
+
845
+ #pragma region Stateful Element Sum Helpers (for compensated GEMM)
846
+
847
+ /* i4x32: Haswell i4 (nk_b128_vec_t containing 32 nibbles in 16 bytes) */
848
+ typedef struct nk_sum_i4x32_state_serial_t {
849
+ nk_i64_t sum;
850
+ } nk_sum_i4x32_state_serial_t;
851
+
852
+ NK_INTERNAL void nk_sum_i4x32_init_serial(nk_sum_i4x32_state_serial_t *state) { state->sum = 0; }
853
+
854
+ NK_INTERNAL void nk_sum_i4x32_update_serial(nk_sum_i4x32_state_serial_t *state, nk_b128_vec_t v) {
855
+ nk_u8_t const *d = (nk_u8_t const *)&v;
856
+ for (int i = 0; i < 16; i++) {
857
+ nk_i8_t low = (nk_i8_t)((d[i] & 0x0F) ^ 0x08) - 8; // sign-extend low nibble
858
+ nk_i8_t high = (nk_i8_t)((d[i] >> 4) ^ 0x08) - 8; // sign-extend high nibble
859
+ state->sum += low + high;
860
+ }
861
+ }
862
+
863
+ NK_INTERNAL nk_i32_t nk_sum_i4x32_finalize_serial(nk_sum_i4x32_state_serial_t const *state, nk_size_t count) {
864
+ nk_unused_(count);
865
+ return (nk_i32_t)state->sum;
866
+ }
867
+
868
+ #pragma endregion Stateful Element Sum Helpers
869
+
870
+ #if defined(__cplusplus)
871
+ } // extern "C"
872
+ #endif
873
+
874
+ #endif // NK_DOT_SERIAL_H