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,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