usearch 2.21.3 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +235 -52
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @brief SIMD-accelerated Spatial Similarity Measures for RISC-V BF16.
3
+ * @file include/numkong/spatial/rvvbf16.h
4
+ * @author Ash Vardanian
5
+ * @date January 5, 2026
6
+ *
7
+ * @sa include/numkong/spatial.h
8
+ *
9
+ * Zvfbfwma provides widening bf16 fused multiply-accumulate to f32:
10
+ * vfwmaccbf16: f32 ← bf16 × bf16
11
+ *
12
+ * For L2 distance, we use the identity: (a−b)² = a² + b² − 2 × a × b
13
+ * This allows us to use vfwmaccbf16 for all computations.
14
+ *
15
+ * Requires: RVV 1.0 + Zvfbfwma extension (GCC 14+ or Clang 18+)
16
+ */
17
+ #ifndef NK_SPATIAL_RVVBF16_H
18
+ #define NK_SPATIAL_RVVBF16_H
19
+
20
+ #if NK_TARGET_RISCV64_
21
+ #if NK_TARGET_RVVBF16
22
+
23
+ #include "numkong/types.h"
24
+ #include "numkong/spatial/rvv.h" // `nk_f32_sqrt_rvv`
25
+
26
+ #if defined(__clang__)
27
+ #pragma clang attribute push(__attribute__((target("arch=+v,+zvfbfwma"))), apply_to = function)
28
+ #elif defined(__GNUC__)
29
+ #pragma GCC push_options
30
+ #pragma GCC target("arch=+v,+zvfbfwma")
31
+ #endif
32
+
33
+ #if defined(__cplusplus)
34
+ extern "C" {
35
+ #endif
36
+
37
+ NK_PUBLIC void nk_sqeuclidean_bf16_rvvbf16(nk_bf16_t const *a_scalars, nk_bf16_t const *b_scalars,
38
+ nk_size_t count_scalars, nk_f32_t *result) {
39
+ // Per-lane accumulators — deferred horizontal reduction
40
+ nk_size_t max_vector_length = __riscv_vsetvlmax_e32m2();
41
+ vfloat32m2_t sq_sum_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length); // a² + b²
42
+ vfloat32m2_t ab_sum_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length); // a × b
43
+
44
+ for (nk_size_t vector_length; count_scalars > 0;
45
+ count_scalars -= vector_length, a_scalars += vector_length, b_scalars += vector_length) {
46
+ vector_length = __riscv_vsetvl_e16m1(count_scalars);
47
+ vuint16m1_t a_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)a_scalars, vector_length);
48
+ vuint16m1_t b_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)b_scalars, vector_length);
49
+ vbfloat16m1_t a_bf16m1 = __riscv_vreinterpret_v_u16m1_bf16m1(a_u16m1);
50
+ vbfloat16m1_t b_bf16m1 = __riscv_vreinterpret_v_u16m1_bf16m1(b_u16m1);
51
+
52
+ // Accumulate a², b², and a×b per-lane (no per-iteration reduction)
53
+ sq_sum_f32m2 = __riscv_vfwmaccbf16_vv_f32m2_tu(sq_sum_f32m2, a_bf16m1, a_bf16m1, vector_length);
54
+ sq_sum_f32m2 = __riscv_vfwmaccbf16_vv_f32m2_tu(sq_sum_f32m2, b_bf16m1, b_bf16m1, vector_length);
55
+ ab_sum_f32m2 = __riscv_vfwmaccbf16_vv_f32m2_tu(ab_sum_f32m2, a_bf16m1, b_bf16m1, vector_length);
56
+ }
57
+
58
+ // Single horizontal reduction after the loop
59
+ vfloat32m1_t zero_f32m1 = __riscv_vfmv_v_f_f32m1(0.0f, 1);
60
+ nk_f32_t sq_sum = __riscv_vfmv_f_s_f32m1_f32(
61
+ __riscv_vfredusum_vs_f32m2_f32m1(sq_sum_f32m2, zero_f32m1, max_vector_length));
62
+ nk_f32_t ab_sum = __riscv_vfmv_f_s_f32m1_f32(
63
+ __riscv_vfredusum_vs_f32m2_f32m1(ab_sum_f32m2, zero_f32m1, max_vector_length));
64
+ *result = sq_sum - 2.0f * ab_sum;
65
+ }
66
+
67
+ NK_PUBLIC void nk_euclidean_bf16_rvvbf16(nk_bf16_t const *a_scalars, nk_bf16_t const *b_scalars,
68
+ nk_size_t count_scalars, nk_f32_t *result) {
69
+ nk_sqeuclidean_bf16_rvvbf16(a_scalars, b_scalars, count_scalars, result);
70
+ // Handle potential negative values from floating point errors
71
+ *result = *result > 0.0f ? nk_f32_sqrt_rvv(*result) : 0.0f;
72
+ }
73
+
74
+ NK_PUBLIC void nk_angular_bf16_rvvbf16(nk_bf16_t const *a_scalars, nk_bf16_t const *b_scalars, nk_size_t count_scalars,
75
+ nk_f32_t *result) {
76
+ // Per-lane accumulators — deferred horizontal reduction
77
+ nk_size_t max_vector_length = __riscv_vsetvlmax_e32m2();
78
+ vfloat32m2_t dot_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
79
+ vfloat32m2_t a_sq_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
80
+ vfloat32m2_t b_sq_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
81
+
82
+ for (nk_size_t vector_length; count_scalars > 0;
83
+ count_scalars -= vector_length, a_scalars += vector_length, b_scalars += vector_length) {
84
+ vector_length = __riscv_vsetvl_e16m1(count_scalars);
85
+ vuint16m1_t a_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)a_scalars, vector_length);
86
+ vuint16m1_t b_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)b_scalars, vector_length);
87
+ vbfloat16m1_t a_bf16m1 = __riscv_vreinterpret_v_u16m1_bf16m1(a_u16m1);
88
+ vbfloat16m1_t b_bf16m1 = __riscv_vreinterpret_v_u16m1_bf16m1(b_u16m1);
89
+
90
+ // dot += a × b
91
+ dot_f32m2 = __riscv_vfwmaccbf16_vv_f32m2_tu(dot_f32m2, a_bf16m1, b_bf16m1, vector_length);
92
+ // a_sq += a × a
93
+ a_sq_f32m2 = __riscv_vfwmaccbf16_vv_f32m2_tu(a_sq_f32m2, a_bf16m1, a_bf16m1, vector_length);
94
+ // b_sq += b × b
95
+ b_sq_f32m2 = __riscv_vfwmaccbf16_vv_f32m2_tu(b_sq_f32m2, b_bf16m1, b_bf16m1, vector_length);
96
+ }
97
+
98
+ // Single horizontal reduction after the loop
99
+ vfloat32m1_t zero_f32m1 = __riscv_vfmv_v_f_f32m1(0.0f, 1);
100
+ nk_f32_t dot = __riscv_vfmv_f_s_f32m1_f32(
101
+ __riscv_vfredusum_vs_f32m2_f32m1(dot_f32m2, zero_f32m1, max_vector_length));
102
+ nk_f32_t a_sq = __riscv_vfmv_f_s_f32m1_f32(
103
+ __riscv_vfredusum_vs_f32m2_f32m1(a_sq_f32m2, zero_f32m1, max_vector_length));
104
+ nk_f32_t b_sq = __riscv_vfmv_f_s_f32m1_f32(
105
+ __riscv_vfredusum_vs_f32m2_f32m1(b_sq_f32m2, zero_f32m1, max_vector_length));
106
+
107
+ // Normalize: 1 − dot / sqrt(‖a‖² × ‖b‖²)
108
+ if (a_sq == 0.0f && b_sq == 0.0f) { *result = 0.0f; }
109
+ else if (dot == 0.0f) { *result = 1.0f; }
110
+ else {
111
+ nk_f32_t unclipped = 1.0f - dot * nk_f32_rsqrt_rvv(a_sq) * nk_f32_rsqrt_rvv(b_sq);
112
+ *result = unclipped > 0.0f ? unclipped : 0.0f;
113
+ }
114
+ }
115
+
116
+ #if defined(__cplusplus)
117
+ } // extern "C"
118
+ #endif
119
+
120
+ #if defined(__clang__)
121
+ #pragma clang attribute pop
122
+ #elif defined(__GNUC__)
123
+ #pragma GCC pop_options
124
+ #endif
125
+
126
+ #endif // NK_TARGET_RVVBF16
127
+ #endif // NK_TARGET_RISCV64_
128
+ #endif // NK_SPATIAL_RVVBF16_H
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @brief SIMD-accelerated Spatial Similarity Measures for RISC-V FP16.
3
+ * @file include/numkong/spatial/rvvhalf.h
4
+ * @author Ash Vardanian
5
+ * @date January 5, 2026
6
+ *
7
+ * @sa include/numkong/spatial.h
8
+ *
9
+ * Zvfh provides native half-precision (f16) vector operations.
10
+ * Uses widening operations (f16 → f32) for precision accumulation.
11
+ *
12
+ * Requires: RVV 1.0 + Zvfh extension (GCC 14+ or Clang 18+)
13
+ */
14
+ #ifndef NK_SPATIAL_RVVHALF_H
15
+ #define NK_SPATIAL_RVVHALF_H
16
+
17
+ #if NK_TARGET_RISCV64_
18
+ #if NK_TARGET_RVVHALF
19
+
20
+ #include "numkong/types.h"
21
+ #include "numkong/spatial/rvv.h" // `nk_f32_sqrt_rvv`
22
+
23
+ #if defined(__clang__)
24
+ #pragma clang attribute push(__attribute__((target("arch=+v,+zvfh"))), apply_to = function)
25
+ #elif defined(__GNUC__)
26
+ #pragma GCC push_options
27
+ #pragma GCC target("arch=+v,+zvfh")
28
+ #endif
29
+
30
+ #if defined(__cplusplus)
31
+ extern "C" {
32
+ #endif
33
+
34
+ NK_PUBLIC void nk_sqeuclidean_f16_rvvhalf(nk_f16_t const *a_scalars, nk_f16_t const *b_scalars, nk_size_t count_scalars,
35
+ nk_f32_t *result) {
36
+ // Per-lane accumulator — deferred horizontal reduction
37
+ nk_size_t max_vector_length = __riscv_vsetvlmax_e32m2();
38
+ vfloat32m2_t sum_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
39
+
40
+ for (nk_size_t vector_length; count_scalars > 0;
41
+ count_scalars -= vector_length, a_scalars += vector_length, b_scalars += vector_length) {
42
+ vector_length = __riscv_vsetvl_e16m1(count_scalars);
43
+ vuint16m1_t a_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)a_scalars, vector_length);
44
+ vuint16m1_t b_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)b_scalars, vector_length);
45
+ vfloat16m1_t a_f16m1 = __riscv_vreinterpret_v_u16m1_f16m1(a_u16m1);
46
+ vfloat16m1_t b_f16m1 = __riscv_vreinterpret_v_u16m1_f16m1(b_u16m1);
47
+ // Upcast to f32 before subtraction to avoid catastrophic cancellation in f16
48
+ vfloat32m2_t a_f32m2 = __riscv_vfwcvt_f_f_v_f32m2(a_f16m1, vector_length);
49
+ vfloat32m2_t b_f32m2 = __riscv_vfwcvt_f_f_v_f32m2(b_f16m1, vector_length);
50
+ vfloat32m2_t diff_f32m2 = __riscv_vfsub_vv_f32m2(a_f32m2, b_f32m2, vector_length);
51
+ // Accumulate diff² in f32
52
+ sum_f32m2 = __riscv_vfmacc_vv_f32m2_tu(sum_f32m2, diff_f32m2, diff_f32m2, vector_length);
53
+ }
54
+
55
+ // Single horizontal reduction after the loop
56
+ vfloat32m1_t zero_f32m1 = __riscv_vfmv_v_f_f32m1(0.0f, 1);
57
+ *result = __riscv_vfmv_f_s_f32m1_f32(__riscv_vfredusum_vs_f32m2_f32m1(sum_f32m2, zero_f32m1, max_vector_length));
58
+ }
59
+
60
+ NK_PUBLIC void nk_euclidean_f16_rvvhalf(nk_f16_t const *a_scalars, nk_f16_t const *b_scalars, nk_size_t count_scalars,
61
+ nk_f32_t *result) {
62
+ nk_sqeuclidean_f16_rvvhalf(a_scalars, b_scalars, count_scalars, result);
63
+ *result = nk_f32_sqrt_rvv(*result);
64
+ }
65
+
66
+ NK_PUBLIC void nk_angular_f16_rvvhalf(nk_f16_t const *a_scalars, nk_f16_t const *b_scalars, nk_size_t count_scalars,
67
+ nk_f32_t *result) {
68
+ // Per-lane accumulators — deferred horizontal reduction
69
+ nk_size_t max_vector_length = __riscv_vsetvlmax_e32m2();
70
+ vfloat32m2_t dot_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
71
+ vfloat32m2_t a_sq_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
72
+ vfloat32m2_t b_sq_f32m2 = __riscv_vfmv_v_f_f32m2(0.0f, max_vector_length);
73
+
74
+ for (nk_size_t vector_length; count_scalars > 0;
75
+ count_scalars -= vector_length, a_scalars += vector_length, b_scalars += vector_length) {
76
+ vector_length = __riscv_vsetvl_e16m1(count_scalars);
77
+ vuint16m1_t a_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)a_scalars, vector_length);
78
+ vuint16m1_t b_u16m1 = __riscv_vle16_v_u16m1((unsigned short const *)b_scalars, vector_length);
79
+ vfloat16m1_t a_f16m1 = __riscv_vreinterpret_v_u16m1_f16m1(a_u16m1);
80
+ vfloat16m1_t b_f16m1 = __riscv_vreinterpret_v_u16m1_f16m1(b_u16m1);
81
+
82
+ // dot += a × b (widened to f32)
83
+ dot_f32m2 = __riscv_vfwmacc_vv_f32m2_tu(dot_f32m2, a_f16m1, b_f16m1, vector_length);
84
+ // a_sq += a × a
85
+ a_sq_f32m2 = __riscv_vfwmacc_vv_f32m2_tu(a_sq_f32m2, a_f16m1, a_f16m1, vector_length);
86
+ // b_sq += b × b
87
+ b_sq_f32m2 = __riscv_vfwmacc_vv_f32m2_tu(b_sq_f32m2, b_f16m1, b_f16m1, vector_length);
88
+ }
89
+
90
+ // Single horizontal reduction after the loop
91
+ vfloat32m1_t zero_f32m1 = __riscv_vfmv_v_f_f32m1(0.0f, 1);
92
+ nk_f32_t dot = __riscv_vfmv_f_s_f32m1_f32(
93
+ __riscv_vfredusum_vs_f32m2_f32m1(dot_f32m2, zero_f32m1, max_vector_length));
94
+ nk_f32_t a_sq = __riscv_vfmv_f_s_f32m1_f32(
95
+ __riscv_vfredusum_vs_f32m2_f32m1(a_sq_f32m2, zero_f32m1, max_vector_length));
96
+ nk_f32_t b_sq = __riscv_vfmv_f_s_f32m1_f32(
97
+ __riscv_vfredusum_vs_f32m2_f32m1(b_sq_f32m2, zero_f32m1, max_vector_length));
98
+
99
+ // Normalize: 1 − dot / sqrt(‖a‖² × ‖b‖²)
100
+ if (a_sq == 0.0f && b_sq == 0.0f) { *result = 0.0f; }
101
+ else if (dot == 0.0f) { *result = 1.0f; }
102
+ else {
103
+ nk_f32_t unclipped = 1.0f - dot * nk_f32_rsqrt_rvv(a_sq) * nk_f32_rsqrt_rvv(b_sq);
104
+ *result = unclipped > 0.0f ? unclipped : 0.0f;
105
+ }
106
+ }
107
+
108
+ #if defined(__cplusplus)
109
+ } // extern "C"
110
+ #endif
111
+
112
+ #if defined(__clang__)
113
+ #pragma clang attribute pop
114
+ #elif defined(__GNUC__)
115
+ #pragma GCC pop_options
116
+ #endif
117
+
118
+ #endif // NK_TARGET_RVVHALF
119
+ #endif // NK_TARGET_RISCV64_
120
+ #endif // NK_SPATIAL_RVVHALF_H
@@ -0,0 +1,347 @@
1
+ /**
2
+ * @brief SWAR-accelerated Spatial Similarity Measures for SIMD-free CPUs.
3
+ * @file include/numkong/spatial/serial.h
4
+ * @author Ash Vardanian
5
+ * @date December 27, 2025
6
+ *
7
+ * @sa include/numkong/spatial.h
8
+ */
9
+ #ifndef NK_SPATIAL_SERIAL_H
10
+ #define NK_SPATIAL_SERIAL_H
11
+
12
+ #include "numkong/types.h"
13
+ #include "numkong/scalar/serial.h" // `nk_f32_rsqrt_serial`
14
+ #include "numkong/cast/serial.h"
15
+ #include "numkong/dot/serial.h" // `nk_dot_f64x2_state_serial_t`
16
+
17
+ #if defined(__cplusplus)
18
+ extern "C" {
19
+ #endif
20
+
21
+ /**
22
+ * @brief Macro for L2 squared distance with Neumaier compensated summation.
23
+ *
24
+ * Implements Neumaier's Kahan-Babuška variant to minimize floating-point rounding errors.
25
+ * Unlike Kahan, Neumaier handles the case where the term being added is larger than the
26
+ * running sum. Achieves O(1) error growth regardless of vector dimension.
27
+ *
28
+ * Performance vs Accuracy Tradeoff:
29
+ * - Adds ~30% overhead (3 extra FP operations per iteration) compared to naive summation
30
+ * - Reduces relative error from ~10⁻⁵ to ~10⁻⁷ at n=100K for f32
31
+ * - Benefits all floating-point types: f64, f32, f16, bf16
32
+ * - Integer types (i8) maintain perfect accuracy regardless
33
+ *
34
+ * Algorithm: For each term, compute t = sum + term, then:
35
+ * - If |sum| ≥ |term|: c += (sum − t) + term (lost low-order bits of term)
36
+ * - Else: c += (term − t) + sum (lost low-order bits of sum)
37
+ *
38
+ * @see Neumaier, A. (1974). "Rundungsfehleranalyse einiger Verfahren zur Summation endlicher Summen"
39
+ */
40
+ #define nk_define_sqeuclidean_(input_type, accumulator_type, output_type, load_and_convert) \
41
+ NK_PUBLIC void nk_sqeuclidean_##input_type##_serial(nk_##input_type##_t const *a, nk_##input_type##_t const *b, \
42
+ nk_size_t n, nk_##output_type##_t *result) { \
43
+ nk_##accumulator_type##_t sum = 0, compensation = 0, a_value, b_value; \
44
+ for (nk_size_t i = 0; i != n; ++i) { \
45
+ load_and_convert(a + i, &a_value); \
46
+ load_and_convert(b + i, &b_value); \
47
+ nk_##accumulator_type##_t diff = a_value - b_value; \
48
+ nk_##accumulator_type##_t term = diff * diff, t = sum + term; \
49
+ compensation += (nk_##accumulator_type##_abs_(sum) >= nk_##accumulator_type##_abs_(term)) \
50
+ ? ((sum - t) + term) \
51
+ : ((term - t) + sum); \
52
+ sum = t; \
53
+ } \
54
+ *result = (nk_##output_type##_t)(sum + compensation); \
55
+ }
56
+
57
+ #define nk_define_euclidean_(input_type, accumulator_type, l2sq_output_type, output_type, load_and_convert, \
58
+ compute_sqrt) \
59
+ NK_PUBLIC void nk_euclidean_##input_type##_serial(nk_##input_type##_t const *a, nk_##input_type##_t const *b, \
60
+ nk_size_t n, nk_##output_type##_t *result) { \
61
+ nk_##l2sq_output_type##_t distance_sq; \
62
+ nk_sqeuclidean_##input_type##_serial(a, b, n, &distance_sq); \
63
+ *result = compute_sqrt((nk_##output_type##_t)distance_sq); \
64
+ }
65
+
66
+ /**
67
+ * @brief Macro for cosine/angular distance with Neumaier compensated summation.
68
+ *
69
+ * Uses Neumaier summation for all three accumulators (dot_product, a_norm_sq, b_norm_sq).
70
+ * Achieves O(1) error growth regardless of vector dimension.
71
+ *
72
+ * @see nk_define_sqeuclidean_ for detailed documentation on Neumaier summation.
73
+ */
74
+ #define nk_define_angular_(input_type, accumulator_type, output_type, load_and_convert, compute_rsqrt) \
75
+ NK_PUBLIC void nk_angular_##input_type##_serial(nk_##input_type##_t const *a, nk_##input_type##_t const *b, \
76
+ nk_size_t n, nk_##output_type##_t *result) { \
77
+ nk_##accumulator_type##_t dot_sum = 0, a_sum = 0, b_sum = 0, a_value, b_value; \
78
+ nk_##accumulator_type##_t compensation_dot = 0, compensation_a = 0, compensation_b = 0; \
79
+ for (nk_size_t i = 0; i != n; ++i) { \
80
+ load_and_convert(a + i, &a_value); \
81
+ load_and_convert(b + i, &b_value); \
82
+ nk_##accumulator_type##_t term_dot = a_value * b_value, t_dot = dot_sum + term_dot; \
83
+ nk_##accumulator_type##_t term_a = a_value * a_value, t_a = a_sum + term_a; \
84
+ nk_##accumulator_type##_t term_b = b_value * b_value, t_b = b_sum + term_b; \
85
+ compensation_dot += (nk_##accumulator_type##_abs_(dot_sum) >= nk_##accumulator_type##_abs_(term_dot)) \
86
+ ? ((dot_sum - t_dot) + term_dot) \
87
+ : ((term_dot - t_dot) + dot_sum); \
88
+ compensation_a += (nk_##accumulator_type##_abs_(a_sum) >= nk_##accumulator_type##_abs_(term_a)) \
89
+ ? ((a_sum - t_a) + term_a) \
90
+ : ((term_a - t_a) + a_sum); \
91
+ compensation_b += (nk_##accumulator_type##_abs_(b_sum) >= nk_##accumulator_type##_abs_(term_b)) \
92
+ ? ((b_sum - t_b) + term_b) \
93
+ : ((term_b - t_b) + b_sum); \
94
+ dot_sum = t_dot; \
95
+ a_sum = t_a; \
96
+ b_sum = t_b; \
97
+ } \
98
+ nk_##accumulator_type##_t dot_product = dot_sum + compensation_dot; \
99
+ nk_##accumulator_type##_t a_norm_sq = a_sum + compensation_a; \
100
+ nk_##accumulator_type##_t b_norm_sq = b_sum + compensation_b; \
101
+ if (a_norm_sq == 0 && b_norm_sq == 0) { *result = 0; } \
102
+ else if (dot_product == 0) { *result = 1; } \
103
+ else { \
104
+ nk_##output_type##_t unclipped_distance = (nk_##output_type##_t)( \
105
+ 1 - (nk_##output_type##_t)dot_product * compute_rsqrt((nk_##output_type##_t)a_norm_sq) * \
106
+ compute_rsqrt((nk_##output_type##_t)b_norm_sq)); \
107
+ *result = unclipped_distance > 0 ? unclipped_distance : 0; \
108
+ } \
109
+ }
110
+
111
+ nk_define_angular_(f64, f64, f64, nk_assign_from_to_, nk_f64_rsqrt_serial) // nk_angular_f64_serial
112
+ nk_define_sqeuclidean_(f64, f64, f64, nk_assign_from_to_) // nk_sqeuclidean_f64_serial
113
+ nk_define_euclidean_(f64, f64, f64, f64, nk_assign_from_to_, nk_f64_sqrt_serial) // nk_euclidean_f64_serial
114
+
115
+ nk_define_angular_(f32, f64, f64, nk_assign_from_to_, nk_f64_rsqrt_serial) // nk_angular_f32_serial
116
+ nk_define_sqeuclidean_(f32, f64, f64, nk_assign_from_to_) // nk_sqeuclidean_f32_serial
117
+ nk_define_euclidean_(f32, f64, f64, f64, nk_assign_from_to_, nk_f64_sqrt_serial) // nk_euclidean_f32_serial
118
+
119
+ nk_define_angular_(f16, f32, f32, nk_f16_to_f32_serial, nk_f32_rsqrt_serial) // nk_angular_f16_serial
120
+ nk_define_sqeuclidean_(f16, f32, f32, nk_f16_to_f32_serial) // nk_sqeuclidean_f16_serial
121
+ nk_define_euclidean_(f16, f32, f32, f32, nk_f16_to_f32_serial, nk_f32_sqrt_serial) // nk_euclidean_f16_serial
122
+
123
+ nk_define_angular_(bf16, f32, f32, nk_bf16_to_f32_serial, nk_f32_rsqrt_serial) // nk_angular_bf16_serial
124
+ nk_define_sqeuclidean_(bf16, f32, f32, nk_bf16_to_f32_serial) // nk_sqeuclidean_bf16_serial
125
+ nk_define_euclidean_(bf16, f32, f32, f32, nk_bf16_to_f32_serial, nk_f32_sqrt_serial) // nk_euclidean_bf16_serial
126
+
127
+ nk_define_angular_(e4m3, f32, f32, nk_e4m3_to_f32_serial, nk_f32_rsqrt_serial) // nk_angular_e4m3_serial
128
+ nk_define_sqeuclidean_(e4m3, f32, f32, nk_e4m3_to_f32_serial) // nk_sqeuclidean_e4m3_serial
129
+ nk_define_euclidean_(e4m3, f32, f32, f32, nk_e4m3_to_f32_serial, nk_f32_sqrt_serial) // nk_euclidean_e4m3_serial
130
+
131
+ nk_define_angular_(e5m2, f32, f32, nk_e5m2_to_f32_serial, nk_f32_rsqrt_serial) // nk_angular_e5m2_serial
132
+ nk_define_sqeuclidean_(e5m2, f32, f32, nk_e5m2_to_f32_serial) // nk_sqeuclidean_e5m2_serial
133
+ nk_define_euclidean_(e5m2, f32, f32, f32, nk_e5m2_to_f32_serial, nk_f32_sqrt_serial) // nk_euclidean_e5m2_serial
134
+
135
+ nk_define_angular_(e2m3, f32, f32, nk_e2m3_to_f32_serial, nk_f32_rsqrt_serial) // nk_angular_e2m3_serial
136
+ nk_define_sqeuclidean_(e2m3, f32, f32, nk_e2m3_to_f32_serial) // nk_sqeuclidean_e2m3_serial
137
+ nk_define_euclidean_(e2m3, f32, f32, f32, nk_e2m3_to_f32_serial, nk_f32_sqrt_serial) // nk_euclidean_e2m3_serial
138
+
139
+ nk_define_angular_(e3m2, f32, f32, nk_e3m2_to_f32_serial, nk_f32_rsqrt_serial) // nk_angular_e3m2_serial
140
+ nk_define_sqeuclidean_(e3m2, f32, f32, nk_e3m2_to_f32_serial) // nk_sqeuclidean_e3m2_serial
141
+ nk_define_euclidean_(e3m2, f32, f32, f32, nk_e3m2_to_f32_serial, nk_f32_sqrt_serial) // nk_euclidean_e3m2_serial
142
+
143
+ nk_define_angular_(i8, i32, f32, nk_assign_from_to_, nk_f32_rsqrt_serial) // nk_angular_i8_serial
144
+ nk_define_sqeuclidean_(i8, i32, u32, nk_assign_from_to_) // nk_sqeuclidean_i8_serial
145
+ nk_define_euclidean_(i8, i32, u32, f32, nk_assign_from_to_, nk_f32_sqrt_serial) // nk_euclidean_i8_serial
146
+
147
+ nk_define_angular_(u8, u32, f32, nk_assign_from_to_, nk_f32_rsqrt_serial) // nk_angular_u8_serial
148
+ nk_define_sqeuclidean_(u8, u32, u32, nk_assign_from_to_) // nk_sqeuclidean_u8_serial
149
+ nk_define_euclidean_(u8, u32, u32, f32, nk_assign_from_to_, nk_f32_sqrt_serial) // nk_euclidean_u8_serial
150
+
151
+ #undef nk_define_sqeuclidean_
152
+ #undef nk_define_euclidean_
153
+ #undef nk_define_angular_
154
+
155
+ NK_PUBLIC void nk_sqeuclidean_i4_serial(nk_i4x2_t const *a, nk_i4x2_t const *b, nk_size_t n, nk_u32_t *result) {
156
+ // i4 values are packed as nibbles: two 4-bit signed values per byte.
157
+ // Parameter `n` is the number of 4-bit values (dimensions), not bytes.
158
+ // Sign extension: (nibble ^ 8) - 8 maps [0,15] to [-8,7]
159
+ n = nk_size_round_up_to_multiple_(n, 2);
160
+ nk_size_t n_bytes = n / 2;
161
+ nk_i32_t sum = 0;
162
+ for (nk_size_t i = 0; i < n_bytes; ++i) {
163
+ nk_i32_t a_low = (nk_i32_t)nk_i4x2_low_(a[i]);
164
+ nk_i32_t b_low = (nk_i32_t)nk_i4x2_low_(b[i]);
165
+ nk_i32_t a_high = (nk_i32_t)nk_i4x2_high_(a[i]);
166
+ nk_i32_t b_high = (nk_i32_t)nk_i4x2_high_(b[i]);
167
+ nk_i32_t diff_low = a_low - b_low, diff_high = a_high - b_high;
168
+ sum += diff_low * diff_low + diff_high * diff_high;
169
+ }
170
+ *result = (nk_u32_t)sum;
171
+ }
172
+
173
+ NK_PUBLIC void nk_euclidean_i4_serial(nk_i4x2_t const *a, nk_i4x2_t const *b, nk_size_t n, nk_f32_t *result) {
174
+ nk_u32_t distance_sq;
175
+ nk_sqeuclidean_i4_serial(a, b, n, &distance_sq);
176
+ *result = nk_f32_sqrt_serial((nk_f32_t)distance_sq);
177
+ }
178
+
179
+ NK_PUBLIC void nk_angular_i4_serial(nk_i4x2_t const *a, nk_i4x2_t const *b, nk_size_t n, nk_f32_t *result) {
180
+ n = nk_size_round_up_to_multiple_(n, 2);
181
+ nk_size_t n_bytes = n / 2;
182
+ nk_i32_t dot_sum = 0, a_norm_sq = 0, b_norm_sq = 0;
183
+ for (nk_size_t i = 0; i < n_bytes; ++i) {
184
+ nk_i32_t a_low = (nk_i32_t)nk_i4x2_low_(a[i]);
185
+ nk_i32_t b_low = (nk_i32_t)nk_i4x2_low_(b[i]);
186
+ nk_i32_t a_high = (nk_i32_t)nk_i4x2_high_(a[i]);
187
+ nk_i32_t b_high = (nk_i32_t)nk_i4x2_high_(b[i]);
188
+ dot_sum += a_low * b_low + a_high * b_high;
189
+ a_norm_sq += a_low * a_low + a_high * a_high;
190
+ b_norm_sq += b_low * b_low + b_high * b_high;
191
+ }
192
+ if (a_norm_sq == 0 && b_norm_sq == 0) { *result = 0; }
193
+ else if (dot_sum == 0) { *result = 1; }
194
+ else {
195
+ nk_f32_t unclipped = 1.0f - (nk_f32_t)dot_sum * nk_f32_rsqrt_serial((nk_f32_t)a_norm_sq) *
196
+ nk_f32_rsqrt_serial((nk_f32_t)b_norm_sq);
197
+ *result = unclipped > 0 ? unclipped : 0;
198
+ }
199
+ }
200
+
201
+ NK_PUBLIC void nk_sqeuclidean_u4_serial(nk_u4x2_t const *a, nk_u4x2_t const *b, nk_size_t n, nk_u32_t *result) {
202
+ // u4 values are packed as nibbles: two 4-bit unsigned values per byte.
203
+ // Parameter `n` is the number of 4-bit values (dimensions), not bytes.
204
+ // No sign extension needed - values are in [0,15].
205
+ n = nk_size_round_up_to_multiple_(n, 2);
206
+ nk_size_t n_bytes = n / 2;
207
+ nk_u32_t sum = 0;
208
+ for (nk_size_t i = 0; i < n_bytes; ++i) {
209
+ nk_i32_t a_low = (nk_i32_t)nk_u4x2_low_(a[i]);
210
+ nk_i32_t b_low = (nk_i32_t)nk_u4x2_low_(b[i]);
211
+ nk_i32_t a_high = (nk_i32_t)nk_u4x2_high_(a[i]);
212
+ nk_i32_t b_high = (nk_i32_t)nk_u4x2_high_(b[i]);
213
+ nk_i32_t diff_low = a_low - b_low, diff_high = a_high - b_high;
214
+ sum += (nk_u32_t)(diff_low * diff_low + diff_high * diff_high);
215
+ }
216
+ *result = sum;
217
+ }
218
+
219
+ NK_PUBLIC void nk_euclidean_u4_serial(nk_u4x2_t const *a, nk_u4x2_t const *b, nk_size_t n, nk_f32_t *result) {
220
+ nk_u32_t distance_sq;
221
+ nk_sqeuclidean_u4_serial(a, b, n, &distance_sq);
222
+ *result = nk_f32_sqrt_serial((nk_f32_t)distance_sq);
223
+ }
224
+
225
+ NK_PUBLIC void nk_angular_u4_serial(nk_u4x2_t const *a, nk_u4x2_t const *b, nk_size_t n, nk_f32_t *result) {
226
+ n = nk_size_round_up_to_multiple_(n, 2);
227
+ nk_size_t n_bytes = n / 2;
228
+ nk_u32_t dot_sum = 0, a_norm_sq = 0, b_norm_sq = 0;
229
+ for (nk_size_t i = 0; i < n_bytes; ++i) {
230
+ nk_u32_t a_low = (nk_u32_t)nk_u4x2_low_(a[i]);
231
+ nk_u32_t b_low = (nk_u32_t)nk_u4x2_low_(b[i]);
232
+ nk_u32_t a_high = (nk_u32_t)nk_u4x2_high_(a[i]);
233
+ nk_u32_t b_high = (nk_u32_t)nk_u4x2_high_(b[i]);
234
+ dot_sum += a_low * b_low + a_high * b_high;
235
+ a_norm_sq += a_low * a_low + a_high * a_high;
236
+ b_norm_sq += b_low * b_low + b_high * b_high;
237
+ }
238
+ if (a_norm_sq == 0 && b_norm_sq == 0) { *result = 0; }
239
+ else if (dot_sum == 0) { *result = 1; }
240
+ else {
241
+ nk_f32_t unclipped = 1.0f - (nk_f32_t)dot_sum * nk_f32_rsqrt_serial((nk_f32_t)a_norm_sq) *
242
+ nk_f32_rsqrt_serial((nk_f32_t)b_norm_sq);
243
+ *result = unclipped > 0 ? unclipped : 0;
244
+ }
245
+ }
246
+
247
+ /** @brief Angular from_dot: computes 1 − dot × rsqrt(query_sumsq × target_sumsq) for 4 pairs (serial). */
248
+ NK_INTERNAL void nk_angular_through_f32_from_dot_serial_(nk_b128_vec_t dots, nk_f32_t query_sumsq,
249
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
250
+ for (int i = 0; i < 4; ++i) {
251
+ nk_f32_t product = query_sumsq * target_sumsqs.f32s[i];
252
+ if (product > 0) {
253
+ nk_f32_t rsqrt_val = nk_f32_rsqrt_serial(product);
254
+ nk_f32_t normalized = dots.f32s[i] * rsqrt_val;
255
+ nk_f32_t result = 1.0f - normalized;
256
+ results->f32s[i] = result > 0 ? result : 0;
257
+ }
258
+ else { results->f32s[i] = (dots.f32s[i] == 0) ? 0.0f : 1.0f; }
259
+ }
260
+ }
261
+
262
+ /** @brief Euclidean from_dot: computes √(query_sumsq + target_sumsq − 2 × dot) for 4 pairs (serial). */
263
+ NK_INTERNAL void nk_euclidean_through_f32_from_dot_serial_(nk_b128_vec_t dots, nk_f32_t query_sumsq,
264
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
265
+ for (int i = 0; i < 4; ++i) {
266
+ nk_f32_t dist_sq = query_sumsq + target_sumsqs.f32s[i] - 2.0f * dots.f32s[i];
267
+ results->f32s[i] = dist_sq > 0 ? nk_f32_sqrt_serial(dist_sq) : 0.0f;
268
+ }
269
+ }
270
+
271
+ /** @brief Angular from_dot for f64 precision. */
272
+ NK_INTERNAL void nk_angular_through_f64_from_dot_serial_(nk_b256_vec_t dots, nk_f64_t query_sumsq,
273
+ nk_b256_vec_t target_sumsqs, nk_b256_vec_t *results) {
274
+ for (int i = 0; i < 4; ++i) {
275
+ nk_f64_t product = query_sumsq * target_sumsqs.f64s[i];
276
+ if (product > 0) {
277
+ nk_f64_t rsqrt_val = nk_f64_rsqrt_serial(product);
278
+ nk_f64_t normalized = dots.f64s[i] * rsqrt_val;
279
+ nk_f64_t result = 1.0 - normalized;
280
+ results->f64s[i] = result > 0 ? result : 0;
281
+ }
282
+ else { results->f64s[i] = (dots.f64s[i] == 0) ? 0.0 : 1.0; }
283
+ }
284
+ }
285
+
286
+ /** @brief Euclidean from_dot for f64 precision. */
287
+ NK_INTERNAL void nk_euclidean_through_f64_from_dot_serial_(nk_b256_vec_t dots, nk_f64_t query_sumsq,
288
+ nk_b256_vec_t target_sumsqs, nk_b256_vec_t *results) {
289
+ for (int i = 0; i < 4; ++i) {
290
+ nk_f64_t dist_sq = query_sumsq + target_sumsqs.f64s[i] - 2.0 * dots.f64s[i];
291
+ results->f64s[i] = dist_sq > 0 ? nk_f64_sqrt_serial(dist_sq) : 0.0;
292
+ }
293
+ }
294
+
295
+ /** @brief Angular from_dot for i32 accumulators: cast to f32, then same math as f32 variant. */
296
+ NK_INTERNAL void nk_angular_through_i32_from_dot_serial_(nk_b128_vec_t dots, nk_i32_t query_sumsq,
297
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
298
+ for (int i = 0; i < 4; ++i) {
299
+ nk_f32_t product = (nk_f32_t)query_sumsq * (nk_f32_t)target_sumsqs.i32s[i];
300
+ if (product > 0) {
301
+ nk_f32_t rsqrt_val = nk_f32_rsqrt_serial(product);
302
+ nk_f32_t normalized = (nk_f32_t)dots.i32s[i] * rsqrt_val;
303
+ nk_f32_t result = 1.0f - normalized;
304
+ results->f32s[i] = result > 0 ? result : 0;
305
+ }
306
+ else { results->f32s[i] = (dots.i32s[i] == 0) ? 0.0f : 1.0f; }
307
+ }
308
+ }
309
+
310
+ /** @brief Euclidean from_dot for i32 accumulators: cast to f32, then same math as f32 variant. */
311
+ NK_INTERNAL void nk_euclidean_through_i32_from_dot_serial_(nk_b128_vec_t dots, nk_i32_t query_sumsq,
312
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
313
+ for (int i = 0; i < 4; ++i) {
314
+ nk_f32_t dist_sq = (nk_f32_t)query_sumsq + (nk_f32_t)target_sumsqs.i32s[i] - 2.0f * (nk_f32_t)dots.i32s[i];
315
+ results->f32s[i] = dist_sq > 0 ? nk_f32_sqrt_serial(dist_sq) : 0.0f;
316
+ }
317
+ }
318
+
319
+ /** @brief Angular from_dot for u32 accumulators: cast to f32, then same math as f32 variant. */
320
+ NK_INTERNAL void nk_angular_through_u32_from_dot_serial_(nk_b128_vec_t dots, nk_u32_t query_sumsq,
321
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
322
+ for (int i = 0; i < 4; ++i) {
323
+ nk_f32_t product = (nk_f32_t)query_sumsq * (nk_f32_t)target_sumsqs.u32s[i];
324
+ if (product > 0) {
325
+ nk_f32_t rsqrt_val = nk_f32_rsqrt_serial(product);
326
+ nk_f32_t normalized = (nk_f32_t)dots.u32s[i] * rsqrt_val;
327
+ nk_f32_t result = 1.0f - normalized;
328
+ results->f32s[i] = result > 0 ? result : 0;
329
+ }
330
+ else { results->f32s[i] = (dots.u32s[i] == 0) ? 0.0f : 1.0f; }
331
+ }
332
+ }
333
+
334
+ /** @brief Euclidean from_dot for u32 accumulators: cast to f32, then same math as f32 variant. */
335
+ NK_INTERNAL void nk_euclidean_through_u32_from_dot_serial_(nk_b128_vec_t dots, nk_u32_t query_sumsq,
336
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
337
+ for (int i = 0; i < 4; ++i) {
338
+ nk_f32_t dist_sq = (nk_f32_t)query_sumsq + (nk_f32_t)target_sumsqs.u32s[i] - 2.0f * (nk_f32_t)dots.u32s[i];
339
+ results->f32s[i] = dist_sq > 0 ? nk_f32_sqrt_serial(dist_sq) : 0.0f;
340
+ }
341
+ }
342
+
343
+ #if defined(__cplusplus)
344
+ } // extern "C"
345
+ #endif
346
+
347
+ #endif // NK_SPATIAL_SERIAL_H