usearch 2.21.3 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +235 -52
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,643 @@
1
+ # NumKong for C and C++
2
+
3
+ NumKong's native SDK is the reference surface for the project.
4
+ The plain C ABI exposes every kernel family directly: dot products, dense distances, binary metrics, probability divergences, geospatial solvers, curved-space kernels, sparse intersections, mesh alignment, packed matrix multiplication, symmetric self-similarity, and late-interaction scoring.
5
+ The ABI is stable, versioned, and callable from any language that can load a shared library.
6
+ There is no runtime overhead: no hidden thread pool, no implicit allocation, no garbage collector interaction.
7
+ The C++ layer stays thin, typed, allocator-aware, and close enough to inline through, adding type-level result promotion and owning containers without hiding the dispatch model or the mixed-precision policy.
8
+
9
+ ## Quickstart
10
+
11
+ ```c
12
+ #include <numkong/numkong.h>
13
+ #include <stdio.h>
14
+
15
+ int main(void) {
16
+ nk_f32_t a[] = {1, 2, 3};
17
+ nk_f32_t b[] = {4, 5, 6};
18
+ nk_f64_t dot = 0;
19
+ nk_configure_thread(nk_capabilities());
20
+ nk_dot_f32(a, b, 3, &dot); // widened f32 → f64 output
21
+ printf("dot=%f\n", dot);
22
+ return 0;
23
+ }
24
+ ```
25
+
26
+ ## Highlights
27
+
28
+ This is the primary SDK in the project.
29
+ It is the right layer if you want exact control over dtypes, allocators, packed buffers, dispatch, and host-side partitioning.
30
+
31
+ __Full kernel surface.__
32
+ All public operation families are reachable from native code.
33
+ __No hidden threading.__
34
+ NumKong does not own a thread pool.
35
+ __No hidden allocation.__
36
+ C APIs take caller-owned buffers, and C++ wrappers make ownership explicit.
37
+ __Mixed precision by default.__
38
+ Small storage types widen into safer accumulator and output types.
39
+ __Allocator-aware containers.__
40
+ `vector`, `tensor`, `packed_matrix`, and `packed_maxsim` accept custom allocators.
41
+ __Unaligned inputs are fine.__
42
+ Packing handles internal layout itself and does not require caller-side alignment.
43
+
44
+ ## Ecosystem Comparison
45
+
46
+ | Feature | NumKong | [OpenBLAS](https://github.com/OpenMathLib/OpenBLAS) | [Eigen](https://gitlab.com/libeigen/eigen) |
47
+ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
48
+ | Operation families | dots, distances, binary, probability, geospatial, curved, mesh, sparse, MaxSim, elementwise, reductions, cast, trig | dense linear algebra only | dense LA, some reductions and elementwise |
49
+ | Precision | Sub-byte to Float64 dtypes; automatic widening per scalar type; Kahan-compensated summation; 0 ULP Float32/Float64 where applicable | Float32, Float64 only; same-type in/out; no compensated summation | Float16/BFloat16 partial; no Float8 or sub-byte; manual casts; no compensated summation |
50
+ | Runtime SIMD dispatch | per-thread at runtime across x86, ARM, RISC-V | load-time CPU detection; one kernel set per process | compile-time ISA flags only |
51
+ | Packed matrix, GEMM-like | `packed_matrix` — pack once, reuse across query batches | internal opaque packing per GEMM call; no persistent packed form | no equivalent packed reuse abstraction |
52
+ | Symmetric kernels, SYRK-like | skips duplicate pairs, up to 2x speedup for self-distance | `SSYRK`/`DSYRK` for rank-k updates | `.selfadjointView` for rank-k updates |
53
+ | Memory model | Caller-owned buffers; C++ adds `tensor<T,A>` with per-container allocators | Caller-managed buffers; no container abstraction | Lazy expression templates avoid most temporaries; `aligned_allocator` provided |
54
+
55
+
56
+
57
+ ## Installation
58
+
59
+ With CMake `FetchContent`:
60
+
61
+ ```cmake
62
+ include(FetchContent)
63
+
64
+ FetchContent_Declare(
65
+ numkong
66
+ GIT_REPOSITORY https://github.com/ashvardanian/NumKong.git
67
+ GIT_SHALLOW TRUE
68
+ )
69
+ FetchContent_MakeAvailable(numkong)
70
+
71
+ target_link_libraries(my_target PRIVATE numkong)
72
+ ```
73
+
74
+ Vendored:
75
+
76
+ ```cmake
77
+ add_subdirectory(external/NumKong)
78
+ target_link_libraries(my_target PRIVATE numkong)
79
+ ```
80
+
81
+ Header-only C++ usage also works for direct template wrappers.
82
+ Most applications should still build the library once and keep `NK_DYNAMIC_DISPATCH=1`.
83
+
84
+ ## The C ABI
85
+
86
+ The C ABI keeps the operation family, input dtype, and output policy visible in the symbol name.
87
+ That makes widening obvious at the call site.
88
+
89
+ ```c
90
+ #include <numkong/numkong.h>
91
+
92
+ nk_i8_t a[1536];
93
+ nk_i8_t b[1536];
94
+ nk_i32_t dot = 0; // widened from int8 storage
95
+ nk_f32_t l2 = 0; // widened from int8 storage
96
+
97
+ nk_dot_i8(a, b, 1536, &dot);
98
+ nk_euclidean_i8(a, b, 1536, &l2);
99
+ ```
100
+
101
+ If you want runtime-selected kernels without naming a specific ISA, use the punned dispatch layer:
102
+
103
+ ```c
104
+ nk_metric_dense_punned_t angular = 0;
105
+ nk_capability_t used = nk_cap_serial_k;
106
+ nk_find_kernel_punned(nk_kernel_angular_k, nk_f32_k,
107
+ nk_capabilities(), (nk_kernel_punned_t *)&angular, &used);
108
+
109
+ nk_f32_t a[768], b[768], result = 0;
110
+ angular(a, b, 768, &result);
111
+ ```
112
+
113
+ That is the lowest-level dynamic path.
114
+ The typed C++ wrappers usually read better unless you are building your own dispatch layer.
115
+
116
+ ## The C++ Layer
117
+
118
+ The C++ wrappers add three things.
119
+ They add type-level result promotion.
120
+ They add explicit owning and non-owning containers.
121
+ They add allocator-aware packed objects for repeated matrix workloads.
122
+
123
+ ```cpp
124
+ #include <numkong/numkong.hpp>
125
+
126
+ namespace nk = ashvardanian::numkong;
127
+
128
+ int main() {
129
+ nk::f32_t a[3] = {1, 2, 3}, b[3] = {4, 5, 6};
130
+ nk::f64_t dot {};
131
+ nk::dot(a, b, 3, &dot); // default result type is nk::f32_t::dot_result_t == nk::f64_t
132
+ }
133
+ ```
134
+
135
+ The API is intentionally not STL-shaped.
136
+ `vector_view`, `tensor_view`, and `matrix_view` prioritize signed strides, sub-byte storage, and kernel compatibility over resizable-container ergonomics.
137
+
138
+ ## Scalar Types and Promotions
139
+
140
+ The scalar wrappers in `include/numkong/types.hpp` are storage-first types.
141
+ They encode raw layout, default output types, and the kernel function pointer signatures for each family.
142
+
143
+ | Type | Layout | Bytes | Range | Inf | NaN |
144
+ | ----------- | ---------------- | ----- | --------------- | --- | --- |
145
+ | `nk_f16_t` | 1+5+10 | 2 | ±65504 | yes | yes |
146
+ | `nk_bf16_t` | 1+8+7 | 2 | ±3.4×10³⁸ | yes | yes |
147
+ | `nk_e4m3_t` | 1+4+3 | 1 | ±448 | no | yes |
148
+ | `nk_e5m2_t` | 1+5+2 | 1 | ±57344 | yes | yes |
149
+ | `nk_e2m3_t` | 1+2+3 | 1 | ±7.5 | no | no |
150
+ | `nk_e3m2_t` | 1+3+2 | 1 | ±28 | no | no |
151
+ | `nk_u1x8_t` | 8 packed bits | 1 | 0 or 1 per bit | — | — |
152
+ | `nk_u4x2_t` | 2x4-bit unsigned | 1 | 0-15 per nibble | — | — |
153
+ | `nk_i4x2_t` | 2x4-bit signed | 1 | -8-7 per nibble | — | — |
154
+
155
+ The layout column shows sign, exponent, and mantissa bit counts for floating-point types.
156
+ For `nk_f16_t`, 1+5+10 means one sign bit, five exponent bits, and ten mantissa bits, totaling 16 bits stored in 2 bytes.
157
+ For `nk_bf16_t`, the wider exponent field (8 bits) gives the same dynamic range as IEEE 754 single precision but with reduced mantissa precision.
158
+ The Float8 types `nk_e4m3_t` and `nk_e5m2_t` follow the OFP8 specification.
159
+ The narrower `nk_e2m3_t` and `nk_e3m2_t` types are MX-compatible micro-floats.
160
+ Sub-byte types `nk_u1x8_t`, `nk_u4x2_t`, and `nk_i4x2_t` pack multiple logical values into a single byte.
161
+
162
+ Default promotions are encoded on the type.
163
+ For example, `f32_t::dot_result_t` is wider than `f32_t`.
164
+ `i8_t::dot_result_t` is `i32_t`.
165
+ `u1x8_t::dot_result_t` is `u32_t`.
166
+
167
+ The higher-level templates use `result_type_ = typename in_type_::dot_result_t` and similar defaults.
168
+ The fast typed overloads are constrained so that overriding the result type away from the native policy can disable the specialized path and fall back to the more generic one.
169
+
170
+ When `__cpp_lib_format >= 202110L` for the C++23 `<format>` header support, all NumKong scalar types provide `std::formatter` specializations with similar format specs to the traditional `float`.
171
+ For the BFloat16 type, the output for `nk::f16_t::from_f32(3.14f)` will look like:
172
+
173
+ | Format spec | Output example | Description |
174
+ | ----------- | -------------------- | -------------------------------------- |
175
+ | `{}` | `3.140625` | Clean float value |
176
+ | `{:#}` | `3.140625 [0x4248]` | Annotated with hex bits |
177
+ | `{:.2f}` | `3.14` | Precision forwarded to float formatter |
178
+ | `{:x}` | `4248` | Raw hex bits |
179
+ | `{:#x}` | `0x4248` | Hex with prefix |
180
+ | `{:X}` | `4248` | Uppercase hex |
181
+ | `{:b}` | `0100001001001000` | Binary bits |
182
+ | `{:#b}` | `0b0100001001001000` | Binary with prefix |
183
+
184
+ ## Dot Products
185
+
186
+ Dot products are one of the broadest parts of the native SDK.
187
+ They include real, complex, packed-binary, mini-float, and mixed-precision forms.
188
+
189
+ ```c
190
+ nk_f32c_t a[384];
191
+ nk_f32c_t b[384];
192
+ nk_f32_t out[2] = {0, 0};
193
+
194
+ nk_dot_f32c(a, b, 384, out); // complex inner product
195
+ nk_vdot_f32c(a, b, 384, out); // conjugated variant, like numpy.vdot
196
+ ```
197
+
198
+ For quantized retrieval pipelines, the storage format often matters more than the nominal math family.
199
+ The native SDK lets you keep the compact representation and still get a widened output.
200
+
201
+ ## Dense Distances
202
+
203
+ The dense spatial kernels cover the SciPy-style `sqeuclidean`, `euclidean`, and `angular` family.
204
+ The important difference is that storage type and output type are not forced to match.
205
+
206
+ ```c
207
+ nk_f16_t a[768];
208
+ nk_f16_t b[768];
209
+ nk_f32_t sqeuclidean = 0, euclidean = 0, angular = 0;
210
+
211
+ // `_Float16` support varies across compilers, and
212
+ // auto-vectorization targets `f32` — not `f16`.
213
+ nk_sqeuclidean_f16(a, b, 768, &sqeuclidean);
214
+ nk_euclidean_f16(a, b, 768, &euclidean);
215
+ nk_angular_f16(a, b, 768, &angular);
216
+ ```
217
+
218
+ For `i8`, `u8`, `i4`, `u4`, and `u1`, the widening is even more important.
219
+ The output type is chosen to avoid the obvious overflow trap of same-width accumulation.
220
+
221
+ ## Set Similarity
222
+
223
+ Packed-binary metrics operate on packed words, not on byte-wise booleans.
224
+ That is why `u1x8_t` exists as a storage type instead of pretending that `bool[8]` is the right primitive.
225
+
226
+ ```c
227
+ nk_u1x8_t a[128], b[128];
228
+ nk_u32_t hamming = 0;
229
+ nk_f32_t jaccard = 0;
230
+ nk_hamming_u1(a, b, 128 * 8, &hamming);
231
+ nk_jaccard_u1(a, b, 128 * 8, &jaccard);
232
+ ```
233
+
234
+ Integer set Jaccard works on sorted arrays of integer identifiers.
235
+
236
+ ```c
237
+ nk_u32_t set_a[] = {1, 3, 5, 7, 9}, set_b[] = {3, 5, 8, 9, 10};
238
+ nk_f32_t jaccard_sets = 0;
239
+ nk_jaccard_u32(set_a, set_b, 5, &jaccard_sets); // |A ∩ B| / |A ∪ B|
240
+ assert(jaccard_sets > 0.0f && jaccard_sets < 1.0f && "|A ∩ B| / |A ∪ B| should be in (0, 1)");
241
+ ```
242
+
243
+ ## Probability Metrics
244
+
245
+ Probability kernels target divergences directly instead of making you rebuild them from scalar loops.
246
+
247
+ ```c
248
+ nk_f32_t p[] = {0.2f, 0.3f, 0.5f}, q[] = {0.1f, 0.3f, 0.6f};
249
+ nk_f64_t kl_forward = 0, kl_reverse = 0, js_forward = 0, js_reverse = 0;
250
+
251
+ nk_kld_f32(p, q, 3, &kl_forward);
252
+ nk_kld_f32(q, p, 3, &kl_reverse);
253
+ assert(kl_forward != kl_reverse && "KLD is asymmetric");
254
+
255
+ nk_jsd_f32(p, q, 3, &js_forward);
256
+ nk_jsd_f32(q, p, 3, &js_reverse);
257
+ assert(js_forward == js_reverse && "JSD is symmetric");
258
+ ```
259
+
260
+ These paths are useful once you move below `f64`.
261
+ Naive implementations are usually dominated by repeated scalar transcendental calls and weak accumulation policy.
262
+
263
+ ## Geospatial Metrics
264
+
265
+ The native SDK exposes both the fast spherical approximation and the more accurate ellipsoidal solver.
266
+ Inputs are in radians.
267
+ Outputs are in meters.
268
+
269
+ ```c
270
+ // Statue of Liberty (40.6892°N, 74.0445°W) → Big Ben (51.5007°N, 0.1246°W)
271
+ nk_f64_t liberty_lat[] = {0.7101605100}, liberty_lon[] = {-1.2923203180};
272
+ nk_f64_t big_ben_lat[] = {0.8988567821}, big_ben_lon[] = {-0.0021746802};
273
+
274
+ nk_f64_t distance[1];
275
+ nk_vincenty_f64(liberty_lat, liberty_lon, big_ben_lat, big_ben_lon, 1, distance); // ≈ 5,589,857 m (ellipsoidal, baseline)
276
+ nk_haversine_f64(liberty_lat, liberty_lon, big_ben_lat, big_ben_lon, 1, distance); // ≈ 5,543,723 m (spherical, ~46 km less)
277
+
278
+ // Vincenty in f32 — drifts ~2 m from f64
279
+ nk_f32_t liberty_lat32[] = {0.7101605100f}, liberty_lon32[] = {-1.2923203180f};
280
+ nk_f32_t big_ben_lat32[] = {0.8988567821f}, big_ben_lon32[] = {-0.0021746802f};
281
+ nk_f32_t distance_f32[1];
282
+ nk_vincenty_f32(liberty_lat32, liberty_lon32, big_ben_lat32, big_ben_lon32, 1, distance_f32); // ≈ 5,589,859 m (+2 m drift)
283
+ ```
284
+
285
+ ## Curved Metrics
286
+
287
+ Curved-space kernels are separate from the flat Euclidean family because their dataflow is different.
288
+ They combine vectors with an extra metric tensor or covariance inverse.
289
+
290
+ ```c
291
+ // Complex bilinear form: aᴴ M b
292
+ nk_f32c_t a[32], b[32], metric[32 * 32];
293
+ nk_f64c_t result = {0, 0};
294
+ nk_bilinear_f32c(a, b, metric, 32, &result);
295
+
296
+ // Real Mahalanobis distance: √((a−b)ᵀ M⁻¹ (a−b))
297
+ nk_f32_t x[64], y[64], inv_cov[64 * 64];
298
+ nk_f64_t distance = 0;
299
+ nk_mahalanobis_f32(x, y, inv_cov, 64, &distance);
300
+ ```
301
+
302
+ ## Tensors, Views, and Memory Layout
303
+
304
+ The native containers are where most integration mistakes happen.
305
+ They need to be documented explicitly.
306
+
307
+ - `vector<T, A>` owns storage and defaults to `aligned_allocator<T, 64>`.
308
+ - `vector_view<T>` is a const strided non-owning view.
309
+ - `vector_span<T>` is a mutable strided non-owning view.
310
+ - `tensor<T, A, R>` owns rank-`R` storage and also defaults to aligned allocation.
311
+ - `tensor_view<T>` and `tensor_span<T>` are the view forms.
312
+ - `matrix`, `matrix_view`, and `matrix_span` are rank-2 aliases.
313
+
314
+ The important layout rules are:
315
+
316
+ - Signed strides are supported by the view types.
317
+ - Reversed and sliced views are valid for many elementwise and reduction kernels.
318
+ - `reshape` and `flatten` require contiguous layout.
319
+ - Matrix-style kernels care about _row contiguity_, not just total tensor contiguity.
320
+ - Negative strides are conceptually valid views, but matrix packing and packed matmul workflows are not written around them.
321
+
322
+ Memory ownership is explicit.
323
+ `vector` and `tensor` deallocate through their allocator.
324
+ `vector_view`, `tensor_view`, `matrix_view`, and spans never own memory.
325
+ And heterogenous index types for `operator[]` enable more interesting access patterns:
326
+
327
+
328
+ ```cpp
329
+ #include <numkong/numkong.hpp>
330
+
331
+ namespace nk = ashvardanian::numkong;
332
+ using nk::slice, nk::all, nk::f32_t, nk::tensor, nk::tensor_view;
333
+
334
+ auto t = tensor<f32_t>::try_from({
335
+ {1, 2, 3},
336
+ {4, 5, 6},
337
+ {7, 8, 9},
338
+ });
339
+
340
+ f32_t scalar_at_2d_coordinate = t[1, -1];
341
+ f32_t scalar_at_global_offset = t[4];
342
+ assert(scalar_at_2d_coordinate == scalar_at_global_offset && "same value");
343
+
344
+ tensor_view<f32_t> scalar_as_tensor = t[1, 1, slice];
345
+ tensor_view<f32_t> second_row = t[1, slice];
346
+ tensor_view<f32_t> second_column = t[all, 1, slice];
347
+ assert(second_row[1] == second_column[1] && "same value");
348
+ ```
349
+
350
+ You can also use a more traditional syntax with member functions, also leveraging built-in functionality for hardware-accelerated strided reductions and elementwise operations along any axis combination.
351
+ Similar to NumPy, but statically typed:
352
+
353
+ ```cpp
354
+ auto first_column = t[all, 1, slice]; // strided column view → {2, 5, 8}
355
+ auto minimum_index = nk::argmin(first_column); // index of the minimum in the second column
356
+ ```
357
+
358
+ The view types are conceptually close to `std::mdspan` from C++23.
359
+ The main differences are sub-byte element support, signed strides, and the kernel dispatch integration that `std::mdspan` does not provide.
360
+ If your codebase already uses `std::mdspan`, converting at the NumKong call boundary is straightforward:
361
+
362
+ ```cpp
363
+ #include <numkong/numkong.hpp>
364
+ #include <mdspan>
365
+
366
+ namespace nk = ashvardanian::numkong;
367
+
368
+ // Existing std::mdspan from your codebase
369
+ float data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
370
+ auto md = std::mdspan<float, std::extents<std::size_t, 3, 3>>(data);
371
+
372
+ // Wrap into a NumKong matrix_view — data pointer, extents, and strides map directly
373
+ auto view = nk::matrix_view<nk::f32_t>(
374
+ reinterpret_cast<nk::f32_t const *>(md.data_handle()),
375
+ md.extent(0), md.extent(1));
376
+
377
+ // Now use any NumKong kernel on it
378
+ nk::f64_t dot {};
379
+ nk::dot(view.row(0), view.row(1), md.extent(1), &dot);
380
+ ```
381
+
382
+ ## Iterators and Enumeration
383
+
384
+ NumKong containers expose random-access iterators for element and row traversal.
385
+
386
+ - __`dim_iterator`__ — random-access iterator over element values, used by `vector`, `vector_view`, and `vector_span`.
387
+ Supports all standard iterator operations plus `index()` to retrieve the current position.
388
+ - __`axis_iterator`__ — random-access iterator over sub-views (rows), used by `tensor_view` and `tensor_span`.
389
+ Also exposes `index()`.
390
+ - __`enumerate()`__ — free function returning a lightweight view that yields `{index, value}` pairs from any container with `begin()`/`end()`/`size()`.
391
+
392
+ ```cpp
393
+ #include <numkong/numkong.hpp>
394
+
395
+ namespace nk = ashvardanian::numkong;
396
+
397
+ nk::vector<nk::f16_t> v(128);
398
+ for (auto [i, val] : nk::enumerate(v))
399
+ std::printf("[%zu] = %f\n", i, val.to_f32());
400
+
401
+ // index() on raw iterators
402
+ for (auto it = v.begin(); it != v.end(); ++it)
403
+ std::printf("[%zu] = %f\n", it.index(), (*it).to_f32());
404
+ ```
405
+
406
+ Since `tensor.hpp` includes `vector.hpp`, `enumerate()` works on tensor row views too.
407
+
408
+ Tensors also support range-for over all logical scalar elements, yielding `(position, value)` pairs.
409
+ For sub-byte types each dimension is a logical scalar. Use `.dims()` to iterate values without positions.
410
+
411
+ ```cpp
412
+ for (auto [pos, val] : matrix) { /* pos is std::array<size_t, R> */ }
413
+ for (auto [pos, ref] : matrix.span()) { ref = nk::f32_t{1}; }
414
+ for (auto val : matrix.dims()) { /* scalar only, no position */ }
415
+ ```
416
+
417
+ ## Packed Matrix Kernels for GEMM-Like Workloads
418
+
419
+ This is a separate native subsystem from the raw vector kernels.
420
+ It is the right tool when the right-hand side is reused many times.
421
+
422
+ ```cpp
423
+ #include <numkong/numkong.hpp>
424
+
425
+ namespace nk = ashvardanian::numkong;
426
+
427
+ auto a = nk::tensor<nk::f32_t>::try_full({2, 4}, nk::f32_t {1});
428
+ auto b = nk::tensor<nk::f32_t>::try_full({3, 4}, nk::f32_t {2});
429
+ auto packed = nk::packed_matrix<nk::f32_t>::try_pack(b.as_matrix_view());
430
+
431
+ // Dot products, angular distances, and Euclidean distances all reuse the same packed B
432
+ auto dots = nk::try_dots_packed(a.as_matrix_view(), packed);
433
+ auto angulars = nk::try_angulars_packed(a.as_matrix_view(), packed);
434
+ auto euclideans = nk::try_euclideans_packed(a.as_matrix_view(), packed);
435
+ ```
436
+
437
+ This is GEMM-like in the workload shape, not in the strict BLAS API.
438
+ The useful economics are:
439
+
440
+ - one-time packing of `B`
441
+ - one-time type preconversion where needed
442
+ - depth padding handled internally
443
+ - per-column norm reuse for `angulars_packed` and `euclideans_packed`
444
+ - repeated reuse of the same packed RHS across many `A` batches
445
+
446
+ Caller-side alignment is not required.
447
+ Owned `packed_matrix` storage uses its allocator.
448
+ The C ABI also exposes `nk_dots_packed_size_*` so you can `malloc` the exact external buffer yourself.
449
+
450
+ ## Symmetric Kernels for SYRK-Like Workloads
451
+
452
+ The symmetric kernels solve a different problem.
453
+ They compute self-similarity or self-distance without paying for both triangles independently.
454
+
455
+ ```cpp
456
+ auto vectors = nk::tensor<nk::f32_t>::try_full({100, 768}, nk::f32_t {1});
457
+ auto gram = nk::try_dots_symmetric(vectors.as_matrix_view());
458
+ auto angular_dists = nk::try_angulars_symmetric(vectors.as_matrix_view());
459
+ auto euclidean_dists = nk::try_euclideans_symmetric(vectors.as_matrix_view());
460
+ ```
461
+
462
+ This is SYRK-like in the sense that the output is square and symmetric.
463
+ The important difference from packed GEMM-style work is the partitioning model.
464
+ You typically split by output row windows, not by distinct left batches against a shared packed right-hand side.
465
+
466
+ The arithmetic advantage is straightforward.
467
+ The symmetric kernels avoid recomputing both `(i, j)` and `(j, i)` pairs.
468
+ That cuts the pair count almost in half before any micro-kernel details matter.
469
+
470
+ ## Sparse Operations and Intersections
471
+
472
+ Sparse helpers cover sorted-index intersection and weighted sparse dot products.
473
+
474
+ ```c
475
+ nk_u32_t a_idx[] = {1, 3, 5, 7}, b_idx[] = {3, 4, 5, 8};
476
+ nk_u32_t intersection[4];
477
+ nk_size_t count = 0;
478
+ nk_sparse_intersect_u32(a_idx, b_idx, 4, 4, intersection, &count);
479
+ assert(count == 2 && "indices 3 and 5");
480
+
481
+ nk_f32_t a_weights[] = {1.0f, 2.0f, 3.0f, 4.0f};
482
+ nk_f32_t b_weights[] = {5.0f, 6.0f, 7.0f, 8.0f};
483
+ nk_f64_t result = 0;
484
+ nk_sparse_dot_u32f32(a_idx, b_idx, a_weights, b_weights, 4, 4, &result);
485
+ assert(result > 0 && "weighted dot over shared indices");
486
+ ```
487
+
488
+ This family deserves explicit mention because it is not just sparse dot.
489
+ Set intersection itself is often the workload.
490
+
491
+ ## Geometric Mesh Alignment
492
+
493
+ Mesh alignment returns structured outputs, not just one scalar.
494
+ The native API covers `rmsd`, `kabsch`, and `umeyama`.
495
+
496
+ ```c
497
+ // Three 3D points, target is source scaled by 2x
498
+ nk_f32_t source[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
499
+ nk_f32_t target[] = {0, 0, 0, 2, 0, 0, 0, 2, 0};
500
+ nk_f32_t a_centroid[3], b_centroid[3], rotation[9];
501
+ nk_f32_t scale = 0, rmsd = 0;
502
+
503
+ nk_umeyama_f32(source, target, 3, a_centroid, b_centroid, rotation, &scale, &rmsd);
504
+ assert(rmsd < 1e-6f && "umeyama should recover exact alignment");
505
+ assert(scale > 1.99f && scale < 2.01f && "umeyama should recover 2x scale");
506
+ ```
507
+
508
+ This family is separate from curved metrics because the output is a transform, not just a distance.
509
+
510
+ ## MaxSim and Late Interaction
511
+
512
+ MaxSim is the late-interaction primitive used by systems such as [ColBERT](https://arxiv.org/abs/2004.12832).
513
+ It is not generic matrix multiplication.
514
+ It packs query and document token vectors into a scoring-specific layout and computes a late-interaction score.
515
+
516
+ ```cpp
517
+ auto queries = nk::tensor<nk::bf16_t>::try_full({32, 128}, nk::bf16_t::one());
518
+ auto docs = nk::tensor<nk::bf16_t>::try_full({192, 128}, nk::bf16_t::one());
519
+
520
+ auto q = nk::packed_maxsim<nk::bf16_t>::try_pack(queries.as_matrix_view());
521
+ auto d = nk::packed_maxsim<nk::bf16_t>::try_pack(docs.as_matrix_view());
522
+ auto score = nk::maxsim(q, d);
523
+ ```
524
+
525
+ `packed_maxsim` is allocator-aware in the same way as `packed_matrix`.
526
+ Its footprint is exposed through `size_bytes()`.
527
+
528
+ ## Runtime Dispatch and Capabilities
529
+
530
+ Dynamic dispatch is the default recommendation for shipping one binary across many CPU generations.
531
+ `nk_configure_thread` enables CPU-specific acceleration features such as Intel AMX.
532
+ It must be called once per thread before using AMX operations and returns 1 on success, 0 on failure.
533
+
534
+ ```c
535
+ nk_capability_t caps = nk_capabilities();
536
+ nk_configure_thread(caps);
537
+ if (caps & nk_cap_sapphireamx_k) { /* AMX available */ }
538
+ ```
539
+
540
+ For exact register-level details, see `capabilities.h`.
541
+ The C++ wrappers can also call directly into named backends if you want to pin a path for testing or benchmarking.
542
+
543
+ ## Parallelism and ForkUnion
544
+
545
+ NumKong does not manage its own threads.
546
+ That is deliberate.
547
+ The library is designed to sit inside a larger scheduler.
548
+
549
+ GEMM-like packed work is usually partitioned across row ranges of `A` against one shared packed `B`:
550
+
551
+ ```cpp
552
+ using nk::range, nk::all, nk::slice;
553
+ fork_union.parallel_for(0, worker_count, [&](std::size_t t) {
554
+ auto start = t * rows_per_worker;
555
+ auto stop = std::min(start + rows_per_worker, total_rows);
556
+ auto a_slice = a[range(start, stop), all, slice].as_matrix_view();
557
+ auto c_slice = c[range(start, stop), all, slice].as_matrix_span();
558
+ nk::dots_packed<value_type_>(a_slice, packed, c_slice);
559
+ });
560
+ ```
561
+
562
+ SYRK-like symmetric work is partitioned by output row windows on one matrix:
563
+
564
+ ```cpp
565
+ fork_union.parallel_for(0, worker_count, [&](std::size_t t) {
566
+ auto start = t * rows_per_worker;
567
+ auto count = std::min(rows_per_worker, total_rows - start);
568
+ nk::dots_symmetric<value_type_>(vectors.as_matrix_view(), gram.as_matrix_span(), start, count);
569
+ nk::angulars_symmetric<value_type_>(vectors.as_matrix_view(), angular_dists.as_matrix_span(), start, count);
570
+ });
571
+ ```
572
+
573
+ We recommend [ForkUnion](https://github.com/ashvardanian/ForkUnion) for that host-side orchestration.
574
+ OpenMP is still a reasonable fit if the rest of your application already uses it.
575
+ Manual thread pools and task systems also work well because the kernels have explicit row-range interfaces.
576
+
577
+ The C++26 Executors TS (`std::execution`) is a natural fit here.
578
+ NumKong kernels take explicit row-range parameters and do not own threads, so they compose directly with `std::execution::bulk` or any sender/receiver scheduler.
579
+ When executors ship in your toolchain, replacing the `parallel_for` lambda above with a `bulk` sender is a one-line change.
580
+
581
+ ## Integration Notes
582
+
583
+ - The C ABI is the easiest place to integrate with foreign runtimes and custom allocators.
584
+ - The C++ layer is the easiest place to express typed packed workflows, tensor slicing, and allocator-aware ownership.
585
+ - `aligned_allocator` defaults to 64-byte alignment for owned containers, but unaligned caller inputs are still valid for the kernels that accept raw pointers or views.
586
+ - If you override result types away from the scalar defaults, document that choice carefully because it can change both performance and numerical policy.
587
+
588
+ ## CMake Configuration
589
+
590
+ The main user-facing CMake options are:
591
+
592
+ - `NK_BUILD_SHARED` builds a shared library, ON by default for standalone builds and OFF when included as a subdirectory.
593
+ - `NK_BUILD_TEST` and `NK_BUILD_BENCH` enable precision tests and benchmarks respectively, both OFF by default.
594
+ - `NK_DYNAMIC_DISPATCH=1` compiles all backends into one binary and selects at runtime via `nk_capabilities()`, recommended for shipping one binary across CPU generations.
595
+ - `NK_COMPARE_TO_BLAS` and `NK_COMPARE_TO_MKL` link benchmarks against a system BLAS or Intel MKL, each accepting `AUTO`, `ON`, or `OFF` with `AUTO` as the default.
596
+
597
+ The build enforces C99 for the C layer and C++23 for the C++ layer.
598
+
599
+ ```sh
600
+ cmake -B build -D CMAKE_BUILD_TYPE=Release -D NK_BUILD_TEST=ON
601
+ cmake -B build -D NK_DYNAMIC_DISPATCH=1 -D NK_BUILD_BENCH=ON -D NK_COMPARE_TO_MKL=ON
602
+ ```
603
+
604
+ ## Cross-Compilation
605
+
606
+ Toolchain files for cross-compilation live in `cmake/`:
607
+
608
+ - `cmake/toolchain-aarch64-gnu.cmake` for ARM64 Linux with the GNU toolchain.
609
+ - `cmake/toolchain-riscv64-gnu.cmake` for RISC-V 64 Linux with the GNU toolchain.
610
+ - `cmake/toolchain-android-arm64.cmake` for Android ARM64 via the NDK.
611
+ - `cmake/toolchain-x86_64-llvm.cmake` and `cmake/toolchain-riscv64-llvm.cmake` for Clang/LLD builds.
612
+ - `cmake/toolchain-wasm.cmake`, `toolchain-wasm64.cmake`, and `toolchain-wasi.cmake` for WebAssembly targets.
613
+
614
+ ```sh
615
+ cmake -B build -D CMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64-gnu.cmake
616
+ ```
617
+
618
+ ## Threading Model
619
+
620
+ NumKong does not use OpenMP and does not create a hidden thread pool.
621
+ Standard pthreads are linked via CMake's `Threads` package.
622
+ Parallelism is host-controlled: partition work across row ranges and dispatch through ForkUnion, `std::thread`, or any external scheduler.
623
+
624
+ ## Addressing External Memory
625
+
626
+ Every kernel takes plain pointers, so any CPU-accessible memory works: mmap, pinned buffers, CUDA unified memory, custom arenas.
627
+ C++ views wrap any pointer without ownership.
628
+ Owning containers accept any C++ Allocator.
629
+
630
+ ```cpp
631
+ template <typename T>
632
+ struct cuda_allocator {
633
+ using value_type = T;
634
+ T *allocate(std::size_t n) { T *p;
635
+ cudaMallocManaged(&p, n * sizeof(T), cudaMemAttachGlobal);
636
+ return p; }
637
+ void deallocate(T *p, std::size_t) noexcept { cudaFree(p); }
638
+ };
639
+
640
+ nk_dot_f32(cuda_managed_ptr, cuda_managed_ptr, 1024, &dot); // C ABI, any pointer
641
+ auto view = nk::tensor_view<nk::f32_t>(mmap_ptr, rows, cols); // non-owning view
642
+ auto v = nk::vector<float, cuda_allocator<float>>::try_zeros(1024); // allocator-aware owning
643
+ ```