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,969 @@
1
+ /**
2
+ * @brief SIMD-accelerated Spatial Similarity Measures for WASM.
3
+ * @file include/numkong/spatial/v128relaxed.h
4
+ * @author Ash Vardanian
5
+ * @date February 2, 2026
6
+ *
7
+ * Contains:
8
+ * - Euclidean (L2) distance
9
+ * - Squared Euclidean (L2SQ) distance
10
+ * - Angular distance (1 - cosine similarity)
11
+ *
12
+ * For dtypes:
13
+ * - 64-bit IEEE floating point (f64)
14
+ * - 32-bit IEEE floating point (f32)
15
+ * - 16-bit IEEE floating point (f16)
16
+ * - 16-bit brain floating point (bf16)
17
+ *
18
+ * Key improvements:
19
+ * - F32→F64 upcast for angular_f32 (matches Haswell/NEON precision strategy)
20
+ * - Parallel SIMD sqrt for normalization (computes both sqrts simultaneously)
21
+ * - Edge case handling (zero vectors, numerical stability)
22
+ * - Uses relaxed FMA for optimal throughput
23
+ *
24
+ * @see For pattern references:
25
+ * - Haswell: include/numkong/spatial/haswell.h
26
+ * - NEON: include/numkong/spatial/neon.h
27
+ */
28
+
29
+ #ifndef NK_SPATIAL_V128RELAXED_H
30
+ #define NK_SPATIAL_V128RELAXED_H
31
+
32
+ #if NK_TARGET_V128RELAXED
33
+
34
+ #include "numkong/types.h"
35
+ #include "numkong/scalar/v128relaxed.h" // `nk_f32_sqrt_v128relaxed`
36
+ #include "numkong/reduce/v128relaxed.h"
37
+ #include "numkong/cast/serial.h"
38
+ #include "numkong/cast/v128relaxed.h"
39
+
40
+ #if defined(__cplusplus)
41
+ extern "C" {
42
+ #endif
43
+
44
+ #if defined(__clang__)
45
+ #pragma clang attribute push(__attribute__((target("relaxed-simd"))), apply_to = function)
46
+ #endif
47
+
48
+ NK_INTERNAL nk_f64_t nk_angular_normalize_f64_v128relaxed_(nk_f64_t ab, nk_f64_t a2, nk_f64_t b2) {
49
+ // Edge case: both vectors have zero magnitude
50
+ if (a2 == 0.0 && b2 == 0.0) return 0.0;
51
+ // Edge case: dot product is zero (perpendicular or one vector is zero)
52
+ if (ab == 0.0) return 1.0;
53
+
54
+ // Compute both square roots in parallel using SIMD (more efficient than 2 scalar sqrts)
55
+ v128_t squares_f64x2 = wasm_f64x2_make(a2, b2);
56
+ v128_t sqrts_f64x2 = wasm_f64x2_sqrt(squares_f64x2);
57
+ nk_f64_t a_sqrt = wasm_f64x2_extract_lane(sqrts_f64x2, 0);
58
+ nk_f64_t b_sqrt = wasm_f64x2_extract_lane(sqrts_f64x2, 1);
59
+
60
+ // Compute angular distance: 1 - cosine_similarity
61
+ nk_f64_t result = 1.0 - ab / (a_sqrt * b_sqrt);
62
+
63
+ // Clamp negative results to 0 (can occur due to floating-point rounding)
64
+ return result > 0.0 ? result : 0.0;
65
+ }
66
+
67
+ #pragma region F32 and F64 Floats
68
+
69
+ NK_PUBLIC void nk_sqeuclidean_f32_v128relaxed(nk_f32_t const *a, nk_f32_t const *b, nk_size_t n, nk_f64_t *result) {
70
+ v128_t sum_f64x2 = wasm_f64x2_splat(0.0);
71
+ nk_f32_t const *a_scalars = a, *b_scalars = b;
72
+ nk_size_t count_scalars = n;
73
+ nk_b64_vec_t a_f32_vec, b_f32_vec;
74
+
75
+ nk_sqeuclidean_f32_v128relaxed_cycle:
76
+ if (count_scalars < 2) {
77
+ nk_partial_load_b32x2_serial_(a_scalars, &a_f32_vec, count_scalars);
78
+ nk_partial_load_b32x2_serial_(b_scalars, &b_f32_vec, count_scalars);
79
+ count_scalars = 0;
80
+ }
81
+ else {
82
+ nk_load_b64_serial_(a_scalars, &a_f32_vec);
83
+ nk_load_b64_serial_(b_scalars, &b_f32_vec);
84
+ a_scalars += 2, b_scalars += 2, count_scalars -= 2;
85
+ }
86
+ v128_t a_f32x2 = wasm_i64x2_splat(a_f32_vec.u64);
87
+ v128_t b_f32x2 = wasm_i64x2_splat(b_f32_vec.u64);
88
+ v128_t a_f64x2 = wasm_f64x2_promote_low_f32x4(a_f32x2);
89
+ v128_t b_f64x2 = wasm_f64x2_promote_low_f32x4(b_f32x2);
90
+ v128_t diff_f64x2 = wasm_f64x2_sub(a_f64x2, b_f64x2);
91
+ sum_f64x2 = wasm_f64x2_relaxed_madd(diff_f64x2, diff_f64x2, sum_f64x2);
92
+ if (count_scalars) goto nk_sqeuclidean_f32_v128relaxed_cycle;
93
+
94
+ *result = nk_reduce_add_f64x2_v128relaxed_(sum_f64x2);
95
+ }
96
+
97
+ NK_PUBLIC void nk_sqeuclidean_f64_v128relaxed(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
98
+ v128_t sum_f64x2 = wasm_f64x2_splat(0.0);
99
+ nk_f64_t const *a_scalars = a, *b_scalars = b;
100
+ nk_size_t count_scalars = n;
101
+ nk_b128_vec_t a_vec, b_vec;
102
+
103
+ nk_sqeuclidean_f64_v128relaxed_cycle:
104
+ if (count_scalars < 2) {
105
+ nk_partial_load_b64x2_serial_(a_scalars, &a_vec, count_scalars);
106
+ nk_partial_load_b64x2_serial_(b_scalars, &b_vec, count_scalars);
107
+ count_scalars = 0;
108
+ }
109
+ else {
110
+ nk_load_b128_v128relaxed_(a_scalars, &a_vec);
111
+ nk_load_b128_v128relaxed_(b_scalars, &b_vec);
112
+ a_scalars += 2, b_scalars += 2, count_scalars -= 2;
113
+ }
114
+ v128_t diff_f64x2 = wasm_f64x2_sub(a_vec.v128, b_vec.v128);
115
+ sum_f64x2 = wasm_f64x2_relaxed_madd(diff_f64x2, diff_f64x2, sum_f64x2);
116
+ if (count_scalars) goto nk_sqeuclidean_f64_v128relaxed_cycle;
117
+
118
+ *result = nk_reduce_add_f64x2_v128relaxed_(sum_f64x2);
119
+ }
120
+
121
+ NK_PUBLIC void nk_euclidean_f32_v128relaxed(nk_f32_t const *a, nk_f32_t const *b, nk_size_t n, nk_f64_t *result) {
122
+ nk_f64_t l2sq;
123
+ nk_sqeuclidean_f32_v128relaxed(a, b, n, &l2sq);
124
+ *result = nk_f64_sqrt_v128relaxed(l2sq);
125
+ }
126
+
127
+ NK_PUBLIC void nk_euclidean_f64_v128relaxed(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
128
+ nk_f64_t l2sq;
129
+ nk_sqeuclidean_f64_v128relaxed(a, b, n, &l2sq);
130
+ *result = nk_f64_sqrt_v128relaxed(l2sq);
131
+ }
132
+
133
+ NK_PUBLIC void nk_angular_f32_v128relaxed(nk_f32_t const *a, nk_f32_t const *b, nk_size_t n, nk_f64_t *result) {
134
+ // F32 → F64 upcast for numerical stability
135
+ v128_t ab_f64x2 = wasm_f64x2_splat(0.0);
136
+ v128_t a2_f64x2 = wasm_f64x2_splat(0.0);
137
+ v128_t b2_f64x2 = wasm_f64x2_splat(0.0);
138
+ nk_f32_t const *a_scalars = a, *b_scalars = b;
139
+ nk_size_t count_scalars = n;
140
+ nk_b64_vec_t a_f32_vec, b_f32_vec;
141
+
142
+ nk_angular_f32_v128relaxed_cycle:
143
+ if (count_scalars < 2) {
144
+ nk_partial_load_b32x2_serial_(a_scalars, &a_f32_vec, count_scalars);
145
+ nk_partial_load_b32x2_serial_(b_scalars, &b_f32_vec, count_scalars);
146
+ count_scalars = 0;
147
+ }
148
+ else {
149
+ nk_load_b64_serial_(a_scalars, &a_f32_vec);
150
+ nk_load_b64_serial_(b_scalars, &b_f32_vec);
151
+ a_scalars += 2, b_scalars += 2, count_scalars -= 2;
152
+ }
153
+
154
+ // Upcast F32x2 → F64x2 for high-precision accumulation
155
+ v128_t a_f32x2 = wasm_i64x2_splat(a_f32_vec.u64);
156
+ v128_t b_f32x2 = wasm_i64x2_splat(b_f32_vec.u64);
157
+ v128_t a_f64x2 = wasm_f64x2_promote_low_f32x4(a_f32x2);
158
+ v128_t b_f64x2 = wasm_f64x2_promote_low_f32x4(b_f32x2);
159
+
160
+ // Accumulate: ab += a·b, a2 += a·a, b2 += b·b
161
+ ab_f64x2 = wasm_f64x2_relaxed_madd(a_f64x2, b_f64x2, ab_f64x2);
162
+ a2_f64x2 = wasm_f64x2_relaxed_madd(a_f64x2, a_f64x2, a2_f64x2);
163
+ b2_f64x2 = wasm_f64x2_relaxed_madd(b_f64x2, b_f64x2, b2_f64x2);
164
+ if (count_scalars) goto nk_angular_f32_v128relaxed_cycle;
165
+
166
+ // Reduce and normalize using F64 arithmetic
167
+ nk_f64_t ab_f64 = nk_reduce_add_f64x2_v128relaxed_(ab_f64x2);
168
+ nk_f64_t a2_f64 = nk_reduce_add_f64x2_v128relaxed_(a2_f64x2);
169
+ nk_f64_t b2_f64 = nk_reduce_add_f64x2_v128relaxed_(b2_f64x2);
170
+ *result = nk_angular_normalize_f64_v128relaxed_(ab_f64, a2_f64, b2_f64);
171
+ }
172
+
173
+ NK_PUBLIC void nk_angular_f64_v128relaxed(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
174
+ v128_t ab_f64x2 = wasm_f64x2_splat(0.0);
175
+ v128_t a2_f64x2 = wasm_f64x2_splat(0.0);
176
+ v128_t b2_f64x2 = wasm_f64x2_splat(0.0);
177
+ nk_f64_t const *a_scalars = a, *b_scalars = b;
178
+ nk_size_t count_scalars = n;
179
+ nk_b128_vec_t a_vec, b_vec;
180
+
181
+ nk_angular_f64_v128relaxed_cycle:
182
+ if (count_scalars < 2) {
183
+ nk_partial_load_b64x2_serial_(a_scalars, &a_vec, count_scalars);
184
+ nk_partial_load_b64x2_serial_(b_scalars, &b_vec, count_scalars);
185
+ count_scalars = 0;
186
+ }
187
+ else {
188
+ nk_load_b128_v128relaxed_(a_scalars, &a_vec);
189
+ nk_load_b128_v128relaxed_(b_scalars, &b_vec);
190
+ a_scalars += 2, b_scalars += 2, count_scalars -= 2;
191
+ }
192
+
193
+ // Accumulate: ab += a·b, a2 += a·a, b2 += b·b
194
+ ab_f64x2 = wasm_f64x2_relaxed_madd(a_vec.v128, b_vec.v128, ab_f64x2);
195
+ a2_f64x2 = wasm_f64x2_relaxed_madd(a_vec.v128, a_vec.v128, a2_f64x2);
196
+ b2_f64x2 = wasm_f64x2_relaxed_madd(b_vec.v128, b_vec.v128, b2_f64x2);
197
+ if (count_scalars) goto nk_angular_f64_v128relaxed_cycle;
198
+
199
+ // Reduce and normalize
200
+ nk_f64_t ab = nk_reduce_add_f64x2_v128relaxed_(ab_f64x2);
201
+ nk_f64_t a2 = nk_reduce_add_f64x2_v128relaxed_(a2_f64x2);
202
+ nk_f64_t b2 = nk_reduce_add_f64x2_v128relaxed_(b2_f64x2);
203
+ *result = nk_angular_normalize_f64_v128relaxed_(ab, a2, b2);
204
+ }
205
+
206
+ #pragma endregion F32 and F64 Floats
207
+ #pragma region F16 and BF16 Floats
208
+
209
+ NK_PUBLIC void nk_sqeuclidean_f16_v128relaxed(nk_f16_t const *a, nk_f16_t const *b, nk_size_t n, nk_f32_t *result) {
210
+ v128_t sum_f32x4 = wasm_f32x4_splat(0.0f);
211
+ nk_f16_t const *a_scalars = a, *b_scalars = b;
212
+ nk_size_t count_scalars = n;
213
+ nk_b64_vec_t a_f16_vec, b_f16_vec;
214
+
215
+ nk_sqeuclidean_f16_v128relaxed_cycle:
216
+ // Tail or full load
217
+ if (count_scalars < 4) {
218
+ nk_partial_load_b16x4_serial_(a_scalars, &a_f16_vec, count_scalars);
219
+ nk_partial_load_b16x4_serial_(b_scalars, &b_f16_vec, count_scalars);
220
+ count_scalars = 0;
221
+ }
222
+ else {
223
+ nk_load_b64_serial_(a_scalars, &a_f16_vec);
224
+ nk_load_b64_serial_(b_scalars, &b_f16_vec);
225
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
226
+ }
227
+
228
+ // Convert f16 → f32 (4 elements)
229
+ nk_b128_vec_t a_f32_vec = nk_f16x4_to_f32x4_v128relaxed_(a_f16_vec);
230
+ nk_b128_vec_t b_f32_vec = nk_f16x4_to_f32x4_v128relaxed_(b_f16_vec);
231
+
232
+ // Accumulate (a - b)²
233
+ v128_t diff_f32x4 = wasm_f32x4_sub(a_f32_vec.v128, b_f32_vec.v128);
234
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_f32x4, diff_f32x4, sum_f32x4);
235
+
236
+ if (count_scalars) goto nk_sqeuclidean_f16_v128relaxed_cycle;
237
+
238
+ *result = nk_reduce_add_f32x4_v128relaxed_(sum_f32x4);
239
+ }
240
+
241
+ NK_PUBLIC void nk_euclidean_f16_v128relaxed(nk_f16_t const *a, nk_f16_t const *b, nk_size_t n, nk_f32_t *result) {
242
+ nk_f32_t l2sq;
243
+ nk_sqeuclidean_f16_v128relaxed(a, b, n, &l2sq);
244
+ *result = nk_f32_sqrt_v128relaxed(l2sq);
245
+ }
246
+
247
+ NK_PUBLIC void nk_angular_f16_v128relaxed(nk_f16_t const *a, nk_f16_t const *b, nk_size_t n, nk_f32_t *result) {
248
+ v128_t ab_f32x4 = wasm_f32x4_splat(0.0f);
249
+ v128_t a2_f32x4 = wasm_f32x4_splat(0.0f);
250
+ v128_t b2_f32x4 = wasm_f32x4_splat(0.0f);
251
+ nk_f16_t const *a_scalars = a, *b_scalars = b;
252
+ nk_size_t count_scalars = n;
253
+ nk_b64_vec_t a_f16_vec, b_f16_vec;
254
+
255
+ nk_angular_f16_v128relaxed_cycle:
256
+ if (count_scalars < 4) {
257
+ nk_partial_load_b16x4_serial_(a_scalars, &a_f16_vec, count_scalars);
258
+ nk_partial_load_b16x4_serial_(b_scalars, &b_f16_vec, count_scalars);
259
+ count_scalars = 0;
260
+ }
261
+ else {
262
+ nk_load_b64_serial_(a_scalars, &a_f16_vec);
263
+ nk_load_b64_serial_(b_scalars, &b_f16_vec);
264
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
265
+ }
266
+
267
+ // Convert f16 → f32
268
+ nk_b128_vec_t a_f32_vec = nk_f16x4_to_f32x4_v128relaxed_(a_f16_vec);
269
+ nk_b128_vec_t b_f32_vec = nk_f16x4_to_f32x4_v128relaxed_(b_f16_vec);
270
+
271
+ // Triple accumulation: ab, a², b²
272
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, b_f32_vec.v128, ab_f32x4);
273
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, a_f32_vec.v128, a2_f32x4);
274
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_f32_vec.v128, b_f32_vec.v128, b2_f32x4);
275
+
276
+ if (count_scalars) goto nk_angular_f16_v128relaxed_cycle;
277
+
278
+ // Reduce accumulators
279
+ nk_f32_t ab = nk_reduce_add_f32x4_v128relaxed_(ab_f32x4);
280
+ nk_f32_t a2 = nk_reduce_add_f32x4_v128relaxed_(a2_f32x4);
281
+ nk_f32_t b2 = nk_reduce_add_f32x4_v128relaxed_(b2_f32x4);
282
+
283
+ // Normalize using f64 helper (handles edge cases: zero vectors, perpendicular, clamping)
284
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_((nk_f64_t)ab, (nk_f64_t)a2, (nk_f64_t)b2);
285
+ }
286
+
287
+ NK_PUBLIC void nk_sqeuclidean_bf16_v128relaxed(nk_bf16_t const *a, nk_bf16_t const *b, nk_size_t n, nk_f32_t *result) {
288
+ v128_t sum_f32x4 = wasm_f32x4_splat(0.0f);
289
+ v128_t mask_high_u32x4 = wasm_i32x4_splat((int)0xFFFF0000);
290
+ nk_bf16_t const *a_scalars = a, *b_scalars = b;
291
+ nk_size_t count_scalars = n;
292
+ nk_b128_vec_t a_bf16_vec, b_bf16_vec;
293
+
294
+ nk_sqeuclidean_bf16_v128relaxed_cycle:
295
+ if (count_scalars < 8) {
296
+ nk_partial_load_b16x8_serial_(a_scalars, &a_bf16_vec, count_scalars);
297
+ nk_partial_load_b16x8_serial_(b_scalars, &b_bf16_vec, count_scalars);
298
+ count_scalars = 0;
299
+ }
300
+ else {
301
+ nk_load_b128_v128relaxed_(a_scalars, &a_bf16_vec);
302
+ nk_load_b128_v128relaxed_(b_scalars, &b_bf16_vec);
303
+ a_scalars += 8, b_scalars += 8, count_scalars -= 8;
304
+ }
305
+ v128_t a_even_f32x4 = wasm_i32x4_shl(a_bf16_vec.v128, 16);
306
+ v128_t b_even_f32x4 = wasm_i32x4_shl(b_bf16_vec.v128, 16);
307
+ v128_t diff_even_f32x4 = wasm_f32x4_sub(a_even_f32x4, b_even_f32x4);
308
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_even_f32x4, diff_even_f32x4, sum_f32x4);
309
+ v128_t a_odd_f32x4 = wasm_v128_and(a_bf16_vec.v128, mask_high_u32x4);
310
+ v128_t b_odd_f32x4 = wasm_v128_and(b_bf16_vec.v128, mask_high_u32x4);
311
+ v128_t diff_odd_f32x4 = wasm_f32x4_sub(a_odd_f32x4, b_odd_f32x4);
312
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_odd_f32x4, diff_odd_f32x4, sum_f32x4);
313
+ if (count_scalars) goto nk_sqeuclidean_bf16_v128relaxed_cycle;
314
+
315
+ *result = nk_reduce_add_f32x4_v128relaxed_(sum_f32x4);
316
+ }
317
+
318
+ NK_PUBLIC void nk_euclidean_bf16_v128relaxed(nk_bf16_t const *a, nk_bf16_t const *b, nk_size_t n, nk_f32_t *result) {
319
+ nk_f32_t l2sq;
320
+ nk_sqeuclidean_bf16_v128relaxed(a, b, n, &l2sq);
321
+ *result = nk_f32_sqrt_v128relaxed(l2sq);
322
+ }
323
+
324
+ NK_PUBLIC void nk_angular_bf16_v128relaxed(nk_bf16_t const *a, nk_bf16_t const *b, nk_size_t n, nk_f32_t *result) {
325
+ v128_t ab_f32x4 = wasm_f32x4_splat(0.0f);
326
+ v128_t a2_f32x4 = wasm_f32x4_splat(0.0f);
327
+ v128_t b2_f32x4 = wasm_f32x4_splat(0.0f);
328
+ v128_t mask_high_u32x4 = wasm_i32x4_splat((int)0xFFFF0000);
329
+ nk_bf16_t const *a_scalars = a, *b_scalars = b;
330
+ nk_size_t count_scalars = n;
331
+ nk_b128_vec_t a_bf16_vec, b_bf16_vec;
332
+
333
+ nk_angular_bf16_v128relaxed_cycle:
334
+ if (count_scalars < 8) {
335
+ nk_partial_load_b16x8_serial_(a_scalars, &a_bf16_vec, count_scalars);
336
+ nk_partial_load_b16x8_serial_(b_scalars, &b_bf16_vec, count_scalars);
337
+ count_scalars = 0;
338
+ }
339
+ else {
340
+ nk_load_b128_v128relaxed_(a_scalars, &a_bf16_vec);
341
+ nk_load_b128_v128relaxed_(b_scalars, &b_bf16_vec);
342
+ a_scalars += 8, b_scalars += 8, count_scalars -= 8;
343
+ }
344
+ v128_t a_even_f32x4 = wasm_i32x4_shl(a_bf16_vec.v128, 16);
345
+ v128_t b_even_f32x4 = wasm_i32x4_shl(b_bf16_vec.v128, 16);
346
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_even_f32x4, b_even_f32x4, ab_f32x4);
347
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_even_f32x4, a_even_f32x4, a2_f32x4);
348
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_even_f32x4, b_even_f32x4, b2_f32x4);
349
+ v128_t a_odd_f32x4 = wasm_v128_and(a_bf16_vec.v128, mask_high_u32x4);
350
+ v128_t b_odd_f32x4 = wasm_v128_and(b_bf16_vec.v128, mask_high_u32x4);
351
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_odd_f32x4, b_odd_f32x4, ab_f32x4);
352
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_odd_f32x4, a_odd_f32x4, a2_f32x4);
353
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_odd_f32x4, b_odd_f32x4, b2_f32x4);
354
+ if (count_scalars) goto nk_angular_bf16_v128relaxed_cycle;
355
+
356
+ nk_f32_t ab = nk_reduce_add_f32x4_v128relaxed_(ab_f32x4);
357
+ nk_f32_t a2 = nk_reduce_add_f32x4_v128relaxed_(a2_f32x4);
358
+ nk_f32_t b2 = nk_reduce_add_f32x4_v128relaxed_(b2_f32x4);
359
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_((nk_f64_t)ab, (nk_f64_t)a2, (nk_f64_t)b2);
360
+ }
361
+
362
+ #pragma endregion F16 and BF16 Floats
363
+ #pragma region FP8 Floats
364
+
365
+ NK_PUBLIC void nk_sqeuclidean_e4m3_v128relaxed(nk_e4m3_t const *a, nk_e4m3_t const *b, nk_size_t n, nk_f32_t *result) {
366
+ v128_t sum_f32x4 = wasm_f32x4_splat(0.0f);
367
+ nk_e4m3_t const *a_scalars = a, *b_scalars = b;
368
+ nk_size_t count_scalars = n;
369
+ nk_b32_vec_t a_raw, b_raw;
370
+
371
+ nk_sqeuclidean_e4m3_v128relaxed_cycle:
372
+ if (count_scalars < 4) {
373
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
374
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
375
+ count_scalars = 0;
376
+ }
377
+ else {
378
+ nk_load_b32_serial_(a_scalars, &a_raw);
379
+ nk_load_b32_serial_(b_scalars, &b_raw);
380
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
381
+ }
382
+ nk_b128_vec_t a_f32_vec = nk_e4m3x4_to_f32x4_v128relaxed_(a_raw);
383
+ nk_b128_vec_t b_f32_vec = nk_e4m3x4_to_f32x4_v128relaxed_(b_raw);
384
+ v128_t diff_f32x4 = wasm_f32x4_sub(a_f32_vec.v128, b_f32_vec.v128);
385
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_f32x4, diff_f32x4, sum_f32x4);
386
+ if (count_scalars) goto nk_sqeuclidean_e4m3_v128relaxed_cycle;
387
+
388
+ *result = nk_reduce_add_f32x4_v128relaxed_(sum_f32x4);
389
+ }
390
+
391
+ NK_PUBLIC void nk_euclidean_e4m3_v128relaxed(nk_e4m3_t const *a, nk_e4m3_t const *b, nk_size_t n, nk_f32_t *result) {
392
+ nk_sqeuclidean_e4m3_v128relaxed(a, b, n, result);
393
+ *result = nk_f32_sqrt_v128relaxed(*result);
394
+ }
395
+
396
+ NK_PUBLIC void nk_angular_e4m3_v128relaxed(nk_e4m3_t const *a, nk_e4m3_t const *b, nk_size_t n, nk_f32_t *result) {
397
+ v128_t ab_f32x4 = wasm_f32x4_splat(0.0f);
398
+ v128_t a2_f32x4 = wasm_f32x4_splat(0.0f);
399
+ v128_t b2_f32x4 = wasm_f32x4_splat(0.0f);
400
+ nk_e4m3_t const *a_scalars = a, *b_scalars = b;
401
+ nk_size_t count_scalars = n;
402
+ nk_b32_vec_t a_raw, b_raw;
403
+
404
+ nk_angular_e4m3_v128relaxed_cycle:
405
+ if (count_scalars < 4) {
406
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
407
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
408
+ count_scalars = 0;
409
+ }
410
+ else {
411
+ nk_load_b32_serial_(a_scalars, &a_raw);
412
+ nk_load_b32_serial_(b_scalars, &b_raw);
413
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
414
+ }
415
+ nk_b128_vec_t a_f32_vec = nk_e4m3x4_to_f32x4_v128relaxed_(a_raw);
416
+ nk_b128_vec_t b_f32_vec = nk_e4m3x4_to_f32x4_v128relaxed_(b_raw);
417
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, b_f32_vec.v128, ab_f32x4);
418
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, a_f32_vec.v128, a2_f32x4);
419
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_f32_vec.v128, b_f32_vec.v128, b2_f32x4);
420
+ if (count_scalars) goto nk_angular_e4m3_v128relaxed_cycle;
421
+
422
+ nk_f32_t ab = nk_reduce_add_f32x4_v128relaxed_(ab_f32x4);
423
+ nk_f32_t a2 = nk_reduce_add_f32x4_v128relaxed_(a2_f32x4);
424
+ nk_f32_t b2 = nk_reduce_add_f32x4_v128relaxed_(b2_f32x4);
425
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_((nk_f64_t)ab, (nk_f64_t)a2, (nk_f64_t)b2);
426
+ }
427
+
428
+ NK_PUBLIC void nk_sqeuclidean_e5m2_v128relaxed(nk_e5m2_t const *a, nk_e5m2_t const *b, nk_size_t n, nk_f32_t *result) {
429
+ v128_t sum_f32x4 = wasm_f32x4_splat(0.0f);
430
+ nk_e5m2_t const *a_scalars = a, *b_scalars = b;
431
+ nk_size_t count_scalars = n;
432
+ nk_b32_vec_t a_raw, b_raw;
433
+
434
+ nk_sqeuclidean_e5m2_v128relaxed_cycle:
435
+ if (count_scalars < 4) {
436
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
437
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
438
+ count_scalars = 0;
439
+ }
440
+ else {
441
+ nk_load_b32_serial_(a_scalars, &a_raw);
442
+ nk_load_b32_serial_(b_scalars, &b_raw);
443
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
444
+ }
445
+ nk_b128_vec_t a_f32_vec = nk_e5m2x4_to_f32x4_v128relaxed_(a_raw);
446
+ nk_b128_vec_t b_f32_vec = nk_e5m2x4_to_f32x4_v128relaxed_(b_raw);
447
+ v128_t diff_f32x4 = wasm_f32x4_sub(a_f32_vec.v128, b_f32_vec.v128);
448
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_f32x4, diff_f32x4, sum_f32x4);
449
+ if (count_scalars) goto nk_sqeuclidean_e5m2_v128relaxed_cycle;
450
+
451
+ *result = nk_reduce_add_f32x4_v128relaxed_(sum_f32x4);
452
+ }
453
+
454
+ NK_PUBLIC void nk_euclidean_e5m2_v128relaxed(nk_e5m2_t const *a, nk_e5m2_t const *b, nk_size_t n, nk_f32_t *result) {
455
+ nk_sqeuclidean_e5m2_v128relaxed(a, b, n, result);
456
+ *result = nk_f32_sqrt_v128relaxed(*result);
457
+ }
458
+
459
+ NK_PUBLIC void nk_angular_e5m2_v128relaxed(nk_e5m2_t const *a, nk_e5m2_t const *b, nk_size_t n, nk_f32_t *result) {
460
+ v128_t ab_f32x4 = wasm_f32x4_splat(0.0f);
461
+ v128_t a2_f32x4 = wasm_f32x4_splat(0.0f);
462
+ v128_t b2_f32x4 = wasm_f32x4_splat(0.0f);
463
+ nk_e5m2_t const *a_scalars = a, *b_scalars = b;
464
+ nk_size_t count_scalars = n;
465
+ nk_b32_vec_t a_raw, b_raw;
466
+
467
+ nk_angular_e5m2_v128relaxed_cycle:
468
+ if (count_scalars < 4) {
469
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
470
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
471
+ count_scalars = 0;
472
+ }
473
+ else {
474
+ nk_load_b32_serial_(a_scalars, &a_raw);
475
+ nk_load_b32_serial_(b_scalars, &b_raw);
476
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
477
+ }
478
+ nk_b128_vec_t a_f32_vec = nk_e5m2x4_to_f32x4_v128relaxed_(a_raw);
479
+ nk_b128_vec_t b_f32_vec = nk_e5m2x4_to_f32x4_v128relaxed_(b_raw);
480
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, b_f32_vec.v128, ab_f32x4);
481
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, a_f32_vec.v128, a2_f32x4);
482
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_f32_vec.v128, b_f32_vec.v128, b2_f32x4);
483
+ if (count_scalars) goto nk_angular_e5m2_v128relaxed_cycle;
484
+
485
+ nk_f32_t ab = nk_reduce_add_f32x4_v128relaxed_(ab_f32x4);
486
+ nk_f32_t a2 = nk_reduce_add_f32x4_v128relaxed_(a2_f32x4);
487
+ nk_f32_t b2 = nk_reduce_add_f32x4_v128relaxed_(b2_f32x4);
488
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_((nk_f64_t)ab, (nk_f64_t)a2, (nk_f64_t)b2);
489
+ }
490
+
491
+ NK_PUBLIC void nk_sqeuclidean_e2m3_v128relaxed(nk_e2m3_t const *a, nk_e2m3_t const *b, nk_size_t n, nk_f32_t *result) {
492
+ v128_t sum_f32x4 = wasm_f32x4_splat(0.0f);
493
+ nk_e2m3_t const *a_scalars = a, *b_scalars = b;
494
+ nk_size_t count_scalars = n;
495
+ nk_b32_vec_t a_raw, b_raw;
496
+
497
+ nk_sqeuclidean_e2m3_v128relaxed_cycle:
498
+ if (count_scalars < 4) {
499
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
500
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
501
+ count_scalars = 0;
502
+ }
503
+ else {
504
+ nk_load_b32_serial_(a_scalars, &a_raw);
505
+ nk_load_b32_serial_(b_scalars, &b_raw);
506
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
507
+ }
508
+ nk_b128_vec_t a_f32_vec = nk_e2m3x4_to_f32x4_v128relaxed_(a_raw);
509
+ nk_b128_vec_t b_f32_vec = nk_e2m3x4_to_f32x4_v128relaxed_(b_raw);
510
+ v128_t diff_f32x4 = wasm_f32x4_sub(a_f32_vec.v128, b_f32_vec.v128);
511
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_f32x4, diff_f32x4, sum_f32x4);
512
+ if (count_scalars) goto nk_sqeuclidean_e2m3_v128relaxed_cycle;
513
+
514
+ *result = nk_reduce_add_f32x4_v128relaxed_(sum_f32x4);
515
+ }
516
+
517
+ NK_PUBLIC void nk_euclidean_e2m3_v128relaxed(nk_e2m3_t const *a, nk_e2m3_t const *b, nk_size_t n, nk_f32_t *result) {
518
+ nk_sqeuclidean_e2m3_v128relaxed(a, b, n, result);
519
+ *result = nk_f32_sqrt_v128relaxed(*result);
520
+ }
521
+
522
+ NK_PUBLIC void nk_angular_e2m3_v128relaxed(nk_e2m3_t const *a, nk_e2m3_t const *b, nk_size_t n, nk_f32_t *result) {
523
+ v128_t ab_f32x4 = wasm_f32x4_splat(0.0f);
524
+ v128_t a2_f32x4 = wasm_f32x4_splat(0.0f);
525
+ v128_t b2_f32x4 = wasm_f32x4_splat(0.0f);
526
+ nk_e2m3_t const *a_scalars = a, *b_scalars = b;
527
+ nk_size_t count_scalars = n;
528
+ nk_b32_vec_t a_raw, b_raw;
529
+
530
+ nk_angular_e2m3_v128relaxed_cycle:
531
+ if (count_scalars < 4) {
532
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
533
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
534
+ count_scalars = 0;
535
+ }
536
+ else {
537
+ nk_load_b32_serial_(a_scalars, &a_raw);
538
+ nk_load_b32_serial_(b_scalars, &b_raw);
539
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
540
+ }
541
+ nk_b128_vec_t a_f32_vec = nk_e2m3x4_to_f32x4_v128relaxed_(a_raw);
542
+ nk_b128_vec_t b_f32_vec = nk_e2m3x4_to_f32x4_v128relaxed_(b_raw);
543
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, b_f32_vec.v128, ab_f32x4);
544
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, a_f32_vec.v128, a2_f32x4);
545
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_f32_vec.v128, b_f32_vec.v128, b2_f32x4);
546
+ if (count_scalars) goto nk_angular_e2m3_v128relaxed_cycle;
547
+
548
+ nk_f32_t ab = nk_reduce_add_f32x4_v128relaxed_(ab_f32x4);
549
+ nk_f32_t a2 = nk_reduce_add_f32x4_v128relaxed_(a2_f32x4);
550
+ nk_f32_t b2 = nk_reduce_add_f32x4_v128relaxed_(b2_f32x4);
551
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_((nk_f64_t)ab, (nk_f64_t)a2, (nk_f64_t)b2);
552
+ }
553
+
554
+ NK_PUBLIC void nk_sqeuclidean_e3m2_v128relaxed(nk_e3m2_t const *a, nk_e3m2_t const *b, nk_size_t n, nk_f32_t *result) {
555
+ v128_t sum_f32x4 = wasm_f32x4_splat(0.0f);
556
+ nk_e3m2_t const *a_scalars = a, *b_scalars = b;
557
+ nk_size_t count_scalars = n;
558
+ nk_b32_vec_t a_raw, b_raw;
559
+
560
+ nk_sqeuclidean_e3m2_v128relaxed_cycle:
561
+ if (count_scalars < 4) {
562
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
563
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
564
+ count_scalars = 0;
565
+ }
566
+ else {
567
+ nk_load_b32_serial_(a_scalars, &a_raw);
568
+ nk_load_b32_serial_(b_scalars, &b_raw);
569
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
570
+ }
571
+ nk_b128_vec_t a_f32_vec = nk_e3m2x4_to_f32x4_v128relaxed_(a_raw);
572
+ nk_b128_vec_t b_f32_vec = nk_e3m2x4_to_f32x4_v128relaxed_(b_raw);
573
+ v128_t diff_f32x4 = wasm_f32x4_sub(a_f32_vec.v128, b_f32_vec.v128);
574
+ sum_f32x4 = wasm_f32x4_relaxed_madd(diff_f32x4, diff_f32x4, sum_f32x4);
575
+ if (count_scalars) goto nk_sqeuclidean_e3m2_v128relaxed_cycle;
576
+
577
+ *result = nk_reduce_add_f32x4_v128relaxed_(sum_f32x4);
578
+ }
579
+
580
+ NK_PUBLIC void nk_euclidean_e3m2_v128relaxed(nk_e3m2_t const *a, nk_e3m2_t const *b, nk_size_t n, nk_f32_t *result) {
581
+ nk_sqeuclidean_e3m2_v128relaxed(a, b, n, result);
582
+ *result = nk_f32_sqrt_v128relaxed(*result);
583
+ }
584
+
585
+ NK_PUBLIC void nk_angular_e3m2_v128relaxed(nk_e3m2_t const *a, nk_e3m2_t const *b, nk_size_t n, nk_f32_t *result) {
586
+ v128_t ab_f32x4 = wasm_f32x4_splat(0.0f);
587
+ v128_t a2_f32x4 = wasm_f32x4_splat(0.0f);
588
+ v128_t b2_f32x4 = wasm_f32x4_splat(0.0f);
589
+ nk_e3m2_t const *a_scalars = a, *b_scalars = b;
590
+ nk_size_t count_scalars = n;
591
+ nk_b32_vec_t a_raw, b_raw;
592
+
593
+ nk_angular_e3m2_v128relaxed_cycle:
594
+ if (count_scalars < 4) {
595
+ a_raw = nk_partial_load_b8x4_serial_(a_scalars, count_scalars);
596
+ b_raw = nk_partial_load_b8x4_serial_(b_scalars, count_scalars);
597
+ count_scalars = 0;
598
+ }
599
+ else {
600
+ nk_load_b32_serial_(a_scalars, &a_raw);
601
+ nk_load_b32_serial_(b_scalars, &b_raw);
602
+ a_scalars += 4, b_scalars += 4, count_scalars -= 4;
603
+ }
604
+ nk_b128_vec_t a_f32_vec = nk_e3m2x4_to_f32x4_v128relaxed_(a_raw);
605
+ nk_b128_vec_t b_f32_vec = nk_e3m2x4_to_f32x4_v128relaxed_(b_raw);
606
+ ab_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, b_f32_vec.v128, ab_f32x4);
607
+ a2_f32x4 = wasm_f32x4_relaxed_madd(a_f32_vec.v128, a_f32_vec.v128, a2_f32x4);
608
+ b2_f32x4 = wasm_f32x4_relaxed_madd(b_f32_vec.v128, b_f32_vec.v128, b2_f32x4);
609
+ if (count_scalars) goto nk_angular_e3m2_v128relaxed_cycle;
610
+
611
+ nk_f32_t ab = nk_reduce_add_f32x4_v128relaxed_(ab_f32x4);
612
+ nk_f32_t a2 = nk_reduce_add_f32x4_v128relaxed_(a2_f32x4);
613
+ nk_f32_t b2 = nk_reduce_add_f32x4_v128relaxed_(b2_f32x4);
614
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_((nk_f64_t)ab, (nk_f64_t)a2, (nk_f64_t)b2);
615
+ }
616
+
617
+ #pragma endregion FP8 Floats
618
+ #pragma region Spatial From Dot Helpers
619
+
620
+ /** @brief Angular from_dot: computes 1 − dot / √(query_sumsq × target_sumsq) for 4 pairs in f32. */
621
+ NK_INTERNAL void nk_angular_through_f32_from_dot_v128relaxed_(nk_b128_vec_t dots, nk_f32_t query_sumsq,
622
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
623
+ v128_t dots_f32x4 = dots.v128;
624
+ v128_t query_sumsq_f32x4 = wasm_f32x4_splat(query_sumsq);
625
+ v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, target_sumsqs.v128);
626
+ v128_t sqrt_products_f32x4 = wasm_f32x4_sqrt(products_f32x4);
627
+ v128_t normalized_f32x4 = wasm_f32x4_div(dots_f32x4, sqrt_products_f32x4);
628
+ v128_t angular_f32x4 = wasm_f32x4_sub(wasm_f32x4_splat(1.0f), normalized_f32x4);
629
+ results->v128 = wasm_f32x4_max(angular_f32x4, wasm_f32x4_splat(0.0f));
630
+ }
631
+
632
+ /** @brief Euclidean from_dot: computes √(query_sumsq + target_sumsq − 2 × dot) for 4 pairs in f32. */
633
+ NK_INTERNAL void nk_euclidean_through_f32_from_dot_v128relaxed_(nk_b128_vec_t dots, nk_f32_t query_sumsq,
634
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
635
+ v128_t dots_f32x4 = dots.v128;
636
+ v128_t query_sumsq_f32x4 = wasm_f32x4_splat(query_sumsq);
637
+ v128_t two_f32x4 = wasm_f32x4_splat(2.0f);
638
+ v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, target_sumsqs.v128);
639
+ v128_t dist_sq_f32x4 = wasm_f32x4_relaxed_nmadd(two_f32x4, dots_f32x4, sum_sq_f32x4);
640
+ dist_sq_f32x4 = wasm_f32x4_max(dist_sq_f32x4, wasm_f32x4_splat(0.0f));
641
+ results->v128 = wasm_f32x4_sqrt(dist_sq_f32x4);
642
+ }
643
+
644
+ /** @brief Angular from_dot for i32 accumulators: cast to f32, then angular normalization. 4 pairs. */
645
+ NK_INTERNAL void nk_angular_through_i32_from_dot_v128relaxed_(nk_b128_vec_t dots, nk_i32_t query_sumsq,
646
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
647
+ v128_t dots_f32x4 = wasm_f32x4_convert_i32x4(dots.v128);
648
+ v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
649
+ v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, wasm_f32x4_convert_i32x4(target_sumsqs.v128));
650
+ v128_t sqrt_products_f32x4 = wasm_f32x4_sqrt(products_f32x4);
651
+ v128_t normalized_f32x4 = wasm_f32x4_div(dots_f32x4, sqrt_products_f32x4);
652
+ v128_t angular_f32x4 = wasm_f32x4_sub(wasm_f32x4_splat(1.0f), normalized_f32x4);
653
+ results->v128 = wasm_f32x4_max(angular_f32x4, wasm_f32x4_splat(0.0f));
654
+ }
655
+
656
+ /** @brief Euclidean from_dot for i32 accumulators: cast to f32, then √(a² + b² − 2ab). 4 pairs. */
657
+ NK_INTERNAL void nk_euclidean_through_i32_from_dot_v128relaxed_(nk_b128_vec_t dots, nk_i32_t query_sumsq,
658
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
659
+ v128_t dots_f32x4 = wasm_f32x4_convert_i32x4(dots.v128);
660
+ v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
661
+ v128_t two_f32x4 = wasm_f32x4_splat(2.0f);
662
+ v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, wasm_f32x4_convert_i32x4(target_sumsqs.v128));
663
+ v128_t dist_sq_f32x4 = wasm_f32x4_relaxed_nmadd(two_f32x4, dots_f32x4, sum_sq_f32x4);
664
+ dist_sq_f32x4 = wasm_f32x4_max(dist_sq_f32x4, wasm_f32x4_splat(0.0f));
665
+ results->v128 = wasm_f32x4_sqrt(dist_sq_f32x4);
666
+ }
667
+
668
+ /** @brief Angular from_dot for u32 accumulators: cast to f32, then angular normalization. 4 pairs. */
669
+ NK_INTERNAL void nk_angular_through_u32_from_dot_v128relaxed_(nk_b128_vec_t dots, nk_u32_t query_sumsq,
670
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
671
+ v128_t dots_f32x4 = wasm_f32x4_convert_u32x4(dots.v128);
672
+ v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
673
+ v128_t products_f32x4 = wasm_f32x4_mul(query_sumsq_f32x4, wasm_f32x4_convert_u32x4(target_sumsqs.v128));
674
+ v128_t sqrt_products_f32x4 = wasm_f32x4_sqrt(products_f32x4);
675
+ v128_t normalized_f32x4 = wasm_f32x4_div(dots_f32x4, sqrt_products_f32x4);
676
+ v128_t angular_f32x4 = wasm_f32x4_sub(wasm_f32x4_splat(1.0f), normalized_f32x4);
677
+ results->v128 = wasm_f32x4_max(angular_f32x4, wasm_f32x4_splat(0.0f));
678
+ }
679
+
680
+ /** @brief Euclidean from_dot for u32 accumulators: cast to f32, then √(a² + b² − 2ab). 4 pairs. */
681
+ NK_INTERNAL void nk_euclidean_through_u32_from_dot_v128relaxed_(nk_b128_vec_t dots, nk_u32_t query_sumsq,
682
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
683
+ v128_t dots_f32x4 = wasm_f32x4_convert_u32x4(dots.v128);
684
+ v128_t query_sumsq_f32x4 = wasm_f32x4_splat((nk_f32_t)query_sumsq);
685
+ v128_t two_f32x4 = wasm_f32x4_splat(2.0f);
686
+ v128_t sum_sq_f32x4 = wasm_f32x4_add(query_sumsq_f32x4, wasm_f32x4_convert_u32x4(target_sumsqs.v128));
687
+ v128_t dist_sq_f32x4 = wasm_f32x4_relaxed_nmadd(two_f32x4, dots_f32x4, sum_sq_f32x4);
688
+ dist_sq_f32x4 = wasm_f32x4_max(dist_sq_f32x4, wasm_f32x4_splat(0.0f));
689
+ results->v128 = wasm_f32x4_sqrt(dist_sq_f32x4);
690
+ }
691
+
692
+ #pragma endregion Spatial From Dot Helpers
693
+ #pragma region I8 and U8 Integers
694
+
695
+ NK_PUBLIC void nk_sqeuclidean_u8_v128relaxed(nk_u8_t const *a, nk_u8_t const *b, nk_size_t n, nk_u32_t *result) {
696
+ v128_t sum_u32x4 = wasm_u32x4_splat(0);
697
+ nk_u8_t const *a_scalars = a, *b_scalars = b;
698
+ nk_size_t count_scalars = n;
699
+ v128_t a_u8x16, b_u8x16;
700
+
701
+ nk_sqeuclidean_u8_v128relaxed_cycle:
702
+ if (count_scalars < 16) {
703
+ nk_b128_vec_t a_vec = {0}, b_vec = {0};
704
+ nk_partial_load_b8x16_serial_(a_scalars, &a_vec, count_scalars);
705
+ nk_partial_load_b8x16_serial_(b_scalars, &b_vec, count_scalars);
706
+ a_u8x16 = a_vec.v128;
707
+ b_u8x16 = b_vec.v128;
708
+ count_scalars = 0;
709
+ }
710
+ else {
711
+ a_u8x16 = wasm_v128_load(a_scalars);
712
+ b_u8x16 = wasm_v128_load(b_scalars);
713
+ a_scalars += 16, b_scalars += 16, count_scalars -= 16;
714
+ }
715
+
716
+ // |a-b| via saturating subtraction: diff = (a ⊖ b) | (b ⊖ a)
717
+ v128_t difference_u8x16 = wasm_v128_or(wasm_u8x16_sub_sat(a_u8x16, b_u8x16), wasm_u8x16_sub_sat(b_u8x16, a_u8x16));
718
+
719
+ // Widen to u16 and square via extmul
720
+ v128_t difference_low_u16x8 = wasm_u16x8_extend_low_u8x16(difference_u8x16);
721
+ v128_t difference_high_u16x8 = wasm_u16x8_extend_high_u8x16(difference_u8x16);
722
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_low_i16x8(difference_low_u16x8, difference_low_u16x8));
723
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_high_i16x8(difference_low_u16x8, difference_low_u16x8));
724
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_low_i16x8(difference_high_u16x8, difference_high_u16x8));
725
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_high_i16x8(difference_high_u16x8, difference_high_u16x8));
726
+ if (count_scalars) goto nk_sqeuclidean_u8_v128relaxed_cycle;
727
+
728
+ *result = nk_reduce_add_u32x4_v128relaxed_(sum_u32x4);
729
+ }
730
+
731
+ NK_PUBLIC void nk_euclidean_u8_v128relaxed(nk_u8_t const *a, nk_u8_t const *b, nk_size_t n, nk_f32_t *result) {
732
+ nk_u32_t distance_squared;
733
+ nk_sqeuclidean_u8_v128relaxed(a, b, n, &distance_squared);
734
+ *result = nk_f32_sqrt_v128relaxed((nk_f32_t)distance_squared);
735
+ }
736
+
737
+ NK_PUBLIC void nk_angular_u8_v128relaxed(nk_u8_t const *a, nk_u8_t const *b, nk_size_t n, nk_f32_t *result) {
738
+ // Bias u8 [0,255] → i8 [-128,127] via XOR 0x80, then use the i8 magnitude+sign
739
+ // decomposition for saturation-safe relaxed_dot.
740
+ //
741
+ // The XOR-only approach (passing raw u8 as first operand) causes vpmaddubsw saturation:
742
+ // u8*i8 pairwise sums can reach 64770, exceeding i16 max (32767).
743
+ // Biasing first ensures i8*u7 products stay in [-16256, 16129], pairs in [-32512, 32258].
744
+ //
745
+ // Let a' = a - 128, b' = b - 128 (via XOR 0x80).
746
+ // Compute biased dots via relaxed_dot with i7 magnitude trick:
747
+ // a'·b' = relaxed_dot(a', b'&0x7F) - 128·Σ(a'[i] where b'[i]<0)
748
+ // Then recover true unsigned dots:
749
+ // a·b = a'·b' + 128·(Σa + Σb) - n·16384
750
+ // a·a = a'·a' + 256·Σa - n·16384
751
+ // b·b = b'·b' + 256·Σb - n·16384
752
+ nk_i64_t biased_ab = 0, biased_aa = 0, biased_bb = 0;
753
+ nk_i64_t sum_a_total = 0, sum_b_total = 0;
754
+ nk_size_t i = 0;
755
+
756
+ // Windowed accumulation loop
757
+ while (i + 16 <= n) {
758
+ v128_t dot_ab_i32x4 = wasm_i32x4_splat(0);
759
+ v128_t dot_aa_i32x4 = wasm_i32x4_splat(0);
760
+ v128_t dot_bb_i32x4 = wasm_i32x4_splat(0);
761
+ v128_t corr_ab_i16x8 = wasm_i16x8_splat(0);
762
+ v128_t corr_aa_i16x8 = wasm_i16x8_splat(0);
763
+ v128_t corr_bb_i16x8 = wasm_i16x8_splat(0);
764
+ v128_t sum_a_u16x8 = wasm_u16x8_splat(0);
765
+ v128_t sum_b_u16x8 = wasm_u16x8_splat(0);
766
+
767
+ // Inner loop: accumulate 127 iterations before widening corrections
768
+ // Overflow safety: max i16 lane = 127 × 254 = 32258 < 32767
769
+ nk_size_t cycle = 0;
770
+ for (; cycle < 127 && i + 16 <= n; ++cycle, i += 16) {
771
+ v128_t a_u8x16 = wasm_v128_load(a + i);
772
+ v128_t b_u8x16 = wasm_v128_load(b + i);
773
+
774
+ // Bias to signed: a' = a ^ 0x80, b' = b ^ 0x80
775
+ v128_t a_i8x16 = wasm_v128_xor(a_u8x16, wasm_i8x16_splat((char)0x80));
776
+ v128_t b_i8x16 = wasm_v128_xor(b_u8x16, wasm_i8x16_splat((char)0x80));
777
+
778
+ // Clear sign bit to get 7-bit unsigned magnitudes
779
+ v128_t a_7bit_u8x16 = wasm_v128_and(a_i8x16, wasm_i8x16_splat(0x7F));
780
+ v128_t b_7bit_u8x16 = wasm_v128_and(b_i8x16, wasm_i8x16_splat(0x7F));
781
+
782
+ // Negative masks for correction
783
+ v128_t a_neg_mask_i8x16 = wasm_i8x16_lt(a_i8x16, wasm_i8x16_splat(0));
784
+ v128_t b_neg_mask_i8x16 = wasm_i8x16_lt(b_i8x16, wasm_i8x16_splat(0));
785
+
786
+ // Three relaxed_dot calls on biased values
787
+ dot_ab_i32x4 = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(a_i8x16, b_7bit_u8x16, dot_ab_i32x4);
788
+ dot_aa_i32x4 = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(a_i8x16, a_7bit_u8x16, dot_aa_i32x4);
789
+ dot_bb_i32x4 = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(b_i8x16, b_7bit_u8x16, dot_bb_i32x4);
790
+
791
+ // Accumulate corrections in i16 (1 widening/iter instead of 2)
792
+ v128_t a_where_b_neg = wasm_v128_and(a_i8x16, b_neg_mask_i8x16);
793
+ v128_t a_where_a_neg = wasm_v128_and(a_i8x16, a_neg_mask_i8x16);
794
+ v128_t b_where_b_neg = wasm_v128_and(b_i8x16, b_neg_mask_i8x16);
795
+ corr_ab_i16x8 = wasm_i16x8_add(corr_ab_i16x8, wasm_i16x8_extadd_pairwise_i8x16(a_where_b_neg));
796
+ corr_aa_i16x8 = wasm_i16x8_add(corr_aa_i16x8, wasm_i16x8_extadd_pairwise_i8x16(a_where_a_neg));
797
+ corr_bb_i16x8 = wasm_i16x8_add(corr_bb_i16x8, wasm_i16x8_extadd_pairwise_i8x16(b_where_b_neg));
798
+
799
+ // Unsigned sums for final unbias correction
800
+ sum_a_u16x8 = wasm_i16x8_add(sum_a_u16x8, wasm_u16x8_extadd_pairwise_u8x16(a_u8x16));
801
+ sum_b_u16x8 = wasm_i16x8_add(sum_b_u16x8, wasm_u16x8_extadd_pairwise_u8x16(b_u8x16));
802
+ }
803
+
804
+ // Deferred widening: i16/u16 → i32/u32 once per window
805
+ v128_t corr_ab_i32x4 = wasm_i32x4_extadd_pairwise_i16x8(corr_ab_i16x8);
806
+ v128_t corr_aa_i32x4 = wasm_i32x4_extadd_pairwise_i16x8(corr_aa_i16x8);
807
+ v128_t corr_bb_i32x4 = wasm_i32x4_extadd_pairwise_i16x8(corr_bb_i16x8);
808
+ v128_t sum_a_u32x4 = wasm_u32x4_extadd_pairwise_u16x8(sum_a_u16x8);
809
+ v128_t sum_b_u32x4 = wasm_u32x4_extadd_pairwise_u16x8(sum_b_u16x8);
810
+ biased_ab += nk_reduce_add_i32x4_v128relaxed_(dot_ab_i32x4) -
811
+ 128LL * nk_reduce_add_i32x4_v128relaxed_(corr_ab_i32x4);
812
+ biased_aa += nk_reduce_add_i32x4_v128relaxed_(dot_aa_i32x4) -
813
+ 128LL * nk_reduce_add_i32x4_v128relaxed_(corr_aa_i32x4);
814
+ biased_bb += nk_reduce_add_i32x4_v128relaxed_(dot_bb_i32x4) -
815
+ 128LL * nk_reduce_add_i32x4_v128relaxed_(corr_bb_i32x4);
816
+ sum_a_total += nk_reduce_add_u32x4_v128relaxed_(sum_a_u32x4);
817
+ sum_b_total += nk_reduce_add_u32x4_v128relaxed_(sum_b_u32x4);
818
+ }
819
+
820
+ // Scalar tail: compute biased products directly
821
+ for (; i < n; i++) {
822
+ nk_i32_t a_biased = (nk_i32_t)a[i] - 128;
823
+ nk_i32_t b_biased = (nk_i32_t)b[i] - 128;
824
+ biased_ab += (nk_i64_t)a_biased * b_biased;
825
+ biased_aa += (nk_i64_t)a_biased * a_biased;
826
+ biased_bb += (nk_i64_t)b_biased * b_biased;
827
+ sum_a_total += a[i];
828
+ sum_b_total += b[i];
829
+ }
830
+
831
+ // Recover true unsigned dots from biased:
832
+ // a·b = (a-128)·(b-128) + 128·Σa + 128·Σb - n·16384
833
+ // a·a = (a-128)·(a-128) + 256·Σa - n·16384
834
+ // b·b = (b-128)·(b-128) + 256·Σb - n·16384
835
+ nk_i64_t n_correction = (nk_i64_t)n * 16384LL;
836
+ nk_f64_t dot_ab = (nk_f64_t)(biased_ab + 128LL * (sum_a_total + sum_b_total) - n_correction);
837
+ nk_f64_t norm_aa = (nk_f64_t)(biased_aa + 256LL * sum_a_total - n_correction);
838
+ nk_f64_t norm_bb = (nk_f64_t)(biased_bb + 256LL * sum_b_total - n_correction);
839
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_(dot_ab, norm_aa, norm_bb);
840
+ }
841
+
842
+ NK_PUBLIC void nk_sqeuclidean_i8_v128relaxed(nk_i8_t const *a, nk_i8_t const *b, nk_size_t n, nk_u32_t *result) {
843
+ // XOR with 0x80 to reinterpret signed as unsigned, then use unsigned algorithm.
844
+ // |a-b|² is invariant under this uniform offset.
845
+ v128_t sum_u32x4 = wasm_u32x4_splat(0);
846
+ v128_t bias_u8x16 = wasm_u8x16_splat(0x80);
847
+ nk_i8_t const *a_scalars = a, *b_scalars = b;
848
+ nk_size_t count_scalars = n;
849
+ v128_t a_u8x16, b_u8x16;
850
+
851
+ nk_sqeuclidean_i8_v128relaxed_cycle:
852
+ if (count_scalars < 16) {
853
+ nk_b128_vec_t a_vec = {0}, b_vec = {0};
854
+ nk_partial_load_b8x16_serial_(a_scalars, &a_vec, count_scalars);
855
+ nk_partial_load_b8x16_serial_(b_scalars, &b_vec, count_scalars);
856
+ a_u8x16 = wasm_v128_xor(a_vec.v128, bias_u8x16);
857
+ b_u8x16 = wasm_v128_xor(b_vec.v128, bias_u8x16);
858
+ count_scalars = 0;
859
+ }
860
+ else {
861
+ a_u8x16 = wasm_v128_xor(wasm_v128_load(a_scalars), bias_u8x16);
862
+ b_u8x16 = wasm_v128_xor(wasm_v128_load(b_scalars), bias_u8x16);
863
+ a_scalars += 16, b_scalars += 16, count_scalars -= 16;
864
+ }
865
+
866
+ v128_t difference_u8x16 = wasm_v128_or(wasm_u8x16_sub_sat(a_u8x16, b_u8x16), wasm_u8x16_sub_sat(b_u8x16, a_u8x16));
867
+ v128_t difference_low_u16x8 = wasm_u16x8_extend_low_u8x16(difference_u8x16);
868
+ v128_t difference_high_u16x8 = wasm_u16x8_extend_high_u8x16(difference_u8x16);
869
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_low_i16x8(difference_low_u16x8, difference_low_u16x8));
870
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_high_i16x8(difference_low_u16x8, difference_low_u16x8));
871
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_low_i16x8(difference_high_u16x8, difference_high_u16x8));
872
+ sum_u32x4 = wasm_i32x4_add(sum_u32x4, wasm_i32x4_extmul_high_i16x8(difference_high_u16x8, difference_high_u16x8));
873
+ if (count_scalars) goto nk_sqeuclidean_i8_v128relaxed_cycle;
874
+
875
+ *result = nk_reduce_add_u32x4_v128relaxed_(sum_u32x4);
876
+ }
877
+
878
+ NK_PUBLIC void nk_euclidean_i8_v128relaxed(nk_i8_t const *a, nk_i8_t const *b, nk_size_t n, nk_f32_t *result) {
879
+ nk_u32_t distance_squared;
880
+ nk_sqeuclidean_i8_v128relaxed(a, b, n, &distance_squared);
881
+ *result = nk_f32_sqrt_v128relaxed((nk_f32_t)distance_squared);
882
+ }
883
+
884
+ NK_PUBLIC void nk_angular_i8_v128relaxed(nk_i8_t const *a, nk_i8_t const *b, nk_size_t n, nk_f32_t *result) {
885
+ // Uses the same relaxed_dot decomposition as nk_dot_i8_v128relaxed:
886
+ // a·b = relaxed_dot(a, b&0x7F) - 128·Σ(a[i] where b[i]<0)
887
+ // a·a = relaxed_dot(a, a&0x7F) - 128·Σ(a[i] where a[i]<0)
888
+ // b·b = relaxed_dot(b, b&0x7F) - 128·Σ(b[i] where b[i]<0)
889
+ nk_i64_t dot_ab_total = 0, dot_aa_total = 0, dot_bb_total = 0;
890
+ nk_i64_t corr_ab_total = 0, corr_aa_total = 0, corr_bb_total = 0;
891
+ nk_size_t i = 0;
892
+
893
+ // Windowed accumulation loop
894
+ while (i + 16 <= n) {
895
+ v128_t dot_ab_i32x4 = wasm_i32x4_splat(0);
896
+ v128_t dot_aa_i32x4 = wasm_i32x4_splat(0);
897
+ v128_t dot_bb_i32x4 = wasm_i32x4_splat(0);
898
+ v128_t corr_ab_i16x8 = wasm_i16x8_splat(0); // accumulate corrections in i16
899
+ v128_t corr_aa_i16x8 = wasm_i16x8_splat(0);
900
+ v128_t corr_bb_i16x8 = wasm_i16x8_splat(0);
901
+
902
+ // Inner loop: accumulate 127 iterations before widening corrections
903
+ // Overflow safety: max i16 lane magnitude = 127 × 254 = 32258 < 32767
904
+ nk_size_t cycle = 0;
905
+ for (; cycle < 127 && i + 16 <= n; ++cycle, i += 16) {
906
+ v128_t a_i8x16 = wasm_v128_load(a + i);
907
+ v128_t b_i8x16 = wasm_v128_load(b + i);
908
+
909
+ // Clear sign bit to get 7-bit unsigned magnitudes
910
+ v128_t a_7bit_u8x16 = wasm_v128_and(a_i8x16, wasm_i8x16_splat(0x7F));
911
+ v128_t b_7bit_u8x16 = wasm_v128_and(b_i8x16, wasm_i8x16_splat(0x7F));
912
+
913
+ // Negative masks for correction
914
+ v128_t a_neg_mask_i8x16 = wasm_i8x16_lt(a_i8x16, wasm_i8x16_splat(0));
915
+ v128_t b_neg_mask_i8x16 = wasm_i8x16_lt(b_i8x16, wasm_i8x16_splat(0));
916
+
917
+ // Three relaxed_dot calls
918
+ dot_ab_i32x4 = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(a_i8x16, b_7bit_u8x16, dot_ab_i32x4);
919
+ dot_aa_i32x4 = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(a_i8x16, a_7bit_u8x16, dot_aa_i32x4);
920
+ dot_bb_i32x4 = wasm_i32x4_relaxed_dot_i8x16_i7x16_add(b_i8x16, b_7bit_u8x16, dot_bb_i32x4);
921
+
922
+ // Accumulate corrections in i16 (1 widening/iter instead of 2)
923
+ v128_t a_where_b_neg = wasm_v128_and(a_i8x16, b_neg_mask_i8x16);
924
+ v128_t a_where_a_neg = wasm_v128_and(a_i8x16, a_neg_mask_i8x16);
925
+ v128_t b_where_b_neg = wasm_v128_and(b_i8x16, b_neg_mask_i8x16);
926
+ corr_ab_i16x8 = wasm_i16x8_add(corr_ab_i16x8, wasm_i16x8_extadd_pairwise_i8x16(a_where_b_neg));
927
+ corr_aa_i16x8 = wasm_i16x8_add(corr_aa_i16x8, wasm_i16x8_extadd_pairwise_i8x16(a_where_a_neg));
928
+ corr_bb_i16x8 = wasm_i16x8_add(corr_bb_i16x8, wasm_i16x8_extadd_pairwise_i8x16(b_where_b_neg));
929
+ }
930
+
931
+ // Deferred widening: i16 → i32 once per window
932
+ v128_t corr_ab_i32x4 = wasm_i32x4_extadd_pairwise_i16x8(corr_ab_i16x8);
933
+ v128_t corr_aa_i32x4 = wasm_i32x4_extadd_pairwise_i16x8(corr_aa_i16x8);
934
+ v128_t corr_bb_i32x4 = wasm_i32x4_extadd_pairwise_i16x8(corr_bb_i16x8);
935
+ dot_ab_total += nk_reduce_add_i32x4_v128relaxed_(dot_ab_i32x4);
936
+ dot_aa_total += nk_reduce_add_i32x4_v128relaxed_(dot_aa_i32x4);
937
+ dot_bb_total += nk_reduce_add_i32x4_v128relaxed_(dot_bb_i32x4);
938
+ corr_ab_total += nk_reduce_add_i32x4_v128relaxed_(corr_ab_i32x4);
939
+ corr_aa_total += nk_reduce_add_i32x4_v128relaxed_(corr_aa_i32x4);
940
+ corr_bb_total += nk_reduce_add_i32x4_v128relaxed_(corr_bb_i32x4);
941
+ }
942
+
943
+ // Scalar tail
944
+ for (; i < n; i++) {
945
+ dot_ab_total += (nk_i32_t)a[i] * (nk_i32_t)b[i];
946
+ dot_aa_total += (nk_i32_t)a[i] * (nk_i32_t)a[i];
947
+ dot_bb_total += (nk_i32_t)b[i] * (nk_i32_t)b[i];
948
+ }
949
+
950
+ // Apply correction: true_dot = relaxed_dot - 128 × correction
951
+ // Scalar tail computes true products directly, so correction only applies to SIMD portion.
952
+ nk_f64_t dot_ab = (nk_f64_t)(dot_ab_total - 128LL * corr_ab_total);
953
+ nk_f64_t norm_aa = (nk_f64_t)(dot_aa_total - 128LL * corr_aa_total);
954
+ nk_f64_t norm_bb = (nk_f64_t)(dot_bb_total - 128LL * corr_bb_total);
955
+ *result = (nk_f32_t)nk_angular_normalize_f64_v128relaxed_(dot_ab, norm_aa, norm_bb);
956
+ }
957
+
958
+ #pragma endregion I8 and U8 Integers
959
+
960
+ #if defined(__clang__)
961
+ #pragma clang attribute pop
962
+ #endif
963
+
964
+ #if defined(__cplusplus)
965
+ } // extern "C"
966
+ #endif
967
+
968
+ #endif // NK_TARGET_V128RELAXED
969
+ #endif // NK_SPATIAL_V128RELAXED_H