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,816 @@
1
+ /**
2
+ * @brief NumKong C++ Benchmark Suite using Google Benchmark - Header file.
3
+ * @file bench/bench.hpp
4
+ * @author Ash Vardanian
5
+ * @date March 14, 2023
6
+ *
7
+ * Comprehensive benchmarks for NumKong SIMD-optimized functions measuring
8
+ * throughput performance. This header contains measurement infrastructure
9
+ * and helper templates used across multiple benchmark files.
10
+ */
11
+
12
+ #pragma once
13
+
14
+ #include <algorithm> // `std::min`, `std::max`
15
+ #include <bit> // `std::bit_floor`
16
+ #include <random> // `std::mt19937`
17
+ #include <string> // `std::string`, `std::to_string`
18
+ #include <vector> // `std::vector`
19
+
20
+ #include <benchmark/benchmark.h>
21
+
22
+ #if !defined(NK_ALLOW_ISA_REDIRECT)
23
+ #define NK_ALLOW_ISA_REDIRECT 0
24
+ #endif
25
+
26
+ #if !defined(NK_COMPARE_TO_MKL)
27
+ #define NK_COMPARE_TO_MKL 0
28
+ #endif
29
+ #if !defined(NK_COMPARE_TO_BLAS)
30
+ #define NK_COMPARE_TO_BLAS 0
31
+ #endif
32
+ #if !defined(NK_COMPARE_TO_ACCELERATE)
33
+ #define NK_COMPARE_TO_ACCELERATE 0
34
+ #endif
35
+
36
+ #if NK_COMPARE_TO_MKL
37
+ #include <mkl.h>
38
+ // MKL provides additional GEMM routines:
39
+ // - cblas_gemm_bf16bf16f32: BF16 inputs -> F32 output
40
+ // - cblas_hgemm: F16 GEMM (if available)
41
+ #elif NK_COMPARE_TO_ACCELERATE
42
+ #include <Accelerate/Accelerate.h> // Apple Accelerate framework
43
+ #elif NK_COMPARE_TO_BLAS
44
+ #include <cblas.h> // Generic CBLAS (OpenBLAS, etc.)
45
+ // OpenBLAS thread control (weak symbol to avoid link errors if not present)
46
+ extern "C" void openblas_set_num_threads(int) __attribute__((weak));
47
+ #endif
48
+
49
+ #include "numkong/types.hpp"
50
+ #include "numkong/tensor.hpp"
51
+ #include "numkong/random.hpp"
52
+
53
+ namespace bm = benchmark;
54
+ namespace nk = ashvardanian::numkong;
55
+
56
+ struct bench_config_t {
57
+ /** Vector dimension for dot products and spatial metrics. Override: `NK_DENSE_DIMENSIONS`. */
58
+ std::size_t dense_dimensions = 1536;
59
+ /** Curved metric dimensions (quadratic impact). Override: `NK_CURVED_DIMENSIONS`. */
60
+ std::size_t curved_dimensions = 64;
61
+ /** Number of 3D points for mesh metrics (RMSD, Kabsch). Override: `NK_MESH_POINTS`. */
62
+ std::size_t mesh_points = 1000;
63
+ /** GEMM M dimension. Override: `NK_MATRIX_HEIGHT`. */
64
+ std::size_t matrix_height = 1024;
65
+ /** GEMM N dimension. Override: `NK_MATRIX_WIDTH`. */
66
+ std::size_t matrix_width = 128;
67
+ /** GEMM K dimension. Override: `NK_MATRIX_DEPTH`. */
68
+ std::size_t matrix_depth = 1536;
69
+ /** Random seed for reproducible benchmarks. Override: `NK_SEED`. */
70
+ std::uint32_t seed = 42;
71
+ /** First sparse set size. Override: `NK_SPARSE_FIRST_LENGTH`. */
72
+ std::size_t sparse_first_length = 1024;
73
+ /** Second sparse set size. Override: `NK_SPARSE_SECOND_LENGTH`. */
74
+ std::size_t sparse_second_length = 8192;
75
+ /** Sparse intersection share [0.0, 1.0]. Override: `NK_SPARSE_INTERSECTION`. */
76
+ double sparse_intersection_share = 0.5;
77
+ /** Max angular separation in degrees for geospatial benchmarks. Override: `NK_MAX_COORD_ANGLE`. */
78
+ float max_coord_angle = 180.0f;
79
+ /** Memory budget in bytes for pre-allocated inputs. Override: `NK_BUDGET_MB`. */
80
+ #if defined(__wasi__)
81
+ std::size_t budget_bytes = std::size_t(32) * 1024 * 1024;
82
+ #else
83
+ std::size_t budget_bytes = std::size_t(1024) * 1024 * 1024;
84
+ #endif
85
+ };
86
+
87
+ extern bench_config_t bench_config;
88
+
89
+ inline std::mt19937 make_random_engine() { return std::mt19937(bench_config.seed); }
90
+
91
+ /**
92
+ * @brief Compute byte count for `count` elements of `dtype`, handling sub-byte and complex types.
93
+ *
94
+ * Uses `nk_dtype_bits` to get the correct bits per element, then rounds up to whole bytes.
95
+ */
96
+ inline std::size_t bench_dtype_bytes(nk_dtype_t dtype, std::size_t count) {
97
+ return nk::divide_round_up(count * nk_dtype_bits(dtype), std::size_t(NK_BITS_PER_BYTE));
98
+ }
99
+
100
+ /**
101
+ * @brief Compute the number of pre-allocated input sets that fit within `bench_budget`.
102
+ *
103
+ * Returns a power-of-two count in [1, 1024] so the benchmark loop can use
104
+ * `iterations & (count - 1)` as a fast modulo for input cycling.
105
+ */
106
+ inline std::size_t bench_input_count(std::size_t bytes_per_set) {
107
+ std::size_t count = bench_config.budget_bytes / std::max(bytes_per_set, std::size_t(1));
108
+ count = std::min(count, std::size_t(1024));
109
+ count = std::max(std::bit_floor(count), std::size_t(1));
110
+ return count;
111
+ }
112
+
113
+ /** @brief Factory function to allocate vectors, potentially raising bad-allocs. */
114
+ template <typename type_>
115
+ [[nodiscard]] nk::vector<type_> make_vector(std::size_t count) {
116
+ auto result = nk::vector<type_>::try_zeros(count);
117
+ #if defined(__cpp_exceptions) && __cpp_exceptions
118
+ if (result.empty() && count > 0) throw std::bad_alloc();
119
+ #else
120
+ if (result.empty() && count > 0) std::abort();
121
+ #endif
122
+ return result;
123
+ }
124
+
125
+ /**
126
+ * @brief Factory function to allocate matrix buffers with correct size for sub-byte types.
127
+ *
128
+ * For sub-byte types (u4, i4, u1), calculates the actual number of raw_t elements needed
129
+ * to store a matrix of logical dimensions rows x cols.
130
+ *
131
+ * @tparam dtype_ The NumKong dtype (e.g., nk_u4_k, nk_i4_k)
132
+ * @param rows Number of logical rows
133
+ * @param cols Number of logical columns per row
134
+ * @return Vector with correct byte capacity for the matrix
135
+ */
136
+ template <nk_dtype_t dtype_>
137
+ [[nodiscard]] nk::vector<typename nk::type_for<dtype_>::type> make_vector_for_matrix(std::size_t rows,
138
+ std::size_t cols) {
139
+ using type_ = typename nk::type_for<dtype_>::type;
140
+ using raw_t = typename type_::raw_t;
141
+
142
+ nk_size_t bits_per_element = nk_dtype_bits(dtype_);
143
+ nk_size_t bits_per_row = cols * bits_per_element;
144
+ nk_size_t bytes_per_row = nk::divide_round_up(bits_per_row, NK_BITS_PER_BYTE);
145
+ nk_size_t total_values = rows * bytes_per_row / sizeof(raw_t);
146
+
147
+ std::size_t total_dims = total_values * nk::dimensions_per_value<type_>();
148
+ auto result = nk::vector<type_>::try_zeros(total_dims);
149
+ #if defined(__cpp_exceptions) && __cpp_exceptions
150
+ if (result.empty() && total_dims > 0) throw std::bad_alloc();
151
+ #else
152
+ if (result.empty() && total_dims > 0) std::abort();
153
+ #endif
154
+ return result;
155
+ }
156
+
157
+ /**
158
+ * @brief Measures the performance of a @b dense kernel function using Google Benchmark.
159
+ *
160
+ * Used by: bench_dot.cpp, bench_spatial.cpp, bench_set.cpp, bench_probability.cpp
161
+ *
162
+ * @param state The benchmark state object provided by Google Benchmark.
163
+ * @param kernel The kernel function to benchmark.
164
+ * @param dimensions The number of dimensions in the vectors.
165
+ */
166
+ template <nk_dtype_t input_dtype_, nk_dtype_t output_dtype_, typename kernel_type_ = void>
167
+ void measure_dense(bm::State &state, kernel_type_ kernel, std::size_t dimensions) {
168
+
169
+ using input_t = typename nk::type_for<input_dtype_>::type;
170
+ using output_t = typename nk::type_for<output_dtype_>::type;
171
+ using input_vector_t = nk::vector<input_t>;
172
+
173
+ // Preallocate inputs: enough vector pairs to fit within bench_budget
174
+ std::size_t const vectors_count = bench_input_count(2 * bench_dtype_bytes(input_dtype_, dimensions));
175
+ std::vector<input_vector_t> first_vectors(vectors_count), second_vectors(vectors_count);
176
+ auto generator = make_random_engine();
177
+ for (std::size_t index = 0; index != vectors_count; ++index) {
178
+ first_vectors[index] = make_vector<input_t>(dimensions);
179
+ second_vectors[index] = make_vector<input_t>(dimensions);
180
+ nk::fill_uniform(generator, first_vectors[index].values_data(), first_vectors[index].size_values());
181
+ nk::fill_uniform(generator, second_vectors[index].values_data(), second_vectors[index].size_values());
182
+ }
183
+
184
+ // Benchmark loop
185
+ std::size_t iterations = 0;
186
+ for (auto _ : state) {
187
+ output_t output;
188
+ std::size_t const index = iterations & (vectors_count - 1);
189
+ kernel(first_vectors[index].raw_values_data(), second_vectors[index].raw_values_data(), dimensions,
190
+ &output.raw_);
191
+ bm::DoNotOptimize(output);
192
+ iterations++;
193
+ }
194
+
195
+ state.counters["bytes"] = bm::Counter(2.0 * iterations * first_vectors[0].size_bytes(), bm::Counter::kIsRate);
196
+ state.counters["calls"] = bm::Counter(iterations, bm::Counter::kIsRate);
197
+ }
198
+
199
+ template <nk_dtype_t input_dtype_, nk_dtype_t output_dtype_, typename kernel_type_ = void>
200
+ void run_dense(std::string name, kernel_type_ *kernel) {
201
+ std::string bench_name = name + "<" + std::to_string(bench_config.dense_dimensions) + "d>";
202
+ bm::RegisterBenchmark(bench_name.c_str(), measure_dense<input_dtype_, output_dtype_, kernel_type_ *>, kernel,
203
+ bench_config.dense_dimensions);
204
+ }
205
+
206
+ // Batched dot products measurement for packed B matrix API
207
+ // Used by: all bench_cross_*.cpp files
208
+ template <nk_dtype_t input_dtype_>
209
+ void measure_dots_packed( //
210
+ bm::State &state, //
211
+ typename nk::type_for<input_dtype_>::type::dots_packed_size_kernel_t packed_size_fn, //
212
+ typename nk::type_for<input_dtype_>::type::dots_pack_kernel_t pack_fn, //
213
+ typename nk::type_for<input_dtype_>::type::dots_packed_kernel_t kernel, //
214
+ std::size_t m, std::size_t n, std::size_t k) {
215
+
216
+ using input_t = typename nk::type_for<input_dtype_>::type;
217
+ using output_t = typename input_t::dot_result_t;
218
+ using raw_input_t = typename input_t::raw_t;
219
+ using raw_output_t = typename output_t::raw_t;
220
+
221
+ // Calculate correct strides for sub-byte types (u4, i4, u1, etc.)
222
+ nk_size_t values_per_row = nk::divide_round_up(k, nk::dimensions_per_value<input_t>());
223
+ nk_size_t a_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
224
+ nk_size_t b_stride_bytes = values_per_row * sizeof(typename input_t::raw_t); // B is n x k, so k columns per row
225
+ nk_size_t packed_bytes = packed_size_fn(n, k);
226
+
227
+ // Preallocate multiple input sets within bench_budget for input diversity
228
+ std::size_t bytes_per_set = m * a_stride_bytes + n * b_stride_bytes + packed_bytes + m * n * sizeof(raw_output_t);
229
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
230
+
231
+ struct gemm_set_t {
232
+ nk::vector<input_t> a, b;
233
+ std::vector<char> b_packed;
234
+ nk::vector<output_t> c;
235
+ };
236
+ std::vector<gemm_set_t> sets(sets_count);
237
+ auto generator = make_random_engine();
238
+ for (auto &s : sets) {
239
+ s.a = make_vector_for_matrix<input_dtype_>(m, k);
240
+ s.b = make_vector_for_matrix<input_dtype_>(n, k);
241
+ s.b_packed.resize(packed_bytes, 0);
242
+ s.c = make_vector<output_t>(m * n);
243
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
244
+ nk::fill_uniform(generator, s.b.values_data(), s.b.size_values());
245
+ pack_fn(s.b.raw_values_data(), n, k, b_stride_bytes, s.b_packed.data());
246
+ }
247
+
248
+ std::size_t iterations = 0;
249
+ for (auto _ : state) {
250
+ auto &s = sets[iterations & (sets_count - 1)];
251
+ bm::DoNotOptimize(s.c.raw_values_data());
252
+ kernel(s.a.raw_values_data(), s.b_packed.data(), s.c.raw_values_data(), //
253
+ m, n, k, a_stride_bytes, n * sizeof(raw_output_t));
254
+ ++iterations;
255
+ }
256
+
257
+ state.counters["scalar-ops"] = bm::Counter(2.0 * iterations * m * n * k, bm::Counter::kIsRate);
258
+ }
259
+
260
+ template <nk_dtype_t input_dtype_>
261
+ void run_dots_packed(std::string name, //
262
+ typename nk::type_for<input_dtype_>::type::dots_packed_size_kernel_t packed_size_fn,
263
+ typename nk::type_for<input_dtype_>::type::dots_pack_kernel_t pack_fn,
264
+ typename nk::type_for<input_dtype_>::type::dots_packed_kernel_t kernel) {
265
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
266
+ std::to_string(bench_config.matrix_width) + "x" +
267
+ std::to_string(bench_config.matrix_depth) + ">";
268
+ bm::RegisterBenchmark(bench_name.c_str(), measure_dots_packed<input_dtype_>, packed_size_fn, pack_fn, kernel,
269
+ bench_config.matrix_height, bench_config.matrix_width, bench_config.matrix_depth);
270
+ }
271
+
272
+ template <nk_dtype_t input_dtype_>
273
+ void measure_angulars_packed( //
274
+ bm::State &state, //
275
+ typename nk::type_for<input_dtype_>::type::dots_packed_size_kernel_t packed_size_fn, //
276
+ typename nk::type_for<input_dtype_>::type::dots_pack_kernel_t pack_fn, //
277
+ typename nk::type_for<input_dtype_>::type::angulars_packed_kernel_t kernel, //
278
+ std::size_t m, std::size_t n, std::size_t k) {
279
+
280
+ using input_t = typename nk::type_for<input_dtype_>::type;
281
+ using output_t = typename input_t::angular_result_t;
282
+ using raw_input_t = typename input_t::raw_t;
283
+ using raw_output_t = typename output_t::raw_t;
284
+
285
+ nk_size_t values_per_row = nk::divide_round_up(k, nk::dimensions_per_value<input_t>());
286
+ nk_size_t a_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
287
+ nk_size_t b_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
288
+ nk_size_t packed_bytes = packed_size_fn(n, k);
289
+
290
+ std::size_t bytes_per_set = m * a_stride_bytes + n * b_stride_bytes + packed_bytes + m * n * sizeof(raw_output_t);
291
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
292
+
293
+ struct gemm_set_t {
294
+ nk::vector<input_t> a, b;
295
+ std::vector<char> b_packed;
296
+ nk::vector<output_t> c;
297
+ };
298
+ std::vector<gemm_set_t> sets(sets_count);
299
+ auto generator = make_random_engine();
300
+ for (auto &s : sets) {
301
+ s.a = make_vector_for_matrix<input_dtype_>(m, k);
302
+ s.b = make_vector_for_matrix<input_dtype_>(n, k);
303
+ s.b_packed.resize(packed_bytes, 0);
304
+ s.c = make_vector<output_t>(m * n);
305
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
306
+ nk::fill_uniform(generator, s.b.values_data(), s.b.size_values());
307
+ pack_fn(s.b.raw_values_data(), n, k, b_stride_bytes, s.b_packed.data());
308
+ }
309
+
310
+ std::size_t iterations = 0;
311
+ for (auto _ : state) {
312
+ auto &s = sets[iterations & (sets_count - 1)];
313
+ bm::DoNotOptimize(s.c.raw_values_data());
314
+ kernel(s.a.raw_values_data(), s.b_packed.data(), s.c.raw_values_data(), //
315
+ m, n, k, a_stride_bytes, n * sizeof(raw_output_t));
316
+ ++iterations;
317
+ }
318
+
319
+ state.counters["scalar-ops"] = bm::Counter(2.0 * iterations * m * n * k, bm::Counter::kIsRate);
320
+ }
321
+
322
+ template <nk_dtype_t input_dtype_>
323
+ void run_angulars_packed(std::string name, //
324
+ typename nk::type_for<input_dtype_>::type::dots_packed_size_kernel_t packed_size_fn,
325
+ typename nk::type_for<input_dtype_>::type::dots_pack_kernel_t pack_fn,
326
+ typename nk::type_for<input_dtype_>::type::angulars_packed_kernel_t kernel) {
327
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
328
+ std::to_string(bench_config.matrix_width) + "x" +
329
+ std::to_string(bench_config.matrix_depth) + ">";
330
+ bm::RegisterBenchmark(bench_name.c_str(), measure_angulars_packed<input_dtype_>, packed_size_fn, pack_fn, kernel,
331
+ bench_config.matrix_height, bench_config.matrix_width, bench_config.matrix_depth);
332
+ }
333
+
334
+ template <nk_dtype_t input_dtype_>
335
+ void measure_euclideans_packed( //
336
+ bm::State &state, //
337
+ typename nk::type_for<input_dtype_>::type::dots_packed_size_kernel_t packed_size_fn, //
338
+ typename nk::type_for<input_dtype_>::type::dots_pack_kernel_t pack_fn, //
339
+ typename nk::type_for<input_dtype_>::type::euclideans_packed_kernel_t kernel, //
340
+ std::size_t m, std::size_t n, std::size_t k) {
341
+
342
+ using input_t = typename nk::type_for<input_dtype_>::type;
343
+ using output_t = typename input_t::euclidean_result_t;
344
+ using raw_input_t = typename input_t::raw_t;
345
+ using raw_output_t = typename output_t::raw_t;
346
+
347
+ nk_size_t values_per_row = nk::divide_round_up(k, nk::dimensions_per_value<input_t>());
348
+ nk_size_t a_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
349
+ nk_size_t b_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
350
+ nk_size_t packed_bytes = packed_size_fn(n, k);
351
+
352
+ std::size_t bytes_per_set = m * a_stride_bytes + n * b_stride_bytes + packed_bytes + m * n * sizeof(raw_output_t);
353
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
354
+
355
+ struct gemm_set_t {
356
+ nk::vector<input_t> a, b;
357
+ std::vector<char> b_packed;
358
+ nk::vector<output_t> c;
359
+ };
360
+ std::vector<gemm_set_t> sets(sets_count);
361
+ auto generator = make_random_engine();
362
+ for (auto &s : sets) {
363
+ s.a = make_vector_for_matrix<input_dtype_>(m, k);
364
+ s.b = make_vector_for_matrix<input_dtype_>(n, k);
365
+ s.b_packed.resize(packed_bytes, 0);
366
+ s.c = make_vector<output_t>(m * n);
367
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
368
+ nk::fill_uniform(generator, s.b.values_data(), s.b.size_values());
369
+ pack_fn(s.b.raw_values_data(), n, k, b_stride_bytes, s.b_packed.data());
370
+ }
371
+
372
+ std::size_t iterations = 0;
373
+ for (auto _ : state) {
374
+ auto &s = sets[iterations & (sets_count - 1)];
375
+ bm::DoNotOptimize(s.c.raw_values_data());
376
+ kernel(s.a.raw_values_data(), s.b_packed.data(), s.c.raw_values_data(), //
377
+ m, n, k, a_stride_bytes, n * sizeof(raw_output_t));
378
+ ++iterations;
379
+ }
380
+
381
+ state.counters["scalar-ops"] = bm::Counter(2.0 * iterations * m * n * k, bm::Counter::kIsRate);
382
+ }
383
+
384
+ template <nk_dtype_t input_dtype_>
385
+ void run_euclideans_packed(std::string name, //
386
+ typename nk::type_for<input_dtype_>::type::dots_packed_size_kernel_t packed_size_fn,
387
+ typename nk::type_for<input_dtype_>::type::dots_pack_kernel_t pack_fn,
388
+ typename nk::type_for<input_dtype_>::type::euclideans_packed_kernel_t kernel) {
389
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
390
+ std::to_string(bench_config.matrix_width) + "x" +
391
+ std::to_string(bench_config.matrix_depth) + ">";
392
+ bm::RegisterBenchmark(bench_name.c_str(), measure_euclideans_packed<input_dtype_>, packed_size_fn, pack_fn, kernel,
393
+ bench_config.matrix_height, bench_config.matrix_width, bench_config.matrix_depth);
394
+ }
395
+
396
+ template <nk_dtype_t input_dtype_>
397
+ void measure_dots_symmetric( //
398
+ bm::State &state, //
399
+ typename nk::type_for<input_dtype_>::type::dots_symmetric_kernel_t kernel, //
400
+ std::size_t n, std::size_t k) {
401
+
402
+ using input_t = typename nk::type_for<input_dtype_>::type;
403
+ using output_t = typename input_t::dot_result_t;
404
+ using raw_input_t = typename input_t::raw_t;
405
+ using raw_output_t = typename output_t::raw_t;
406
+
407
+ // Calculate correct strides for sub-byte types (u4, i4, u1, etc.)
408
+ nk_size_t input_values_per_row = nk::divide_round_up(k, nk::dimensions_per_value<input_t>());
409
+ nk_size_t input_stride_bytes = input_values_per_row * sizeof(typename input_t::raw_t);
410
+ nk_size_t output_stride_bytes = n * sizeof(raw_output_t);
411
+
412
+ // Preallocate multiple input sets within bench_budget
413
+ std::size_t bytes_per_set = n * input_stride_bytes + n * n * sizeof(raw_output_t);
414
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
415
+
416
+ struct syrk_set_t {
417
+ nk::vector<input_t> a;
418
+ nk::vector<output_t> c;
419
+ };
420
+ std::vector<syrk_set_t> sets(sets_count);
421
+ auto generator = make_random_engine();
422
+ for (auto &s : sets) {
423
+ s.a = make_vector_for_matrix<input_dtype_>(n, k);
424
+ s.c = make_vector<output_t>(n * n);
425
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
426
+ }
427
+
428
+ std::size_t iterations = 0;
429
+ for (auto _ : state) {
430
+ auto &s = sets[iterations & (sets_count - 1)];
431
+ bm::DoNotOptimize(s.c.raw_values_data());
432
+ kernel(s.a.raw_values_data(), n, k, input_stride_bytes, //
433
+ s.c.raw_values_data(), output_stride_bytes, 0, n);
434
+ ++iterations;
435
+ }
436
+
437
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * n * (n + 1) * k, bm::Counter::kIsRate);
438
+ }
439
+
440
+ template <nk_dtype_t input_dtype_>
441
+ void run_dots_symmetric(std::string name, //
442
+ typename nk::type_for<input_dtype_>::type::dots_symmetric_kernel_t kernel) {
443
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
444
+ std::to_string(bench_config.matrix_depth) + ">";
445
+ bm::RegisterBenchmark(bench_name.c_str(), measure_dots_symmetric<input_dtype_>, //
446
+ kernel, bench_config.matrix_height, bench_config.matrix_depth);
447
+ }
448
+
449
+ template <nk_dtype_t input_dtype_>
450
+ void measure_angulars_symmetric( //
451
+ bm::State &state, //
452
+ typename nk::type_for<input_dtype_>::type::angulars_symmetric_kernel_t kernel, //
453
+ std::size_t n, std::size_t k) {
454
+
455
+ using input_t = typename nk::type_for<input_dtype_>::type;
456
+ using output_t = typename input_t::angular_result_t;
457
+ using raw_input_t = typename input_t::raw_t;
458
+ using raw_output_t = typename output_t::raw_t;
459
+
460
+ nk_size_t input_values_per_row = nk::divide_round_up(k, nk::dimensions_per_value<input_t>());
461
+ nk_size_t input_stride_bytes = input_values_per_row * sizeof(typename input_t::raw_t);
462
+ nk_size_t output_stride_bytes = n * sizeof(raw_output_t);
463
+
464
+ std::size_t bytes_per_set = n * input_stride_bytes + n * n * sizeof(raw_output_t);
465
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
466
+
467
+ struct syrk_set_t {
468
+ nk::vector<input_t> a;
469
+ nk::vector<output_t> c;
470
+ };
471
+ std::vector<syrk_set_t> sets(sets_count);
472
+ auto generator = make_random_engine();
473
+ for (auto &s : sets) {
474
+ s.a = make_vector_for_matrix<input_dtype_>(n, k);
475
+ s.c = make_vector<output_t>(n * n);
476
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
477
+ }
478
+
479
+ std::size_t iterations = 0;
480
+ for (auto _ : state) {
481
+ auto &s = sets[iterations & (sets_count - 1)];
482
+ bm::DoNotOptimize(s.c.raw_values_data());
483
+ kernel(s.a.raw_values_data(), n, k, input_stride_bytes, //
484
+ s.c.raw_values_data(), output_stride_bytes, 0, n);
485
+ ++iterations;
486
+ }
487
+
488
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * n * (n + 1) * k, bm::Counter::kIsRate);
489
+ }
490
+
491
+ template <nk_dtype_t input_dtype_>
492
+ void run_angulars_symmetric(std::string name, //
493
+ typename nk::type_for<input_dtype_>::type::angulars_symmetric_kernel_t kernel) {
494
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
495
+ std::to_string(bench_config.matrix_depth) + ">";
496
+ bm::RegisterBenchmark(bench_name.c_str(), measure_angulars_symmetric<input_dtype_>, //
497
+ kernel, bench_config.matrix_height, bench_config.matrix_depth);
498
+ }
499
+
500
+ template <nk_dtype_t input_dtype_>
501
+ void measure_euclideans_symmetric( //
502
+ bm::State &state, //
503
+ typename nk::type_for<input_dtype_>::type::euclideans_symmetric_kernel_t kernel, //
504
+ std::size_t n, std::size_t k) {
505
+
506
+ using input_t = typename nk::type_for<input_dtype_>::type;
507
+ using output_t = typename input_t::euclidean_result_t;
508
+ using raw_input_t = typename input_t::raw_t;
509
+ using raw_output_t = typename output_t::raw_t;
510
+
511
+ nk_size_t input_values_per_row = nk::divide_round_up(k, nk::dimensions_per_value<input_t>());
512
+ nk_size_t input_stride_bytes = input_values_per_row * sizeof(typename input_t::raw_t);
513
+ nk_size_t output_stride_bytes = n * sizeof(raw_output_t);
514
+
515
+ std::size_t bytes_per_set = n * input_stride_bytes + n * n * sizeof(raw_output_t);
516
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
517
+
518
+ struct syrk_set_t {
519
+ nk::vector<input_t> a;
520
+ nk::vector<output_t> c;
521
+ };
522
+ std::vector<syrk_set_t> sets(sets_count);
523
+ auto generator = make_random_engine();
524
+ for (auto &s : sets) {
525
+ s.a = make_vector_for_matrix<input_dtype_>(n, k);
526
+ s.c = make_vector<output_t>(n * n);
527
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
528
+ }
529
+
530
+ std::size_t iterations = 0;
531
+ for (auto _ : state) {
532
+ auto &s = sets[iterations & (sets_count - 1)];
533
+ bm::DoNotOptimize(s.c.raw_values_data());
534
+ kernel(s.a.raw_values_data(), n, k, input_stride_bytes, //
535
+ s.c.raw_values_data(), output_stride_bytes, 0, n);
536
+ ++iterations;
537
+ }
538
+
539
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * n * (n + 1) * k, bm::Counter::kIsRate);
540
+ }
541
+
542
+ template <nk_dtype_t input_dtype_>
543
+ void run_euclideans_symmetric(std::string name, //
544
+ typename nk::type_for<input_dtype_>::type::euclideans_symmetric_kernel_t kernel) {
545
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
546
+ std::to_string(bench_config.matrix_depth) + ">";
547
+ bm::RegisterBenchmark(bench_name.c_str(), measure_euclideans_symmetric<input_dtype_>, //
548
+ kernel, bench_config.matrix_height, bench_config.matrix_depth);
549
+ }
550
+
551
+ /**
552
+ * @brief Measure packed Hamming distance computation.
553
+ * Used by: all bench_cross_*.cpp files
554
+ */
555
+ template <nk_dtype_t input_dtype_>
556
+ void measure_hammings_packed( //
557
+ bm::State &state, //
558
+ typename nk::type_for<input_dtype_>::type::hammings_packed_size_kernel_t packed_size_fn, //
559
+ typename nk::type_for<input_dtype_>::type::hammings_pack_kernel_t pack_fn, //
560
+ typename nk::type_for<input_dtype_>::type::hammings_packed_kernel_t kernel, //
561
+ std::size_t m, std::size_t n, std::size_t k) {
562
+
563
+ using input_t = typename nk::type_for<input_dtype_>::type;
564
+ using output_t = typename input_t::hamming_result_t;
565
+ using raw_input_t = typename input_t::raw_t;
566
+ using raw_output_t = typename output_t::raw_t;
567
+
568
+ // Calculate correct strides for binary data (k is in bits)
569
+ nk_size_t values_per_row = nk::divide_round_up(k, 8);
570
+ nk_size_t a_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
571
+ nk_size_t b_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
572
+ nk_size_t packed_bytes = packed_size_fn(n, k);
573
+
574
+ // Preallocate multiple input sets within bench_budget
575
+ std::size_t bytes_per_set = m * a_stride_bytes + n * b_stride_bytes + packed_bytes + m * n * sizeof(raw_output_t);
576
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
577
+
578
+ struct hamming_set_t {
579
+ nk::vector<input_t> a, b;
580
+ std::vector<char> b_packed;
581
+ nk::vector<output_t> c;
582
+ };
583
+ std::vector<hamming_set_t> sets(sets_count);
584
+ auto generator = make_random_engine();
585
+ for (auto &s : sets) {
586
+ s.a = make_vector<input_t>(m * k);
587
+ s.b = make_vector<input_t>(n * k);
588
+ s.b_packed.resize(packed_bytes, 0);
589
+ s.c = make_vector<output_t>(m * n);
590
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
591
+ nk::fill_uniform(generator, s.b.values_data(), s.b.size_values());
592
+ pack_fn(s.b.raw_values_data(), n, k, b_stride_bytes, s.b_packed.data());
593
+ }
594
+
595
+ std::size_t iterations = 0;
596
+ for (auto _ : state) {
597
+ auto &s = sets[iterations & (sets_count - 1)];
598
+ bm::DoNotOptimize(s.c.raw_values_data());
599
+ kernel(s.a.raw_values_data(), s.b_packed.data(), s.c.raw_values_data(), //
600
+ m, n, k, a_stride_bytes, n * sizeof(raw_output_t));
601
+ ++iterations;
602
+ }
603
+
604
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * m * n * k, bm::Counter::kIsRate);
605
+ }
606
+
607
+ /**
608
+ * @brief Measure symmetric Hamming distance matrix computation.
609
+ */
610
+ template <nk_dtype_t input_dtype_>
611
+ void measure_hammings_symmetric( //
612
+ bm::State &state, //
613
+ typename nk::type_for<input_dtype_>::type::hammings_symmetric_kernel_t kernel, //
614
+ std::size_t n, std::size_t k) {
615
+
616
+ using input_t = typename nk::type_for<input_dtype_>::type;
617
+ using output_t = typename input_t::hamming_result_t;
618
+ using raw_input_t = typename input_t::raw_t;
619
+ using raw_output_t = typename output_t::raw_t;
620
+
621
+ // Calculate correct strides for binary data (k is in bits)
622
+ nk_size_t input_values_per_row = nk::divide_round_up(k, 8);
623
+ nk_size_t input_stride_bytes = input_values_per_row * sizeof(typename input_t::raw_t);
624
+ nk_size_t output_stride_bytes = n * sizeof(raw_output_t);
625
+
626
+ // Preallocate multiple input sets within bench_budget
627
+ std::size_t bytes_per_set = n * input_stride_bytes + n * n * sizeof(raw_output_t);
628
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
629
+
630
+ struct hamming_sym_set_t {
631
+ nk::vector<input_t> a;
632
+ nk::vector<output_t> c;
633
+ };
634
+ std::vector<hamming_sym_set_t> sets(sets_count);
635
+ auto generator = make_random_engine();
636
+ for (auto &s : sets) {
637
+ s.a = make_vector<input_t>(n * k);
638
+ s.c = make_vector<output_t>(n * n);
639
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
640
+ }
641
+
642
+ std::size_t iterations = 0;
643
+ for (auto _ : state) {
644
+ auto &s = sets[iterations & (sets_count - 1)];
645
+ bm::DoNotOptimize(s.c.raw_values_data());
646
+ kernel(s.a.raw_values_data(), n, k, input_stride_bytes, //
647
+ s.c.raw_values_data(), output_stride_bytes, 0, n);
648
+ ++iterations;
649
+ }
650
+
651
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * n * (n + 1) * k / 2.0, bm::Counter::kIsRate);
652
+ }
653
+
654
+ template <nk_dtype_t input_dtype_>
655
+ void run_hammings_packed(std::string name, //
656
+ typename nk::type_for<input_dtype_>::type::hammings_packed_size_kernel_t packed_size_fn,
657
+ typename nk::type_for<input_dtype_>::type::hammings_pack_kernel_t pack_fn,
658
+ typename nk::type_for<input_dtype_>::type::hammings_packed_kernel_t kernel) {
659
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
660
+ std::to_string(bench_config.matrix_width) + "x" +
661
+ std::to_string(bench_config.matrix_depth) + ">";
662
+ bm::RegisterBenchmark(bench_name.c_str(), measure_hammings_packed<input_dtype_>, packed_size_fn, pack_fn, kernel,
663
+ bench_config.matrix_height, bench_config.matrix_width, bench_config.matrix_depth);
664
+ }
665
+
666
+ template <nk_dtype_t input_dtype_>
667
+ void run_hammings_symmetric(std::string name, //
668
+ typename nk::type_for<input_dtype_>::type::hammings_symmetric_kernel_t kernel) {
669
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
670
+ std::to_string(bench_config.matrix_depth) + ">";
671
+ bm::RegisterBenchmark(bench_name.c_str(), measure_hammings_symmetric<input_dtype_>, //
672
+ kernel, bench_config.matrix_height, bench_config.matrix_depth);
673
+ }
674
+
675
+ /**
676
+ * @brief Measure packed Jaccard distance matrix computation.
677
+ */
678
+ template <nk_dtype_t input_dtype_>
679
+ void measure_jaccards_packed( //
680
+ bm::State &state, //
681
+ typename nk::type_for<input_dtype_>::type::jaccards_packed_size_kernel_t packed_size_fn, //
682
+ typename nk::type_for<input_dtype_>::type::jaccards_pack_kernel_t pack_fn, //
683
+ typename nk::type_for<input_dtype_>::type::jaccards_packed_kernel_t kernel, //
684
+ std::size_t m, std::size_t n, std::size_t k) {
685
+
686
+ using input_t = typename nk::type_for<input_dtype_>::type;
687
+ using raw_input_t = typename input_t::raw_t;
688
+
689
+ nk_size_t values_per_row = nk::divide_round_up(k, 8);
690
+ nk_size_t a_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
691
+ nk_size_t b_stride_bytes = values_per_row * sizeof(typename input_t::raw_t);
692
+ nk_size_t packed_bytes = packed_size_fn(n, k);
693
+
694
+ std::size_t bytes_per_set = m * a_stride_bytes + n * b_stride_bytes + packed_bytes + m * n * sizeof(nk_f32_t);
695
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
696
+
697
+ struct jaccards_set_t {
698
+ nk::vector<input_t> a, b;
699
+ std::vector<char> b_packed;
700
+ std::vector<nk_f32_t> c;
701
+ };
702
+ std::vector<jaccards_set_t> sets(sets_count);
703
+ auto generator = make_random_engine();
704
+ for (auto &s : sets) {
705
+ s.a = make_vector<input_t>(m * k);
706
+ s.b = make_vector<input_t>(n * k);
707
+ s.b_packed.resize(packed_bytes, 0);
708
+ s.c.resize(m * n, 0);
709
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
710
+ nk::fill_uniform(generator, s.b.values_data(), s.b.size_values());
711
+ pack_fn(s.b.raw_values_data(), n, k, b_stride_bytes, s.b_packed.data());
712
+ }
713
+
714
+ std::size_t iterations = 0;
715
+ for (auto _ : state) {
716
+ auto &s = sets[iterations & (sets_count - 1)];
717
+ bm::DoNotOptimize(s.c.data());
718
+ kernel(s.a.raw_values_data(), s.b_packed.data(), s.c.data(), //
719
+ m, n, k, a_stride_bytes, n * sizeof(nk_f32_t));
720
+ ++iterations;
721
+ }
722
+
723
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * m * n * k, bm::Counter::kIsRate);
724
+ }
725
+
726
+ /**
727
+ * @brief Measure symmetric Jaccard distance matrix computation.
728
+ */
729
+ template <nk_dtype_t input_dtype_>
730
+ void measure_jaccards_symmetric( //
731
+ bm::State &state, //
732
+ typename nk::type_for<input_dtype_>::type::jaccards_symmetric_kernel_t kernel, //
733
+ std::size_t n, std::size_t k) {
734
+
735
+ using input_t = typename nk::type_for<input_dtype_>::type;
736
+ using raw_input_t = typename input_t::raw_t;
737
+
738
+ nk_size_t input_values_per_row = nk::divide_round_up(k, 8);
739
+ nk_size_t input_stride_bytes = input_values_per_row * sizeof(typename input_t::raw_t);
740
+ nk_size_t output_stride_bytes = n * sizeof(nk_f32_t);
741
+
742
+ std::size_t bytes_per_set = n * input_stride_bytes + n * n * sizeof(nk_f32_t);
743
+ std::size_t const sets_count = bench_input_count(bytes_per_set);
744
+
745
+ struct jaccards_sym_set_t {
746
+ nk::vector<input_t> a;
747
+ std::vector<nk_f32_t> c;
748
+ };
749
+ std::vector<jaccards_sym_set_t> sets(sets_count);
750
+ auto generator = make_random_engine();
751
+ for (auto &s : sets) {
752
+ s.a = make_vector<input_t>(n * k);
753
+ s.c.resize(n * n, 0);
754
+ nk::fill_uniform(generator, s.a.values_data(), s.a.size_values());
755
+ }
756
+
757
+ std::size_t iterations = 0;
758
+ for (auto _ : state) {
759
+ auto &s = sets[iterations & (sets_count - 1)];
760
+ bm::DoNotOptimize(s.c.data());
761
+ kernel(s.a.raw_values_data(), n, k, input_stride_bytes, //
762
+ s.c.data(), output_stride_bytes, 0, n);
763
+ ++iterations;
764
+ }
765
+
766
+ state.counters["scalar-ops"] = bm::Counter(1.0 * iterations * n * (n + 1) * k / 2.0, bm::Counter::kIsRate);
767
+ }
768
+
769
+ template <nk_dtype_t input_dtype_>
770
+ void run_jaccards_packed(std::string name, //
771
+ typename nk::type_for<input_dtype_>::type::jaccards_packed_size_kernel_t packed_size_fn,
772
+ typename nk::type_for<input_dtype_>::type::jaccards_pack_kernel_t pack_fn,
773
+ typename nk::type_for<input_dtype_>::type::jaccards_packed_kernel_t kernel) {
774
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
775
+ std::to_string(bench_config.matrix_width) + "x" +
776
+ std::to_string(bench_config.matrix_depth) + ">";
777
+ bm::RegisterBenchmark(bench_name.c_str(), measure_jaccards_packed<input_dtype_>, packed_size_fn, pack_fn, kernel,
778
+ bench_config.matrix_height, bench_config.matrix_width, bench_config.matrix_depth);
779
+ }
780
+
781
+ template <nk_dtype_t input_dtype_>
782
+ void run_jaccards_symmetric(std::string name, //
783
+ typename nk::type_for<input_dtype_>::type::jaccards_symmetric_kernel_t kernel) {
784
+ std::string bench_name = name + "<" + std::to_string(bench_config.matrix_height) + "x" +
785
+ std::to_string(bench_config.matrix_depth) + ">";
786
+ bm::RegisterBenchmark(bench_name.c_str(), measure_jaccards_symmetric<input_dtype_>, //
787
+ kernel, bench_config.matrix_height, bench_config.matrix_depth);
788
+ }
789
+
790
+ // Forward declarations for benchmark registration functions (defined in separate files)
791
+ void bench_dot();
792
+ void bench_spatial();
793
+ void bench_set();
794
+ void bench_curved();
795
+ void bench_probability();
796
+ void bench_each();
797
+ void bench_trigonometry();
798
+ void bench_geospatial();
799
+ void bench_mesh();
800
+ void bench_sparse();
801
+ void bench_sparse_dot();
802
+ void bench_cast();
803
+ void bench_reduce();
804
+ void bench_maxsim();
805
+
806
+ // Forward declarations for cross/batch operations (ISA-family files)
807
+ void bench_cross_serial();
808
+ void bench_cross_x86();
809
+ void bench_cross_amx();
810
+ void bench_cross_arm();
811
+ void bench_cross_sme();
812
+ void bench_cross_blas();
813
+ void bench_cross_rvv();
814
+ void bench_cross_power();
815
+ void bench_cross_wasm();
816
+ void bench_cross_loongarch();