usearch 2.21.4 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/README.md +24 -24
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +7 -7
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +83 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/dist/cjs/usearch.d.ts +8 -3
  16. package/javascript/dist/cjs/usearch.js +12 -4
  17. package/javascript/dist/esm/usearch.d.ts +8 -3
  18. package/javascript/dist/esm/usearch.js +12 -4
  19. package/javascript/lib.cpp +17 -0
  20. package/javascript/usearch.ts +14 -6
  21. package/numkong/.clang-tidy +30 -0
  22. package/{simsimd → numkong}/.cmake-format.py +18 -0
  23. package/numkong/.editorconfig +12 -0
  24. package/numkong/.git-blame-ignore-revs +123 -0
  25. package/numkong/.mailmap +15 -0
  26. package/numkong/.spi.yml +11 -0
  27. package/numkong/.swift-format +14 -0
  28. package/numkong/CITATION.cff +81 -0
  29. package/numkong/CONTRIBUTING.md +500 -0
  30. package/numkong/Cargo.toml +54 -0
  31. package/numkong/MANIFEST.in +8 -0
  32. package/numkong/Package.swift +84 -0
  33. package/numkong/README.md +569 -0
  34. package/numkong/bench/README.md +217 -0
  35. package/numkong/bench/bench-browser.html +323 -0
  36. package/numkong/bench/bench.cpp +344 -0
  37. package/numkong/bench/bench.hpp +816 -0
  38. package/numkong/bench/bench.js +148 -0
  39. package/numkong/bench/bench.mjs +616 -0
  40. package/numkong/bench/bench_attention.cpp +113 -0
  41. package/numkong/bench/bench_cast.cpp +264 -0
  42. package/numkong/bench/bench_cross_amx.cpp +62 -0
  43. package/numkong/bench/bench_cross_arm.cpp +245 -0
  44. package/numkong/bench/bench_cross_blas.cpp +309 -0
  45. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  46. package/numkong/bench/bench_cross_power.cpp +84 -0
  47. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  48. package/numkong/bench/bench_cross_serial.cpp +151 -0
  49. package/numkong/bench/bench_cross_sme.cpp +163 -0
  50. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  51. package/numkong/bench/bench_cross_x86.cpp +455 -0
  52. package/numkong/bench/bench_curved.cpp +210 -0
  53. package/numkong/bench/bench_dot.cpp +315 -0
  54. package/numkong/bench/bench_each.cpp +503 -0
  55. package/numkong/bench/bench_geospatial.cpp +112 -0
  56. package/numkong/bench/bench_maxsim.cpp +154 -0
  57. package/numkong/bench/bench_mesh.cpp +148 -0
  58. package/numkong/bench/bench_probability.cpp +60 -0
  59. package/numkong/bench/bench_reduce.cpp +371 -0
  60. package/numkong/bench/bench_set.cpp +73 -0
  61. package/numkong/bench/bench_sparse.cpp +198 -0
  62. package/numkong/bench/bench_spatial.cpp +347 -0
  63. package/numkong/bench/bench_trigonometry.cpp +137 -0
  64. package/numkong/bench/swift/Bench.swift +506 -0
  65. package/numkong/binding.gyp +169 -0
  66. package/numkong/build.rs +484 -0
  67. package/numkong/c/dispatch.h +512 -0
  68. package/numkong/c/dispatch_bf16.c +447 -0
  69. package/numkong/c/dispatch_bf16c.c +52 -0
  70. package/numkong/c/dispatch_e2m3.c +296 -0
  71. package/numkong/c/dispatch_e3m2.c +284 -0
  72. package/numkong/c/dispatch_e4m3.c +318 -0
  73. package/numkong/c/dispatch_e5m2.c +316 -0
  74. package/numkong/c/dispatch_f16.c +452 -0
  75. package/numkong/c/dispatch_f16c.c +58 -0
  76. package/numkong/c/dispatch_f32.c +434 -0
  77. package/numkong/c/dispatch_f32c.c +99 -0
  78. package/numkong/c/dispatch_f64.c +348 -0
  79. package/numkong/c/dispatch_f64c.c +98 -0
  80. package/numkong/c/dispatch_i16.c +96 -0
  81. package/numkong/c/dispatch_i32.c +89 -0
  82. package/numkong/c/dispatch_i4.c +153 -0
  83. package/numkong/c/dispatch_i64.c +86 -0
  84. package/numkong/c/dispatch_i8.c +348 -0
  85. package/numkong/c/dispatch_other.c +348 -0
  86. package/numkong/c/dispatch_u1.c +193 -0
  87. package/numkong/c/dispatch_u16.c +124 -0
  88. package/numkong/c/dispatch_u32.c +118 -0
  89. package/numkong/c/dispatch_u4.c +153 -0
  90. package/numkong/c/dispatch_u64.c +102 -0
  91. package/numkong/c/dispatch_u8.c +364 -0
  92. package/numkong/c/numkong.c +940 -0
  93. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  94. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  95. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  96. package/numkong/cmake/nk_math_lib.cmake +46 -0
  97. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  99. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  100. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  101. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  102. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  103. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  104. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  105. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  106. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  107. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  108. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  109. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  110. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  111. package/numkong/include/README.md +643 -0
  112. package/numkong/include/module.modulemap +129 -0
  113. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  114. package/numkong/include/numkong/attention/sme.h +2075 -0
  115. package/numkong/include/numkong/attention.h +49 -0
  116. package/numkong/include/numkong/capabilities.h +930 -0
  117. package/numkong/include/numkong/cast/README.md +262 -0
  118. package/numkong/include/numkong/cast/diamond.h +64 -0
  119. package/numkong/include/numkong/cast/haswell.h +823 -0
  120. package/numkong/include/numkong/cast/icelake.h +475 -0
  121. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  122. package/numkong/include/numkong/cast/neon.h +1174 -0
  123. package/numkong/include/numkong/cast/powervsx.h +449 -0
  124. package/numkong/include/numkong/cast/rvv.h +970 -0
  125. package/numkong/include/numkong/cast/sapphire.h +262 -0
  126. package/numkong/include/numkong/cast/serial.h +2336 -0
  127. package/numkong/include/numkong/cast/skylake.h +915 -0
  128. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  129. package/numkong/include/numkong/cast.h +254 -0
  130. package/numkong/include/numkong/cast.hpp +44 -0
  131. package/numkong/include/numkong/curved/README.md +223 -0
  132. package/numkong/include/numkong/curved/genoa.h +182 -0
  133. package/numkong/include/numkong/curved/haswell.h +276 -0
  134. package/numkong/include/numkong/curved/neon.h +329 -0
  135. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  136. package/numkong/include/numkong/curved/rvv.h +305 -0
  137. package/numkong/include/numkong/curved/serial.h +207 -0
  138. package/numkong/include/numkong/curved/skylake.h +457 -0
  139. package/numkong/include/numkong/curved/smef64.h +530 -0
  140. package/numkong/include/numkong/curved.h +513 -0
  141. package/numkong/include/numkong/curved.hpp +144 -0
  142. package/numkong/include/numkong/dot/README.md +442 -0
  143. package/numkong/include/numkong/dot/alder.h +563 -0
  144. package/numkong/include/numkong/dot/diamond.h +158 -0
  145. package/numkong/include/numkong/dot/genoa.h +289 -0
  146. package/numkong/include/numkong/dot/haswell.h +1723 -0
  147. package/numkong/include/numkong/dot/icelake.h +997 -0
  148. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  149. package/numkong/include/numkong/dot/neon.h +869 -0
  150. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  151. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  152. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  153. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  154. package/numkong/include/numkong/dot/powervsx.h +752 -0
  155. package/numkong/include/numkong/dot/rvv.h +722 -0
  156. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  157. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  158. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  159. package/numkong/include/numkong/dot/sapphire.h +141 -0
  160. package/numkong/include/numkong/dot/serial.h +874 -0
  161. package/numkong/include/numkong/dot/sierra.h +405 -0
  162. package/numkong/include/numkong/dot/skylake.h +1116 -0
  163. package/numkong/include/numkong/dot/sve.h +420 -0
  164. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  165. package/numkong/include/numkong/dot/svehalf.h +168 -0
  166. package/numkong/include/numkong/dot/svesdot.h +90 -0
  167. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  168. package/numkong/include/numkong/dot.h +1136 -0
  169. package/numkong/include/numkong/dot.hpp +94 -0
  170. package/numkong/include/numkong/dots/README.md +496 -0
  171. package/numkong/include/numkong/dots/alder.h +117 -0
  172. package/numkong/include/numkong/dots/diamond.h +86 -0
  173. package/numkong/include/numkong/dots/genoa.h +100 -0
  174. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  175. package/numkong/include/numkong/dots/haswell.h +310 -0
  176. package/numkong/include/numkong/dots/icelake.h +180 -0
  177. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  178. package/numkong/include/numkong/dots/neon.h +123 -0
  179. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  180. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  181. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  182. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  183. package/numkong/include/numkong/dots/powervsx.h +194 -0
  184. package/numkong/include/numkong/dots/rvv.h +2593 -0
  185. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  186. package/numkong/include/numkong/dots/serial.h +2867 -0
  187. package/numkong/include/numkong/dots/sierra.h +100 -0
  188. package/numkong/include/numkong/dots/skylake.h +207 -0
  189. package/numkong/include/numkong/dots/sme.h +5041 -0
  190. package/numkong/include/numkong/dots/smebi32.h +477 -0
  191. package/numkong/include/numkong/dots/smef64.h +1328 -0
  192. package/numkong/include/numkong/dots/smehalf.h +47 -0
  193. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  194. package/numkong/include/numkong/dots.h +3110 -0
  195. package/numkong/include/numkong/dots.hpp +641 -0
  196. package/numkong/include/numkong/each/README.md +465 -0
  197. package/numkong/include/numkong/each/haswell.h +1658 -0
  198. package/numkong/include/numkong/each/icelake.h +272 -0
  199. package/numkong/include/numkong/each/neon.h +1138 -0
  200. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  201. package/numkong/include/numkong/each/neonhalf.h +318 -0
  202. package/numkong/include/numkong/each/rvv.h +1121 -0
  203. package/numkong/include/numkong/each/sapphire.h +343 -0
  204. package/numkong/include/numkong/each/serial.h +282 -0
  205. package/numkong/include/numkong/each/skylake.h +1562 -0
  206. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  207. package/numkong/include/numkong/each.h +2232 -0
  208. package/numkong/include/numkong/each.hpp +434 -0
  209. package/numkong/include/numkong/geospatial/README.md +147 -0
  210. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  211. package/numkong/include/numkong/geospatial/neon.h +615 -0
  212. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  213. package/numkong/include/numkong/geospatial/serial.h +309 -0
  214. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  215. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  216. package/numkong/include/numkong/geospatial.h +453 -0
  217. package/numkong/include/numkong/geospatial.hpp +235 -0
  218. package/numkong/include/numkong/matrix.hpp +336 -0
  219. package/numkong/include/numkong/maxsim/README.md +187 -0
  220. package/numkong/include/numkong/maxsim/alder.h +511 -0
  221. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  222. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  223. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  224. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  225. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  226. package/numkong/include/numkong/maxsim/serial.h +490 -0
  227. package/numkong/include/numkong/maxsim/sme.h +993 -0
  228. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  229. package/numkong/include/numkong/maxsim.h +571 -0
  230. package/numkong/include/numkong/maxsim.hpp +133 -0
  231. package/numkong/include/numkong/mesh/README.md +219 -0
  232. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  233. package/numkong/include/numkong/mesh/neon.h +1821 -0
  234. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  235. package/numkong/include/numkong/mesh/rvv.h +936 -0
  236. package/numkong/include/numkong/mesh/serial.h +721 -0
  237. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  238. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  239. package/numkong/include/numkong/mesh.h +666 -0
  240. package/numkong/include/numkong/mesh.hpp +701 -0
  241. package/numkong/include/numkong/numkong.h +78 -0
  242. package/numkong/include/numkong/numkong.hpp +58 -0
  243. package/numkong/include/numkong/probability/README.md +177 -0
  244. package/numkong/include/numkong/probability/haswell.h +267 -0
  245. package/numkong/include/numkong/probability/neon.h +255 -0
  246. package/numkong/include/numkong/probability/rvv.h +414 -0
  247. package/numkong/include/numkong/probability/serial.h +181 -0
  248. package/numkong/include/numkong/probability/skylake.h +324 -0
  249. package/numkong/include/numkong/probability.h +380 -0
  250. package/numkong/include/numkong/probability.hpp +120 -0
  251. package/numkong/include/numkong/random.h +50 -0
  252. package/numkong/include/numkong/random.hpp +285 -0
  253. package/numkong/include/numkong/reduce/README.md +552 -0
  254. package/numkong/include/numkong/reduce/alder.h +636 -0
  255. package/numkong/include/numkong/reduce/genoa.h +201 -0
  256. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  257. package/numkong/include/numkong/reduce/icelake.h +549 -0
  258. package/numkong/include/numkong/reduce/neon.h +3980 -0
  259. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  260. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  261. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  262. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  263. package/numkong/include/numkong/reduce/serial.h +753 -0
  264. package/numkong/include/numkong/reduce/sierra.h +338 -0
  265. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  266. package/numkong/include/numkong/reduce/sve.h +52 -0
  267. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  268. package/numkong/include/numkong/reduce.h +1582 -0
  269. package/numkong/include/numkong/reduce.hpp +778 -0
  270. package/numkong/include/numkong/scalar/README.md +89 -0
  271. package/numkong/include/numkong/scalar/haswell.h +122 -0
  272. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  273. package/numkong/include/numkong/scalar/neon.h +122 -0
  274. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  275. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  276. package/numkong/include/numkong/scalar/rvv.h +211 -0
  277. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  278. package/numkong/include/numkong/scalar/serial.h +332 -0
  279. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  280. package/numkong/include/numkong/scalar.h +696 -0
  281. package/numkong/include/numkong/set/README.md +179 -0
  282. package/numkong/include/numkong/set/haswell.h +334 -0
  283. package/numkong/include/numkong/set/icelake.h +485 -0
  284. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  285. package/numkong/include/numkong/set/neon.h +363 -0
  286. package/numkong/include/numkong/set/powervsx.h +326 -0
  287. package/numkong/include/numkong/set/rvv.h +226 -0
  288. package/numkong/include/numkong/set/rvvbb.h +117 -0
  289. package/numkong/include/numkong/set/serial.h +174 -0
  290. package/numkong/include/numkong/set/sve.h +187 -0
  291. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  292. package/numkong/include/numkong/set.h +471 -0
  293. package/numkong/include/numkong/set.hpp +114 -0
  294. package/numkong/include/numkong/sets/README.md +149 -0
  295. package/numkong/include/numkong/sets/haswell.h +63 -0
  296. package/numkong/include/numkong/sets/icelake.h +66 -0
  297. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  298. package/numkong/include/numkong/sets/neon.h +61 -0
  299. package/numkong/include/numkong/sets/powervsx.h +65 -0
  300. package/numkong/include/numkong/sets/serial.h +43 -0
  301. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  302. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  303. package/numkong/include/numkong/sets.h +382 -0
  304. package/numkong/include/numkong/sparse/README.md +156 -0
  305. package/numkong/include/numkong/sparse/icelake.h +463 -0
  306. package/numkong/include/numkong/sparse/neon.h +288 -0
  307. package/numkong/include/numkong/sparse/serial.h +117 -0
  308. package/numkong/include/numkong/sparse/sve2.h +504 -0
  309. package/numkong/include/numkong/sparse/turin.h +322 -0
  310. package/numkong/include/numkong/sparse.h +363 -0
  311. package/numkong/include/numkong/sparse.hpp +113 -0
  312. package/numkong/include/numkong/spatial/README.md +439 -0
  313. package/numkong/include/numkong/spatial/alder.h +604 -0
  314. package/numkong/include/numkong/spatial/diamond.h +240 -0
  315. package/numkong/include/numkong/spatial/genoa.h +222 -0
  316. package/numkong/include/numkong/spatial/haswell.h +979 -0
  317. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  318. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  319. package/numkong/include/numkong/spatial/neon.h +846 -0
  320. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  321. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  322. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  323. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  324. package/numkong/include/numkong/spatial/rvv.h +991 -0
  325. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  326. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  327. package/numkong/include/numkong/spatial/serial.h +347 -0
  328. package/numkong/include/numkong/spatial/sierra.h +516 -0
  329. package/numkong/include/numkong/spatial/skylake.h +605 -0
  330. package/numkong/include/numkong/spatial/sve.h +246 -0
  331. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  332. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  333. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  334. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  335. package/numkong/include/numkong/spatial.h +1681 -0
  336. package/numkong/include/numkong/spatial.hpp +183 -0
  337. package/numkong/include/numkong/spatials/README.md +580 -0
  338. package/numkong/include/numkong/spatials/alder.h +94 -0
  339. package/numkong/include/numkong/spatials/diamond.h +82 -0
  340. package/numkong/include/numkong/spatials/genoa.h +94 -0
  341. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  342. package/numkong/include/numkong/spatials/haswell.h +219 -0
  343. package/numkong/include/numkong/spatials/icelake.h +113 -0
  344. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  345. package/numkong/include/numkong/spatials/neon.h +109 -0
  346. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  347. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  348. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  349. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  350. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  351. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  352. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  353. package/numkong/include/numkong/spatials/serial.h +248 -0
  354. package/numkong/include/numkong/spatials/sierra.h +96 -0
  355. package/numkong/include/numkong/spatials/skylake.h +184 -0
  356. package/numkong/include/numkong/spatials/sme.h +1927 -0
  357. package/numkong/include/numkong/spatials/smef64.h +483 -0
  358. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  359. package/numkong/include/numkong/spatials.h +3374 -0
  360. package/numkong/include/numkong/spatials.hpp +509 -0
  361. package/numkong/include/numkong/tensor.hpp +1981 -0
  362. package/numkong/include/numkong/trigonometry/README.md +184 -0
  363. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  364. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  365. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  366. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  367. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  368. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  369. package/numkong/include/numkong/trigonometry.h +467 -0
  370. package/numkong/include/numkong/trigonometry.hpp +166 -0
  371. package/numkong/include/numkong/types.h +1695 -0
  372. package/numkong/include/numkong/types.hpp +6027 -0
  373. package/numkong/include/numkong/vector.hpp +766 -0
  374. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  375. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  376. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  377. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  378. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  380. package/numkong/javascript/README.md +254 -0
  381. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  382. package/numkong/javascript/numkong-browser.ts +40 -0
  383. package/numkong/javascript/numkong-wasm.ts +750 -0
  384. package/numkong/javascript/numkong.c +712 -0
  385. package/numkong/javascript/numkong.ts +613 -0
  386. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  387. package/numkong/javascript/tsconfig-cjs.json +13 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  389. package/numkong/javascript/types.ts +784 -0
  390. package/numkong/numkong.gypi +104 -0
  391. package/numkong/package.json +108 -0
  392. package/numkong/probes/arm_neon.c +8 -0
  393. package/numkong/probes/arm_neon_bfdot.c +9 -0
  394. package/numkong/probes/arm_neon_fhm.c +9 -0
  395. package/numkong/probes/arm_neon_half.c +8 -0
  396. package/numkong/probes/arm_neon_sdot.c +9 -0
  397. package/numkong/probes/arm_neonfp8.c +9 -0
  398. package/numkong/probes/arm_sme.c +16 -0
  399. package/numkong/probes/arm_sme2.c +16 -0
  400. package/numkong/probes/arm_sme2p1.c +16 -0
  401. package/numkong/probes/arm_sme_bf16.c +16 -0
  402. package/numkong/probes/arm_sme_bi32.c +16 -0
  403. package/numkong/probes/arm_sme_f64.c +16 -0
  404. package/numkong/probes/arm_sme_fa64.c +14 -0
  405. package/numkong/probes/arm_sme_half.c +16 -0
  406. package/numkong/probes/arm_sme_lut2.c +15 -0
  407. package/numkong/probes/arm_sve.c +18 -0
  408. package/numkong/probes/arm_sve2.c +20 -0
  409. package/numkong/probes/arm_sve2p1.c +18 -0
  410. package/numkong/probes/arm_sve_bfdot.c +20 -0
  411. package/numkong/probes/arm_sve_half.c +18 -0
  412. package/numkong/probes/arm_sve_sdot.c +21 -0
  413. package/numkong/probes/loongarch_lasx.c +12 -0
  414. package/numkong/probes/power_vsx.c +12 -0
  415. package/numkong/probes/probe.js +127 -0
  416. package/numkong/probes/riscv_rvv.c +14 -0
  417. package/numkong/probes/riscv_rvv_bb.c +15 -0
  418. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  419. package/numkong/probes/riscv_rvv_half.c +14 -0
  420. package/numkong/probes/wasm_v128relaxed.c +11 -0
  421. package/numkong/probes/x86_alder.c +17 -0
  422. package/numkong/probes/x86_diamond.c +17 -0
  423. package/numkong/probes/x86_genoa.c +17 -0
  424. package/numkong/probes/x86_graniteamx.c +19 -0
  425. package/numkong/probes/x86_haswell.c +11 -0
  426. package/numkong/probes/x86_icelake.c +17 -0
  427. package/numkong/probes/x86_sapphire.c +16 -0
  428. package/numkong/probes/x86_sapphireamx.c +18 -0
  429. package/numkong/probes/x86_sierra.c +17 -0
  430. package/numkong/probes/x86_skylake.c +15 -0
  431. package/numkong/probes/x86_turin.c +17 -0
  432. package/numkong/rust/README.md +698 -0
  433. package/numkong/rust/capabilities.rs +96 -0
  434. package/numkong/rust/cast.rs +314 -0
  435. package/numkong/rust/curved.rs +391 -0
  436. package/numkong/rust/each.rs +2721 -0
  437. package/numkong/rust/geospatial.rs +343 -0
  438. package/numkong/rust/matrix.rs +5424 -0
  439. package/numkong/rust/maxsim.rs +540 -0
  440. package/numkong/rust/mesh.rs +837 -0
  441. package/numkong/rust/numkong.rs +409 -0
  442. package/numkong/rust/probability.rs +272 -0
  443. package/numkong/rust/reduce.rs +1249 -0
  444. package/numkong/rust/set.rs +194 -0
  445. package/numkong/rust/sparse.rs +513 -0
  446. package/numkong/rust/spatial.rs +1815 -0
  447. package/numkong/rust/tensor.rs +7565 -0
  448. package/numkong/rust/types.rs +3666 -0
  449. package/numkong/rust/vector.rs +1899 -0
  450. package/numkong/rustfmt.toml +2 -0
  451. package/numkong/swift/Matrix.swift +1388 -0
  452. package/numkong/swift/MaxSim.swift +151 -0
  453. package/numkong/swift/NumKong.swift +283 -0
  454. package/numkong/swift/Numerics.swift +329 -0
  455. package/numkong/swift/README.md +433 -0
  456. package/numkong/swift/Scalar.swift +741 -0
  457. package/numkong/swift/Tensor.swift +209 -0
  458. package/numkong/test/README.md +315 -0
  459. package/numkong/test/playwright.config.ts +16 -0
  460. package/numkong/test/swift/Test.swift +534 -0
  461. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  462. package/numkong/test/test-browser-bundle.html +188 -0
  463. package/numkong/test/test-browser-runner.mjs +43 -0
  464. package/numkong/test/test-browser.html +305 -0
  465. package/numkong/test/test-dtypes.mjs +453 -0
  466. package/numkong/test/test-wasm.mjs +267 -0
  467. package/numkong/test/test.cpp +442 -0
  468. package/numkong/test/test.hpp +580 -0
  469. package/numkong/test/test.mjs +363 -0
  470. package/numkong/test/test_base.py +1041 -0
  471. package/numkong/test/test_cast.cpp +242 -0
  472. package/numkong/test/test_cross.hpp +551 -0
  473. package/numkong/test/test_cross.py +467 -0
  474. package/numkong/test/test_cross_amx.cpp +50 -0
  475. package/numkong/test/test_cross_arm.cpp +225 -0
  476. package/numkong/test/test_cross_blas.cpp +354 -0
  477. package/numkong/test/test_cross_loongarch.cpp +90 -0
  478. package/numkong/test/test_cross_power.cpp +73 -0
  479. package/numkong/test/test_cross_rvv.cpp +109 -0
  480. package/numkong/test/test_cross_serial.cpp +181 -0
  481. package/numkong/test/test_cross_sme.cpp +148 -0
  482. package/numkong/test/test_cross_wasm.cpp +141 -0
  483. package/numkong/test/test_cross_x86.cpp +442 -0
  484. package/numkong/test/test_curved.cpp +182 -0
  485. package/numkong/test/test_curved.py +207 -0
  486. package/numkong/test/test_dot.cpp +353 -0
  487. package/numkong/test/test_dot.py +296 -0
  488. package/numkong/test/test_each.cpp +437 -0
  489. package/numkong/test/test_each.py +756 -0
  490. package/numkong/test/test_geospatial.cpp +155 -0
  491. package/numkong/test/test_geospatial.py +241 -0
  492. package/numkong/test/test_maxsim.cpp +138 -0
  493. package/numkong/test/test_maxsim.py +209 -0
  494. package/numkong/test/test_mesh.cpp +203 -0
  495. package/numkong/test/test_mesh.py +394 -0
  496. package/numkong/test/test_probability.cpp +136 -0
  497. package/numkong/test/test_probability.py +166 -0
  498. package/numkong/test/test_reduce.cpp +563 -0
  499. package/numkong/test/test_reduce.py +781 -0
  500. package/numkong/test/test_set.cpp +151 -0
  501. package/numkong/test/test_set.py +120 -0
  502. package/numkong/test/test_similarities.py +579 -0
  503. package/numkong/test/test_sparse.cpp +121 -0
  504. package/numkong/test/test_sparse.py +118 -0
  505. package/numkong/test/test_spatial.cpp +518 -0
  506. package/numkong/test/test_spatial.py +269 -0
  507. package/numkong/test/test_tensor.cpp +884 -0
  508. package/numkong/test/test_tensor.py +1417 -0
  509. package/numkong/test/test_trigonometry.cpp +156 -0
  510. package/numkong/test/test_trigonometry.py +180 -0
  511. package/package.json +7 -8
  512. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  513. package/prebuilds/linux-arm64/usearch.node +0 -0
  514. package/prebuilds/linux-x64/usearch.node +0 -0
  515. package/fp16/CMakeLists.txt +0 -176
  516. package/fp16/LICENSE +0 -11
  517. package/fp16/README.md +0 -20
  518. package/fp16/bench/alt-element.cc +0 -89
  519. package/fp16/bench/from-alt-array.cc +0 -175
  520. package/fp16/bench/from-ieee-array.cc +0 -399
  521. package/fp16/bench/ieee-element.cc +0 -272
  522. package/fp16/bench/to-alt-array.cc +0 -91
  523. package/fp16/bench/to-ieee-array.cc +0 -303
  524. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  525. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  526. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  527. package/fp16/configure.py +0 -65
  528. package/fp16/confu.yaml +0 -8
  529. package/fp16/include/fp16/__init__.py +0 -0
  530. package/fp16/include/fp16/avx.py +0 -50
  531. package/fp16/include/fp16/avx2.py +0 -53
  532. package/fp16/include/fp16/bitcasts.h +0 -92
  533. package/fp16/include/fp16/fp16.h +0 -451
  534. package/fp16/include/fp16/psimd.h +0 -131
  535. package/fp16/include/fp16.h +0 -11
  536. package/fp16/jni/Android.mk +0 -6
  537. package/fp16/jni/Application.mk +0 -4
  538. package/fp16/test/alt-from-fp32-value.cc +0 -498
  539. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  540. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  541. package/fp16/test/alt-to-fp32-value.cc +0 -348
  542. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  543. package/fp16/test/bitcasts.cc +0 -56
  544. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  545. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  546. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  547. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  548. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  549. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  550. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  551. package/fp16/test/peachpy/stubs.py +0 -38
  552. package/fp16/test/tables.cc +0 -530
  553. package/fp16/test/tables.h +0 -13
  554. package/fp16/third-party/THHalf.h +0 -92
  555. package/fp16/third-party/eigen-half.h +0 -170
  556. package/fp16/third-party/float16-compressor.h +0 -80
  557. package/fp16/third-party/half.hpp +0 -2916
  558. package/fp16/third-party/npy-halffloat.h +0 -328
  559. package/simsimd/.git-blame-ignore-revs +0 -2
  560. package/simsimd/CONTRIBUTING.md +0 -321
  561. package/simsimd/Cargo.toml +0 -49
  562. package/simsimd/MANIFEST.in +0 -4
  563. package/simsimd/Package.swift +0 -28
  564. package/simsimd/README.md +0 -1493
  565. package/simsimd/binding.gyp +0 -35
  566. package/simsimd/build.rs +0 -70
  567. package/simsimd/c/lib.c +0 -374
  568. package/simsimd/include/module.modulemap +0 -4
  569. package/simsimd/include/simsimd/binary.h +0 -486
  570. package/simsimd/include/simsimd/curved.h +0 -1541
  571. package/simsimd/include/simsimd/dot.h +0 -1853
  572. package/simsimd/include/simsimd/elementwise.h +0 -2465
  573. package/simsimd/include/simsimd/geospatial.h +0 -43
  574. package/simsimd/include/simsimd/mesh.h +0 -69
  575. package/simsimd/include/simsimd/probability.h +0 -606
  576. package/simsimd/include/simsimd/simsimd.h +0 -2567
  577. package/simsimd/include/simsimd/sparse.h +0 -1384
  578. package/simsimd/include/simsimd/spatial.h +0 -2335
  579. package/simsimd/include/simsimd/types.h +0 -666
  580. package/simsimd/javascript/fallback.ts +0 -233
  581. package/simsimd/javascript/lib.c +0 -125
  582. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  583. package/simsimd/javascript/simsimd.ts +0 -179
  584. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  585. package/simsimd/package-lock.json +0 -1761
  586. package/simsimd/package.json +0 -61
  587. package/simsimd/rust/lib.rs +0 -1821
  588. package/simsimd/scripts/bench.cxx +0 -1170
  589. package/simsimd/scripts/bench.ipynb +0 -187
  590. package/simsimd/scripts/bench.js +0 -127
  591. package/simsimd/scripts/bench.rs +0 -876
  592. package/simsimd/scripts/bench_vectors.py +0 -734
  593. package/simsimd/scripts/bench_vectors_live.py +0 -213
  594. package/simsimd/scripts/test.c +0 -187
  595. package/simsimd/scripts/test.mjs +0 -220
  596. package/simsimd/scripts/test.py +0 -1505
  597. package/simsimd/swift/SimSIMD.swift +0 -149
  598. package/simsimd/swift/Test.swift +0 -128
  599. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  600. /package/{simsimd → numkong}/LICENSE +0 -0
  601. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  602. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,884 @@
