usearch 2.21.4 → 2.25.1

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 (604) hide show
  1. package/README.md +65 -69
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +8 -8
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +124 -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/README.md +1 -1
  16. package/javascript/dist/cjs/usearch.d.ts +8 -3
  17. package/javascript/dist/cjs/usearch.js +12 -4
  18. package/javascript/dist/esm/usearch.d.ts +8 -3
  19. package/javascript/dist/esm/usearch.js +12 -4
  20. package/javascript/lib.cpp +17 -0
  21. package/javascript/usearch.test.js +117 -94
  22. package/javascript/usearch.ts +14 -6
  23. package/numkong/.clang-tidy +30 -0
  24. package/{simsimd → numkong}/.cmake-format.py +18 -0
  25. package/numkong/.editorconfig +12 -0
  26. package/numkong/.git-blame-ignore-revs +123 -0
  27. package/numkong/.mailmap +15 -0
  28. package/numkong/.spi.yml +11 -0
  29. package/numkong/.swift-format +14 -0
  30. package/numkong/CITATION.cff +81 -0
  31. package/numkong/CONTRIBUTING.md +500 -0
  32. package/numkong/Cargo.toml +54 -0
  33. package/numkong/MANIFEST.in +8 -0
  34. package/numkong/Package.swift +84 -0
  35. package/numkong/README.md +569 -0
  36. package/numkong/bench/README.md +217 -0
  37. package/numkong/bench/bench-browser.html +323 -0
  38. package/numkong/bench/bench.cpp +344 -0
  39. package/numkong/bench/bench.hpp +816 -0
  40. package/numkong/bench/bench.js +148 -0
  41. package/numkong/bench/bench.mjs +616 -0
  42. package/numkong/bench/bench_attention.cpp +113 -0
  43. package/numkong/bench/bench_cast.cpp +264 -0
  44. package/numkong/bench/bench_cross_amx.cpp +62 -0
  45. package/numkong/bench/bench_cross_arm.cpp +245 -0
  46. package/numkong/bench/bench_cross_blas.cpp +309 -0
  47. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  48. package/numkong/bench/bench_cross_power.cpp +84 -0
  49. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  50. package/numkong/bench/bench_cross_serial.cpp +151 -0
  51. package/numkong/bench/bench_cross_sme.cpp +163 -0
  52. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  53. package/numkong/bench/bench_cross_x86.cpp +455 -0
  54. package/numkong/bench/bench_curved.cpp +210 -0
  55. package/numkong/bench/bench_dot.cpp +315 -0
  56. package/numkong/bench/bench_each.cpp +503 -0
  57. package/numkong/bench/bench_geospatial.cpp +112 -0
  58. package/numkong/bench/bench_maxsim.cpp +154 -0
  59. package/numkong/bench/bench_mesh.cpp +148 -0
  60. package/numkong/bench/bench_probability.cpp +60 -0
  61. package/numkong/bench/bench_reduce.cpp +371 -0
  62. package/numkong/bench/bench_set.cpp +73 -0
  63. package/numkong/bench/bench_sparse.cpp +198 -0
  64. package/numkong/bench/bench_spatial.cpp +347 -0
  65. package/numkong/bench/bench_trigonometry.cpp +137 -0
  66. package/numkong/bench/swift/Bench.swift +506 -0
  67. package/numkong/binding.gyp +169 -0
  68. package/numkong/build.rs +484 -0
  69. package/numkong/c/dispatch.h +512 -0
  70. package/numkong/c/dispatch_bf16.c +447 -0
  71. package/numkong/c/dispatch_bf16c.c +52 -0
  72. package/numkong/c/dispatch_e2m3.c +296 -0
  73. package/numkong/c/dispatch_e3m2.c +284 -0
  74. package/numkong/c/dispatch_e4m3.c +318 -0
  75. package/numkong/c/dispatch_e5m2.c +316 -0
  76. package/numkong/c/dispatch_f16.c +452 -0
  77. package/numkong/c/dispatch_f16c.c +58 -0
  78. package/numkong/c/dispatch_f32.c +434 -0
  79. package/numkong/c/dispatch_f32c.c +99 -0
  80. package/numkong/c/dispatch_f64.c +348 -0
  81. package/numkong/c/dispatch_f64c.c +98 -0
  82. package/numkong/c/dispatch_i16.c +96 -0
  83. package/numkong/c/dispatch_i32.c +89 -0
  84. package/numkong/c/dispatch_i4.c +153 -0
  85. package/numkong/c/dispatch_i64.c +86 -0
  86. package/numkong/c/dispatch_i8.c +348 -0
  87. package/numkong/c/dispatch_other.c +348 -0
  88. package/numkong/c/dispatch_u1.c +193 -0
  89. package/numkong/c/dispatch_u16.c +124 -0
  90. package/numkong/c/dispatch_u32.c +118 -0
  91. package/numkong/c/dispatch_u4.c +153 -0
  92. package/numkong/c/dispatch_u64.c +102 -0
  93. package/numkong/c/dispatch_u8.c +364 -0
  94. package/numkong/c/numkong.c +940 -0
  95. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  96. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  97. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_math_lib.cmake +46 -0
  99. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  100. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  101. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  102. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  103. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  104. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  105. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  106. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  107. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  108. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  109. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  110. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  111. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  112. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  113. package/numkong/include/README.md +643 -0
  114. package/numkong/include/module.modulemap +129 -0
  115. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  116. package/numkong/include/numkong/attention/sme.h +2075 -0
  117. package/numkong/include/numkong/attention.h +49 -0
  118. package/numkong/include/numkong/capabilities.h +930 -0
  119. package/numkong/include/numkong/cast/README.md +262 -0
  120. package/numkong/include/numkong/cast/diamond.h +64 -0
  121. package/numkong/include/numkong/cast/haswell.h +823 -0
  122. package/numkong/include/numkong/cast/icelake.h +475 -0
  123. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  124. package/numkong/include/numkong/cast/neon.h +1174 -0
  125. package/numkong/include/numkong/cast/powervsx.h +449 -0
  126. package/numkong/include/numkong/cast/rvv.h +970 -0
  127. package/numkong/include/numkong/cast/sapphire.h +262 -0
  128. package/numkong/include/numkong/cast/serial.h +2336 -0
  129. package/numkong/include/numkong/cast/skylake.h +915 -0
  130. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  131. package/numkong/include/numkong/cast.h +254 -0
  132. package/numkong/include/numkong/cast.hpp +44 -0
  133. package/numkong/include/numkong/curved/README.md +223 -0
  134. package/numkong/include/numkong/curved/genoa.h +182 -0
  135. package/numkong/include/numkong/curved/haswell.h +276 -0
  136. package/numkong/include/numkong/curved/neon.h +329 -0
  137. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  138. package/numkong/include/numkong/curved/rvv.h +305 -0
  139. package/numkong/include/numkong/curved/serial.h +207 -0
  140. package/numkong/include/numkong/curved/skylake.h +457 -0
  141. package/numkong/include/numkong/curved/smef64.h +530 -0
  142. package/numkong/include/numkong/curved.h +513 -0
  143. package/numkong/include/numkong/curved.hpp +144 -0
  144. package/numkong/include/numkong/dot/README.md +442 -0
  145. package/numkong/include/numkong/dot/alder.h +563 -0
  146. package/numkong/include/numkong/dot/diamond.h +158 -0
  147. package/numkong/include/numkong/dot/genoa.h +289 -0
  148. package/numkong/include/numkong/dot/haswell.h +1723 -0
  149. package/numkong/include/numkong/dot/icelake.h +997 -0
  150. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  151. package/numkong/include/numkong/dot/neon.h +869 -0
  152. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  153. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  154. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  155. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  156. package/numkong/include/numkong/dot/powervsx.h +752 -0
  157. package/numkong/include/numkong/dot/rvv.h +722 -0
  158. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  159. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  160. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  161. package/numkong/include/numkong/dot/sapphire.h +141 -0
  162. package/numkong/include/numkong/dot/serial.h +874 -0
  163. package/numkong/include/numkong/dot/sierra.h +405 -0
  164. package/numkong/include/numkong/dot/skylake.h +1116 -0
  165. package/numkong/include/numkong/dot/sve.h +420 -0
  166. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  167. package/numkong/include/numkong/dot/svehalf.h +168 -0
  168. package/numkong/include/numkong/dot/svesdot.h +90 -0
  169. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  170. package/numkong/include/numkong/dot.h +1136 -0
  171. package/numkong/include/numkong/dot.hpp +94 -0
  172. package/numkong/include/numkong/dots/README.md +496 -0
  173. package/numkong/include/numkong/dots/alder.h +117 -0
  174. package/numkong/include/numkong/dots/diamond.h +86 -0
  175. package/numkong/include/numkong/dots/genoa.h +100 -0
  176. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  177. package/numkong/include/numkong/dots/haswell.h +310 -0
  178. package/numkong/include/numkong/dots/icelake.h +180 -0
  179. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  180. package/numkong/include/numkong/dots/neon.h +123 -0
  181. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  182. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  183. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  184. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  185. package/numkong/include/numkong/dots/powervsx.h +194 -0
  186. package/numkong/include/numkong/dots/rvv.h +2593 -0
  187. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  188. package/numkong/include/numkong/dots/serial.h +2867 -0
  189. package/numkong/include/numkong/dots/sierra.h +100 -0
  190. package/numkong/include/numkong/dots/skylake.h +207 -0
  191. package/numkong/include/numkong/dots/sme.h +5041 -0
  192. package/numkong/include/numkong/dots/smebi32.h +477 -0
  193. package/numkong/include/numkong/dots/smef64.h +1328 -0
  194. package/numkong/include/numkong/dots/smehalf.h +47 -0
  195. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  196. package/numkong/include/numkong/dots.h +3110 -0
  197. package/numkong/include/numkong/dots.hpp +641 -0
  198. package/numkong/include/numkong/each/README.md +465 -0
  199. package/numkong/include/numkong/each/haswell.h +1658 -0
  200. package/numkong/include/numkong/each/icelake.h +272 -0
  201. package/numkong/include/numkong/each/neon.h +1138 -0
  202. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  203. package/numkong/include/numkong/each/neonhalf.h +318 -0
  204. package/numkong/include/numkong/each/rvv.h +1121 -0
  205. package/numkong/include/numkong/each/sapphire.h +343 -0
  206. package/numkong/include/numkong/each/serial.h +282 -0
  207. package/numkong/include/numkong/each/skylake.h +1562 -0
  208. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  209. package/numkong/include/numkong/each.h +2232 -0
  210. package/numkong/include/numkong/each.hpp +434 -0
  211. package/numkong/include/numkong/geospatial/README.md +147 -0
  212. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  213. package/numkong/include/numkong/geospatial/neon.h +615 -0
  214. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  215. package/numkong/include/numkong/geospatial/serial.h +309 -0
  216. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  217. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  218. package/numkong/include/numkong/geospatial.h +453 -0
  219. package/numkong/include/numkong/geospatial.hpp +235 -0
  220. package/numkong/include/numkong/matrix.hpp +336 -0
  221. package/numkong/include/numkong/maxsim/README.md +187 -0
  222. package/numkong/include/numkong/maxsim/alder.h +511 -0
  223. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  224. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  225. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  226. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  227. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  228. package/numkong/include/numkong/maxsim/serial.h +490 -0
  229. package/numkong/include/numkong/maxsim/sme.h +993 -0
  230. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  231. package/numkong/include/numkong/maxsim.h +571 -0
  232. package/numkong/include/numkong/maxsim.hpp +133 -0
  233. package/numkong/include/numkong/mesh/README.md +219 -0
  234. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  235. package/numkong/include/numkong/mesh/neon.h +1821 -0
  236. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  237. package/numkong/include/numkong/mesh/rvv.h +936 -0
  238. package/numkong/include/numkong/mesh/serial.h +721 -0
  239. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  240. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  241. package/numkong/include/numkong/mesh.h +666 -0
  242. package/numkong/include/numkong/mesh.hpp +701 -0
  243. package/numkong/include/numkong/numkong.h +78 -0
  244. package/numkong/include/numkong/numkong.hpp +58 -0
  245. package/numkong/include/numkong/probability/README.md +177 -0
  246. package/numkong/include/numkong/probability/haswell.h +267 -0
  247. package/numkong/include/numkong/probability/neon.h +255 -0
  248. package/numkong/include/numkong/probability/rvv.h +414 -0
  249. package/numkong/include/numkong/probability/serial.h +181 -0
  250. package/numkong/include/numkong/probability/skylake.h +324 -0
  251. package/numkong/include/numkong/probability.h +380 -0
  252. package/numkong/include/numkong/probability.hpp +120 -0
  253. package/numkong/include/numkong/random.h +50 -0
  254. package/numkong/include/numkong/random.hpp +285 -0
  255. package/numkong/include/numkong/reduce/README.md +552 -0
  256. package/numkong/include/numkong/reduce/alder.h +636 -0
  257. package/numkong/include/numkong/reduce/genoa.h +201 -0
  258. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  259. package/numkong/include/numkong/reduce/icelake.h +549 -0
  260. package/numkong/include/numkong/reduce/neon.h +3980 -0
  261. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  262. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  263. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  264. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  265. package/numkong/include/numkong/reduce/serial.h +753 -0
  266. package/numkong/include/numkong/reduce/sierra.h +338 -0
  267. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  268. package/numkong/include/numkong/reduce/sve.h +52 -0
  269. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  270. package/numkong/include/numkong/reduce.h +1582 -0
  271. package/numkong/include/numkong/reduce.hpp +778 -0
  272. package/numkong/include/numkong/scalar/README.md +89 -0
  273. package/numkong/include/numkong/scalar/haswell.h +122 -0
  274. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  275. package/numkong/include/numkong/scalar/neon.h +122 -0
  276. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  277. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  278. package/numkong/include/numkong/scalar/rvv.h +211 -0
  279. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  280. package/numkong/include/numkong/scalar/serial.h +332 -0
  281. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  282. package/numkong/include/numkong/scalar.h +696 -0
  283. package/numkong/include/numkong/set/README.md +179 -0
  284. package/numkong/include/numkong/set/haswell.h +334 -0
  285. package/numkong/include/numkong/set/icelake.h +485 -0
  286. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  287. package/numkong/include/numkong/set/neon.h +363 -0
  288. package/numkong/include/numkong/set/powervsx.h +326 -0
  289. package/numkong/include/numkong/set/rvv.h +226 -0
  290. package/numkong/include/numkong/set/rvvbb.h +117 -0
  291. package/numkong/include/numkong/set/serial.h +174 -0
  292. package/numkong/include/numkong/set/sve.h +187 -0
  293. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  294. package/numkong/include/numkong/set.h +471 -0
  295. package/numkong/include/numkong/set.hpp +114 -0
  296. package/numkong/include/numkong/sets/README.md +149 -0
  297. package/numkong/include/numkong/sets/haswell.h +63 -0
  298. package/numkong/include/numkong/sets/icelake.h +66 -0
  299. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  300. package/numkong/include/numkong/sets/neon.h +61 -0
  301. package/numkong/include/numkong/sets/powervsx.h +65 -0
  302. package/numkong/include/numkong/sets/serial.h +43 -0
  303. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  304. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  305. package/numkong/include/numkong/sets.h +382 -0
  306. package/numkong/include/numkong/sparse/README.md +156 -0
  307. package/numkong/include/numkong/sparse/icelake.h +463 -0
  308. package/numkong/include/numkong/sparse/neon.h +288 -0
  309. package/numkong/include/numkong/sparse/serial.h +117 -0
  310. package/numkong/include/numkong/sparse/sve2.h +504 -0
  311. package/numkong/include/numkong/sparse/turin.h +322 -0
  312. package/numkong/include/numkong/sparse.h +363 -0
  313. package/numkong/include/numkong/sparse.hpp +113 -0
  314. package/numkong/include/numkong/spatial/README.md +439 -0
  315. package/numkong/include/numkong/spatial/alder.h +604 -0
  316. package/numkong/include/numkong/spatial/diamond.h +240 -0
  317. package/numkong/include/numkong/spatial/genoa.h +222 -0
  318. package/numkong/include/numkong/spatial/haswell.h +979 -0
  319. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  320. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  321. package/numkong/include/numkong/spatial/neon.h +846 -0
  322. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  323. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  324. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  325. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  326. package/numkong/include/numkong/spatial/rvv.h +991 -0
  327. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  328. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  329. package/numkong/include/numkong/spatial/serial.h +347 -0
  330. package/numkong/include/numkong/spatial/sierra.h +516 -0
  331. package/numkong/include/numkong/spatial/skylake.h +605 -0
  332. package/numkong/include/numkong/spatial/sve.h +246 -0
  333. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  334. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  335. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  336. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  337. package/numkong/include/numkong/spatial.h +1681 -0
  338. package/numkong/include/numkong/spatial.hpp +183 -0
  339. package/numkong/include/numkong/spatials/README.md +580 -0
  340. package/numkong/include/numkong/spatials/alder.h +94 -0
  341. package/numkong/include/numkong/spatials/diamond.h +82 -0
  342. package/numkong/include/numkong/spatials/genoa.h +94 -0
  343. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  344. package/numkong/include/numkong/spatials/haswell.h +219 -0
  345. package/numkong/include/numkong/spatials/icelake.h +113 -0
  346. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  347. package/numkong/include/numkong/spatials/neon.h +109 -0
  348. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  349. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  350. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  351. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  352. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  353. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  354. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  355. package/numkong/include/numkong/spatials/serial.h +248 -0
  356. package/numkong/include/numkong/spatials/sierra.h +96 -0
  357. package/numkong/include/numkong/spatials/skylake.h +184 -0
  358. package/numkong/include/numkong/spatials/sme.h +1927 -0
  359. package/numkong/include/numkong/spatials/smef64.h +483 -0
  360. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  361. package/numkong/include/numkong/spatials.h +3374 -0
  362. package/numkong/include/numkong/spatials.hpp +509 -0
  363. package/numkong/include/numkong/tensor.hpp +1981 -0
  364. package/numkong/include/numkong/trigonometry/README.md +184 -0
  365. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  366. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  367. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  368. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  369. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  370. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  371. package/numkong/include/numkong/trigonometry.h +467 -0
  372. package/numkong/include/numkong/trigonometry.hpp +166 -0
  373. package/numkong/include/numkong/types.h +1695 -0
  374. package/numkong/include/numkong/types.hpp +6027 -0
  375. package/numkong/include/numkong/vector.hpp +766 -0
  376. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  377. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  378. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  380. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  381. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  382. package/numkong/javascript/README.md +254 -0
  383. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  384. package/numkong/javascript/numkong-browser.ts +40 -0
  385. package/numkong/javascript/numkong-wasm.ts +750 -0
  386. package/numkong/javascript/numkong.c +712 -0
  387. package/numkong/javascript/numkong.ts +613 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  389. package/numkong/javascript/tsconfig-cjs.json +13 -0
  390. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  391. package/numkong/javascript/types.ts +784 -0
  392. package/numkong/numkong.gypi +104 -0
  393. package/numkong/package.json +108 -0
  394. package/numkong/probes/arm_neon.c +8 -0
  395. package/numkong/probes/arm_neon_bfdot.c +9 -0
  396. package/numkong/probes/arm_neon_fhm.c +9 -0
  397. package/numkong/probes/arm_neon_half.c +8 -0
  398. package/numkong/probes/arm_neon_sdot.c +9 -0
  399. package/numkong/probes/arm_neonfp8.c +9 -0
  400. package/numkong/probes/arm_sme.c +16 -0
  401. package/numkong/probes/arm_sme2.c +16 -0
  402. package/numkong/probes/arm_sme2p1.c +16 -0
  403. package/numkong/probes/arm_sme_bf16.c +16 -0
  404. package/numkong/probes/arm_sme_bi32.c +16 -0
  405. package/numkong/probes/arm_sme_f64.c +16 -0
  406. package/numkong/probes/arm_sme_fa64.c +14 -0
  407. package/numkong/probes/arm_sme_half.c +16 -0
  408. package/numkong/probes/arm_sme_lut2.c +15 -0
  409. package/numkong/probes/arm_sve.c +18 -0
  410. package/numkong/probes/arm_sve2.c +20 -0
  411. package/numkong/probes/arm_sve2p1.c +18 -0
  412. package/numkong/probes/arm_sve_bfdot.c +20 -0
  413. package/numkong/probes/arm_sve_half.c +18 -0
  414. package/numkong/probes/arm_sve_sdot.c +21 -0
  415. package/numkong/probes/loongarch_lasx.c +12 -0
  416. package/numkong/probes/power_vsx.c +12 -0
  417. package/numkong/probes/probe.js +127 -0
  418. package/numkong/probes/riscv_rvv.c +14 -0
  419. package/numkong/probes/riscv_rvv_bb.c +15 -0
  420. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  421. package/numkong/probes/riscv_rvv_half.c +14 -0
  422. package/numkong/probes/wasm_v128relaxed.c +11 -0
  423. package/numkong/probes/x86_alder.c +17 -0
  424. package/numkong/probes/x86_diamond.c +17 -0
  425. package/numkong/probes/x86_genoa.c +17 -0
  426. package/numkong/probes/x86_graniteamx.c +19 -0
  427. package/numkong/probes/x86_haswell.c +11 -0
  428. package/numkong/probes/x86_icelake.c +17 -0
  429. package/numkong/probes/x86_sapphire.c +16 -0
  430. package/numkong/probes/x86_sapphireamx.c +18 -0
  431. package/numkong/probes/x86_sierra.c +17 -0
  432. package/numkong/probes/x86_skylake.c +15 -0
  433. package/numkong/probes/x86_turin.c +17 -0
  434. package/numkong/rust/README.md +698 -0
  435. package/numkong/rust/capabilities.rs +96 -0
  436. package/numkong/rust/cast.rs +314 -0
  437. package/numkong/rust/curved.rs +391 -0
  438. package/numkong/rust/each.rs +2721 -0
  439. package/numkong/rust/geospatial.rs +343 -0
  440. package/numkong/rust/matrix.rs +5424 -0
  441. package/numkong/rust/maxsim.rs +540 -0
  442. package/numkong/rust/mesh.rs +837 -0
  443. package/numkong/rust/numkong.rs +409 -0
  444. package/numkong/rust/probability.rs +272 -0
  445. package/numkong/rust/reduce.rs +1249 -0
  446. package/numkong/rust/set.rs +194 -0
  447. package/numkong/rust/sparse.rs +513 -0
  448. package/numkong/rust/spatial.rs +1815 -0
  449. package/numkong/rust/tensor.rs +7565 -0
  450. package/numkong/rust/types.rs +3666 -0
  451. package/numkong/rust/vector.rs +1899 -0
  452. package/numkong/rustfmt.toml +2 -0
  453. package/numkong/swift/Matrix.swift +1388 -0
  454. package/numkong/swift/MaxSim.swift +151 -0
  455. package/numkong/swift/NumKong.swift +283 -0
  456. package/numkong/swift/Numerics.swift +329 -0
  457. package/numkong/swift/README.md +433 -0
  458. package/numkong/swift/Scalar.swift +741 -0
  459. package/numkong/swift/Tensor.swift +209 -0
  460. package/numkong/test/README.md +315 -0
  461. package/numkong/test/playwright.config.ts +16 -0
  462. package/numkong/test/swift/Test.swift +534 -0
  463. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  464. package/numkong/test/test-browser-bundle.html +188 -0
  465. package/numkong/test/test-browser-runner.mjs +43 -0
  466. package/numkong/test/test-browser.html +305 -0
  467. package/numkong/test/test-dtypes.mjs +453 -0
  468. package/numkong/test/test-wasm.mjs +267 -0
  469. package/numkong/test/test.cpp +442 -0
  470. package/numkong/test/test.hpp +580 -0
  471. package/numkong/test/test.mjs +363 -0
  472. package/numkong/test/test_base.py +1041 -0
  473. package/numkong/test/test_cast.cpp +242 -0
  474. package/numkong/test/test_cross.hpp +551 -0
  475. package/numkong/test/test_cross.py +467 -0
  476. package/numkong/test/test_cross_amx.cpp +50 -0
  477. package/numkong/test/test_cross_arm.cpp +225 -0
  478. package/numkong/test/test_cross_blas.cpp +354 -0
  479. package/numkong/test/test_cross_loongarch.cpp +90 -0
  480. package/numkong/test/test_cross_power.cpp +73 -0
  481. package/numkong/test/test_cross_rvv.cpp +109 -0
  482. package/numkong/test/test_cross_serial.cpp +181 -0
  483. package/numkong/test/test_cross_sme.cpp +148 -0
  484. package/numkong/test/test_cross_wasm.cpp +141 -0
  485. package/numkong/test/test_cross_x86.cpp +442 -0
  486. package/numkong/test/test_curved.cpp +182 -0
  487. package/numkong/test/test_curved.py +207 -0
  488. package/numkong/test/test_dot.cpp +353 -0
  489. package/numkong/test/test_dot.py +296 -0
  490. package/numkong/test/test_each.cpp +437 -0
  491. package/numkong/test/test_each.py +756 -0
  492. package/numkong/test/test_geospatial.cpp +155 -0
  493. package/numkong/test/test_geospatial.py +241 -0
  494. package/numkong/test/test_maxsim.cpp +138 -0
  495. package/numkong/test/test_maxsim.py +209 -0
  496. package/numkong/test/test_mesh.cpp +203 -0
  497. package/numkong/test/test_mesh.py +394 -0
  498. package/numkong/test/test_probability.cpp +136 -0
  499. package/numkong/test/test_probability.py +166 -0
  500. package/numkong/test/test_reduce.cpp +563 -0
  501. package/numkong/test/test_reduce.py +781 -0
  502. package/numkong/test/test_set.cpp +151 -0
  503. package/numkong/test/test_set.py +120 -0
  504. package/numkong/test/test_similarities.py +579 -0
  505. package/numkong/test/test_sparse.cpp +121 -0
  506. package/numkong/test/test_sparse.py +118 -0
  507. package/numkong/test/test_spatial.cpp +518 -0
  508. package/numkong/test/test_spatial.py +269 -0
  509. package/numkong/test/test_tensor.cpp +884 -0
  510. package/numkong/test/test_tensor.py +1417 -0
  511. package/numkong/test/test_trigonometry.cpp +156 -0
  512. package/numkong/test/test_trigonometry.py +180 -0
  513. package/package.json +7 -8
  514. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  515. package/prebuilds/linux-arm64/usearch.node +0 -0
  516. package/prebuilds/linux-x64/usearch.node +0 -0
  517. package/fp16/CMakeLists.txt +0 -176
  518. package/fp16/LICENSE +0 -11
  519. package/fp16/README.md +0 -20
  520. package/fp16/bench/alt-element.cc +0 -89
  521. package/fp16/bench/from-alt-array.cc +0 -175
  522. package/fp16/bench/from-ieee-array.cc +0 -399
  523. package/fp16/bench/ieee-element.cc +0 -272
  524. package/fp16/bench/to-alt-array.cc +0 -91
  525. package/fp16/bench/to-ieee-array.cc +0 -303
  526. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  527. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  528. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  529. package/fp16/configure.py +0 -65
  530. package/fp16/confu.yaml +0 -8
  531. package/fp16/include/fp16/__init__.py +0 -0
  532. package/fp16/include/fp16/avx.py +0 -50
  533. package/fp16/include/fp16/avx2.py +0 -53
  534. package/fp16/include/fp16/bitcasts.h +0 -92
  535. package/fp16/include/fp16/fp16.h +0 -451
  536. package/fp16/include/fp16/psimd.h +0 -131
  537. package/fp16/include/fp16.h +0 -11
  538. package/fp16/jni/Android.mk +0 -6
  539. package/fp16/jni/Application.mk +0 -4
  540. package/fp16/test/alt-from-fp32-value.cc +0 -498
  541. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  542. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  543. package/fp16/test/alt-to-fp32-value.cc +0 -348
  544. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  545. package/fp16/test/bitcasts.cc +0 -56
  546. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  547. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  548. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  549. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  550. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  551. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  552. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  553. package/fp16/test/peachpy/stubs.py +0 -38
  554. package/fp16/test/tables.cc +0 -530
  555. package/fp16/test/tables.h +0 -13
  556. package/fp16/third-party/THHalf.h +0 -92
  557. package/fp16/third-party/eigen-half.h +0 -170
  558. package/fp16/third-party/float16-compressor.h +0 -80
  559. package/fp16/third-party/half.hpp +0 -2916
  560. package/fp16/third-party/npy-halffloat.h +0 -328
  561. package/simsimd/.git-blame-ignore-revs +0 -2
  562. package/simsimd/CONTRIBUTING.md +0 -321
  563. package/simsimd/Cargo.toml +0 -49
  564. package/simsimd/MANIFEST.in +0 -4
  565. package/simsimd/Package.swift +0 -28
  566. package/simsimd/README.md +0 -1493
  567. package/simsimd/binding.gyp +0 -35
  568. package/simsimd/build.rs +0 -70
  569. package/simsimd/c/lib.c +0 -374
  570. package/simsimd/include/module.modulemap +0 -4
  571. package/simsimd/include/simsimd/binary.h +0 -486
  572. package/simsimd/include/simsimd/curved.h +0 -1541
  573. package/simsimd/include/simsimd/dot.h +0 -1853
  574. package/simsimd/include/simsimd/elementwise.h +0 -2465
  575. package/simsimd/include/simsimd/geospatial.h +0 -43
  576. package/simsimd/include/simsimd/mesh.h +0 -69
  577. package/simsimd/include/simsimd/probability.h +0 -606
  578. package/simsimd/include/simsimd/simsimd.h +0 -2567
  579. package/simsimd/include/simsimd/sparse.h +0 -1384
  580. package/simsimd/include/simsimd/spatial.h +0 -2335
  581. package/simsimd/include/simsimd/types.h +0 -666
  582. package/simsimd/javascript/fallback.ts +0 -233
  583. package/simsimd/javascript/lib.c +0 -125
  584. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  585. package/simsimd/javascript/simsimd.ts +0 -179
  586. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  587. package/simsimd/package-lock.json +0 -1761
  588. package/simsimd/package.json +0 -61
  589. package/simsimd/rust/lib.rs +0 -1821
  590. package/simsimd/scripts/bench.cxx +0 -1170
  591. package/simsimd/scripts/bench.ipynb +0 -187
  592. package/simsimd/scripts/bench.js +0 -127
  593. package/simsimd/scripts/bench.rs +0 -876
  594. package/simsimd/scripts/bench_vectors.py +0 -734
  595. package/simsimd/scripts/bench_vectors_live.py +0 -213
  596. package/simsimd/scripts/test.c +0 -187
  597. package/simsimd/scripts/test.mjs +0 -220
  598. package/simsimd/scripts/test.py +0 -1505
  599. package/simsimd/swift/SimSIMD.swift +0 -149
  600. package/simsimd/swift/Test.swift +0 -128
  601. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  602. /package/{simsimd → numkong}/LICENSE +0 -0
  603. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  604. /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