usearch 2.21.4 → 2.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/README.md +65 -69
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +8 -8
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +124 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/README.md +1 -1
  16. package/javascript/dist/cjs/usearch.d.ts +8 -3
  17. package/javascript/dist/cjs/usearch.js +12 -4
  18. package/javascript/dist/esm/usearch.d.ts +8 -3
  19. package/javascript/dist/esm/usearch.js +12 -4
  20. package/javascript/lib.cpp +17 -0
  21. package/javascript/usearch.test.js +117 -94
  22. package/javascript/usearch.ts +14 -6
  23. package/numkong/.clang-tidy +30 -0
  24. package/{simsimd → numkong}/.cmake-format.py +18 -0
  25. package/numkong/.editorconfig +12 -0
  26. package/numkong/.git-blame-ignore-revs +123 -0
  27. package/numkong/.mailmap +15 -0
  28. package/numkong/.spi.yml +11 -0
  29. package/numkong/.swift-format +14 -0
  30. package/numkong/CITATION.cff +81 -0
  31. package/numkong/CONTRIBUTING.md +500 -0
  32. package/numkong/Cargo.toml +54 -0
  33. package/numkong/MANIFEST.in +8 -0
  34. package/numkong/Package.swift +84 -0
  35. package/numkong/README.md +569 -0
  36. package/numkong/bench/README.md +217 -0
  37. package/numkong/bench/bench-browser.html +323 -0
  38. package/numkong/bench/bench.cpp +344 -0
  39. package/numkong/bench/bench.hpp +816 -0
  40. package/numkong/bench/bench.js +148 -0
  41. package/numkong/bench/bench.mjs +616 -0
  42. package/numkong/bench/bench_attention.cpp +113 -0
  43. package/numkong/bench/bench_cast.cpp +264 -0
  44. package/numkong/bench/bench_cross_amx.cpp +62 -0
  45. package/numkong/bench/bench_cross_arm.cpp +245 -0
  46. package/numkong/bench/bench_cross_blas.cpp +309 -0
  47. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  48. package/numkong/bench/bench_cross_power.cpp +84 -0
  49. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  50. package/numkong/bench/bench_cross_serial.cpp +151 -0
  51. package/numkong/bench/bench_cross_sme.cpp +163 -0
  52. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  53. package/numkong/bench/bench_cross_x86.cpp +455 -0
  54. package/numkong/bench/bench_curved.cpp +210 -0
  55. package/numkong/bench/bench_dot.cpp +315 -0
  56. package/numkong/bench/bench_each.cpp +503 -0
  57. package/numkong/bench/bench_geospatial.cpp +112 -0
  58. package/numkong/bench/bench_maxsim.cpp +154 -0
  59. package/numkong/bench/bench_mesh.cpp +148 -0
  60. package/numkong/bench/bench_probability.cpp +60 -0
  61. package/numkong/bench/bench_reduce.cpp +371 -0
  62. package/numkong/bench/bench_set.cpp +73 -0
  63. package/numkong/bench/bench_sparse.cpp +198 -0
  64. package/numkong/bench/bench_spatial.cpp +347 -0
  65. package/numkong/bench/bench_trigonometry.cpp +137 -0
  66. package/numkong/bench/swift/Bench.swift +506 -0
  67. package/numkong/binding.gyp +169 -0
  68. package/numkong/build.rs +484 -0
  69. package/numkong/c/dispatch.h +512 -0
  70. package/numkong/c/dispatch_bf16.c +447 -0
  71. package/numkong/c/dispatch_bf16c.c +52 -0
  72. package/numkong/c/dispatch_e2m3.c +296 -0
  73. package/numkong/c/dispatch_e3m2.c +284 -0
  74. package/numkong/c/dispatch_e4m3.c +318 -0
  75. package/numkong/c/dispatch_e5m2.c +316 -0
  76. package/numkong/c/dispatch_f16.c +452 -0
  77. package/numkong/c/dispatch_f16c.c +58 -0
  78. package/numkong/c/dispatch_f32.c +434 -0
  79. package/numkong/c/dispatch_f32c.c +99 -0
  80. package/numkong/c/dispatch_f64.c +348 -0
  81. package/numkong/c/dispatch_f64c.c +98 -0
  82. package/numkong/c/dispatch_i16.c +96 -0
  83. package/numkong/c/dispatch_i32.c +89 -0
  84. package/numkong/c/dispatch_i4.c +153 -0
  85. package/numkong/c/dispatch_i64.c +86 -0
  86. package/numkong/c/dispatch_i8.c +348 -0
  87. package/numkong/c/dispatch_other.c +348 -0
  88. package/numkong/c/dispatch_u1.c +193 -0
  89. package/numkong/c/dispatch_u16.c +124 -0
  90. package/numkong/c/dispatch_u32.c +118 -0
  91. package/numkong/c/dispatch_u4.c +153 -0
  92. package/numkong/c/dispatch_u64.c +102 -0
  93. package/numkong/c/dispatch_u8.c +364 -0
  94. package/numkong/c/numkong.c +940 -0
  95. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  96. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  97. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_math_lib.cmake +46 -0
  99. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  100. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  101. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  102. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  103. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  104. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  105. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  106. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  107. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  108. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  109. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  110. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  111. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  112. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  113. package/numkong/include/README.md +643 -0
  114. package/numkong/include/module.modulemap +129 -0
  115. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  116. package/numkong/include/numkong/attention/sme.h +2075 -0
  117. package/numkong/include/numkong/attention.h +49 -0
  118. package/numkong/include/numkong/capabilities.h +930 -0
  119. package/numkong/include/numkong/cast/README.md +262 -0
  120. package/numkong/include/numkong/cast/diamond.h +64 -0
  121. package/numkong/include/numkong/cast/haswell.h +823 -0
  122. package/numkong/include/numkong/cast/icelake.h +475 -0
  123. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  124. package/numkong/include/numkong/cast/neon.h +1174 -0
  125. package/numkong/include/numkong/cast/powervsx.h +449 -0
  126. package/numkong/include/numkong/cast/rvv.h +970 -0
  127. package/numkong/include/numkong/cast/sapphire.h +262 -0
  128. package/numkong/include/numkong/cast/serial.h +2336 -0
  129. package/numkong/include/numkong/cast/skylake.h +915 -0
  130. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  131. package/numkong/include/numkong/cast.h +254 -0
  132. package/numkong/include/numkong/cast.hpp +44 -0
  133. package/numkong/include/numkong/curved/README.md +223 -0
  134. package/numkong/include/numkong/curved/genoa.h +182 -0
  135. package/numkong/include/numkong/curved/haswell.h +276 -0
  136. package/numkong/include/numkong/curved/neon.h +329 -0
  137. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  138. package/numkong/include/numkong/curved/rvv.h +305 -0
  139. package/numkong/include/numkong/curved/serial.h +207 -0
  140. package/numkong/include/numkong/curved/skylake.h +457 -0
  141. package/numkong/include/numkong/curved/smef64.h +530 -0
  142. package/numkong/include/numkong/curved.h +513 -0
  143. package/numkong/include/numkong/curved.hpp +144 -0
  144. package/numkong/include/numkong/dot/README.md +442 -0
  145. package/numkong/include/numkong/dot/alder.h +563 -0
  146. package/numkong/include/numkong/dot/diamond.h +158 -0
  147. package/numkong/include/numkong/dot/genoa.h +289 -0
  148. package/numkong/include/numkong/dot/haswell.h +1723 -0
  149. package/numkong/include/numkong/dot/icelake.h +997 -0
  150. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  151. package/numkong/include/numkong/dot/neon.h +869 -0
  152. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  153. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  154. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  155. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  156. package/numkong/include/numkong/dot/powervsx.h +752 -0
  157. package/numkong/include/numkong/dot/rvv.h +722 -0
  158. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  159. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  160. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  161. package/numkong/include/numkong/dot/sapphire.h +141 -0
  162. package/numkong/include/numkong/dot/serial.h +874 -0
  163. package/numkong/include/numkong/dot/sierra.h +405 -0
  164. package/numkong/include/numkong/dot/skylake.h +1116 -0
  165. package/numkong/include/numkong/dot/sve.h +420 -0
  166. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  167. package/numkong/include/numkong/dot/svehalf.h +168 -0
  168. package/numkong/include/numkong/dot/svesdot.h +90 -0
  169. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  170. package/numkong/include/numkong/dot.h +1136 -0
  171. package/numkong/include/numkong/dot.hpp +94 -0
  172. package/numkong/include/numkong/dots/README.md +496 -0
  173. package/numkong/include/numkong/dots/alder.h +117 -0
  174. package/numkong/include/numkong/dots/diamond.h +86 -0
  175. package/numkong/include/numkong/dots/genoa.h +100 -0
  176. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  177. package/numkong/include/numkong/dots/haswell.h +310 -0
  178. package/numkong/include/numkong/dots/icelake.h +180 -0
  179. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  180. package/numkong/include/numkong/dots/neon.h +123 -0
  181. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  182. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  183. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  184. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  185. package/numkong/include/numkong/dots/powervsx.h +194 -0
  186. package/numkong/include/numkong/dots/rvv.h +2593 -0
  187. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  188. package/numkong/include/numkong/dots/serial.h +2867 -0
  189. package/numkong/include/numkong/dots/sierra.h +100 -0
  190. package/numkong/include/numkong/dots/skylake.h +207 -0
  191. package/numkong/include/numkong/dots/sme.h +5041 -0
  192. package/numkong/include/numkong/dots/smebi32.h +477 -0
  193. package/numkong/include/numkong/dots/smef64.h +1328 -0
  194. package/numkong/include/numkong/dots/smehalf.h +47 -0
  195. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  196. package/numkong/include/numkong/dots.h +3110 -0
  197. package/numkong/include/numkong/dots.hpp +641 -0
  198. package/numkong/include/numkong/each/README.md +465 -0
  199. package/numkong/include/numkong/each/haswell.h +1658 -0
  200. package/numkong/include/numkong/each/icelake.h +272 -0
  201. package/numkong/include/numkong/each/neon.h +1138 -0
  202. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  203. package/numkong/include/numkong/each/neonhalf.h +318 -0
  204. package/numkong/include/numkong/each/rvv.h +1121 -0
  205. package/numkong/include/numkong/each/sapphire.h +343 -0
  206. package/numkong/include/numkong/each/serial.h +282 -0
  207. package/numkong/include/numkong/each/skylake.h +1562 -0
  208. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  209. package/numkong/include/numkong/each.h +2232 -0
  210. package/numkong/include/numkong/each.hpp +434 -0
  211. package/numkong/include/numkong/geospatial/README.md +147 -0
  212. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  213. package/numkong/include/numkong/geospatial/neon.h +615 -0
  214. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  215. package/numkong/include/numkong/geospatial/serial.h +309 -0
  216. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  217. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  218. package/numkong/include/numkong/geospatial.h +453 -0
  219. package/numkong/include/numkong/geospatial.hpp +235 -0
  220. package/numkong/include/numkong/matrix.hpp +336 -0
  221. package/numkong/include/numkong/maxsim/README.md +187 -0
  222. package/numkong/include/numkong/maxsim/alder.h +511 -0
  223. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  224. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  225. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  226. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  227. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  228. package/numkong/include/numkong/maxsim/serial.h +490 -0
  229. package/numkong/include/numkong/maxsim/sme.h +993 -0
  230. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  231. package/numkong/include/numkong/maxsim.h +571 -0
  232. package/numkong/include/numkong/maxsim.hpp +133 -0
  233. package/numkong/include/numkong/mesh/README.md +219 -0
  234. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  235. package/numkong/include/numkong/mesh/neon.h +1821 -0
  236. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  237. package/numkong/include/numkong/mesh/rvv.h +936 -0
  238. package/numkong/include/numkong/mesh/serial.h +721 -0
  239. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  240. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  241. package/numkong/include/numkong/mesh.h +666 -0
  242. package/numkong/include/numkong/mesh.hpp +701 -0
  243. package/numkong/include/numkong/numkong.h +78 -0
  244. package/numkong/include/numkong/numkong.hpp +58 -0
  245. package/numkong/include/numkong/probability/README.md +177 -0
  246. package/numkong/include/numkong/probability/haswell.h +267 -0
  247. package/numkong/include/numkong/probability/neon.h +255 -0
  248. package/numkong/include/numkong/probability/rvv.h +414 -0
  249. package/numkong/include/numkong/probability/serial.h +181 -0
  250. package/numkong/include/numkong/probability/skylake.h +324 -0
  251. package/numkong/include/numkong/probability.h +380 -0
  252. package/numkong/include/numkong/probability.hpp +120 -0
  253. package/numkong/include/numkong/random.h +50 -0
  254. package/numkong/include/numkong/random.hpp +285 -0
  255. package/numkong/include/numkong/reduce/README.md +552 -0
  256. package/numkong/include/numkong/reduce/alder.h +636 -0
  257. package/numkong/include/numkong/reduce/genoa.h +201 -0
  258. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  259. package/numkong/include/numkong/reduce/icelake.h +549 -0
  260. package/numkong/include/numkong/reduce/neon.h +3980 -0
  261. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  262. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  263. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  264. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  265. package/numkong/include/numkong/reduce/serial.h +753 -0
  266. package/numkong/include/numkong/reduce/sierra.h +338 -0
  267. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  268. package/numkong/include/numkong/reduce/sve.h +52 -0
  269. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  270. package/numkong/include/numkong/reduce.h +1582 -0
  271. package/numkong/include/numkong/reduce.hpp +778 -0
  272. package/numkong/include/numkong/scalar/README.md +89 -0
  273. package/numkong/include/numkong/scalar/haswell.h +122 -0
  274. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  275. package/numkong/include/numkong/scalar/neon.h +122 -0
  276. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  277. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  278. package/numkong/include/numkong/scalar/rvv.h +211 -0
  279. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  280. package/numkong/include/numkong/scalar/serial.h +332 -0
  281. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  282. package/numkong/include/numkong/scalar.h +696 -0
  283. package/numkong/include/numkong/set/README.md +179 -0
  284. package/numkong/include/numkong/set/haswell.h +334 -0
  285. package/numkong/include/numkong/set/icelake.h +485 -0
  286. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  287. package/numkong/include/numkong/set/neon.h +363 -0
  288. package/numkong/include/numkong/set/powervsx.h +326 -0
  289. package/numkong/include/numkong/set/rvv.h +226 -0
  290. package/numkong/include/numkong/set/rvvbb.h +117 -0
  291. package/numkong/include/numkong/set/serial.h +174 -0
  292. package/numkong/include/numkong/set/sve.h +187 -0
  293. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  294. package/numkong/include/numkong/set.h +471 -0
  295. package/numkong/include/numkong/set.hpp +114 -0
  296. package/numkong/include/numkong/sets/README.md +149 -0
  297. package/numkong/include/numkong/sets/haswell.h +63 -0
  298. package/numkong/include/numkong/sets/icelake.h +66 -0
  299. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  300. package/numkong/include/numkong/sets/neon.h +61 -0
  301. package/numkong/include/numkong/sets/powervsx.h +65 -0
  302. package/numkong/include/numkong/sets/serial.h +43 -0
  303. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  304. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  305. package/numkong/include/numkong/sets.h +382 -0
  306. package/numkong/include/numkong/sparse/README.md +156 -0
  307. package/numkong/include/numkong/sparse/icelake.h +463 -0
  308. package/numkong/include/numkong/sparse/neon.h +288 -0
  309. package/numkong/include/numkong/sparse/serial.h +117 -0
  310. package/numkong/include/numkong/sparse/sve2.h +504 -0
  311. package/numkong/include/numkong/sparse/turin.h +322 -0
  312. package/numkong/include/numkong/sparse.h +363 -0
  313. package/numkong/include/numkong/sparse.hpp +113 -0
  314. package/numkong/include/numkong/spatial/README.md +439 -0
  315. package/numkong/include/numkong/spatial/alder.h +604 -0
  316. package/numkong/include/numkong/spatial/diamond.h +240 -0
  317. package/numkong/include/numkong/spatial/genoa.h +222 -0
  318. package/numkong/include/numkong/spatial/haswell.h +979 -0
  319. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  320. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  321. package/numkong/include/numkong/spatial/neon.h +846 -0
  322. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  323. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  324. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  325. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  326. package/numkong/include/numkong/spatial/rvv.h +991 -0
  327. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  328. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  329. package/numkong/include/numkong/spatial/serial.h +347 -0
  330. package/numkong/include/numkong/spatial/sierra.h +516 -0
  331. package/numkong/include/numkong/spatial/skylake.h +605 -0
  332. package/numkong/include/numkong/spatial/sve.h +246 -0
  333. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  334. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  335. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  336. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  337. package/numkong/include/numkong/spatial.h +1681 -0
  338. package/numkong/include/numkong/spatial.hpp +183 -0
  339. package/numkong/include/numkong/spatials/README.md +580 -0
  340. package/numkong/include/numkong/spatials/alder.h +94 -0
  341. package/numkong/include/numkong/spatials/diamond.h +82 -0
  342. package/numkong/include/numkong/spatials/genoa.h +94 -0
  343. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  344. package/numkong/include/numkong/spatials/haswell.h +219 -0
  345. package/numkong/include/numkong/spatials/icelake.h +113 -0
  346. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  347. package/numkong/include/numkong/spatials/neon.h +109 -0
  348. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  349. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  350. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  351. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  352. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  353. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  354. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  355. package/numkong/include/numkong/spatials/serial.h +248 -0
  356. package/numkong/include/numkong/spatials/sierra.h +96 -0
  357. package/numkong/include/numkong/spatials/skylake.h +184 -0
  358. package/numkong/include/numkong/spatials/sme.h +1927 -0
  359. package/numkong/include/numkong/spatials/smef64.h +483 -0
  360. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  361. package/numkong/include/numkong/spatials.h +3374 -0
  362. package/numkong/include/numkong/spatials.hpp +509 -0
  363. package/numkong/include/numkong/tensor.hpp +1981 -0
  364. package/numkong/include/numkong/trigonometry/README.md +184 -0
  365. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  366. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  367. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  368. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  369. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  370. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  371. package/numkong/include/numkong/trigonometry.h +467 -0
  372. package/numkong/include/numkong/trigonometry.hpp +166 -0
  373. package/numkong/include/numkong/types.h +1695 -0
  374. package/numkong/include/numkong/types.hpp +6027 -0
  375. package/numkong/include/numkong/vector.hpp +766 -0
  376. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  377. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  378. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  380. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  381. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  382. package/numkong/javascript/README.md +254 -0
  383. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  384. package/numkong/javascript/numkong-browser.ts +40 -0
  385. package/numkong/javascript/numkong-wasm.ts +750 -0
  386. package/numkong/javascript/numkong.c +712 -0
  387. package/numkong/javascript/numkong.ts +613 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  389. package/numkong/javascript/tsconfig-cjs.json +13 -0
  390. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  391. package/numkong/javascript/types.ts +784 -0
  392. package/numkong/numkong.gypi +104 -0
  393. package/numkong/package.json +108 -0
  394. package/numkong/probes/arm_neon.c +8 -0
  395. package/numkong/probes/arm_neon_bfdot.c +9 -0
  396. package/numkong/probes/arm_neon_fhm.c +9 -0
  397. package/numkong/probes/arm_neon_half.c +8 -0
  398. package/numkong/probes/arm_neon_sdot.c +9 -0
  399. package/numkong/probes/arm_neonfp8.c +9 -0
  400. package/numkong/probes/arm_sme.c +16 -0
  401. package/numkong/probes/arm_sme2.c +16 -0
  402. package/numkong/probes/arm_sme2p1.c +16 -0
  403. package/numkong/probes/arm_sme_bf16.c +16 -0
  404. package/numkong/probes/arm_sme_bi32.c +16 -0
  405. package/numkong/probes/arm_sme_f64.c +16 -0
  406. package/numkong/probes/arm_sme_fa64.c +14 -0
  407. package/numkong/probes/arm_sme_half.c +16 -0
  408. package/numkong/probes/arm_sme_lut2.c +15 -0
  409. package/numkong/probes/arm_sve.c +18 -0
  410. package/numkong/probes/arm_sve2.c +20 -0
  411. package/numkong/probes/arm_sve2p1.c +18 -0
  412. package/numkong/probes/arm_sve_bfdot.c +20 -0
  413. package/numkong/probes/arm_sve_half.c +18 -0
  414. package/numkong/probes/arm_sve_sdot.c +21 -0
  415. package/numkong/probes/loongarch_lasx.c +12 -0
  416. package/numkong/probes/power_vsx.c +12 -0
  417. package/numkong/probes/probe.js +127 -0
  418. package/numkong/probes/riscv_rvv.c +14 -0
  419. package/numkong/probes/riscv_rvv_bb.c +15 -0
  420. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  421. package/numkong/probes/riscv_rvv_half.c +14 -0
  422. package/numkong/probes/wasm_v128relaxed.c +11 -0
  423. package/numkong/probes/x86_alder.c +17 -0
  424. package/numkong/probes/x86_diamond.c +17 -0
  425. package/numkong/probes/x86_genoa.c +17 -0
  426. package/numkong/probes/x86_graniteamx.c +19 -0
  427. package/numkong/probes/x86_haswell.c +11 -0
  428. package/numkong/probes/x86_icelake.c +17 -0
  429. package/numkong/probes/x86_sapphire.c +16 -0
  430. package/numkong/probes/x86_sapphireamx.c +18 -0
  431. package/numkong/probes/x86_sierra.c +17 -0
  432. package/numkong/probes/x86_skylake.c +15 -0
  433. package/numkong/probes/x86_turin.c +17 -0
  434. package/numkong/rust/README.md +698 -0
  435. package/numkong/rust/capabilities.rs +96 -0
  436. package/numkong/rust/cast.rs +314 -0
  437. package/numkong/rust/curved.rs +391 -0
  438. package/numkong/rust/each.rs +2721 -0
  439. package/numkong/rust/geospatial.rs +343 -0
  440. package/numkong/rust/matrix.rs +5424 -0
  441. package/numkong/rust/maxsim.rs +540 -0
  442. package/numkong/rust/mesh.rs +837 -0
  443. package/numkong/rust/numkong.rs +409 -0
  444. package/numkong/rust/probability.rs +272 -0
  445. package/numkong/rust/reduce.rs +1249 -0
  446. package/numkong/rust/set.rs +194 -0
  447. package/numkong/rust/sparse.rs +513 -0
  448. package/numkong/rust/spatial.rs +1815 -0
  449. package/numkong/rust/tensor.rs +7565 -0
  450. package/numkong/rust/types.rs +3666 -0
  451. package/numkong/rust/vector.rs +1899 -0
  452. package/numkong/rustfmt.toml +2 -0
  453. package/numkong/swift/Matrix.swift +1388 -0
  454. package/numkong/swift/MaxSim.swift +151 -0
  455. package/numkong/swift/NumKong.swift +283 -0
  456. package/numkong/swift/Numerics.swift +329 -0
  457. package/numkong/swift/README.md +433 -0
  458. package/numkong/swift/Scalar.swift +741 -0
  459. package/numkong/swift/Tensor.swift +209 -0
  460. package/numkong/test/README.md +315 -0
  461. package/numkong/test/playwright.config.ts +16 -0
  462. package/numkong/test/swift/Test.swift +534 -0
  463. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  464. package/numkong/test/test-browser-bundle.html +188 -0
  465. package/numkong/test/test-browser-runner.mjs +43 -0
  466. package/numkong/test/test-browser.html +305 -0
  467. package/numkong/test/test-dtypes.mjs +453 -0
  468. package/numkong/test/test-wasm.mjs +267 -0
  469. package/numkong/test/test.cpp +442 -0
  470. package/numkong/test/test.hpp +580 -0
  471. package/numkong/test/test.mjs +363 -0
  472. package/numkong/test/test_base.py +1041 -0
  473. package/numkong/test/test_cast.cpp +242 -0
  474. package/numkong/test/test_cross.hpp +551 -0
  475. package/numkong/test/test_cross.py +467 -0
  476. package/numkong/test/test_cross_amx.cpp +50 -0
  477. package/numkong/test/test_cross_arm.cpp +225 -0
  478. package/numkong/test/test_cross_blas.cpp +354 -0
  479. package/numkong/test/test_cross_loongarch.cpp +90 -0
  480. package/numkong/test/test_cross_power.cpp +73 -0
  481. package/numkong/test/test_cross_rvv.cpp +109 -0
  482. package/numkong/test/test_cross_serial.cpp +181 -0
  483. package/numkong/test/test_cross_sme.cpp +148 -0
  484. package/numkong/test/test_cross_wasm.cpp +141 -0
  485. package/numkong/test/test_cross_x86.cpp +442 -0
  486. package/numkong/test/test_curved.cpp +182 -0
  487. package/numkong/test/test_curved.py +207 -0
  488. package/numkong/test/test_dot.cpp +353 -0
  489. package/numkong/test/test_dot.py +296 -0
  490. package/numkong/test/test_each.cpp +437 -0
  491. package/numkong/test/test_each.py +756 -0
  492. package/numkong/test/test_geospatial.cpp +155 -0
  493. package/numkong/test/test_geospatial.py +241 -0
  494. package/numkong/test/test_maxsim.cpp +138 -0
  495. package/numkong/test/test_maxsim.py +209 -0
  496. package/numkong/test/test_mesh.cpp +203 -0
  497. package/numkong/test/test_mesh.py +394 -0
  498. package/numkong/test/test_probability.cpp +136 -0
  499. package/numkong/test/test_probability.py +166 -0
  500. package/numkong/test/test_reduce.cpp +563 -0
  501. package/numkong/test/test_reduce.py +781 -0
  502. package/numkong/test/test_set.cpp +151 -0
  503. package/numkong/test/test_set.py +120 -0
  504. package/numkong/test/test_similarities.py +579 -0
  505. package/numkong/test/test_sparse.cpp +121 -0
  506. package/numkong/test/test_sparse.py +118 -0
  507. package/numkong/test/test_spatial.cpp +518 -0
  508. package/numkong/test/test_spatial.py +269 -0
  509. package/numkong/test/test_tensor.cpp +884 -0
  510. package/numkong/test/test_tensor.py +1417 -0
  511. package/numkong/test/test_trigonometry.cpp +156 -0
  512. package/numkong/test/test_trigonometry.py +180 -0
  513. package/package.json +7 -8
  514. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  515. package/prebuilds/linux-arm64/usearch.node +0 -0
  516. package/prebuilds/linux-x64/usearch.node +0 -0
  517. package/fp16/CMakeLists.txt +0 -176
  518. package/fp16/LICENSE +0 -11
  519. package/fp16/README.md +0 -20
  520. package/fp16/bench/alt-element.cc +0 -89
  521. package/fp16/bench/from-alt-array.cc +0 -175
  522. package/fp16/bench/from-ieee-array.cc +0 -399
  523. package/fp16/bench/ieee-element.cc +0 -272
  524. package/fp16/bench/to-alt-array.cc +0 -91
  525. package/fp16/bench/to-ieee-array.cc +0 -303
  526. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  527. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  528. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  529. package/fp16/configure.py +0 -65
  530. package/fp16/confu.yaml +0 -8
  531. package/fp16/include/fp16/__init__.py +0 -0
  532. package/fp16/include/fp16/avx.py +0 -50
  533. package/fp16/include/fp16/avx2.py +0 -53
  534. package/fp16/include/fp16/bitcasts.h +0 -92
  535. package/fp16/include/fp16/fp16.h +0 -451
  536. package/fp16/include/fp16/psimd.h +0 -131
  537. package/fp16/include/fp16.h +0 -11
  538. package/fp16/jni/Android.mk +0 -6
  539. package/fp16/jni/Application.mk +0 -4
  540. package/fp16/test/alt-from-fp32-value.cc +0 -498
  541. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  542. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  543. package/fp16/test/alt-to-fp32-value.cc +0 -348
  544. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  545. package/fp16/test/bitcasts.cc +0 -56
  546. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  547. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  548. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  549. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  550. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  551. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  552. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  553. package/fp16/test/peachpy/stubs.py +0 -38
  554. package/fp16/test/tables.cc +0 -530
  555. package/fp16/test/tables.h +0 -13
  556. package/fp16/third-party/THHalf.h +0 -92
  557. package/fp16/third-party/eigen-half.h +0 -170
  558. package/fp16/third-party/float16-compressor.h +0 -80
  559. package/fp16/third-party/half.hpp +0 -2916
  560. package/fp16/third-party/npy-halffloat.h +0 -328
  561. package/simsimd/.git-blame-ignore-revs +0 -2
  562. package/simsimd/CONTRIBUTING.md +0 -321
  563. package/simsimd/Cargo.toml +0 -49
  564. package/simsimd/MANIFEST.in +0 -4
  565. package/simsimd/Package.swift +0 -28
  566. package/simsimd/README.md +0 -1493
  567. package/simsimd/binding.gyp +0 -35
  568. package/simsimd/build.rs +0 -70
  569. package/simsimd/c/lib.c +0 -374
  570. package/simsimd/include/module.modulemap +0 -4
  571. package/simsimd/include/simsimd/binary.h +0 -486
  572. package/simsimd/include/simsimd/curved.h +0 -1541
  573. package/simsimd/include/simsimd/dot.h +0 -1853
  574. package/simsimd/include/simsimd/elementwise.h +0 -2465
  575. package/simsimd/include/simsimd/geospatial.h +0 -43
  576. package/simsimd/include/simsimd/mesh.h +0 -69
  577. package/simsimd/include/simsimd/probability.h +0 -606
  578. package/simsimd/include/simsimd/simsimd.h +0 -2567
  579. package/simsimd/include/simsimd/sparse.h +0 -1384
  580. package/simsimd/include/simsimd/spatial.h +0 -2335
  581. package/simsimd/include/simsimd/types.h +0 -666
  582. package/simsimd/javascript/fallback.ts +0 -233
  583. package/simsimd/javascript/lib.c +0 -125
  584. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  585. package/simsimd/javascript/simsimd.ts +0 -179
  586. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  587. package/simsimd/package-lock.json +0 -1761
  588. package/simsimd/package.json +0 -61
  589. package/simsimd/rust/lib.rs +0 -1821
  590. package/simsimd/scripts/bench.cxx +0 -1170
  591. package/simsimd/scripts/bench.ipynb +0 -187
  592. package/simsimd/scripts/bench.js +0 -127
  593. package/simsimd/scripts/bench.rs +0 -876
  594. package/simsimd/scripts/bench_vectors.py +0 -734
  595. package/simsimd/scripts/bench_vectors_live.py +0 -213
  596. package/simsimd/scripts/test.c +0 -187
  597. package/simsimd/scripts/test.mjs +0 -220
  598. package/simsimd/scripts/test.py +0 -1505
  599. package/simsimd/swift/SimSIMD.swift +0 -149
  600. package/simsimd/swift/Test.swift +0 -128
  601. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  602. /package/{simsimd → numkong}/LICENSE +0 -0
  603. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  604. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,579 @@
