usearch 2.21.4 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,846 @@
1
+ /**
2
+ * @brief SIMD-accelerated Spatial Similarity Measures for NEON.
3
+ * @file include/numkong/spatial/neon.h
4
+ * @author Ash Vardanian
5
+ * @date December 27, 2025
6
+ *
7
+ * @sa include/numkong/spatial.h
8
+ *
9
+ * @section spatial_neon_instructions Key NEON Spatial Instructions
10
+ *
11
+ * ARM NEON instructions for distance computations:
12
+ *
13
+ * Intrinsic Instruction A76 M5
14
+ * vfmaq_f32 FMLA (V.4S, V.4S, V.4S) 4cy @ 2p 3cy @ 4p
15
+ * vmulq_f32 FMUL (V.4S, V.4S, V.4S) 3cy @ 2p 3cy @ 4p
16
+ * vaddq_f32 FADD (V.4S, V.4S, V.4S) 2cy @ 2p 2cy @ 4p
17
+ * vsubq_f32 FSUB (V.4S, V.4S, V.4S) 2cy @ 2p 2cy @ 4p
18
+ * vrsqrteq_f32 FRSQRTE (V.4S, V.4S) 2cy @ 2p 3cy @ 1p
19
+ * vsqrtq_f32 FSQRT (V.4S, V.4S) 12cy @ 1p 9cy @ 1p
20
+ * vrecpeq_f32 FRECPE (V.4S, V.4S) 2cy @ 2p 3cy @ 1p
21
+ *
22
+ * FRSQRTE provides ~8-bit precision; two Newton-Raphson iterations via vrsqrtsq_f32 achieve
23
+ * ~23-bit precision, sufficient for f32. This is much faster than FSQRT (0.25/cy).
24
+ *
25
+ * Distance computations (L2, angular) benefit from 2x throughput on 4-pipe cores (Apple M4+,
26
+ * Graviton3+, Oryon), but FSQRT remains slow on all cores. Use rsqrt+NR when precision allows.
27
+ */
28
+ #ifndef NK_SPATIAL_NEON_H
29
+ #define NK_SPATIAL_NEON_H
30
+
31
+ #if NK_TARGET_ARM64_
32
+ #if NK_TARGET_NEON
33
+
34
+ #include "numkong/types.h"
35
+ #include "numkong/scalar/neon.h" // `nk_f32_sqrt_neon`
36
+ #include "numkong/dot/neon.h" // `nk_dot_stable_sum_f64x2_neon_`
37
+
38
+ #if defined(__cplusplus)
39
+ extern "C" {
40
+ #endif
41
+
42
+ #if defined(__clang__)
43
+ #pragma clang attribute push(__attribute__((target("arch=armv8-a+simd"))), apply_to = function)
44
+ #elif defined(__GNUC__)
45
+ #pragma GCC push_options
46
+ #pragma GCC target("arch=armv8-a+simd")
47
+ #endif
48
+
49
+ /**
50
+ * @brief Reciprocal square root of 4 floats with Newton-Raphson refinement.
51
+ *
52
+ * Uses `vrsqrteq_f32` (~8-bit initial estimate) followed by two Newton-Raphson iterations
53
+ * via `vrsqrtsq_f32`, achieving ~23-bit precision — sufficient for f32.
54
+ * Much faster than `vsqrtq_f32` (2 cy vs 9-12 cy latency, 2/cy vs 0.25/cy throughput).
55
+ */
56
+ NK_INTERNAL float32x4_t nk_rsqrt_f32x4_neon_(float32x4_t x) {
57
+ float32x4_t rsqrt_f32x4 = vrsqrteq_f32(x);
58
+ rsqrt_f32x4 = vmulq_f32(rsqrt_f32x4, vrsqrtsq_f32(vmulq_f32(x, rsqrt_f32x4), rsqrt_f32x4));
59
+ rsqrt_f32x4 = vmulq_f32(rsqrt_f32x4, vrsqrtsq_f32(vmulq_f32(x, rsqrt_f32x4), rsqrt_f32x4));
60
+ return rsqrt_f32x4;
61
+ }
62
+
63
+ /**
64
+ * @brief Reciprocal square root of 2 doubles with Newton-Raphson refinement.
65
+ *
66
+ * Uses `vrsqrteq_f64` (~8-bit initial estimate) followed by three Newton-Raphson iterations
67
+ * via `vrsqrtsq_f64`, achieving ~48-bit precision — reasonable for f64 distance computations
68
+ * where the final result is often narrowed to f32. For full 52-bit mantissa fidelity,
69
+ * prefer `vsqrtq_f64` instead.
70
+ */
71
+ NK_INTERNAL float64x2_t nk_rsqrt_f64x2_neon_(float64x2_t x) {
72
+ float64x2_t rsqrt_f64x2 = vrsqrteq_f64(x);
73
+ rsqrt_f64x2 = vmulq_f64(rsqrt_f64x2, vrsqrtsq_f64(vmulq_f64(x, rsqrt_f64x2), rsqrt_f64x2));
74
+ rsqrt_f64x2 = vmulq_f64(rsqrt_f64x2, vrsqrtsq_f64(vmulq_f64(x, rsqrt_f64x2), rsqrt_f64x2));
75
+ rsqrt_f64x2 = vmulq_f64(rsqrt_f64x2, vrsqrtsq_f64(vmulq_f64(x, rsqrt_f64x2), rsqrt_f64x2));
76
+ return rsqrt_f64x2;
77
+ }
78
+
79
+ NK_INTERNAL nk_f32_t nk_angular_normalize_f32_neon_(nk_f32_t ab, nk_f32_t a2, nk_f32_t b2) {
80
+ if (a2 == 0 && b2 == 0) return 0;
81
+ if (ab == 0) return 1;
82
+ nk_f32_t squares_arr[2] = {a2, b2};
83
+ float32x2_t squares_f32x2 = vld1_f32(squares_arr);
84
+ // Unlike x86, Arm NEON manuals don't explicitly mention the accuracy of their `rsqrt` approximation.
85
+ // Third-party research suggests that it's less accurate than SSE instructions, having an error of 1.5×2⁻¹².
86
+ // One or two rounds of Newton-Raphson refinement are recommended to improve the accuracy.
87
+ // https://github.com/lighttransport/embree-aarch64/issues/24
88
+ // https://github.com/lighttransport/embree-aarch64/blob/3f75f8cb4e553d13dced941b5fefd4c826835a6b/common/math/math.h#L137-L145
89
+ float32x2_t rsqrts_f32x2 = vrsqrte_f32(squares_f32x2);
90
+ // Perform two rounds of Newton-Raphson refinement:
91
+ // https://en.wikipedia.org/wiki/Newton%27s_method
92
+ rsqrts_f32x2 = vmul_f32(rsqrts_f32x2, vrsqrts_f32(vmul_f32(squares_f32x2, rsqrts_f32x2), rsqrts_f32x2));
93
+ rsqrts_f32x2 = vmul_f32(rsqrts_f32x2, vrsqrts_f32(vmul_f32(squares_f32x2, rsqrts_f32x2), rsqrts_f32x2));
94
+ vst1_f32(squares_arr, rsqrts_f32x2);
95
+ nk_f32_t result = 1 - ab * squares_arr[0] * squares_arr[1];
96
+ return result > 0 ? result : 0;
97
+ }
98
+
99
+ NK_INTERNAL nk_f64_t nk_angular_normalize_f64_neon_(nk_f64_t ab, nk_f64_t a2, nk_f64_t b2) {
100
+ if (a2 == 0 && b2 == 0) return 0;
101
+ if (ab == 0) return 1;
102
+ nk_f64_t squares_arr[2] = {a2, b2};
103
+ float64x2_t squares_f64x2 = vld1q_f64(squares_arr);
104
+
105
+ // Unlike x86, Arm NEON manuals don't explicitly mention the accuracy of their `rsqrt` approximation.
106
+ // Third-party research suggests that it's less accurate than SSE instructions, having an error of 1.5×2⁻¹².
107
+ // One or two rounds of Newton-Raphson refinement are recommended to improve the accuracy.
108
+ // https://github.com/lighttransport/embree-aarch64/issues/24
109
+ // https://github.com/lighttransport/embree-aarch64/blob/3f75f8cb4e553d13dced941b5fefd4c826835a6b/common/math/math.h#L137-L145
110
+ float64x2_t rsqrts_f64x2 = vrsqrteq_f64(squares_f64x2);
111
+ // Perform three rounds of Newton-Raphson refinement for f64 precision (~48 bits):
112
+ // https://en.wikipedia.org/wiki/Newton%27s_method
113
+ rsqrts_f64x2 = vmulq_f64(rsqrts_f64x2, vrsqrtsq_f64(vmulq_f64(squares_f64x2, rsqrts_f64x2), rsqrts_f64x2));
114
+ rsqrts_f64x2 = vmulq_f64(rsqrts_f64x2, vrsqrtsq_f64(vmulq_f64(squares_f64x2, rsqrts_f64x2), rsqrts_f64x2));
115
+ rsqrts_f64x2 = vmulq_f64(rsqrts_f64x2, vrsqrtsq_f64(vmulq_f64(squares_f64x2, rsqrts_f64x2), rsqrts_f64x2));
116
+ vst1q_f64(squares_arr, rsqrts_f64x2);
117
+ nk_f64_t result = 1 - ab * squares_arr[0] * squares_arr[1];
118
+ return result > 0 ? result : 0;
119
+ }
120
+
121
+ #pragma region F32 and F64 Floats
122
+
123
+ NK_PUBLIC void nk_sqeuclidean_f32_neon(nk_f32_t const *a, nk_f32_t const *b, nk_size_t n, nk_f64_t *result) {
124
+ // Accumulate in f64 for numerical stability (2 f32s per iteration, avoids slow vget_low/high)
125
+ float64x2_t sum_f64x2 = vdupq_n_f64(0);
126
+ nk_size_t i = 0;
127
+ for (; i + 2 <= n; i += 2) {
128
+ float32x2_t a_f32x2 = vld1_f32(a + i);
129
+ float32x2_t b_f32x2 = vld1_f32(b + i);
130
+ float32x2_t diff_f32x2 = vsub_f32(a_f32x2, b_f32x2);
131
+ float64x2_t diff_f64x2 = vcvt_f64_f32(diff_f32x2);
132
+ sum_f64x2 = vfmaq_f64(sum_f64x2, diff_f64x2, diff_f64x2);
133
+ }
134
+ nk_f64_t sum_f64 = vaddvq_f64(sum_f64x2);
135
+ for (; i < n; ++i) {
136
+ nk_f64_t diff_f64 = (nk_f64_t)a[i] - (nk_f64_t)b[i];
137
+ sum_f64 += diff_f64 * diff_f64;
138
+ }
139
+ *result = sum_f64;
140
+ }
141
+
142
+ NK_PUBLIC void nk_euclidean_f32_neon(nk_f32_t const *a, nk_f32_t const *b, nk_size_t n, nk_f64_t *result) {
143
+ nk_sqeuclidean_f32_neon(a, b, n, result);
144
+ *result = nk_f64_sqrt_neon(*result);
145
+ }
146
+
147
+ NK_PUBLIC void nk_angular_f32_neon(nk_f32_t const *a, nk_f32_t const *b, nk_size_t n, nk_f64_t *result) {
148
+ // Accumulate in f64 for numerical stability (2 f32s per iteration, avoids slow vget_low/high)
149
+ float64x2_t ab_f64x2 = vdupq_n_f64(0);
150
+ float64x2_t a2_f64x2 = vdupq_n_f64(0);
151
+ float64x2_t b2_f64x2 = vdupq_n_f64(0);
152
+ nk_size_t i = 0;
153
+ for (; i + 2 <= n; i += 2) {
154
+ float32x2_t a_f32x2 = vld1_f32(a + i);
155
+ float32x2_t b_f32x2 = vld1_f32(b + i);
156
+ float64x2_t a_f64x2 = vcvt_f64_f32(a_f32x2);
157
+ float64x2_t b_f64x2 = vcvt_f64_f32(b_f32x2);
158
+ ab_f64x2 = vfmaq_f64(ab_f64x2, a_f64x2, b_f64x2);
159
+ a2_f64x2 = vfmaq_f64(a2_f64x2, a_f64x2, a_f64x2);
160
+ b2_f64x2 = vfmaq_f64(b2_f64x2, b_f64x2, b_f64x2);
161
+ }
162
+ nk_f64_t ab_f64 = vaddvq_f64(ab_f64x2);
163
+ nk_f64_t a2_f64 = vaddvq_f64(a2_f64x2);
164
+ nk_f64_t b2_f64 = vaddvq_f64(b2_f64x2);
165
+ for (; i < n; ++i) {
166
+ nk_f64_t ai = (nk_f64_t)a[i], bi = (nk_f64_t)b[i];
167
+ ab_f64 += ai * bi, a2_f64 += ai * ai, b2_f64 += bi * bi;
168
+ }
169
+ *result = nk_angular_normalize_f64_neon_(ab_f64, a2_f64, b2_f64);
170
+ }
171
+
172
+ NK_PUBLIC void nk_sqeuclidean_f64_neon(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
173
+ float64x2_t sum_f64x2 = vdupq_n_f64(0);
174
+ float64x2_t a_f64x2, b_f64x2;
175
+
176
+ nk_sqeuclidean_f64_neon_cycle:
177
+ if (n < 2) {
178
+ nk_b128_vec_t a_tail, b_tail;
179
+ nk_partial_load_b64x2_serial_(a, &a_tail, n);
180
+ nk_partial_load_b64x2_serial_(b, &b_tail, n);
181
+ a_f64x2 = a_tail.f64x2;
182
+ b_f64x2 = b_tail.f64x2;
183
+ n = 0;
184
+ }
185
+ else {
186
+ a_f64x2 = vld1q_f64(a);
187
+ b_f64x2 = vld1q_f64(b);
188
+ a += 2, b += 2, n -= 2;
189
+ }
190
+ float64x2_t diff_f64x2 = vsubq_f64(a_f64x2, b_f64x2);
191
+ sum_f64x2 = vfmaq_f64(sum_f64x2, diff_f64x2, diff_f64x2);
192
+ if (n) goto nk_sqeuclidean_f64_neon_cycle;
193
+
194
+ *result = vaddvq_f64(sum_f64x2);
195
+ }
196
+
197
+ NK_PUBLIC void nk_euclidean_f64_neon(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
198
+ nk_sqeuclidean_f64_neon(a, b, n, result);
199
+ *result = nk_f64_sqrt_neon(*result);
200
+ }
201
+
202
+ NK_PUBLIC void nk_angular_f64_neon(nk_f64_t const *a, nk_f64_t const *b, nk_size_t n, nk_f64_t *result) {
203
+ // Dot2 (Ogita-Rump-Oishi) for cross-product ab (may have cancellation),
204
+ // simple FMA for self-products a2/b2 (all positive, no cancellation)
205
+ float64x2_t ab_sum_f64x2 = vdupq_n_f64(0);
206
+ float64x2_t ab_compensation_f64x2 = vdupq_n_f64(0);
207
+ float64x2_t a2_f64x2 = vdupq_n_f64(0);
208
+ float64x2_t b2_f64x2 = vdupq_n_f64(0);
209
+ float64x2_t a_f64x2, b_f64x2;
210
+
211
+ nk_angular_f64_neon_cycle:
212
+ if (n < 2) {
213
+ nk_b128_vec_t a_tail, b_tail;
214
+ nk_partial_load_b64x2_serial_(a, &a_tail, n);
215
+ nk_partial_load_b64x2_serial_(b, &b_tail, n);
216
+ a_f64x2 = a_tail.f64x2;
217
+ b_f64x2 = b_tail.f64x2;
218
+ n = 0;
219
+ }
220
+ else {
221
+ a_f64x2 = vld1q_f64(a);
222
+ b_f64x2 = vld1q_f64(b);
223
+ a += 2, b += 2, n -= 2;
224
+ }
225
+ // TwoProd for ab: product = a*b, error = fma(a,b,-product)
226
+ float64x2_t product_f64x2 = vmulq_f64(a_f64x2, b_f64x2);
227
+ float64x2_t product_error_f64x2 = vnegq_f64(vfmsq_f64(product_f64x2, a_f64x2, b_f64x2));
228
+ // TwoSum: (t, q) = TwoSum(sum, product)
229
+ float64x2_t tentative_sum_f64x2 = vaddq_f64(ab_sum_f64x2, product_f64x2);
230
+ float64x2_t virtual_addend_f64x2 = vsubq_f64(tentative_sum_f64x2, ab_sum_f64x2);
231
+ float64x2_t sum_error_f64x2 = vaddq_f64(
232
+ vsubq_f64(ab_sum_f64x2, vsubq_f64(tentative_sum_f64x2, virtual_addend_f64x2)),
233
+ vsubq_f64(product_f64x2, virtual_addend_f64x2));
234
+ ab_sum_f64x2 = tentative_sum_f64x2;
235
+ ab_compensation_f64x2 = vaddq_f64(ab_compensation_f64x2, vaddq_f64(sum_error_f64x2, product_error_f64x2));
236
+ // Simple FMA for self-products (no cancellation)
237
+ a2_f64x2 = vfmaq_f64(a2_f64x2, a_f64x2, a_f64x2);
238
+ b2_f64x2 = vfmaq_f64(b2_f64x2, b_f64x2, b_f64x2);
239
+ if (n) goto nk_angular_f64_neon_cycle;
240
+
241
+ *result = nk_angular_normalize_f64_neon_( //
242
+ nk_dot_stable_sum_f64x2_neon_(ab_sum_f64x2, ab_compensation_f64x2), vaddvq_f64(a2_f64x2), vaddvq_f64(b2_f64x2));
243
+ }
244
+
245
+ #pragma endregion F32 and F64 Floats
246
+ #pragma region F16 and BF16 Floats
247
+
248
+ NK_PUBLIC void nk_sqeuclidean_bf16_neon(nk_bf16_t const *a, nk_bf16_t const *b, nk_size_t n, nk_f32_t *result) {
249
+ uint16x8_t a_u16x8, b_u16x8;
250
+ float32x4_t sum_f32x4 = vdupq_n_f32(0);
251
+ nk_sqeuclidean_bf16_neon_cycle:
252
+ if (n < 8) {
253
+ nk_b128_vec_t a_vec, b_vec;
254
+ nk_partial_load_b16x8_serial_(a, &a_vec, n);
255
+ nk_partial_load_b16x8_serial_(b, &b_vec, n);
256
+ a_u16x8 = a_vec.u16x8;
257
+ b_u16x8 = b_vec.u16x8;
258
+ n = 0;
259
+ }
260
+ else {
261
+ a_u16x8 = vld1q_u16((nk_u16_t const *)a);
262
+ b_u16x8 = vld1q_u16((nk_u16_t const *)b);
263
+ a += 8, b += 8, n -= 8;
264
+ }
265
+ float32x4_t a_low_f32x4 = vreinterpretq_f32_u32(vshll_n_u16(vget_low_u16(a_u16x8), 16));
266
+ float32x4_t a_high_f32x4 = vreinterpretq_f32_u32(vshll_high_n_u16(a_u16x8, 16));
267
+ float32x4_t b_low_f32x4 = vreinterpretq_f32_u32(vshll_n_u16(vget_low_u16(b_u16x8), 16));
268
+ float32x4_t b_high_f32x4 = vreinterpretq_f32_u32(vshll_high_n_u16(b_u16x8, 16));
269
+ float32x4_t diff_low_f32x4 = vsubq_f32(a_low_f32x4, b_low_f32x4);
270
+ float32x4_t diff_high_f32x4 = vsubq_f32(a_high_f32x4, b_high_f32x4);
271
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_low_f32x4, diff_low_f32x4);
272
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_high_f32x4, diff_high_f32x4);
273
+ if (n) goto nk_sqeuclidean_bf16_neon_cycle;
274
+ *result = vaddvq_f32(sum_f32x4);
275
+ }
276
+
277
+ NK_PUBLIC void nk_euclidean_bf16_neon(nk_bf16_t const *a, nk_bf16_t const *b, nk_size_t n, nk_f32_t *result) {
278
+ nk_sqeuclidean_bf16_neon(a, b, n, result);
279
+ *result = nk_f32_sqrt_neon(*result);
280
+ }
281
+
282
+ NK_PUBLIC void nk_angular_bf16_neon(nk_bf16_t const *a, nk_bf16_t const *b, nk_size_t n, nk_f32_t *result) {
283
+ uint16x8_t a_u16x8, b_u16x8;
284
+ float32x4_t ab_f32x4 = vdupq_n_f32(0);
285
+ float32x4_t a2_f32x4 = vdupq_n_f32(0);
286
+ float32x4_t b2_f32x4 = vdupq_n_f32(0);
287
+ nk_angular_bf16_neon_cycle:
288
+ if (n < 8) {
289
+ nk_b128_vec_t a_vec, b_vec;
290
+ nk_partial_load_b16x8_serial_(a, &a_vec, n);
291
+ nk_partial_load_b16x8_serial_(b, &b_vec, n);
292
+ a_u16x8 = a_vec.u16x8;
293
+ b_u16x8 = b_vec.u16x8;
294
+ n = 0;
295
+ }
296
+ else {
297
+ a_u16x8 = vld1q_u16((nk_u16_t const *)a);
298
+ b_u16x8 = vld1q_u16((nk_u16_t const *)b);
299
+ a += 8, b += 8, n -= 8;
300
+ }
301
+ float32x4_t a_low_f32x4 = vreinterpretq_f32_u32(vshll_n_u16(vget_low_u16(a_u16x8), 16));
302
+ float32x4_t a_high_f32x4 = vreinterpretq_f32_u32(vshll_high_n_u16(a_u16x8, 16));
303
+ float32x4_t b_low_f32x4 = vreinterpretq_f32_u32(vshll_n_u16(vget_low_u16(b_u16x8), 16));
304
+ float32x4_t b_high_f32x4 = vreinterpretq_f32_u32(vshll_high_n_u16(b_u16x8, 16));
305
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_low_f32x4, b_low_f32x4);
306
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_high_f32x4, b_high_f32x4);
307
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_low_f32x4, a_low_f32x4);
308
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_high_f32x4, a_high_f32x4);
309
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_low_f32x4, b_low_f32x4);
310
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_high_f32x4, b_high_f32x4);
311
+ if (n) goto nk_angular_bf16_neon_cycle;
312
+ nk_f32_t ab = vaddvq_f32(ab_f32x4);
313
+ nk_f32_t a2 = vaddvq_f32(a2_f32x4);
314
+ nk_f32_t b2 = vaddvq_f32(b2_f32x4);
315
+ *result = nk_angular_normalize_f32_neon_(ab, a2, b2);
316
+ }
317
+
318
+ NK_PUBLIC void nk_sqeuclidean_f16_neon(nk_f16_t const *a, nk_f16_t const *b, nk_size_t n, nk_f32_t *result) {
319
+ uint16x8_t a_u16x8, b_u16x8;
320
+ float32x4_t sum_f32x4 = vdupq_n_f32(0);
321
+ nk_sqeuclidean_f16_neon_cycle:
322
+ if (n < 8) {
323
+ nk_b128_vec_t a_vec, b_vec;
324
+ nk_partial_load_b16x8_serial_(a, &a_vec, n);
325
+ nk_partial_load_b16x8_serial_(b, &b_vec, n);
326
+ a_u16x8 = a_vec.u16x8;
327
+ b_u16x8 = b_vec.u16x8;
328
+ n = 0;
329
+ }
330
+ else {
331
+ a_u16x8 = vld1q_u16((nk_u16_t const *)a);
332
+ b_u16x8 = vld1q_u16((nk_u16_t const *)b);
333
+ a += 8, b += 8, n -= 8;
334
+ }
335
+ float16x8_t a_f16x8 = vreinterpretq_f16_u16(a_u16x8);
336
+ float16x8_t b_f16x8 = vreinterpretq_f16_u16(b_u16x8);
337
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
338
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
339
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
340
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
341
+ float32x4_t diff_low_f32x4 = vsubq_f32(a_low_f32x4, b_low_f32x4);
342
+ float32x4_t diff_high_f32x4 = vsubq_f32(a_high_f32x4, b_high_f32x4);
343
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_low_f32x4, diff_low_f32x4);
344
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_high_f32x4, diff_high_f32x4);
345
+ if (n) goto nk_sqeuclidean_f16_neon_cycle;
346
+ *result = vaddvq_f32(sum_f32x4);
347
+ }
348
+
349
+ NK_PUBLIC void nk_euclidean_f16_neon(nk_f16_t const *a, nk_f16_t const *b, nk_size_t n, nk_f32_t *result) {
350
+ nk_sqeuclidean_f16_neon(a, b, n, result);
351
+ *result = nk_f32_sqrt_neon(*result);
352
+ }
353
+
354
+ NK_PUBLIC void nk_angular_f16_neon(nk_f16_t const *a, nk_f16_t const *b, nk_size_t n, nk_f32_t *result) {
355
+ uint16x8_t a_u16x8, b_u16x8;
356
+ float32x4_t ab_f32x4 = vdupq_n_f32(0);
357
+ float32x4_t a2_f32x4 = vdupq_n_f32(0);
358
+ float32x4_t b2_f32x4 = vdupq_n_f32(0);
359
+ nk_angular_f16_neon_cycle:
360
+ if (n < 8) {
361
+ nk_b128_vec_t a_vec, b_vec;
362
+ nk_partial_load_b16x8_serial_(a, &a_vec, n);
363
+ nk_partial_load_b16x8_serial_(b, &b_vec, n);
364
+ a_u16x8 = a_vec.u16x8;
365
+ b_u16x8 = b_vec.u16x8;
366
+ n = 0;
367
+ }
368
+ else {
369
+ a_u16x8 = vld1q_u16((nk_u16_t const *)a);
370
+ b_u16x8 = vld1q_u16((nk_u16_t const *)b);
371
+ a += 8, b += 8, n -= 8;
372
+ }
373
+ float16x8_t a_f16x8 = vreinterpretq_f16_u16(a_u16x8);
374
+ float16x8_t b_f16x8 = vreinterpretq_f16_u16(b_u16x8);
375
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
376
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
377
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
378
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
379
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_low_f32x4, b_low_f32x4);
380
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_high_f32x4, b_high_f32x4);
381
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_low_f32x4, a_low_f32x4);
382
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_high_f32x4, a_high_f32x4);
383
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_low_f32x4, b_low_f32x4);
384
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_high_f32x4, b_high_f32x4);
385
+ if (n) goto nk_angular_f16_neon_cycle;
386
+ nk_f32_t ab = vaddvq_f32(ab_f32x4);
387
+ nk_f32_t a2 = vaddvq_f32(a2_f32x4);
388
+ nk_f32_t b2 = vaddvq_f32(b2_f32x4);
389
+ *result = nk_angular_normalize_f32_neon_(ab, a2, b2);
390
+ }
391
+
392
+ NK_PUBLIC void nk_sqeuclidean_e2m3_neon(nk_e2m3_t const *a, nk_e2m3_t const *b, nk_size_t n, nk_f32_t *result) {
393
+ float16x8_t a_f16x8, b_f16x8;
394
+ float32x4_t sum_f32x4 = vdupq_n_f32(0);
395
+ nk_sqeuclidean_e2m3_neon_cycle:
396
+ if (n < 8) {
397
+ nk_b64_vec_t a_vec, b_vec;
398
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
399
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
400
+ a_f16x8 = nk_e2m3x8_to_f16x8_neon_(a_vec.u8x8);
401
+ b_f16x8 = nk_e2m3x8_to_f16x8_neon_(b_vec.u8x8);
402
+ n = 0;
403
+ }
404
+ else {
405
+ a_f16x8 = nk_e2m3x8_to_f16x8_neon_(vld1_u8(a));
406
+ b_f16x8 = nk_e2m3x8_to_f16x8_neon_(vld1_u8(b));
407
+ a += 8, b += 8, n -= 8;
408
+ }
409
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
410
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
411
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
412
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
413
+ float32x4_t diff_low_f32x4 = vsubq_f32(a_low_f32x4, b_low_f32x4);
414
+ float32x4_t diff_high_f32x4 = vsubq_f32(a_high_f32x4, b_high_f32x4);
415
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_low_f32x4, diff_low_f32x4);
416
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_high_f32x4, diff_high_f32x4);
417
+ if (n) goto nk_sqeuclidean_e2m3_neon_cycle;
418
+ *result = vaddvq_f32(sum_f32x4);
419
+ }
420
+
421
+ NK_PUBLIC void nk_euclidean_e2m3_neon(nk_e2m3_t const *a, nk_e2m3_t const *b, nk_size_t n, nk_f32_t *result) {
422
+ nk_sqeuclidean_e2m3_neon(a, b, n, result);
423
+ *result = nk_f32_sqrt_neon(*result);
424
+ }
425
+
426
+ NK_PUBLIC void nk_angular_e2m3_neon(nk_e2m3_t const *a, nk_e2m3_t const *b, nk_size_t n, nk_f32_t *result) {
427
+ float16x8_t a_f16x8, b_f16x8;
428
+ float32x4_t ab_f32x4 = vdupq_n_f32(0);
429
+ float32x4_t a2_f32x4 = vdupq_n_f32(0);
430
+ float32x4_t b2_f32x4 = vdupq_n_f32(0);
431
+ nk_angular_e2m3_neon_cycle:
432
+ if (n < 8) {
433
+ nk_b64_vec_t a_vec, b_vec;
434
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
435
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
436
+ a_f16x8 = nk_e2m3x8_to_f16x8_neon_(a_vec.u8x8);
437
+ b_f16x8 = nk_e2m3x8_to_f16x8_neon_(b_vec.u8x8);
438
+ n = 0;
439
+ }
440
+ else {
441
+ a_f16x8 = nk_e2m3x8_to_f16x8_neon_(vld1_u8(a));
442
+ b_f16x8 = nk_e2m3x8_to_f16x8_neon_(vld1_u8(b));
443
+ a += 8, b += 8, n -= 8;
444
+ }
445
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
446
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
447
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
448
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
449
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_low_f32x4, b_low_f32x4);
450
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_high_f32x4, b_high_f32x4);
451
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_low_f32x4, a_low_f32x4);
452
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_high_f32x4, a_high_f32x4);
453
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_low_f32x4, b_low_f32x4);
454
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_high_f32x4, b_high_f32x4);
455
+ if (n) goto nk_angular_e2m3_neon_cycle;
456
+ nk_f32_t ab = vaddvq_f32(ab_f32x4);
457
+ nk_f32_t a2 = vaddvq_f32(a2_f32x4);
458
+ nk_f32_t b2 = vaddvq_f32(b2_f32x4);
459
+ *result = nk_angular_normalize_f32_neon_(ab, a2, b2);
460
+ }
461
+
462
+ NK_PUBLIC void nk_sqeuclidean_e3m2_neon(nk_e3m2_t const *a, nk_e3m2_t const *b, nk_size_t n, nk_f32_t *result) {
463
+ float16x8_t a_f16x8, b_f16x8;
464
+ float32x4_t sum_f32x4 = vdupq_n_f32(0);
465
+ nk_sqeuclidean_e3m2_neon_cycle:
466
+ if (n < 8) {
467
+ nk_b64_vec_t a_vec, b_vec;
468
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
469
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
470
+ a_f16x8 = nk_e3m2x8_to_f16x8_neon_(a_vec.u8x8);
471
+ b_f16x8 = nk_e3m2x8_to_f16x8_neon_(b_vec.u8x8);
472
+ n = 0;
473
+ }
474
+ else {
475
+ a_f16x8 = nk_e3m2x8_to_f16x8_neon_(vld1_u8(a));
476
+ b_f16x8 = nk_e3m2x8_to_f16x8_neon_(vld1_u8(b));
477
+ a += 8, b += 8, n -= 8;
478
+ }
479
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
480
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
481
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
482
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
483
+ float32x4_t diff_low_f32x4 = vsubq_f32(a_low_f32x4, b_low_f32x4);
484
+ float32x4_t diff_high_f32x4 = vsubq_f32(a_high_f32x4, b_high_f32x4);
485
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_low_f32x4, diff_low_f32x4);
486
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_high_f32x4, diff_high_f32x4);
487
+ if (n) goto nk_sqeuclidean_e3m2_neon_cycle;
488
+ *result = vaddvq_f32(sum_f32x4);
489
+ }
490
+
491
+ NK_PUBLIC void nk_euclidean_e3m2_neon(nk_e3m2_t const *a, nk_e3m2_t const *b, nk_size_t n, nk_f32_t *result) {
492
+ nk_sqeuclidean_e3m2_neon(a, b, n, result);
493
+ *result = nk_f32_sqrt_neon(*result);
494
+ }
495
+
496
+ NK_PUBLIC void nk_angular_e3m2_neon(nk_e3m2_t const *a, nk_e3m2_t const *b, nk_size_t n, nk_f32_t *result) {
497
+ float16x8_t a_f16x8, b_f16x8;
498
+ float32x4_t ab_f32x4 = vdupq_n_f32(0);
499
+ float32x4_t a2_f32x4 = vdupq_n_f32(0);
500
+ float32x4_t b2_f32x4 = vdupq_n_f32(0);
501
+ nk_angular_e3m2_neon_cycle:
502
+ if (n < 8) {
503
+ nk_b64_vec_t a_vec, b_vec;
504
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
505
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
506
+ a_f16x8 = nk_e3m2x8_to_f16x8_neon_(a_vec.u8x8);
507
+ b_f16x8 = nk_e3m2x8_to_f16x8_neon_(b_vec.u8x8);
508
+ n = 0;
509
+ }
510
+ else {
511
+ a_f16x8 = nk_e3m2x8_to_f16x8_neon_(vld1_u8(a));
512
+ b_f16x8 = nk_e3m2x8_to_f16x8_neon_(vld1_u8(b));
513
+ a += 8, b += 8, n -= 8;
514
+ }
515
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
516
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
517
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
518
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
519
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_low_f32x4, b_low_f32x4);
520
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_high_f32x4, b_high_f32x4);
521
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_low_f32x4, a_low_f32x4);
522
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_high_f32x4, a_high_f32x4);
523
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_low_f32x4, b_low_f32x4);
524
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_high_f32x4, b_high_f32x4);
525
+ if (n) goto nk_angular_e3m2_neon_cycle;
526
+ nk_f32_t ab = vaddvq_f32(ab_f32x4);
527
+ nk_f32_t a2 = vaddvq_f32(a2_f32x4);
528
+ nk_f32_t b2 = vaddvq_f32(b2_f32x4);
529
+ *result = nk_angular_normalize_f32_neon_(ab, a2, b2);
530
+ }
531
+
532
+ NK_PUBLIC void nk_sqeuclidean_e4m3_neon(nk_e4m3_t const *a, nk_e4m3_t const *b, nk_size_t n, nk_f32_t *result) {
533
+ float16x8_t a_f16x8, b_f16x8;
534
+ float32x4_t sum_f32x4 = vdupq_n_f32(0);
535
+ nk_sqeuclidean_e4m3_neon_cycle:
536
+ if (n < 8) {
537
+ nk_b64_vec_t a_vec, b_vec;
538
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
539
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
540
+ a_f16x8 = nk_e4m3x8_to_f16x8_neon_(a_vec.u8x8);
541
+ b_f16x8 = nk_e4m3x8_to_f16x8_neon_(b_vec.u8x8);
542
+ n = 0;
543
+ }
544
+ else {
545
+ a_f16x8 = nk_e4m3x8_to_f16x8_neon_(vld1_u8(a));
546
+ b_f16x8 = nk_e4m3x8_to_f16x8_neon_(vld1_u8(b));
547
+ a += 8, b += 8, n -= 8;
548
+ }
549
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
550
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
551
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
552
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
553
+ float32x4_t diff_low_f32x4 = vsubq_f32(a_low_f32x4, b_low_f32x4);
554
+ float32x4_t diff_high_f32x4 = vsubq_f32(a_high_f32x4, b_high_f32x4);
555
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_low_f32x4, diff_low_f32x4);
556
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_high_f32x4, diff_high_f32x4);
557
+ if (n) goto nk_sqeuclidean_e4m3_neon_cycle;
558
+ *result = vaddvq_f32(sum_f32x4);
559
+ }
560
+
561
+ NK_PUBLIC void nk_euclidean_e4m3_neon(nk_e4m3_t const *a, nk_e4m3_t const *b, nk_size_t n, nk_f32_t *result) {
562
+ nk_sqeuclidean_e4m3_neon(a, b, n, result);
563
+ *result = nk_f32_sqrt_neon(*result);
564
+ }
565
+
566
+ NK_PUBLIC void nk_angular_e4m3_neon(nk_e4m3_t const *a, nk_e4m3_t const *b, nk_size_t n, nk_f32_t *result) {
567
+ float16x8_t a_f16x8, b_f16x8;
568
+ float32x4_t ab_f32x4 = vdupq_n_f32(0);
569
+ float32x4_t a2_f32x4 = vdupq_n_f32(0);
570
+ float32x4_t b2_f32x4 = vdupq_n_f32(0);
571
+ nk_angular_e4m3_neon_cycle:
572
+ if (n < 8) {
573
+ nk_b64_vec_t a_vec, b_vec;
574
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
575
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
576
+ a_f16x8 = nk_e4m3x8_to_f16x8_neon_(a_vec.u8x8);
577
+ b_f16x8 = nk_e4m3x8_to_f16x8_neon_(b_vec.u8x8);
578
+ n = 0;
579
+ }
580
+ else {
581
+ a_f16x8 = nk_e4m3x8_to_f16x8_neon_(vld1_u8(a));
582
+ b_f16x8 = nk_e4m3x8_to_f16x8_neon_(vld1_u8(b));
583
+ a += 8, b += 8, n -= 8;
584
+ }
585
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
586
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
587
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
588
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
589
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_low_f32x4, b_low_f32x4);
590
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_high_f32x4, b_high_f32x4);
591
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_low_f32x4, a_low_f32x4);
592
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_high_f32x4, a_high_f32x4);
593
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_low_f32x4, b_low_f32x4);
594
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_high_f32x4, b_high_f32x4);
595
+ if (n) goto nk_angular_e4m3_neon_cycle;
596
+ nk_f32_t ab = vaddvq_f32(ab_f32x4);
597
+ nk_f32_t a2 = vaddvq_f32(a2_f32x4);
598
+ nk_f32_t b2 = vaddvq_f32(b2_f32x4);
599
+ *result = nk_angular_normalize_f32_neon_(ab, a2, b2);
600
+ }
601
+
602
+ NK_PUBLIC void nk_sqeuclidean_e5m2_neon(nk_e5m2_t const *a, nk_e5m2_t const *b, nk_size_t n, nk_f32_t *result) {
603
+ float16x8_t a_f16x8, b_f16x8;
604
+ float32x4_t sum_f32x4 = vdupq_n_f32(0);
605
+ nk_sqeuclidean_e5m2_neon_cycle:
606
+ if (n < 8) {
607
+ nk_b64_vec_t a_vec, b_vec;
608
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
609
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
610
+ a_f16x8 = nk_e5m2x8_to_f16x8_neon_(a_vec.u8x8);
611
+ b_f16x8 = nk_e5m2x8_to_f16x8_neon_(b_vec.u8x8);
612
+ n = 0;
613
+ }
614
+ else {
615
+ a_f16x8 = nk_e5m2x8_to_f16x8_neon_(vld1_u8(a));
616
+ b_f16x8 = nk_e5m2x8_to_f16x8_neon_(vld1_u8(b));
617
+ a += 8, b += 8, n -= 8;
618
+ }
619
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
620
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
621
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
622
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
623
+ float32x4_t diff_low_f32x4 = vsubq_f32(a_low_f32x4, b_low_f32x4);
624
+ float32x4_t diff_high_f32x4 = vsubq_f32(a_high_f32x4, b_high_f32x4);
625
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_low_f32x4, diff_low_f32x4);
626
+ sum_f32x4 = vfmaq_f32(sum_f32x4, diff_high_f32x4, diff_high_f32x4);
627
+ if (n) goto nk_sqeuclidean_e5m2_neon_cycle;
628
+ *result = vaddvq_f32(sum_f32x4);
629
+ }
630
+
631
+ NK_PUBLIC void nk_euclidean_e5m2_neon(nk_e5m2_t const *a, nk_e5m2_t const *b, nk_size_t n, nk_f32_t *result) {
632
+ nk_sqeuclidean_e5m2_neon(a, b, n, result);
633
+ *result = nk_f32_sqrt_neon(*result);
634
+ }
635
+
636
+ NK_PUBLIC void nk_angular_e5m2_neon(nk_e5m2_t const *a, nk_e5m2_t const *b, nk_size_t n, nk_f32_t *result) {
637
+ float16x8_t a_f16x8, b_f16x8;
638
+ float32x4_t ab_f32x4 = vdupq_n_f32(0);
639
+ float32x4_t a2_f32x4 = vdupq_n_f32(0);
640
+ float32x4_t b2_f32x4 = vdupq_n_f32(0);
641
+ nk_angular_e5m2_neon_cycle:
642
+ if (n < 8) {
643
+ nk_b64_vec_t a_vec, b_vec;
644
+ nk_partial_load_b8x8_serial_(a, &a_vec, n);
645
+ nk_partial_load_b8x8_serial_(b, &b_vec, n);
646
+ a_f16x8 = nk_e5m2x8_to_f16x8_neon_(a_vec.u8x8);
647
+ b_f16x8 = nk_e5m2x8_to_f16x8_neon_(b_vec.u8x8);
648
+ n = 0;
649
+ }
650
+ else {
651
+ a_f16x8 = nk_e5m2x8_to_f16x8_neon_(vld1_u8(a));
652
+ b_f16x8 = nk_e5m2x8_to_f16x8_neon_(vld1_u8(b));
653
+ a += 8, b += 8, n -= 8;
654
+ }
655
+ float32x4_t a_low_f32x4 = vcvt_f32_f16(vget_low_f16(a_f16x8));
656
+ float32x4_t a_high_f32x4 = vcvt_high_f32_f16(a_f16x8);
657
+ float32x4_t b_low_f32x4 = vcvt_f32_f16(vget_low_f16(b_f16x8));
658
+ float32x4_t b_high_f32x4 = vcvt_high_f32_f16(b_f16x8);
659
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_low_f32x4, b_low_f32x4);
660
+ ab_f32x4 = vfmaq_f32(ab_f32x4, a_high_f32x4, b_high_f32x4);
661
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_low_f32x4, a_low_f32x4);
662
+ a2_f32x4 = vfmaq_f32(a2_f32x4, a_high_f32x4, a_high_f32x4);
663
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_low_f32x4, b_low_f32x4);
664
+ b2_f32x4 = vfmaq_f32(b2_f32x4, b_high_f32x4, b_high_f32x4);
665
+ if (n) goto nk_angular_e5m2_neon_cycle;
666
+ nk_f32_t ab = vaddvq_f32(ab_f32x4);
667
+ nk_f32_t a2 = vaddvq_f32(a2_f32x4);
668
+ nk_f32_t b2 = vaddvq_f32(b2_f32x4);
669
+ *result = nk_angular_normalize_f32_neon_(ab, a2, b2);
670
+ }
671
+
672
+ /** @brief Angular from_dot: computes 1 − dot × rsqrt(query_sumsq × target_sumsq) for 4 pairs in f64. */
673
+ NK_INTERNAL void nk_angular_through_f64_from_dot_neon_(nk_b256_vec_t dots, nk_f64_t query_sumsq,
674
+ nk_b256_vec_t target_sumsqs, nk_b256_vec_t *results) {
675
+ float64x2_t dots_ab_f64x2 = dots.f64x2s[0];
676
+ float64x2_t dots_cd_f64x2 = dots.f64x2s[1];
677
+ float64x2_t query_sumsq_f64x2 = vdupq_n_f64(query_sumsq);
678
+ float64x2_t target_sumsqs_ab_f64x2 = target_sumsqs.f64x2s[0];
679
+ float64x2_t target_sumsqs_cd_f64x2 = target_sumsqs.f64x2s[1];
680
+
681
+ // products = query_sumsq * target_sumsq
682
+ float64x2_t products_ab_f64x2 = vmulq_f64(query_sumsq_f64x2, target_sumsqs_ab_f64x2);
683
+ float64x2_t products_cd_f64x2 = vmulq_f64(query_sumsq_f64x2, target_sumsqs_cd_f64x2);
684
+
685
+ // rsqrt with Newton-Raphson (2 iterations for ~48-bit precision)
686
+ float64x2_t rsqrt_ab_f64x2 = vrsqrteq_f64(products_ab_f64x2);
687
+ float64x2_t rsqrt_cd_f64x2 = vrsqrteq_f64(products_cd_f64x2);
688
+ rsqrt_ab_f64x2 = vmulq_f64(rsqrt_ab_f64x2,
689
+ vrsqrtsq_f64(vmulq_f64(products_ab_f64x2, rsqrt_ab_f64x2), rsqrt_ab_f64x2));
690
+ rsqrt_cd_f64x2 = vmulq_f64(rsqrt_cd_f64x2,
691
+ vrsqrtsq_f64(vmulq_f64(products_cd_f64x2, rsqrt_cd_f64x2), rsqrt_cd_f64x2));
692
+ rsqrt_ab_f64x2 = vmulq_f64(rsqrt_ab_f64x2,
693
+ vrsqrtsq_f64(vmulq_f64(products_ab_f64x2, rsqrt_ab_f64x2), rsqrt_ab_f64x2));
694
+ rsqrt_cd_f64x2 = vmulq_f64(rsqrt_cd_f64x2,
695
+ vrsqrtsq_f64(vmulq_f64(products_cd_f64x2, rsqrt_cd_f64x2), rsqrt_cd_f64x2));
696
+
697
+ // angular = 1 − dot × rsqrt(product)
698
+ float64x2_t ones_f64x2 = vdupq_n_f64(1.0);
699
+ float64x2_t zeros_f64x2 = vdupq_n_f64(0.0);
700
+ float64x2_t result_ab_f64x2 = vsubq_f64(ones_f64x2, vmulq_f64(dots_ab_f64x2, rsqrt_ab_f64x2));
701
+ float64x2_t result_cd_f64x2 = vsubq_f64(ones_f64x2, vmulq_f64(dots_cd_f64x2, rsqrt_cd_f64x2));
702
+
703
+ // Clamp to [0, inf)
704
+ result_ab_f64x2 = vmaxq_f64(result_ab_f64x2, zeros_f64x2);
705
+ result_cd_f64x2 = vmaxq_f64(result_cd_f64x2, zeros_f64x2);
706
+
707
+ // Handle edge cases with vectorized selects
708
+ uint64x2_t products_zero_ab_u64x2 = vceqq_f64(products_ab_f64x2, zeros_f64x2);
709
+ uint64x2_t products_zero_cd_u64x2 = vceqq_f64(products_cd_f64x2, zeros_f64x2);
710
+ uint64x2_t dots_zero_ab_u64x2 = vceqq_f64(dots_ab_f64x2, zeros_f64x2);
711
+ uint64x2_t dots_zero_cd_u64x2 = vceqq_f64(dots_cd_f64x2, zeros_f64x2);
712
+
713
+ // Both zero → result = 0; products zero but dots nonzero → result = 1
714
+ uint64x2_t both_zero_ab_u64x2 = vandq_u64(products_zero_ab_u64x2, dots_zero_ab_u64x2);
715
+ uint64x2_t both_zero_cd_u64x2 = vandq_u64(products_zero_cd_u64x2, dots_zero_cd_u64x2);
716
+ result_ab_f64x2 = vbslq_f64(both_zero_ab_u64x2, zeros_f64x2, result_ab_f64x2);
717
+ result_cd_f64x2 = vbslq_f64(both_zero_cd_u64x2, zeros_f64x2, result_cd_f64x2);
718
+
719
+ uint64x2_t prod_zero_dot_nonzero_ab_u64x2 = vandq_u64(
720
+ products_zero_ab_u64x2, vreinterpretq_u64_u32(vmvnq_u32(vreinterpretq_u32_u64(dots_zero_ab_u64x2))));
721
+ uint64x2_t prod_zero_dot_nonzero_cd_u64x2 = vandq_u64(
722
+ products_zero_cd_u64x2, vreinterpretq_u64_u32(vmvnq_u32(vreinterpretq_u32_u64(dots_zero_cd_u64x2))));
723
+ result_ab_f64x2 = vbslq_f64(prod_zero_dot_nonzero_ab_u64x2, ones_f64x2, result_ab_f64x2);
724
+ result_cd_f64x2 = vbslq_f64(prod_zero_dot_nonzero_cd_u64x2, ones_f64x2, result_cd_f64x2);
725
+
726
+ results->f64x2s[0] = result_ab_f64x2;
727
+ results->f64x2s[1] = result_cd_f64x2;
728
+ }
729
+
730
+ /** @brief Euclidean from_dot: computes √(query_sumsq + target_sumsq − 2 × dot) for 4 pairs in f64. */
731
+ NK_INTERNAL void nk_euclidean_through_f64_from_dot_neon_(nk_b256_vec_t dots, nk_f64_t query_sumsq,
732
+ nk_b256_vec_t target_sumsqs, nk_b256_vec_t *results) {
733
+ float64x2_t dots_ab_f64x2 = dots.f64x2s[0];
734
+ float64x2_t dots_cd_f64x2 = dots.f64x2s[1];
735
+ float64x2_t query_sumsq_f64x2 = vdupq_n_f64(query_sumsq);
736
+ float64x2_t target_sumsqs_ab_f64x2 = target_sumsqs.f64x2s[0];
737
+ float64x2_t target_sumsqs_cd_f64x2 = target_sumsqs.f64x2s[1];
738
+
739
+ // dist_sq = query_sumsq + target_sumsq − 2 × dot
740
+ float64x2_t neg_two_f64x2 = vdupq_n_f64(-2.0);
741
+ float64x2_t sum_sq_ab_f64x2 = vaddq_f64(query_sumsq_f64x2, target_sumsqs_ab_f64x2);
742
+ float64x2_t sum_sq_cd_f64x2 = vaddq_f64(query_sumsq_f64x2, target_sumsqs_cd_f64x2);
743
+ float64x2_t dist_sq_ab_f64x2 = vfmaq_f64(sum_sq_ab_f64x2, neg_two_f64x2, dots_ab_f64x2);
744
+ float64x2_t dist_sq_cd_f64x2 = vfmaq_f64(sum_sq_cd_f64x2, neg_two_f64x2, dots_cd_f64x2);
745
+
746
+ // Clamp and sqrt in f64
747
+ float64x2_t zeros_f64x2 = vdupq_n_f64(0.0);
748
+ dist_sq_ab_f64x2 = vmaxq_f64(dist_sq_ab_f64x2, zeros_f64x2);
749
+ dist_sq_cd_f64x2 = vmaxq_f64(dist_sq_cd_f64x2, zeros_f64x2);
750
+ float64x2_t dist_ab_f64x2 = vsqrtq_f64(dist_sq_ab_f64x2);
751
+ float64x2_t dist_cd_f64x2 = vsqrtq_f64(dist_sq_cd_f64x2);
752
+
753
+ results->f64x2s[0] = dist_ab_f64x2;
754
+ results->f64x2s[1] = dist_cd_f64x2;
755
+ }
756
+
757
+ /** @brief Angular from_dot: computes 1 − dot × rsqrt(query_sumsq × target_sumsq) for 4 pairs in f32. */
758
+ NK_INTERNAL void nk_angular_through_f32_from_dot_neon_(nk_b128_vec_t dots, nk_f32_t query_sumsq,
759
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
760
+ float32x4_t dots_f32x4 = dots.f32x4;
761
+ float32x4_t query_sumsq_f32x4 = vdupq_n_f32(query_sumsq);
762
+ float32x4_t products_f32x4 = vmulq_f32(query_sumsq_f32x4, target_sumsqs.f32x4);
763
+
764
+ // rsqrt with Newton-Raphson refinement (2 iterations)
765
+ float32x4_t rsqrt_f32x4 = vrsqrteq_f32(products_f32x4);
766
+ rsqrt_f32x4 = vmulq_f32(rsqrt_f32x4, vrsqrtsq_f32(vmulq_f32(products_f32x4, rsqrt_f32x4), rsqrt_f32x4));
767
+ rsqrt_f32x4 = vmulq_f32(rsqrt_f32x4, vrsqrtsq_f32(vmulq_f32(products_f32x4, rsqrt_f32x4), rsqrt_f32x4));
768
+
769
+ float32x4_t normalized_f32x4 = vmulq_f32(dots_f32x4, rsqrt_f32x4);
770
+ float32x4_t angular_f32x4 = vsubq_f32(vdupq_n_f32(1.0f), normalized_f32x4);
771
+ results->f32x4 = vmaxq_f32(angular_f32x4, vdupq_n_f32(0.0f));
772
+ }
773
+
774
+ /** @brief Euclidean from_dot: computes √(query_sumsq + target_sumsq − 2 × dot) for 4 pairs in f32. */
775
+ NK_INTERNAL void nk_euclidean_through_f32_from_dot_neon_(nk_b128_vec_t dots, nk_f32_t query_sumsq,
776
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
777
+ float32x4_t dots_f32x4 = dots.f32x4;
778
+ float32x4_t query_sumsq_f32x4 = vdupq_n_f32(query_sumsq);
779
+ float32x4_t sum_sq_f32x4 = vaddq_f32(query_sumsq_f32x4, target_sumsqs.f32x4);
780
+ // dist_sq = sum_sq − 2 × dot
781
+ float32x4_t dist_sq_f32x4 = vfmsq_f32(sum_sq_f32x4, vdupq_n_f32(2.0f), dots_f32x4);
782
+ // Clamp and sqrt
783
+ dist_sq_f32x4 = vmaxq_f32(dist_sq_f32x4, vdupq_n_f32(0.0f));
784
+ results->f32x4 = vsqrtq_f32(dist_sq_f32x4);
785
+ }
786
+
787
+ /** @brief Angular from_dot for i32 accumulators: cast to f32, rsqrt+NR, clamp. 4 pairs. */
788
+ NK_INTERNAL void nk_angular_through_i32_from_dot_neon_(nk_b128_vec_t dots, nk_i32_t query_sumsq,
789
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
790
+ float32x4_t dots_f32x4 = vcvtq_f32_s32(dots.i32x4);
791
+ float32x4_t query_sumsq_f32x4 = vdupq_n_f32((nk_f32_t)query_sumsq);
792
+ float32x4_t products_f32x4 = vmulq_f32(query_sumsq_f32x4, vcvtq_f32_s32(target_sumsqs.i32x4));
793
+ float32x4_t rsqrt_f32x4 = nk_rsqrt_f32x4_neon_(products_f32x4);
794
+ float32x4_t normalized_f32x4 = vmulq_f32(dots_f32x4, rsqrt_f32x4);
795
+ float32x4_t angular_f32x4 = vsubq_f32(vdupq_n_f32(1.0f), normalized_f32x4);
796
+ results->f32x4 = vmaxq_f32(angular_f32x4, vdupq_n_f32(0.0f));
797
+ }
798
+
799
+ /** @brief Euclidean from_dot for i32 accumulators: cast to f32, then √(a² + b² − 2ab). 4 pairs. */
800
+ NK_INTERNAL void nk_euclidean_through_i32_from_dot_neon_(nk_b128_vec_t dots, nk_i32_t query_sumsq,
801
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
802
+ float32x4_t dots_f32x4 = vcvtq_f32_s32(dots.i32x4);
803
+ float32x4_t query_sumsq_f32x4 = vdupq_n_f32((nk_f32_t)query_sumsq);
804
+ float32x4_t sum_sq_f32x4 = vaddq_f32(query_sumsq_f32x4, vcvtq_f32_s32(target_sumsqs.i32x4));
805
+ float32x4_t dist_sq_f32x4 = vfmsq_f32(sum_sq_f32x4, vdupq_n_f32(2.0f), dots_f32x4);
806
+ dist_sq_f32x4 = vmaxq_f32(dist_sq_f32x4, vdupq_n_f32(0.0f));
807
+ results->f32x4 = vsqrtq_f32(dist_sq_f32x4);
808
+ }
809
+
810
+ /** @brief Angular from_dot for u32 accumulators: cast to f32, rsqrt+NR, clamp. 4 pairs. */
811
+ NK_INTERNAL void nk_angular_through_u32_from_dot_neon_(nk_b128_vec_t dots, nk_u32_t query_sumsq,
812
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
813
+ float32x4_t dots_f32x4 = vcvtq_f32_u32(dots.u32x4);
814
+ float32x4_t query_sumsq_f32x4 = vdupq_n_f32((nk_f32_t)query_sumsq);
815
+ float32x4_t products_f32x4 = vmulq_f32(query_sumsq_f32x4, vcvtq_f32_u32(target_sumsqs.u32x4));
816
+ float32x4_t rsqrt_f32x4 = nk_rsqrt_f32x4_neon_(products_f32x4);
817
+ float32x4_t normalized_f32x4 = vmulq_f32(dots_f32x4, rsqrt_f32x4);
818
+ float32x4_t angular_f32x4 = vsubq_f32(vdupq_n_f32(1.0f), normalized_f32x4);
819
+ results->f32x4 = vmaxq_f32(angular_f32x4, vdupq_n_f32(0.0f));
820
+ }
821
+
822
+ /** @brief Euclidean from_dot for u32 accumulators: cast to f32, then √(a² + b² − 2ab). 4 pairs. */
823
+ NK_INTERNAL void nk_euclidean_through_u32_from_dot_neon_(nk_b128_vec_t dots, nk_u32_t query_sumsq,
824
+ nk_b128_vec_t target_sumsqs, nk_b128_vec_t *results) {
825
+ float32x4_t dots_f32x4 = vcvtq_f32_u32(dots.u32x4);
826
+ float32x4_t query_sumsq_f32x4 = vdupq_n_f32((nk_f32_t)query_sumsq);
827
+ float32x4_t sum_sq_f32x4 = vaddq_f32(query_sumsq_f32x4, vcvtq_f32_u32(target_sumsqs.u32x4));
828
+ float32x4_t dist_sq_f32x4 = vfmsq_f32(sum_sq_f32x4, vdupq_n_f32(2.0f), dots_f32x4);
829
+ dist_sq_f32x4 = vmaxq_f32(dist_sq_f32x4, vdupq_n_f32(0.0f));
830
+ results->f32x4 = vsqrtq_f32(dist_sq_f32x4);
831
+ }
832
+
833
+ #if defined(__clang__)
834
+ #pragma clang attribute pop
835
+ #elif defined(__GNUC__)
836
+ #pragma GCC pop_options
837
+ #endif
838
+
839
+ #if defined(__cplusplus)
840
+ } // extern "C"
841
+ #endif
842
+
843
+ #pragma endregion F16 and BF16 Floats
844
+ #endif // NK_TARGET_NEON
845
+ #endif // NK_TARGET_ARM64_
846
+ #endif // NK_SPATIAL_NEON_H