1
+ /**
2
+ * @brief C++ vector type instantiation tests.
3
+ * @file test/test_tensor.cpp
4
+ * @author Ash Vardanian
5
+ * @date February 6, 2026
6
+ */
7
+ #include <array>
8
+ #include <cassert>
9
+ #include <complex>
10
+
11
+ #include "test.hpp"
12
+
13
+ #include "numkong/cast.hpp"
14
+ #include "numkong/dot.hpp"
15
+ #include "numkong/spatial.hpp"
16
+ #include "numkong/curved.hpp"
17
+
18
+ #if __has_include(<format>)
19
+ #include <format>
20
+ #if defined(__cpp_lib_format) && __cpp_lib_format >= 202110L
21
+ #define NK_TEST_FORMAT_ 1
22
+ #endif
23
+ #endif
24
+ #ifndef NK_TEST_FORMAT_
25
+ #define NK_TEST_FORMAT_ 0
26
+ #endif
27
+
28
+ #if NK_TEST_FORMAT_
29
+ void test_format_scalars();
30
+ #endif
31
+
32
+ // Explicit instantiations for tensor types — forces full compilation of all APIs
33
+ template class nk::tensor<nk::f32_t>;
34
+ template class nk::tensor<nk::f64_t>;
35
+ template class nk::tensor<nk::f16_t>;
36
+ template class nk::tensor<nk::bf16_t>;
37
+ template class nk::tensor<nk::i8_t>;
38
+
39
+ // Views and spans for rank-2 (matrix) and default rank
40
+ template class nk::tensor_view<nk::f32_t, 2>;
41
+ template class nk::tensor_view<nk::f32_t, 8>;
42
+ template class nk::tensor_span<nk::f32_t, 2>;
43
+ template class nk::tensor_span<nk::f32_t, 8>;
44
+ template class nk::tensor_view<nk::bf16_t, 2>;
45
+ template class nk::tensor_span<nk::bf16_t, 2>;
46
+
47
+ template <typename value_type_>
48
+ void test_vector_basics() {
49
+ constexpr std::size_t dims_per_value = nk::dimensions_per_value<value_type_>();
50
+ constexpr std::size_t test_dims = 64 * dims_per_value;
51
+ auto v = make_vector<value_type_>(test_dims);
52
+ assert(v.size() == test_dims);
53
+ assert(v.size_values() == test_dims / dims_per_value);
54
+ std::size_t count = 0;
55
+ for (auto it = v.begin(); it != v.end(); ++it) ++count;
56
+ assert(count == test_dims);
57
+ }
58
+
59
+ void test_signed_indexing() {
60
+ auto v = make_vector<float>(100);
61
+ v[50] = 3.14f;
62
+ assert(v[50] == 3.14f && "float operator[] failed");
63
+ v[-1] = 42.0f;
64
+ assert(v[99] == 42.0f && "float signed indexing failed");
65
+ }
66
+
67
+ void test_integral_indexing_api() {
68
+ auto v = make_vector<float>(5);
69
+ for (std::size_t i = 0; i < v.size(); ++i) v[i] = static_cast<float>(i + 1);
70
+
71
+ auto view = nk::vector_view<float>(v.values_data(), unsigned(v.size()));
72
+ auto span = nk::vector_span<float>(v.values_data(), unsigned(v.size()));
73
+ auto strided = nk::vector_view<float>(reinterpret_cast<char const *>(v.values_data()), 3u, sizeof(float));
74
+
75
+ assert(v[std::size_t {2}] == 3.0f && "vector unsigned indexing failed");
76
+ assert(view[2u] == 3.0f && "view unsigned indexing failed");
77
+ assert(view[std::ptrdiff_t {-1}] == 5.0f && "view signed indexing failed");
78
+ assert(span[unsigned {3}] == 4.0f && "span unsigned indexing failed");
79
+ assert(strided[2u] == 3.0f && "raw view unsigned stride ctor failed");
80
+
81
+ auto sub = view[nk::range(1u, 4u)];
82
+ assert(sub.size() == 3 && "unsigned range size mismatch");
83
+ assert(sub[0u] == 2.0f && "unsigned range first element mismatch");
84
+
85
+ auto tail = view[nk::range(-3, -1)];
86
+ assert(tail.size() == 2 && "signed range size mismatch");
87
+ assert(tail[0u] == 3.0f && "signed range first element mismatch");
88
+ assert(tail[1u] == 4.0f && "signed range last element mismatch");
89
+ }
90
+
91
+ void test_tensor_operator_indexing() {
92
+ auto t = nk::tensor<float>::try_zeros({2, 3});
93
+ assert(!t.empty() && "tensor allocation failed");
94
+
95
+ for (int i = 0; i < 6; ++i) t[i] = static_cast<float>(i + 1);
96
+
97
+ assert(t[0] == 1.0f && "flat tensor lookup failed");
98
+ assert(t[-1] == 6.0f && "negative flat tensor lookup failed");
99
+ assert((t[0, 0] == 1.0f) && "exact tensor lookup failed");
100
+ assert((t[1, -1] == 6.0f) && "negative exact tensor lookup failed");
101
+
102
+ auto whole = t[nk::slice];
103
+ assert(whole.rank() == 2 && "slice identity rank mismatch");
104
+ assert(whole.extent(0) == 2 && whole.extent(1) == 3 && "slice identity extents mismatch");
105
+
106
+ auto row1 = t[1, nk::slice];
107
+ assert(row1.rank() == 1 && "row slice rank mismatch");
108
+ assert(row1.extent(0) == 3 && "row slice extent mismatch");
109
+ assert(row1[0] == 4.0f && row1[-1] == 6.0f && "row slice values mismatch");
110
+ row1[1] = 42.0f;
111
+ assert((t[1, 1] == 42.0f) && "row slice write-through failed");
112
+
113
+ auto cell = t[1, 1, nk::slice];
114
+ assert(cell.rank() == 0 && "scalar slice rank mismatch");
115
+ assert(cell.scalar() == 42.0f && "scalar slice value mismatch");
116
+ cell.scalar_ref() = 24.0f;
117
+ assert((t[1, 1] == 24.0f) && "scalar slice write-through failed");
118
+
119
+ auto const &ct = t;
120
+ auto const last_row = ct[-1, nk::slice];
121
+ assert(last_row.rank() == 1 && "const row slice rank mismatch");
122
+ assert(last_row[0] == 4.0f && "const row slice mismatch");
123
+
124
+ auto cube = nk::tensor<float>::try_zeros({2, 3, 4});
125
+ assert(!cube.empty() && "cube allocation failed");
126
+ for (int i = 0; i < 24; ++i) cube[i] = static_cast<float>(i);
127
+
128
+ auto plane = cube[1, nk::slice];
129
+ assert(plane.rank() == 2 && plane.extent(0) == 3 && plane.extent(1) == 4 && "plane slice mismatch");
130
+ auto line = cube[1, 2, nk::slice];
131
+ assert(line.rank() == 1 && line.extent(0) == 4 && "line slice mismatch");
132
+ assert((line[3] == cube[1, 2, 3]) && "line slice element mismatch");
133
+ auto point = cube[1, 2, 3, nk::slice];
134
+ assert((point.rank() == 0 && point.scalar() == cube[1, 2, 3]) && "point slice mismatch");
135
+
136
+ // all_t slicing: extract a column
137
+ auto second_column = t[nk::all, 1, nk::slice];
138
+ assert(second_column.rank() == 1 && "all_t column rank mismatch");
139
+ assert(second_column.numel() == 2 && "all_t column numel mismatch");
140
+
141
+ // range slicing: extract a sub-range of rows
142
+ auto first_two_planes = cube[nk::range(0, 2), nk::slice];
143
+ assert(first_two_planes.rank() == 3 && "range slice rank mismatch");
144
+ assert(first_two_planes.extent(0) == 2 && "range slice extent mismatch");
145
+
146
+ // combined: range + all_t + slice on a 3D tensor
147
+ auto sub = cube[nk::range(0, 2), nk::all, nk::slice];
148
+ assert(sub.rank() == 3 && sub.extent(0) == 2 && sub.extent(1) == 3 && "range+all slice mismatch");
149
+
150
+ // row() access
151
+ auto row0 = t.row(0);
152
+ assert(row0.rank() == 1 && row0.extent(0) == 3 && "row() rank/extent mismatch");
153
+ auto row0_via_slice = t[0, nk::slice];
154
+ assert(row0[0] == row0_via_slice[0] && "row() should match t[0, slice]");
155
+ }
156
+
157
+ void test_packed_tensor_operator_indexing() {
158
+ auto t4 = nk::tensor<nk::u4x2_t>::try_zeros({2, 4});
159
+ assert(!t4.empty() && "packed u4 tensor allocation failed");
160
+
161
+ for (int i = 0; i < 8; ++i) t4[i] = i + 1;
162
+
163
+ assert(int(t4[0]) == 1 && "packed flat lookup failed");
164
+ assert(int(t4[-1]) == 8 && "packed negative flat lookup failed");
165
+ assert((int(t4[0, 3]) == 4) && "packed exact lookup failed");
166
+ assert((int(t4[1, -1]) == 8) && "packed negative exact lookup failed");
167
+
168
+ auto second_row = t4[1, nk::slice];
169
+ assert(second_row.rank() == 1 && second_row.extent(0) == 4 && "packed row slice rank mismatch");
170
+ assert(int(second_row[0]) == 5 && int(second_row[-1]) == 8 && "packed row slice values mismatch");
171
+ second_row[1] = 14;
172
+ assert((int(t4[1, 1]) == 14) && "packed row slice write-through failed");
173
+
174
+ auto t1 = nk::tensor<nk::u1x8_t>::try_zeros({2, 8});
175
+ assert(!t1.empty() && "packed u1 tensor allocation failed");
176
+ t1[0] = true;
177
+ t1[7] = true;
178
+ t1[11] = true;
179
+ t1[-1] = true;
180
+
181
+ assert(bool(t1[0]) && "packed bit flat lookup failed");
182
+ assert((bool(t1[0, 7])) && "packed bit exact lookup failed");
183
+ assert((bool(t1[1, 3])) && "packed bit second-row lookup failed");
184
+ assert(bool(t1[-1]) && "packed bit negative flat lookup failed");
185
+
186
+ auto bits = t1[1, nk::slice];
187
+ assert(bits.rank() == 1 && bits.extent(0) == 8 && "packed bit slice rank mismatch");
188
+ bits[4] = true;
189
+ assert((bool(t1[1, 4])) && "packed bit slice write-through failed");
190
+ }
191
+
192
+ void test_move_semantics() {
193
+ auto v1 = make_vector<nk::f32_t>(100);
194
+ v1[50] = nk::f32_t(42.0f);
195
+
196
+ nk::vector<nk::f32_t> v2 = std::move(v1);
197
+ assert(v2.size() == 100 && "move ctor size mismatch");
198
+ assert(v2[50] == nk::f32_t(42.0f) && "move ctor value mismatch");
199
+ assert(v1.size() == 0 && "moved-from vector not empty"); // NOLINT(bugprone-use-after-move)
200
+
201
+ nk::vector<nk::f32_t> v3;
202
+ v3 = std::move(v2);
203
+ assert(v3.size() == 100 && "move assign size mismatch");
204
+ assert(v3[50] == nk::f32_t(42.0f) && "move assign value mismatch");
205
+ }
206
+
207
+ void test_swap() {
208
+ auto v1 = make_vector<nk::i8_t>(10);
209
+ auto v2 = make_vector<nk::i8_t>(20);
210
+ v1[0] = nk::i8_t(1);
211
+ v2[0] = nk::i8_t(2);
212
+
213
+ swap(v1, v2);
214
+ assert(v1.size() == 20 && "swap v1 size mismatch");
215
+ assert(v2.size() == 10 && "swap v2 size mismatch");
216
+ assert(v1[0] == nk::i8_t(2) && "swap v1 value mismatch");
217
+ assert(v2[0] == nk::i8_t(1) && "swap v2 value mismatch");
218
+ }
219
+
220
+ void test_view_span_rev() {
221
+ auto v = make_vector<float>(5);
222
+ v[0] = 1.0f;
223
+ v[1] = 2.0f;
224
+ v[2] = 3.0f;
225
+ v[3] = 4.0f;
226
+ v[4] = 5.0f;
227
+
228
+ auto view = v.view();
229
+ assert(view.size() == 5 && "view size mismatch");
230
+ assert(view[-1] == 5.0f && "view signed indexing failed");
231
+
232
+ auto span = v.span();
233
+ span[0] = 10.0f;
234
+ assert(v[0] == 10.0f && "span write-through failed");
235
+
236
+ auto rev = view.rev();
237
+ assert(rev[0] == 5.0f && "reversed view first element mismatch");
238
+ assert(rev[4] == 10.0f && "reversed view last element mismatch");
239
+ }
240
+
241
+ void test_range_slicing() {
242
+ auto v = make_vector<float>(5);
243
+ v[0] = 1.0f;
244
+ v[1] = 2.0f;
245
+ v[2] = 3.0f;
246
+ v[3] = 4.0f;
247
+ v[4] = 5.0f;
248
+
249
+ auto sub = v[nk::range(1, 4)];
250
+ assert(sub.size() == 3 && "range slice size mismatch");
251
+ assert(sub[0] == 2.0f && "range slice first element mismatch");
252
+ assert(sub[2] == 4.0f && "range slice last element mismatch");
253
+ }
254
+
255
+ void test_sub_byte_i4x2() {
256
+ auto v = make_vector<nk::i4x2_t>(100);
257
+ assert(v.size() == 100 && "i4x2_t size mismatch");
258
+ assert(v.size_values() == 50 && "i4x2_t size_values mismatch (should be dims/2)");
259
+
260
+ v[0] = 5, v[1] = -3;
261
+ assert(v[0] == 5 && "i4x2_t dim 0 mismatch");
262
+ assert(v[1] == -3 && "i4x2_t dim 1 mismatch");
263
+ }
264
+
265
+ void test_sub_byte_u1x8() {
266
+ auto v = make_vector<nk::u1x8_t>(64);
267
+ assert(v.size() == 64 && "u1x8_t size mismatch");
268
+ assert(v.size_values() == 8 && "u1x8_t size_values mismatch (should be dims/8)");
269
+
270
+ v[0] = true, v[1] = false, v[7] = true;
271
+ assert(v[0] == true && "u1x8_t dim 0 mismatch");
272
+ assert(v[1] == false && "u1x8_t dim 1 mismatch");
273
+ assert(v[7] == true && "u1x8_t dim 7 mismatch");
274
+ }
275
+
276
+ void test_custom_allocator() {
277
+ using custom_alloc_t = nk::aligned_allocator<nk::f32_t, 128>;
278
+ auto v = nk::vector<nk::f32_t, custom_alloc_t>::try_zeros(256);
279
+ assert(v.size() == 256 && "custom allocator size mismatch");
280
+ v[128] = nk::f32_t(99.0f);
281
+ assert(v[128] == nk::f32_t(99.0f) && "custom allocator value mismatch");
282
+ }
283
+
284
+ template <typename value_type_, std::size_t cols_>
285
+ void test_sub_byte_tensor_axis_reduction_case(std::array<int, cols_> const &first_row,
286
+ std::array<int, cols_> const &second_row,
287
+ std::array<int, cols_> const &expected_sums,
288
+ std::array<int, cols_> const &expected_mins,
289
+ std::array<int, cols_> const &expected_maxs) {
290
+ using tensor_t = nk::tensor<value_type_>;
291
+ using sum_t = typename value_type_::reduce_moments_sum_t;
292
+ using minmax_t = typename value_type_::reduce_minmax_value_t;
293
+
294
+ auto t = tensor_t::try_zeros({2, cols_});
295
+ assert(!t.empty() && "tensor allocation failed");
296
+
297
+ auto span = t.span();
298
+ auto row0 = span.slice_leading(0).as_vector();
299
+ auto row1 = span.slice_leading(1).as_vector();
300
+ for (std::size_t i = 0; i < cols_; ++i) {
301
+ row0[i] = first_row[i];
302
+ row1[i] = second_row[i];
303
+ }
304
+
305
+ auto sums = nk::try_sum<value_type_>(t.view(), 0);
306
+ assert(!sums.empty() && "axis-0 sum failed");
307
+ auto sum_view = sums.as_vector_view();
308
+ for (std::size_t i = 0; i < cols_; ++i) assert(sum_view[i] == sum_t(expected_sums[i]) && "axis-0 sum mismatch");
309
+
310
+ auto minmax = nk::try_minmax<value_type_>(t.view(), 0);
311
+ assert(!minmax.min_value.empty() && !minmax.max_value.empty() && "axis-0 minmax failed");
312
+ auto min_view = minmax.min_value.as_vector_view();
313
+ auto max_view = minmax.max_value.as_vector_view();
314
+ for (std::size_t i = 0; i < cols_; ++i) {
315
+ assert(min_view[i] == minmax_t(expected_mins[i]) && "axis-0 min mismatch");
316
+ assert(max_view[i] == minmax_t(expected_maxs[i]) && "axis-0 max mismatch");
317
+ }
318
+ }
319
+
320
+ template <typename tensor_type_, typename expected_type_, std::size_t dims_>
321
+ void assert_flat_tensor_equals(tensor_type_ const &tensor, std::array<expected_type_, dims_> const &expected) {
322
+ auto flat = tensor.view().flatten();
323
+ assert(!flat.empty() && "tensor flatten failed");
324
+ auto vec = flat.as_vector();
325
+ assert(vec.size() == dims_ && "flattened tensor size mismatch");
326
+ using actual_t = typename tensor_type_::value_type;
327
+ for (std::size_t i = 0; i < dims_; ++i)
328
+ assert(vec[i] == actual_t(expected[i]) && "flattened tensor value mismatch");
329
+ }
330
+
331
+ template <typename tensor_type_, typename expected_type_>
332
+ void assert_scalar_tensor_equals(tensor_type_ const &tensor, expected_type_ expected) {
333
+ auto flat = tensor.view().flatten();
334
+ assert(!flat.empty() && "tensor flatten failed");
335
+ auto vec = flat.as_vector();
336
+ assert(vec.size() == 1 && "scalar tensor should flatten to one value");
337
+ using actual_t = typename tensor_type_::value_type;
338
+ assert(vec[0u] == actual_t(expected) && "scalar tensor value mismatch");
339
+ }
340
+
341
+ template <typename value_type_, std::size_t cols_>
342
+ void test_sub_byte_tensor_rank3_axis_case(
343
+ std::array<int, cols_> const &a00, std::array<int, cols_> const &a01, std::array<int, cols_> const &a10,
344
+ std::array<int, cols_> const &a11, std::array<int, cols_ * 2> const &expected_sum_axis0,
345
+ std::array<int, cols_ * 2> const &expected_sum_axis1, std::array<int, 4> const &expected_sum_axis2,
346
+ std::array<int, cols_ * 2> const &expected_min_axis0, std::array<int, cols_ * 2> const &expected_max_axis0,
347
+ std::array<int, cols_ * 2> const &expected_min_axis1, std::array<int, cols_ * 2> const &expected_max_axis1,
348
+ std::array<int, 4> const &expected_min_axis2, std::array<int, 4> const &expected_max_axis2) {
349
+ using tensor_t = nk::tensor<value_type_>;
350
+ using sum_t = typename value_type_::reduce_moments_sum_t;
351
+ using minmax_t = typename value_type_::reduce_minmax_value_t;
352
+
353
+ auto t = tensor_t::try_zeros({2, 2, cols_});
354
+ assert(!t.empty() && "rank-3 tensor allocation failed");
355
+
356
+ auto span = t.span();
357
+ auto row00 = span.slice_leading(0).slice_leading(0).as_vector();
358
+ auto row01 = span.slice_leading(0).slice_leading(1).as_vector();
359
+ auto row10 = span.slice_leading(1).slice_leading(0).as_vector();
360
+ auto row11 = span.slice_leading(1).slice_leading(1).as_vector();
361
+ for (std::size_t i = 0; i < cols_; ++i) {
362
+ row00[i] = a00[i];
363
+ row01[i] = a01[i];
364
+ row10[i] = a10[i];
365
+ row11[i] = a11[i];
366
+ }
367
+
368
+ auto sums0 = nk::try_sum<value_type_>(t.view(), 0);
369
+ auto sums1 = nk::try_sum<value_type_>(t.view(), 1);
370
+ auto sums2 = nk::try_sum<value_type_>(t.view(), 2);
371
+ assert_flat_tensor_equals(sums0, expected_sum_axis0);
372
+ assert_flat_tensor_equals(sums1, expected_sum_axis1);
373
+ assert_flat_tensor_equals(sums2, expected_sum_axis2);
374
+
375
+ auto moments0 = nk::try_moments<value_type_>(t.view(), 0);
376
+ auto moments1 = nk::try_moments<value_type_>(t.view(), 1);
377
+ auto moments2 = nk::try_moments<value_type_>(t.view(), 2);
378
+ assert_flat_tensor_equals(moments0.sum, expected_sum_axis0);
379
+ assert_flat_tensor_equals(moments1.sum, expected_sum_axis1);
380
+ assert_flat_tensor_equals(moments2.sum, expected_sum_axis2);
381
+
382
+ auto minmax0 = nk::try_minmax<value_type_>(t.view(), 0);
383
+ auto minmax1 = nk::try_minmax<value_type_>(t.view(), 1);
384
+ auto minmax2 = nk::try_minmax<value_type_>(t.view(), 2);
385
+ assert_flat_tensor_equals(minmax0.min_value, expected_min_axis0);
386
+ assert_flat_tensor_equals(minmax0.max_value, expected_max_axis0);
387
+ assert_flat_tensor_equals(minmax1.min_value, expected_min_axis1);
388
+ assert_flat_tensor_equals(minmax1.max_value, expected_max_axis1);
389
+ assert_flat_tensor_equals(minmax2.min_value, expected_min_axis2);
390
+ assert_flat_tensor_equals(minmax2.max_value, expected_max_axis2);
391
+ }
392
+
393
+ void test_sub_byte_tensor_axis_reductions() {
394
+ test_sub_byte_tensor_axis_reduction_case<nk::i4x2_t, 4>({1, -2, 7, -8}, {-3, 4, -5, 6}, {-2, 2, 2, -2},
395
+ {-3, -2, -5, -8}, {1, 4, 7, 6});
396
+ test_sub_byte_tensor_axis_reduction_case<nk::u4x2_t, 4>({1, 15, 3, 8}, {14, 2, 9, 7}, {15, 17, 12, 15},
397
+ {1, 2, 3, 7}, {14, 15, 9, 8});
398
+ test_sub_byte_tensor_axis_reduction_case<nk::u1x8_t, 8>({1, 0, 1, 1, 0, 0, 1, 0}, {0, 1, 1, 0, 1, 0, 0, 1},
399
+ {1, 1, 2, 1, 1, 0, 1, 1}, {0, 0, 1, 0, 0, 0, 0, 0},
400
+ {1, 1, 1, 1, 1, 0, 1, 1});
401
+ }
402
+
403
+ void test_sub_byte_tensor_rank3_axis_reductions() {
404
+ test_sub_byte_tensor_rank3_axis_case<nk::i4x2_t, 4>(
405
+ {1, -2, 3, -4}, {5, -6, 7, -8}, {-1, 2, -3, 4}, {-5, 6, -7, 7}, {0, 0, 0, 0, 0, 0, 0, -1},
406
+ {6, -8, 10, -12, -6, 8, -10, 11}, {-2, -2, 2, 1}, {-1, -2, -3, -4, -5, -6, -7, -8}, {1, 2, 3, 4, 5, 6, 7, 7},
407
+ {1, -6, 3, -8, -5, 2, -7, 4}, {5, -2, 7, -4, -1, 6, -3, 7}, {-4, -8, -3, -7}, {3, 7, 4, 7});
408
+
409
+ test_sub_byte_tensor_rank3_axis_case<nk::u4x2_t, 4>(
410
+ {1, 2, 3, 4}, {5, 6, 7, 8}, {14, 13, 12, 11}, {10, 9, 8, 7}, {15, 15, 15, 15, 15, 15, 15, 15},
411
+ {6, 8, 10, 12, 24, 22, 20, 18}, {10, 26, 50, 34}, {1, 2, 3, 4, 5, 6, 7, 7}, {14, 13, 12, 11, 10, 9, 8, 8},
412
+ {1, 2, 3, 4, 10, 9, 8, 7}, {5, 6, 7, 8, 14, 13, 12, 11}, {1, 5, 11, 7}, {4, 8, 14, 10});
413
+
414
+ test_sub_byte_tensor_rank3_axis_case<nk::u1x8_t, 8>(
415
+ {1, 0, 1, 0, 1, 0, 1, 0}, {0, 1, 0, 1, 0, 1, 0, 1}, {1, 1, 0, 0, 1, 1, 0, 0}, {0, 0, 1, 1, 0, 0, 1, 1},
416
+ {2, 1, 1, 0, 2, 1, 1, 0, 0, 1, 1, 2, 0, 1, 1, 2}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
417
+ {4, 4, 4, 4}, {1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1},
418
+ {1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
419
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 0}, {1, 1, 1, 1});
420
+ }
421
+
422
+ void test_rank1_negative_stride_reductions() {
423
+ using value_t = nk::f32_t;
424
+ using sum_t = typename value_t::reduce_moments_sum_t;
425
+ using minmax_t = typename value_t::reduce_minmax_value_t;
426
+
427
+ value_t data[] = {1.0f, 2.0f, 3.0f, 4.0f};
428
+ nk::shape_storage_<8> shape {};
429
+ shape.rank = 1;
430
+ shape.extents[0] = 4;
431
+ shape.strides[0] = -static_cast<std::ptrdiff_t>(sizeof(value_t));
432
+ nk::tensor_view<value_t> reversed(reinterpret_cast<char const *>(data + 3), shape);
433
+
434
+ auto m = nk::moments(reversed);
435
+ auto mm = nk::minmax(reversed);
436
+ assert(m.sum == sum_t(10.0) && "negative-stride sum mismatch");
437
+ assert(m.sumsq == typename value_t::reduce_moments_sumsq_t(30.0) && "negative-stride sumsq mismatch");
438
+ assert(mm.min_value == minmax_t(1.0f) && "negative-stride min mismatch");
439
+ assert(mm.max_value == minmax_t(4.0f) && "negative-stride max mismatch");
440
+ }
441
+
442
+ void test_rank1_axis_reductions() {
443
+ auto v = nk::tensor<nk::i8_t>::try_zeros({4});
444
+ assert(!v.empty() && "rank-1 tensor allocation failed");
445
+ auto values = v.as_vector_span();
446
+ values[0u] = 4;
447
+ values[1u] = -2;
448
+ values[2u] = 7;
449
+ values[3u] = -5;
450
+
451
+ auto sums = nk::try_sum<nk::i8_t>(v.view(), 0);
452
+ auto moments = nk::try_moments<nk::i8_t>(v.view(), 0);
453
+ auto mins = nk::try_min<nk::i8_t>(v.view(), 0);
454
+ auto maxs = nk::try_max<nk::i8_t>(v.view(), 0);
455
+ auto argmins = nk::try_argmin<nk::i8_t>(v.view(), 0);
456
+ auto argmaxs = nk::try_argmax<nk::i8_t>(v.view(), 0);
457
+
458
+ assert(!sums.empty() && !moments.sum.empty() && "rank-1 axis moments failed");
459
+ assert(!mins.empty() && !maxs.empty() && !argmins.empty() && !argmaxs.empty() && "rank-1 axis minmax failed");
460
+ assert(sums.rank() == 0 && moments.sum.rank() == 0 && "collapsed rank-1 reductions should produce rank-0 tensors");
461
+ assert_scalar_tensor_equals(sums, 4);
462
+ assert_scalar_tensor_equals(moments.sum, 4);
463
+ assert_scalar_tensor_equals(mins, -5);
464
+ assert_scalar_tensor_equals(maxs, 7);
465
+ assert_scalar_tensor_equals(argmins, 3);
466
+ assert_scalar_tensor_equals(argmaxs, 2);
467
+ }
468
+
469
+ void test_packed_tensor_fail_closed_views() {
470
+ auto packed = nk::tensor<nk::i4x2_t>::try_zeros({2, 4});
471
+ assert(!packed.empty() && "packed tensor allocation failed");
472
+ assert(packed.view().transpose().empty() && "packed transpose should fail closed");
473
+ assert((!packed[1, nk::slice].empty()) && "packed row slice should remain supported");
474
+ assert((packed[1, 2, nk::slice].empty()) && "packed scalar trailing slice should fail closed");
475
+ }
476
+
477
+ void test_vector_types() {
478
+ std::printf("Testing vector type instantiations...\n");
479
+
480
+ // Template-based type coverage
481
+ test_vector_basics<float>();
482
+ test_vector_basics<double>();
483
+ test_vector_basics<nk::f16_t>();
484
+ test_vector_basics<nk::bf16_t>();
485
+ test_vector_basics<nk::i8_t>();
486
+ test_vector_basics<nk::f32c_t>();
487
+ test_vector_basics<std::complex<double>>();
488
+ test_vector_basics<nk::i4x2_t>();
489
+ test_vector_basics<nk::u1x8_t>();
490
+ std::printf(" vector basics (9 types): OK\n");
491
+
492
+ // Feature tests (non-template, using specific types)
493
+ test_signed_indexing();
494
+ std::printf(" signed indexing: OK\n");
495
+
496
+ test_integral_indexing_api();
497
+ std::printf(" integral indexing api: OK\n");
498
+
499
+ test_move_semantics();
500
+ std::printf(" move semantics: OK\n");
501
+
502
+ test_swap();
503
+ std::printf(" swap: OK\n");
504
+
505
+ test_view_span_rev();
506
+ std::printf(" view/span/rev: OK\n");
507
+
508
+ test_range_slicing();
509
+ std::printf(" range slicing: OK\n");
510
+
511
+ test_sub_byte_i4x2();
512
+ test_sub_byte_u1x8();
513
+ std::printf(" sub-byte i4x2/u1x8: OK\n");
514
+
515
+ test_custom_allocator();
516
+ std::printf(" custom allocator: OK\n");
517
+
518
+ #if NK_TEST_FORMAT_
519
+ test_format_scalars();
520
+ std::printf(" std::format scalars+refs: OK\n");
521
+ #endif
522
+ }
523
+
524
+ /**
525
+ * @brief Explicit template instantiation test for all tensor-level operations.
526
+ *
527
+ * Forces the compiler to fully instantiate every type × operation combination,
528
+ * catching signature mismatches, missing type traits, and implicit conversion errors
529
+ * that syntax-only checks miss.
530
+ */
531
+ template <typename value_type_>
532
+ void test_tensor_ops_for_type() {
533
+ using tensor_t = nk::tensor<value_type_>;
534
+
535
+ // Create small test tensors
536
+ auto a = tensor_t::try_zeros({4, 8});
537
+ auto b = tensor_t::try_zeros({4, 8});
538
+ assert(!a.empty() && !b.empty());
539
+
540
+ auto av = a.view();
541
+ auto bv = b.view();
542
+
543
+ // Scalar reductions
544
+ { [[maybe_unused]] auto r = nk::sum<value_type_>(av); }
545
+ { [[maybe_unused]] auto r = nk::moments<value_type_>(av); }
546
+ { [[maybe_unused]] auto r = nk::min<value_type_>(av); }
547
+ { [[maybe_unused]] auto r = nk::max<value_type_>(av); }
548
+ { [[maybe_unused]] auto r = nk::argmin<value_type_>(av); }
549
+ { [[maybe_unused]] auto r = nk::argmax<value_type_>(av); }
550
+ { [[maybe_unused]] auto r = nk::minmax<value_type_>(av); }
551
+
552
+ // Axis reductions
553
+ { [[maybe_unused]] auto r = nk::try_sum<value_type_>(av, 0); }
554
+ { [[maybe_unused]] auto r = nk::try_sum<value_type_>(av, 1, nk::keep_dims_k); }
555
+ { [[maybe_unused]] auto r = nk::try_moments<value_type_>(av, 1); }
556
+ { [[maybe_unused]] auto r = nk::try_minmax<value_type_>(av, 0); }
557
+ { [[maybe_unused]] auto r = nk::try_minmax<value_type_>(av, 1, nk::keep_dims_k); }
558
+ { [[maybe_unused]] auto r = nk::try_min<value_type_>(av, 0); }
559
+ { [[maybe_unused]] auto r = nk::try_min<value_type_>(av, 1, nk::keep_dims_k); }
560
+ { [[maybe_unused]] auto r = nk::try_max<value_type_>(av, 0); }
561
+ { [[maybe_unused]] auto r = nk::try_max<value_type_>(av, 1, nk::keep_dims_k); }
562
+ { [[maybe_unused]] auto r = nk::try_argmin<value_type_>(av, 0); }
563
+ { [[maybe_unused]] auto r = nk::try_argmax<value_type_>(av, 1, nk::keep_dims_k); }
564
+
565
+ // Elementwise binary
566
+ { [[maybe_unused]] auto r = nk::try_add<value_type_>(av, bv); }
567
+ { [[maybe_unused]] auto r = nk::try_sub<value_type_>(av, bv); }
568
+ { [[maybe_unused]] auto r = nk::try_mul<value_type_>(av, bv); }
569
+
570
+ // Elementwise binary with scalar
571
+ using scale_t = typename value_type_::scale_t;
572
+ scale_t scalar {1};
573
+ { [[maybe_unused]] auto r = nk::try_add<value_type_>(av, scalar); }
574
+ { [[maybe_unused]] auto r = nk::try_sub<value_type_>(av, scalar); }
575
+ { [[maybe_unused]] auto r = nk::try_mul<value_type_>(av, scalar); }
576
+
577
+ // Elementwise into
578
+ auto out = tensor_t::try_zeros({4, 8});
579
+ { [[maybe_unused]] bool ok = nk::add<value_type_>(av, bv, out.span()); }
580
+ { [[maybe_unused]] bool ok = nk::sub<value_type_>(av, bv, out.span()); }
581
+ { [[maybe_unused]] bool ok = nk::mul<value_type_>(av, bv, out.span()); }
582
+ { [[maybe_unused]] bool ok = nk::add<value_type_>(av, scalar, out.span()); }
583
+ { [[maybe_unused]] bool ok = nk::sub<value_type_>(av, scalar, out.span()); }
584
+ { [[maybe_unused]] bool ok = nk::mul<value_type_>(av, scalar, out.span()); }
585
+
586
+ // Affine
587
+ scale_t alpha {1}, beta {0};
588
+ { [[maybe_unused]] auto r = nk::try_scale<value_type_>(av, alpha, beta); }
589
+ { [[maybe_unused]] auto r = nk::try_blend<value_type_>(av, bv, alpha, beta); }
590
+ { [[maybe_unused]] auto r = nk::try_fma<value_type_>(av, bv, av, alpha, beta); }
591
+ { [[maybe_unused]] bool ok = nk::scale<value_type_>(av, alpha, beta, out.span()); }
592
+ { [[maybe_unused]] bool ok = nk::blend<value_type_>(av, bv, alpha, beta, out.span()); }
593
+ { [[maybe_unused]] bool ok = nk::fma<value_type_>(av, bv, av, alpha, beta, out.span()); }
594
+
595
+ // try_from 1D
596
+ {
597
+ auto from1d = tensor_t::try_from({value_type_ {}, value_type_ {}, value_type_ {}});
598
+ assert(!from1d.empty() && "try_from 1D failed");
599
+ assert(from1d.rank() == 1 && from1d.numel() == 3 && "try_from 1D shape mismatch");
600
+ }
601
+
602
+ // try_from 2D
603
+ {
604
+ auto from2d = tensor_t::try_from({{value_type_ {}, value_type_ {}}, {value_type_ {}, value_type_ {}}});
605
+ assert(!from2d.empty() && "try_from 2D failed");
606
+ assert(from2d.rank() == 2 && from2d.extent(0) == 2 && from2d.extent(1) == 2 && "try_from 2D shape mismatch");
607
+ }
608
+
609
+ // row() access
610
+ {
611
+ auto row0 = a.row(0);
612
+ assert(row0.rank() == 1 && row0.extent(0) == 8 && "row() shape mismatch");
613
+ }
614
+
615
+ // Convenience view constructor (ptr, rows, cols)
616
+ {
617
+ nk::tensor_view<value_type_> view_from_ptr(a.data(), 4, 8);
618
+ assert(view_from_ptr.rank() == 2 && view_from_ptr.extent(0) == 4 && "convenience view ctor mismatch");
619
+ }
620
+ }
621
+
622
+ template <typename value_type_>
623
+ void test_tensor_trig_for_type() {
624
+ using tensor_t = nk::tensor<value_type_>;
625
+ auto a = tensor_t::try_zeros({4, 8});
626
+ auto out = tensor_t::try_zeros({4, 8});
627
+ auto av = a.view();
628
+
629
+ { [[maybe_unused]] auto r = nk::try_sin<value_type_>(av); }
630
+ { [[maybe_unused]] auto r = nk::try_cos<value_type_>(av); }
631
+ { [[maybe_unused]] auto r = nk::try_atan<value_type_>(av); }
632
+ { [[maybe_unused]] bool ok = nk::sin<value_type_>(av, out.span()); }
633
+ { [[maybe_unused]] bool ok = nk::cos<value_type_>(av, out.span()); }
634
+ { [[maybe_unused]] bool ok = nk::atan<value_type_>(av, out.span()); }
635
+ }
636
+
637
+ template <typename value_type_>
638
+ void test_tensor_symmetric_for_type() {
639
+ using tensor_t = nk::tensor<value_type_>;
640
+ auto a = tensor_t::try_zeros({4, 8});
641
+ auto am = a.as_matrix_view();
642
+
643
+ { [[maybe_unused]] auto r = nk::try_dots_symmetric<value_type_>(am); }
644
+ { [[maybe_unused]] auto r = nk::try_angulars_symmetric<value_type_>(am); }
645
+ { [[maybe_unused]] auto r = nk::try_euclideans_symmetric<value_type_>(am); }
646
+ }
647
+
648
+ template <typename value_type_>
649
+ void test_tensor_packed_for_type() {
650
+ using tensor_t = nk::tensor<value_type_>;
651
+ auto a = tensor_t::try_zeros({4, 8});
652
+ auto b = tensor_t::try_zeros({6, 8});
653
+
654
+ // packed_matrix
655
+ auto bm = b.as_matrix_view();
656
+ auto packed = nk::packed_matrix<value_type_, nk::aligned_allocator<char>>::try_pack(bm);
657
+ auto am = a.as_matrix_view();
658
+ auto result = nk::matrix<typename value_type_::dot_result_t>::try_zeros({4, 6});
659
+ nk::dots_packed<value_type_>(am, packed, result.span());
660
+ }
661
+
662
+ template <typename value_type_>
663
+ void test_tensor_maxsim_for_type() {
664
+ using tensor_t = nk::tensor<value_type_>;
665
+ auto q = tensor_t::try_zeros({3, 16});
666
+ auto d = tensor_t::try_zeros({5, 16});
667
+
668
+ auto qm = q.as_matrix_view();
669
+ auto dm = d.as_matrix_view();
670
+
671
+ auto pq = nk::packed_maxsim<value_type_>::try_pack(qm);
672
+ auto pd = nk::packed_maxsim<value_type_>::try_pack(dm);
673
+ { [[maybe_unused]] auto r = nk::maxsim(pq, pd); }
674
+ }
675
+
676
+ void test_view_overloads() {
677
+ nk::f32_t a_data[8] {}, b_data[8] {}, c_data[64] {};
678
+ nk::f32_t result {};
679
+ auto a_view = nk::vector_view<nk::f32_t>(a_data, 8u);
680
+ auto b_view = nk::vector_view<nk::f32_t>(b_data, 8u);
681
+
682
+ nk::dot(a_view, b_view, 8, &result);
683
+ nk::euclidean(a_view, b_view, 8, &result);
684
+ nk::sqeuclidean(a_view, b_view, 8, &result);
685
+ nk::angular(a_view, b_view, 8, &result);
686
+
687
+ auto c_view = nk::vector_view<nk::f32_t>(c_data, 64u);
688
+ nk::bilinear(a_view, b_view, c_view, 8, &result);
689
+ nk::mahalanobis(a_view, b_view, c_view, 8, &result);
690
+ }
691
+
692
+ void test_custom_allocator_try_fns() {
693
+ using custom_alloc_t = nk::aligned_allocator<nk::f32_t, 128>;
694
+ auto a = nk::tensor<nk::f32_t>::try_zeros({4, 8});
695
+ auto av = a.view();
696
+
697
+ { auto r = nk::try_scale<nk::f32_t, 8, custom_alloc_t>(av, 1.0, 0.0); }
698
+ { auto r = nk::try_sin<nk::f32_t, 8, custom_alloc_t>(av); }
699
+
700
+ using sum_alloc_t = nk::aligned_allocator<nk::f64_t, 128>;
701
+ { auto r = nk::try_sum<nk::f32_t, 8, sum_alloc_t>(av, 0); }
702
+ }
703
+
704
+ template <typename value_type_>
705
+ void test_vector_reductions_for_type() {
706
+ auto v = make_vector<value_type_>(32);
707
+ std::mt19937 generator(42);
708
+ fill_random(generator, v);
709
+ auto view = nk::vector_view<value_type_>(v.values_data(), static_cast<std::size_t>(v.size()));
710
+
711
+ { [[maybe_unused]] auto r = nk::moments(view); }
712
+ { [[maybe_unused]] auto r = nk::minmax(view); }
713
+ { [[maybe_unused]] auto r = nk::sum(view); }
714
+ { [[maybe_unused]] auto r = nk::min(view); }
715
+ { [[maybe_unused]] auto r = nk::max(view); }
716
+ { [[maybe_unused]] auto r = nk::argmin(view); }
717
+ { [[maybe_unused]] auto r = nk::argmax(view); }
718
+ }
719
+
720
+ void test_vector_reductions_correctness() {
721
+ nk::f32_t data[] = {nk::f32_t(1), nk::f32_t(2), nk::f32_t(3), nk::f32_t(4), nk::f32_t(5)};
722
+ auto view = nk::vector_view<nk::f32_t>(data, std::size_t {5});
723
+
724
+ auto m = nk::moments(view);
725
+ assert(m.sum.raw_ == 15.0 && "vector moments sum");
726
+ assert(m.sumsq.raw_ == 55.0 && "vector moments sumsq");
727
+
728
+ auto mm = nk::minmax(view);
729
+ assert(mm.min_value.raw_ == 1.0f && "vector min");
730
+ assert(mm.max_value.raw_ == 5.0f && "vector max");
731
+ assert(mm.min_index == 0 && "vector argmin");
732
+ assert(mm.max_index == 4 && "vector argmax");
733
+ }
734
+
735
+ template <typename from_type_, typename to_type_>
736
+ void test_cast_for_types() {
737
+ auto src = make_vector<from_type_>(64);
738
+ auto dst = make_vector<to_type_>(64);
739
+ std::mt19937 generator(42);
740
+ fill_random(generator, src);
741
+
742
+ auto src_view = nk::vector_view<from_type_>(src.values_data(), static_cast<std::size_t>(src.size()));
743
+ auto dst_span = nk::vector_span<to_type_>(dst.values_data(), static_cast<std::size_t>(dst.size()));
744
+
745
+ // Pointer-level API
746
+ nk::cast<from_type_, to_type_>(src.values_data(), src.size(), dst.values_data());
747
+ // Vector view/span API
748
+ nk::cast<from_type_, to_type_>(src_view, dst_span);
749
+ }
750
+
751
+ #if NK_TEST_FORMAT_
752
+ void test_format_scalars() {
753
+ // Float scalar formatters
754
+ { [[maybe_unused]] auto s = std::format("{}", nk::f16_t(3.14f)); }
755
+ { [[maybe_unused]] auto s = std::format("{:#}", nk::f16_t(3.14f)); }
756
+ { [[maybe_unused]] auto s = std::format("{:.2f}", nk::f16_t(3.14f)); }
757
+ { [[maybe_unused]] auto s = std::format("{:x}", nk::f16_t(3.14f)); }
758
+ { [[maybe_unused]] auto s = std::format("{:b}", nk::f16_t(3.14f)); }
759
+ { [[maybe_unused]] auto s = std::format("{}", nk::bf16_t(2.5f)); }
760
+ { [[maybe_unused]] auto s = std::format("{}", nk::e4m3_t(1.0f)); }
761
+ { [[maybe_unused]] auto s = std::format("{}", nk::e5m2_t(1.0f)); }
762
+ { [[maybe_unused]] auto s = std::format("{}", nk::e2m3_t(1.0f)); }
763
+ { [[maybe_unused]] auto s = std::format("{}", nk::e3m2_t(1.0f)); }
764
+
765
+ // Packed type formatters
766
+ { [[maybe_unused]] auto s = std::format("{}", nk::i4x2_t {}); }
767
+ { [[maybe_unused]] auto s = std::format("{:x}", nk::u4x2_t {}); }
768
+ { [[maybe_unused]] auto s = std::format("{}", nk::u1x8_t {}); }
769
+
770
+ // Complex type formatters
771
+ { [[maybe_unused]] auto s = std::format("{}", nk::f16c_t(nk::f16_t(1), nk::f16_t(2))); }
772
+ { [[maybe_unused]] auto s = std::format("{:#}", nk::bf16c_t(nk::bf16_t(1), nk::bf16_t(2))); }
773
+
774
+ // Sub-byte ref formatters
775
+ nk_i4x2_t packed_i = 0x53;
776
+ nk::sub_byte_ref<nk::i4x2_t> iref(&packed_i, 0);
777
+ assert(std::format("{}", iref) == "3" && "i4 sub_byte_ref default format");
778
+ assert(std::format("{:x}", iref) == "3" && "i4 sub_byte_ref hex format");
779
+ assert(std::format("{:b}", iref) == "0011" && "i4 sub_byte_ref binary format");
780
+ assert(std::format("{:#}", iref) == "3 [0x3]" && "i4 sub_byte_ref annotated format");
781
+
782
+ nk_u4x2_t packed_u = 0xA7;
783
+ nk::sub_byte_ref<nk::u4x2_t> uref(&packed_u, 1);
784
+ assert(std::format("{}", uref) == "10" && "u4 sub_byte_ref default format");
785
+ assert(std::format("{:x}", uref) == "a" && "u4 sub_byte_ref hex format");
786
+ assert(std::format("{:b}", uref) == "1010" && "u4 sub_byte_ref binary format");
787
+
788
+ nk_u1x8_t packed_b = 0x05;
789
+ nk::sub_byte_ref<nk::u1x8_t> bref(&packed_b, 0);
790
+ assert(std::format("{}", bref) == "1" && "u1 sub_byte_ref format");
791
+ }
792
+ #endif // NK_TEST_FORMAT_
793
+
794
+ void test_tensor_ops() {
795
+ std::printf("Testing tensor op instantiations...\n");
796
+
797
+ // Core numeric types: all operations
798
+ test_tensor_ops_for_type<nk::f32_t>();
799
+ test_tensor_ops_for_type<nk::f64_t>();
800
+ test_tensor_ops_for_type<nk::f16_t>();
801
+ test_tensor_ops_for_type<nk::bf16_t>();
802
+ test_tensor_ops_for_type<nk::i8_t>();
803
+ test_tensor_ops_for_type<nk::u8_t>();
804
+ std::printf(" ops (6 types): OK\n");
805
+
806
+ test_sub_byte_tensor_axis_reductions();
807
+ std::printf(" tensor axis sub-byte: OK\n");
808
+
809
+ test_sub_byte_tensor_rank3_axis_reductions();
810
+ std::printf(" tensor axis rank-3 packed: OK\n");
811
+
812
+ test_rank1_negative_stride_reductions();
813
+ std::printf(" tensor negative stride: OK\n");
814
+
815
+ test_rank1_axis_reductions();
816
+ std::printf(" tensor rank-1 axis: OK\n");
817
+
818
+ test_tensor_operator_indexing();
819
+ std::printf(" tensor operator[]: OK\n");
820
+
821
+ test_packed_tensor_operator_indexing();
822
+ std::printf(" tensor packed operator[]: OK\n");
823
+
824
+ test_packed_tensor_fail_closed_views();
825
+ std::printf(" tensor fail-closed views: OK\n");
826
+
827
+ // Trig (float-capable types)
828
+ test_tensor_trig_for_type<nk::f32_t>();
829
+ test_tensor_trig_for_type<nk::f64_t>();
830
+ test_tensor_trig_for_type<nk::f16_t>();
831
+ test_tensor_trig_for_type<nk::bf16_t>();
832
+ std::printf(" trig (4 types): OK\n");
833
+
834
+ // Symmetric distances
835
+ test_tensor_symmetric_for_type<nk::f32_t>();
836
+ test_tensor_symmetric_for_type<nk::f64_t>();
837
+ test_tensor_symmetric_for_type<nk::f16_t>();
838
+ test_tensor_symmetric_for_type<nk::bf16_t>();
839
+ test_tensor_symmetric_for_type<nk::i8_t>();
840
+ std::printf(" symmetric dist (5 types): OK\n");
841
+
842
+ // Packed GEMM
843
+ test_tensor_packed_for_type<nk::f32_t>();
844
+ test_tensor_packed_for_type<nk::f64_t>();
845
+ test_tensor_packed_for_type<nk::f16_t>();
846
+ test_tensor_packed_for_type<nk::bf16_t>();
847
+ test_tensor_packed_for_type<nk::i8_t>();
848
+ std::printf(" packed GEMM (5 types): OK\n");
849
+
850
+ // MaxSim (bf16, f32, f16 only)
851
+ test_tensor_maxsim_for_type<nk::bf16_t>();
852
+ test_tensor_maxsim_for_type<nk::f32_t>();
853
+ test_tensor_maxsim_for_type<nk::f16_t>();
854
+ std::printf(" packed MaxSim (3 types): OK\n");
855
+
856
+ test_view_overloads();
857
+ std::printf(" view overloads: OK\n");
858
+
859
+ test_custom_allocator_try_fns();
860
+ std::printf(" custom allocator try_fns: OK\n");
861
+
862
+ // Vector-level reductions
863
+ test_vector_reductions_for_type<nk::f32_t>();
864
+ test_vector_reductions_for_type<nk::f64_t>();
865
+ test_vector_reductions_for_type<nk::f16_t>();
866
+ test_vector_reductions_for_type<nk::bf16_t>();
867
+ test_vector_reductions_for_type<nk::i8_t>();
868
+ test_vector_reductions_for_type<nk::u8_t>();
869
+ std::printf(" vector reductions (6 types): OK\n");
870
+
871
+ test_vector_reductions_correctness();
872
+ std::printf(" vector reductions correct: OK\n");
873
+
874
+ // Cast wrapper
875
+ test_cast_for_types<nk::f32_t, nk::f16_t>();
876
+ test_cast_for_types<nk::f16_t, nk::f32_t>();
877
+ test_cast_for_types<nk::f32_t, nk::bf16_t>();
878
+ test_cast_for_types<nk::bf16_t, nk::f32_t>();
879
+ test_cast_for_types<nk::f32_t, nk::e4m3_t>();
880
+ test_cast_for_types<nk::e4m3_t, nk::f32_t>();
881
+ test_cast_for_types<nk::i8_t, nk::i32_t>();
882
+ test_cast_for_types<nk::f64_t, nk::f32_t>();
883
+ std::printf(" cast wrapper (8 pairs): OK\n");
884
+ }