1
+ #!/usr/bin/env python3
2
+ """Test pairwise cross-distances: nk.cdist for all metric families.
3
+
4
+ Dtypes: float64, float32, float16, bfloat16, int8, uint8, sub-byte floats.
5
+ Baselines: SciPy cdist.
6
+ Matches C++ suite: test_cross_*.cpp.
7
+ """
8
+
9
+ import atexit
10
+ from typing import TYPE_CHECKING
11
+
12
+ import pytest
13
+
14
+ if TYPE_CHECKING:
15
+ import numpy as np # static-analysis-only; the runtime try/except below is authoritative
16
+
17
+ try:
18
+ import numpy as np
19
+
20
+ numpy_available = True
21
+ except Exception:
22
+ numpy_available = False
23
+
24
+ try:
25
+ from scipy.stats import entropy as scipy_entropy
26
+ except ImportError:
27
+ scipy_entropy = None # type: ignore[assignment]
28
+
29
+ import numkong as nk
30
+ from test_base import (
31
+ NK_ATOL,
32
+ NK_RTOL,
33
+ PACKING_GRANULARITY,
34
+ assert_allclose,
35
+ create_stats,
36
+ dense_dimensions,
37
+ keep_one_capability,
38
+ make_random,
39
+ ml_dtypes_available,
40
+ nk_seed, # noqa: F401 — pytest fixture
41
+ numpy_available,
42
+ possible_capabilities,
43
+ print_stats_report,
44
+ randomized_repetitions_count,
45
+ round_up_to,
46
+ scipy_available,
47
+ scipy_metric_name,
48
+ seed_rng, # noqa: F401 — pytest fixture (autouse)
49
+ )
50
+
51
+ try:
52
+ import scipy.spatial.distance as spd
53
+ except ImportError:
54
+ spd = None # type: ignore[assignment]
55
+
56
+ try:
57
+ import ml_dtypes
58
+ except ImportError:
59
+ ml_dtypes = None # type: ignore[assignment]
60
+
61
+ stats = create_stats()
62
+ atexit.register(print_stats_report, stats)
63
+
64
+
65
+ def round_and_clip_even(values, out_dtype):
66
+ nk_dtype_conversion_info = np.iinfo(out_dtype)
67
+ finite_values = np.nan_to_num(
68
+ values, nan=0.0, posinf=float(nk_dtype_conversion_info.max), neginf=float(nk_dtype_conversion_info.min)
69
+ )
70
+ clipped_values = np.clip(finite_values, nk_dtype_conversion_info.min, nk_dtype_conversion_info.max)
71
+ return np.rint(clipped_values).astype(out_dtype)
72
+
73
+
74
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
75
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
76
+ @pytest.mark.parametrize("ndim", dense_dimensions)
77
+ @pytest.mark.parametrize("input_dtype", ["float64", "float32"])
78
+ @pytest.mark.parametrize("metric", ["dot", "angular", "euclidean"])
79
+ @pytest.mark.parametrize("capability", possible_capabilities)
80
+ def test_cdist_batch_metrics(ndim, input_dtype, metric, capability):
81
+ """Verify the SIMD batch dispatch for dot, angular, and euclidean.
82
+
83
+ Sets ``out_dtype`` equal to ``input_dtype`` (float64 or float32) so that the
84
+ kernel's native output type matches and the fast packed/symmetric batch path
85
+ is selected instead of the scalar pairwise fallback. Uses asymmetric matrix
86
+ sizes (7 x 11) to exercise the general rectangular case.
87
+
88
+ Dimensions are inherited from ``NK_DENSE_DIMENSIONS``; capabilities from
89
+ platform auto-detection via ``possible_capabilities``. Baseline for ``dot``
90
+ is ``np.dot`` (SciPy has no ``cdist`` metric for inner product); other
91
+ metrics use ``scipy.spatial.distance.cdist``.
92
+ """
93
+ keep_one_capability(capability)
94
+
95
+ num_rows_a, num_rows_b = 7, 11
96
+ a_matrix = np.random.randn(num_rows_a, ndim).astype(input_dtype)
97
+ b_matrix = np.random.randn(num_rows_b, ndim).astype(input_dtype)
98
+
99
+ # Use native out_dtype to force batch path (float64->float64, float32->float32)
100
+ out_dtype = input_dtype
101
+ scipy_metric = scipy_metric_name(metric)
102
+
103
+ if metric == "dot":
104
+ expected = np.array(
105
+ [[np.dot(a_matrix[i], b_matrix[j]) for j in range(num_rows_b)] for i in range(num_rows_a)]
106
+ ).astype(out_dtype)
107
+ else:
108
+ expected = spd.cdist(a_matrix, b_matrix, scipy_metric).astype(out_dtype)
109
+
110
+ result = nk.cdist(a_matrix, b_matrix, metric=metric, out_dtype=out_dtype)
111
+ assert_allclose(result, expected, atol=NK_ATOL, rtol=NK_RTOL)
112
+
113
+
114
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
115
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
116
+ @pytest.mark.parametrize("ndim", dense_dimensions)
117
+ @pytest.mark.parametrize("input_dtype", ["float64", "float32"])
118
+ @pytest.mark.parametrize("metric", ["dot", "angular", "euclidean", "sqeuclidean"])
119
+ def test_cdist_self_distance(ndim, input_dtype, metric):
120
+ """Verify ``cdist(A, A)`` produces a complete, correct symmetric matrix.
121
+
122
+ When both operands are the same object the C code takes a symmetric batch
123
+ shortcut that only computes the upper triangle. A post-kernel mirror loop
124
+ must fill the lower triangle. This test checks:
125
+
126
+ 1. Default ``out_dtype=float64`` (pairwise fallback on f32 input) — full
127
+ matrix against SciPy.
128
+ 2. Native ``out_dtype=input_dtype`` (forces batch symmetric path) — full
129
+ matrix, with an explicit lower-triangle mask assertion to catch missing
130
+ mirror writes.
131
+
132
+ No ``capability`` parameter: runs on whatever the default backend is (all
133
+ ISA-specific paths are already covered by ``test_cdist_batch_metrics``).
134
+ Dimensions from ``NK_DENSE_DIMENSIONS``.
135
+ """
136
+ a_matrix = np.random.randn(10, ndim).astype(input_dtype)
137
+
138
+ scipy_metric = scipy_metric_name(metric)
139
+ if metric == "dot":
140
+ expected = np.array([[np.dot(a_matrix[i], a_matrix[j]) for j in range(10)] for i in range(10)]).astype(
141
+ np.float64
142
+ )
143
+ else:
144
+ expected = spd.cdist(a_matrix, a_matrix, scipy_metric)
145
+
146
+ # Default out_dtype (f64) — may use pairwise fallback
147
+ result_default = np.asarray(nk.cdist(a_matrix, a_matrix, metric=metric))
148
+ assert_allclose(result_default, expected, atol=NK_ATOL, rtol=NK_RTOL)
149
+ # Check lower triangle explicitly
150
+ mask_lower = np.tril(np.ones((10, 10), dtype=bool), k=-1)
151
+ assert_allclose(result_default[mask_lower], expected[mask_lower], atol=NK_ATOL, rtol=NK_RTOL)
152
+
153
+ # Native out_dtype — should force batch symmetric path for f32
154
+ native_out_dtype = input_dtype
155
+ if metric == "dot":
156
+ expected_native = np.array([[np.dot(a_matrix[i], a_matrix[j]) for j in range(10)] for i in range(10)]).astype(
157
+ native_out_dtype
158
+ )
159
+ else:
160
+ expected_native = spd.cdist(a_matrix, a_matrix, scipy_metric).astype(native_out_dtype)
161
+ result_native = np.asarray(nk.cdist(a_matrix, a_matrix, metric=metric, out_dtype=native_out_dtype))
162
+ assert_allclose(result_native, expected_native, atol=NK_ATOL, rtol=NK_RTOL)
163
+ assert_allclose(result_native[mask_lower], expected_native[mask_lower], atol=NK_ATOL, rtol=NK_RTOL)
164
+
165
+
166
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
167
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
168
+ @pytest.mark.parametrize("ndim", dense_dimensions)
169
+ @pytest.mark.parametrize("input_dtype", ["float64", "float32", "float16"])
170
+ @pytest.mark.parametrize("out_dtype", [None, "float32", "int32"])
171
+ @pytest.mark.parametrize("metric", ["angular", "sqeuclidean", "euclidean", "dot"])
172
+ @pytest.mark.parametrize("capability", possible_capabilities)
173
+ def test_cdist_float_accuracy(ndim, input_dtype, out_dtype, metric, capability):
174
+ """Broad coverage of cdist for standard IEEE float inputs.
175
+
176
+ Exercises four metrics (angular, sqeuclidean, euclidean, dot) across three
177
+ input dtypes (float64, float32, float16) and three output modes (default
178
+ float64, explicit float32, explicit int32). Inputs are intentionally
179
+ *strided* — sliced from wider arrays — so the kernel must respect non-
180
+ contiguous memory layouts.
181
+
182
+ Additionally tests the ``out=`` buffer path: a strided slice of a wider
183
+ allocation is passed and checked for correct in-place writes.
184
+
185
+ Skips:
186
+ * ``angular`` at ndim=1 — degenerate (norm is a single element, 0/0).
187
+
188
+ Dimensions from ``NK_DENSE_DIMENSIONS``; capabilities from platform
189
+ auto-detection. Integer output uses ``atol=1`` (discrete rounding);
190
+ floats use ``NK_ATOL / NK_RTOL``.
191
+ """
192
+ if metric == "angular" and ndim == 1:
193
+ pytest.skip("angular at ndim=1 is degenerate (0/0 from single-element norms)")
194
+ keep_one_capability(capability)
195
+
196
+ num_rows_a, num_rows_b = 10, 15
197
+ a_matrix_extended = np.random.randn(num_rows_a, ndim + 1).astype(input_dtype)
198
+ b_matrix_extended = np.random.randn(num_rows_b, ndim + 3).astype(input_dtype)
199
+ a_matrix = a_matrix_extended[:, :ndim]
200
+ b_matrix = b_matrix_extended[:, :ndim]
201
+
202
+ is_integer_output = out_dtype in ("int32", "int64", "int16", "int8", "uint32", "uint64", "uint16", "uint8")
203
+ scipy_metric = scipy_metric_name(metric)
204
+
205
+ if metric == "dot":
206
+ baseline = np.array(
207
+ [
208
+ [np.dot(a_matrix[i].astype(np.float64), b_matrix[j].astype(np.float64)) for j in range(num_rows_b)]
209
+ for i in range(num_rows_a)
210
+ ]
211
+ )
212
+ else:
213
+ baseline = spd.cdist(a_matrix, b_matrix, scipy_metric)
214
+
215
+ if out_dtype is None:
216
+ expected = baseline
217
+ result = nk.cdist(a_matrix, b_matrix, metric)
218
+ else:
219
+ expected = round_and_clip_even(baseline, out_dtype) if is_integer_output else baseline.astype(out_dtype)
220
+ result = nk.cdist(a_matrix, b_matrix, metric, out_dtype=out_dtype)
221
+
222
+ atol = 1 if is_integer_output else NK_ATOL
223
+ assert_allclose(result, expected, atol=atol, rtol=NK_RTOL)
224
+
225
+ # Test out= buffer with strides
226
+ out_np_dtype = out_dtype if out_dtype else "float64"
227
+ output_buffer_extended = np.zeros((num_rows_a, num_rows_b + 7), dtype=out_np_dtype)
228
+ output_buffer = output_buffer_extended[:, :num_rows_b]
229
+ assert nk.cdist(a_matrix, b_matrix, metric, out=output_buffer) is None
230
+ assert_allclose(output_buffer, expected, atol=atol, rtol=NK_RTOL)
231
+
232
+
233
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
234
+ @pytest.mark.parametrize("ndim", dense_dimensions)
235
+ @pytest.mark.parametrize("input_dtype", ["complex128", "complex64"])
236
+ @pytest.mark.parametrize("out_dtype", [None, "complex128", "complex64"])
237
+ @pytest.mark.parametrize("metric", ["dot", "vdot"])
238
+ @pytest.mark.parametrize("capability", possible_capabilities)
239
+ def test_cdist_complex(ndim, input_dtype, out_dtype, metric, capability):
240
+ """Verify cdist for complex-valued dot and vdot metrics.
241
+
242
+ Tests three output modes (default complex128, explicit complex128,
243
+ explicit complex64) for both ``dot`` (Hermitian-unaware) and ``vdot``
244
+ (conjugate dot) metrics. Exercises:
245
+
246
+ * 1D scalar result (single row vs single row).
247
+ * 2D matrix result (10 x 15).
248
+ * ``out=`` buffer path with strided column slice.
249
+
250
+ Inputs are strided (sliced from wider allocations). Dimensions from
251
+ ``NK_DENSE_DIMENSIONS``; capabilities from platform auto-detection.
252
+ """
253
+ keep_one_capability(capability)
254
+
255
+ num_rows_a, num_rows_b = 10, 15
256
+ a_matrix_extended = np.random.randn(num_rows_a, ndim + 1).astype(input_dtype)
257
+ b_matrix_extended = np.random.randn(num_rows_b, ndim + 3).astype(input_dtype)
258
+ a_matrix = a_matrix_extended[:, :ndim]
259
+ b_matrix = b_matrix_extended[:, :ndim]
260
+ c_matrix_extended = np.random.randn(num_rows_a, num_rows_b + 7).astype(out_dtype if out_dtype else np.complex128)
261
+ c_matrix = c_matrix_extended[:, :num_rows_b]
262
+
263
+ expected = np.zeros((num_rows_a, num_rows_b), dtype=out_dtype if out_dtype else np.complex128)
264
+ baseline_kernel = np.dot if metric == "dot" else np.vdot
265
+ for i in range(num_rows_a):
266
+ for j in range(num_rows_b):
267
+ expected[i, j] = baseline_kernel(a_matrix[i], b_matrix[j])
268
+
269
+ if out_dtype is None:
270
+ result1d = nk.cdist(a_matrix[0], b_matrix[0], metric=metric)
271
+ result2d = nk.cdist(a_matrix, b_matrix, metric=metric)
272
+ assert nk.cdist(a_matrix, b_matrix, metric=metric, out=c_matrix) is None
273
+ else:
274
+ expected = expected.astype(out_dtype)
275
+ result1d = nk.cdist(a_matrix[0], b_matrix[0], metric=metric, out_dtype=out_dtype)
276
+ result2d = nk.cdist(a_matrix, b_matrix, metric=metric, out_dtype=out_dtype)
277
+ assert nk.cdist(a_matrix, b_matrix, metric=metric, out_dtype=out_dtype, out=c_matrix) is None
278
+
279
+ assert_allclose(result1d, expected[0, 0], atol=NK_ATOL, rtol=NK_RTOL)
280
+ assert_allclose(result2d, expected, atol=NK_ATOL, rtol=NK_RTOL)
281
+ assert_allclose(c_matrix, expected, atol=NK_ATOL, rtol=NK_RTOL)
282
+
283
+
284
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
285
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
286
+ @pytest.mark.repeat(randomized_repetitions_count)
287
+ @pytest.mark.parametrize("ndim", dense_dimensions)
288
+ @pytest.mark.parametrize("out_dtype", [None, "float32", "float16", "int8"])
289
+ @pytest.mark.parametrize("capability", possible_capabilities)
290
+ def test_cdist_hamming(ndim, out_dtype, capability):
291
+ """Verify cdist Hamming distance on packed bit vectors.
292
+
293
+ Generates random binary matrices, packs them via ``np.packbits``, and passes
294
+ ``dtype="uint1"`` so the kernel interprets each byte as 8 bits. Baseline is
295
+ ``scipy.spatial.distance.cdist(bits, bits, "hamming") * ndim`` — SciPy
296
+ normalises by dimension, so we undo that.
297
+
298
+ Output dtype coverage: default (float64), float32, float16, int8. Integer
299
+ output uses standard ``NK_ATOL / NK_RTOL`` (Hamming counts are exact for
300
+ integer types but may round for float16).
301
+
302
+ Randomised via ``@pytest.mark.repeat(randomized_repetitions_count)`` (env
303
+ ``NK_RANDOMIZED_REPETITIONS``, default 1). Dimensions from
304
+ ``NK_DENSE_DIMENSIONS``; capabilities from platform auto-detection.
305
+ """
306
+ keep_one_capability(capability)
307
+
308
+ num_rows_a, num_rows_b = 10, 15
309
+ a_bits = np.random.randint(2, size=(num_rows_a, ndim)).astype(np.uint8)
310
+ b_bits = np.random.randint(2, size=(num_rows_b, ndim)).astype(np.uint8)
311
+ a_packed_bits, b_packed_bits = np.packbits(a_bits, axis=1), np.packbits(b_bits, axis=1)
312
+
313
+ if out_dtype is None:
314
+ expected = spd.cdist(a_bits, b_bits, "hamming") * ndim
315
+ result = nk.cdist(a_packed_bits, b_packed_bits, metric="hamming", dtype="uint1")
316
+ else:
317
+ raw = spd.cdist(a_bits, b_bits, "hamming") * ndim
318
+ if np.issubdtype(np.dtype(out_dtype), np.integer):
319
+ expected = round_and_clip_even(raw, out_dtype)
320
+ else:
321
+ expected = raw.astype(out_dtype)
322
+ result = nk.cdist(a_packed_bits, b_packed_bits, metric="hamming", dtype="uint1", out_dtype=out_dtype)
323
+
324
+ assert_allclose(result, expected, atol=NK_ATOL, rtol=NK_RTOL)
325
+
326
+
327
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
328
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
329
+ @pytest.mark.repeat(randomized_repetitions_count)
330
+ @pytest.mark.parametrize("ndim", dense_dimensions)
331
+ @pytest.mark.parametrize("out_dtype", [None, "float32"])
332
+ @pytest.mark.parametrize("capability", possible_capabilities)
333
+ def test_cdist_jaccard(ndim, out_dtype, capability):
334
+ """Verify cdist Jaccard distance on packed bit vectors.
335
+
336
+ Same ``np.packbits`` + ``dtype="uint1"`` pattern as the Hamming test, but
337
+ with ``metric="jaccard"``. Baseline is ``scipy.spatial.distance.cdist``
338
+ with ``"jaccard"`` (already normalised — ratio of disagreeing bits to bits
339
+ where at least one is set).
340
+
341
+ Output dtype coverage: default (float64) and explicit float32.
342
+
343
+ Randomised via ``@pytest.mark.repeat``; dimensions from
344
+ ``NK_DENSE_DIMENSIONS``; capabilities from platform auto-detection.
345
+ """
346
+ keep_one_capability(capability)
347
+
348
+ num_rows_a, num_rows_b = 10, 15
349
+ a_bits = np.random.randint(2, size=(num_rows_a, ndim)).astype(np.uint8)
350
+ b_bits = np.random.randint(2, size=(num_rows_b, ndim)).astype(np.uint8)
351
+ a_packed_bits, b_packed_bits = np.packbits(a_bits, axis=1), np.packbits(b_bits, axis=1)
352
+
353
+ if out_dtype is None:
354
+ expected = spd.cdist(a_bits, b_bits, "jaccard")
355
+ result = nk.cdist(a_packed_bits, b_packed_bits, metric="jaccard", dtype="uint1")
356
+ else:
357
+ expected = spd.cdist(a_bits, b_bits, "jaccard").astype(out_dtype)
358
+ result = nk.cdist(a_packed_bits, b_packed_bits, metric="jaccard", dtype="uint1", out_dtype=out_dtype)
359
+
360
+ assert_allclose(result, expected, atol=NK_ATOL, rtol=NK_RTOL)
361
+
362
+
363
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
364
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
365
+ @pytest.mark.parametrize("ndim", dense_dimensions)
366
+ @pytest.mark.parametrize("input_dtype", ["float64", "float32"])
367
+ @pytest.mark.parametrize("metric", ["kld", "jsd"])
368
+ @pytest.mark.parametrize("capability", possible_capabilities)
369
+ def test_cdist_probability(ndim, input_dtype, metric, capability):
370
+ """Verify cdist for Kullback-Leibler divergence and Jensen-Shannon distance.
371
+
372
+ Inputs are positive probability vectors (softmax of randn + epsilon) using
373
+ asymmetric 7 x 11 matrix sizes.
374
+
375
+ Baselines:
376
+ * **KLD** — ``scipy_entropy(p, q)`` which computes
377
+ ``sum(p * ln(p/q))`` in natural log (nats), matching ``nk.kld``.
378
+ Note: KLD is asymmetric, so ``cdist(A, B)`` != ``cdist(B, A)``.
379
+ * **JSD** — ``scipy.spatial.distance.jensenshannon`` with default
380
+ ``base=e`` (natural log), returning ``sqrt(JS divergence)`` which
381
+ matches ``nk.jsd`` directly.
382
+
383
+ Only float64 and float32 input dtypes are supported. No ``out_dtype``
384
+ variants — probability divergences always produce float64 output.
385
+ Dimensions from ``NK_DENSE_DIMENSIONS``; capabilities from platform
386
+ auto-detection.
387
+ """
388
+ keep_one_capability(capability)
389
+
390
+ num_rows_a, num_rows_b = 7, 11
391
+ # Positive normalized vectors (softmax of randn)
392
+ a_raw = np.abs(np.random.randn(num_rows_a, ndim)).astype(input_dtype) + 1e-6
393
+ b_raw = np.abs(np.random.randn(num_rows_b, ndim)).astype(input_dtype) + 1e-6
394
+ a_matrix = (a_raw / a_raw.sum(axis=1, keepdims=True)).astype(input_dtype)
395
+ b_matrix = (b_raw / b_raw.sum(axis=1, keepdims=True)).astype(input_dtype)
396
+
397
+ if metric == "kld":
398
+ # scipy_entropy(p, q) = sum(p * ln(p/q)), natural log, matches nk.kld
399
+ expected = spd.cdist(
400
+ a_matrix.astype(np.float64),
401
+ b_matrix.astype(np.float64),
402
+ lambda u, v: scipy_entropy(u, v),
403
+ )
404
+ else:
405
+ # spd.jensenshannon defaults to base=e (natural log), returns sqrt(JS divergence)
406
+ expected = spd.cdist(a_matrix.astype(np.float64), b_matrix.astype(np.float64), "jensenshannon")
407
+
408
+ result = nk.cdist(a_matrix, b_matrix, metric=metric)
409
+ assert_allclose(result, expected, atol=NK_ATOL, rtol=NK_RTOL)
410
+
411
+
412
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
413
+ @pytest.mark.parametrize("ndim", dense_dimensions)
414
+ @pytest.mark.parametrize(
415
+ "input_dtype",
416
+ ["bfloat16", "e4m3", "e5m2", "e2m3", "e3m2", "int8", "uint8", "int4", "uint4"],
417
+ )
418
+ @pytest.mark.parametrize("metric", ["dot", "euclidean"])
419
+ def test_cdist_exotic_dtypes(ndim, input_dtype, metric):
420
+ """Verify cdist for sub-byte and non-standard types via pairwise fallback.
421
+
422
+ Covers bfloat16, e4m3, e5m2, e2m3, e3m2, int8, uint8, int4, and uint4 for
423
+ the ``dot`` and ``euclidean`` metrics. These dtypes have no batch-path
424
+ kernel, so cdist always falls back to the scalar pairwise loop with float64
425
+ output.
426
+
427
+ Baselines are computed from the float64 arrays returned by ``make_random``
428
+ (second return value), avoiding sub-byte row-indexing issues on
429
+ ``nk.Tensor``. Raw numpy byte-arrays are passed to cdist with an explicit
430
+ ``dtype=`` parameter so the C code knows how to interpret the data.
431
+
432
+ Sub-byte types (int4, uint4, uint1) have their ``ndim`` rounded up to
433
+ the packing alignment (2 for nibble types, 8 for bit types) so the
434
+ kernel sees a whole number of packed bytes per row.
435
+
436
+ No ``capability`` parameter — only the default backend is tested.
437
+ Dimensions from ``NK_DENSE_DIMENSIONS``.
438
+ """
439
+ ndim = round_up_to(ndim, PACKING_GRANULARITY.get(input_dtype, 1))
440
+
441
+ num_rows_a, num_rows_b = 5, 7
442
+ a_raw, a_baseline = make_random((num_rows_a, ndim), input_dtype)
443
+ b_raw, b_baseline = make_random((num_rows_b, ndim), input_dtype)
444
+
445
+ # Baseline: compute from float64 baseline arrays (avoids sub-byte row indexing issues)
446
+ if metric == "dot":
447
+ expected = a_baseline @ b_baseline.T
448
+ else:
449
+ expected = np.zeros((num_rows_a, num_rows_b), dtype=np.float64)
450
+ for i in range(num_rows_a):
451
+ for j in range(num_rows_b):
452
+ expected[i, j] = np.sqrt(np.sum((a_baseline[i] - b_baseline[j]) ** 2))
453
+
454
+ # Use raw numpy arrays with explicit dtype= for sub-byte/exotic types
455
+ cdist_kwargs = {"metric": metric, "dtype": input_dtype}
456
+
457
+ # Test with default out_dtype (f64, pairwise fallback)
458
+ result_f64 = nk.cdist(a_raw, b_raw, **cdist_kwargs)
459
+ assert_allclose(result_f64, expected, atol=NK_ATOL, rtol=NK_RTOL)
460
+
461
+
462
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
463
+ @pytest.mark.skipif(not scipy_available, reason="SciPy is not installed")
464
+ @pytest.mark.parametrize(
465
+ "m,n,k",
466
+ [(1, 1, 8), (1, 5, 16), (5, 1, 16), (1, 1, 1), (2, 3, 4096), (13, 17, 97)],
467
+ )
468
+ def test_cdist_shapes(m, n, k):
469
+ """Verify cdist output shape and correctness for diverse matrix geometries.
470
+
471
+ Uses a hardcoded list of ``(m, n, k)`` triples that exercise edge cases
472
+ the dimension-parameterised tests miss:
473
+
474
+ * ``(1, 1, 8)`` — minimal single-row × single-row.
475
+ * ``(1, 5, 16)`` and ``(5, 1, 16)`` — 1-row broadcasting in each direction.
476
+ * ``(1, 1, 1)`` — absolute minimum dimensions.
477
+ * ``(2, 3, 4096)`` — large vector depth (exercises SIMD tail handling).
478
+ * ``(13, 17, 97)`` — odd prime dimensions with no alignment.
479
+
480
+ Both ``euclidean`` (may use batch path) and ``sqeuclidean`` (pairwise only)
481
+ are tested on float32 input with default float64 output. Asserts both
482
+ correctness (against SciPy) and output shape ``(m, n)``.
483
+
484
+ Not parameterised by capability — shape handling is ISA-independent.
485
+ """
486
+ a_matrix = np.random.randn(m, k).astype(np.float32)
487
+ b_matrix = np.random.randn(n, k).astype(np.float32)
488
+
489
+ # euclidean (may use batch path)
490
+ expected_euc = spd.cdist(a_matrix, b_matrix, "euclidean")
491
+ result_euc = nk.cdist(a_matrix, b_matrix, "euclidean")
492
+ assert result_euc.shape == (m, n), f"Expected shape ({m}, {n}), got {result_euc.shape}"
493
+ assert_allclose(result_euc, expected_euc, atol=NK_ATOL, rtol=NK_RTOL)
494
+
495
+ # sqeuclidean (pairwise)
496
+ expected_sqeuc = spd.cdist(a_matrix, b_matrix, "sqeuclidean")
497
+ result_sqeuc = nk.cdist(a_matrix, b_matrix, "sqeuclidean")
498
+ assert result_sqeuc.shape == (m, n), f"Expected shape ({m}, {n}), got {result_sqeuc.shape}"
499
+ assert_allclose(result_sqeuc, expected_sqeuc, atol=NK_ATOL, rtol=NK_RTOL)
500
+
501
+
502
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
503
+ @pytest.mark.parametrize("m", [31, 64, 129])
504
+ def test_cdist_threads(m):
505
+ """Verify OpenMP-parallel cdist matches the serial path across tile boundaries.
506
+
507
+ Exercises both the symmetric batch path (A vs A) and the packed batch path
508
+ (A vs B). Packed tile is 64, symmetric tile is 32, so ``m`` values are
509
+ chosen to straddle one and two tiles.
510
+ """
511
+ k = 32
512
+ a_matrix = np.random.randn(m, k).astype(np.float32)
513
+ b_matrix = np.random.randn(m, k).astype(np.float32)
514
+
515
+ # Symmetric batch path
516
+ serial_symmetric = nk.cdist(a_matrix, a_matrix, "sqeuclidean", threads=1)
517
+ parallel_symmetric = nk.cdist(a_matrix, a_matrix, "sqeuclidean", threads=4)
518
+ assert_allclose(parallel_symmetric, serial_symmetric, atol=NK_ATOL, rtol=NK_RTOL)
519
+
520
+ # Packed batch path
521
+ serial_packed = nk.cdist(a_matrix, b_matrix, "euclidean", threads=1)
522
+ parallel_packed = nk.cdist(a_matrix, b_matrix, "euclidean", threads=4)
523
+ assert_allclose(parallel_packed, serial_packed, atol=NK_ATOL, rtol=NK_RTOL)
524
+
525
+
526
+ def test_cdist_edge_cases(nk_seed):
527
+ """Verify cdist edge cases: scalar return, error handling, and kwarg validation.
528
+
529
+ Covers four categories:
530
+
531
+ 1. **Scalar return** — passing two 1D vectors ``(D,)`` must return a scalar
532
+ float, not a ``(1, 1)`` matrix.
533
+ 2. **Accepted kwargs** — ``threads=`` controls OpenMP parallelism and must
534
+ produce results identical to the single-threaded path.
535
+ 3. **Rejected kwargs** — unknown keywords must raise ``TypeError`` with
536
+ "unexpected keyword" so callers get a clear error.
537
+ 4. **Input validation** — mismatched dimensions and empty matrices must
538
+ raise ``ValueError``.
539
+
540
+ Not parameterised — uses fixed 16-element vectors on float32.
541
+ """
542
+ ndim = 16
543
+ a_vec = nk.hash((ndim,), seed=nk_seed, dtype="float32")
544
+ b_vec = nk.hash((ndim,), seed=nk_seed + 1, dtype="float32")
545
+
546
+ # 1D vectors → scalar float return, not matrix
547
+ result = nk.cdist(a_vec, b_vec, "euclidean")
548
+ assert isinstance(result, (int, float)), f"Expected scalar for 1D inputs, got {type(result)}"
549
+
550
+ # threads= is accepted and must match the single-threaded result
551
+ a_matrix = nk.ones((4, ndim), dtype="float32")
552
+ b_matrix = nk.ones((4, ndim), dtype="float32")
553
+ result_serial = nk.cdist(a_matrix, b_matrix, "euclidean", threads=1)
554
+ result_parallel = nk.cdist(a_matrix, b_matrix, "euclidean", threads=2)
555
+ assert_allclose(result_serial, result_parallel, atol=NK_ATOL, rtol=NK_RTOL)
556
+
557
+ # Unknown kwargs are rejected
558
+ with pytest.raises(TypeError, match="unexpected keyword"):
559
+ nk.cdist(a_matrix, b_matrix, not_a_real_kwarg=2)
560
+
561
+ # Mismatched dimensions → ValueError
562
+ with pytest.raises(ValueError):
563
+ nk.cdist(nk.ones((2, 3), dtype="float32"), nk.ones((2, 5), dtype="float32"), "euclidean")
564
+
565
+ # Empty matrix → ValueError
566
+ with pytest.raises(ValueError):
567
+ nk.cdist(nk.ones((0, 3), dtype="float32"), nk.ones((2, 3), dtype="float32"), "euclidean")
568
+
569
+
570
+ @pytest.mark.skipif(not numpy_available, reason="NumPy is not installed")
571
+ @pytest.mark.skipif(not ml_dtypes_available, reason="ml_dtypes not installed")
572
+ @pytest.mark.parametrize("ml_dtype", ["bfloat16", "float8_e4m3fn", "float8_e5m2", "float6_e2m3fn", "float6_e3m2fn"])
573
+ def test_cdist_with_ml_dtypes(ml_dtype):
574
+ """Verify cdist accepts ml_dtypes arrays via __array_interface__ fallback."""
575
+ dt = getattr(ml_dtypes, ml_dtype)
576
+ a = np.random.randn(4, 8).astype(np.float32).clip(-1, 1).astype(dt)
577
+ b = np.random.randn(4, 8).astype(np.float32).clip(-1, 1).astype(dt)
578
+ result = nk.cdist(a, b, "dot")
579
+ assert result.shape == (4, 4)