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
@@ -1,734 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- Module: bench.py
5
-
6
- This script benchmarks the performance of SimSIMD against other libraries,
7
- such as NumPy, SciPy, scikit-learn, PyTorch, TensorFlow, and JAX.
8
- It can operate in 2 modes:
9
-
10
- 1. Batch mode
11
- 2. All-Pairs mode.
12
-
13
- It also provides necessary primitives for performance visualizations and
14
- other benchmarking scripts, like `bench_vectors_live.py`.
15
- """
16
- import os
17
- import time
18
- import argparse
19
- from typing import List, Generator, Union
20
- from dataclasses import dataclass
21
-
22
-
23
- #! Before all else, ensure that we use only one thread for each library
24
- os.environ["OMP_NUM_THREADS"] = "1" # OpenMP
25
- os.environ["MKL_NUM_THREADS"] = "1" # MKL
26
- os.environ["NUMEXPR_NUM_THREADS"] = "1" # NumExpr
27
- os.environ["VECLIB_MAXIMUM_THREADS"] = "1" # Accelerate
28
- os.environ["OPENBLAS_NUM_THREADS"] = "1" # OpenBLAS
29
-
30
- # NumPy and SimSIMD are obligatory for benchmarking
31
- import numpy as np
32
- import simsimd as simd
33
- import tabulate
34
-
35
- # Set to ignore all floating-point errors
36
- np.seterr(all="ignore")
37
-
38
-
39
- metric_families = [
40
- "dot", # Dot product
41
- "spatial", # Euclidean and Cosine distance
42
- "binary", # Hamming and Jaccard distance for binary vectors
43
- "probability", # Jensen-Shannon and Kullback-Leibler divergences for probability distributions
44
- "sparse", # Intersection of two sparse integer sets, with float/int weights
45
- ]
46
- dtype_names = [
47
- "bin8", #! Not supported by SciPy
48
- "int8", #! Presented as supported, but overflows most of the time
49
- "uint16",
50
- "uint32",
51
- "float16",
52
- "float32",
53
- "float64",
54
- "bfloat16", #! Not supported by NumPy
55
- "complex32", #! Not supported by NumPy
56
- "complex64",
57
- "complex128",
58
- ]
59
-
60
-
61
- @dataclass
62
- class Kernel:
63
- """Data class to store information about a numeric kernel."""
64
-
65
- name: str
66
- dtype: str
67
- baseline_one_to_one_func: callable
68
- baseline_many_to_many_func: callable
69
- baseline_all_pairs_func: callable
70
- simsimd_func: callable
71
- simsimd_all_pairs_func: callable
72
- tensor_type: callable = np.array
73
-
74
-
75
- def serial_cosine(a: List[float], b: List[float]) -> float:
76
- dot_product = sum(ai * bi for ai, bi in zip(a, b))
77
- norm_a = sum(ai * ai for ai in a) ** 0.5
78
- norm_b = sum(bi * bi for bi in b) ** 0.5
79
- if norm_a == 0 and norm_b == 0:
80
- return 1
81
- if dot_product == 0:
82
- return 0
83
- return dot_product / (norm_a * norm_b)
84
-
85
-
86
- def serial_sqeuclidean(a: List[float], b: List[float]) -> float:
87
- return sum((ai - bi) ** 2 for ai, bi in zip(a, b))
88
-
89
-
90
- def yield_kernels(
91
- metric_families: List[str],
92
- dtype_names: List[str],
93
- include_scipy: bool = False,
94
- include_scikit: bool = False,
95
- include_torch: bool = False,
96
- include_tf: bool = False,
97
- include_jax: bool = False,
98
- ) -> Generator[Kernel, None, None]:
99
- """Yield a list of kernels to latency."""
100
-
101
- if include_scipy:
102
- import scipy as sp
103
- import scipy.spatial.distance as spd
104
- import scipy.special as scs
105
-
106
- if include_scikit:
107
- import sklearn as sk
108
- import sklearn.metrics.pairwise as skp
109
-
110
- if include_torch:
111
- import torch
112
- if include_tf:
113
- # Disable TensorFlow warning messages
114
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" # This hides INFO and WARNING messages
115
-
116
- import tensorflow as tf
117
-
118
- # This will show only ERROR messages, not WARNING messages.
119
- # Additionally, to filter out oneDNN related warnings, you might need to:
120
- tf.get_logger().setLevel("FATAL")
121
-
122
- if include_jax:
123
- import jax
124
- import jax.numpy as jnp
125
-
126
- # Define a few helper functions to wrap non-vectorized kernels
127
- def wrap_rows_batch_calls(baseline_one_to_one_func):
128
- """Wrap a function to apply it row-wise to rows of two matrices.
129
- It's needed as SciPy functions don't support batch processing out of the box."""
130
-
131
- def wrapped(A, B):
132
- for i in range(A.shape[0]):
133
- baseline_one_to_one_func(A[i], B[i])
134
-
135
- return wrapped
136
-
137
- def wrap_rows_all_pairs_calls(baseline_one_to_one_func):
138
- """Wrap a function to apply it row-wise to all possible pairs of rows of two matrices.
139
- It's needed as NumPy `vdot`-like functions don't support batch processing out of the box."""
140
-
141
- def wrapped(A, B):
142
- for i in range(A.shape[0]):
143
- for j in range(B.shape[0]):
144
- baseline_one_to_one_func(A[i], B[j])
145
-
146
- return wrapped
147
-
148
- def raise_(ex):
149
- """Utility function to allow raising exceptions in lambda functions."""
150
- raise ex
151
-
152
- def for_dtypes(
153
- name: str,
154
- dtypes: List[str],
155
- baseline_one_to_one_func: callable,
156
- baseline_many_to_many_func: callable,
157
- baseline_all_pairs_func: callable,
158
- simsimd_func: callable,
159
- simsimd_all_pairs_func: callable,
160
- tensor_type: callable = np.array,
161
- ) -> list:
162
- """Filter out unsupported data types."""
163
- return [
164
- Kernel(
165
- name=name,
166
- baseline_one_to_one_func=baseline_one_to_one_func,
167
- baseline_many_to_many_func=baseline_many_to_many_func,
168
- baseline_all_pairs_func=baseline_all_pairs_func,
169
- simsimd_func=simsimd_func,
170
- simsimd_all_pairs_func=simsimd_all_pairs_func,
171
- tensor_type=tensor_type,
172
- dtype=dtype,
173
- )
174
- for dtype in dtypes
175
- if dtype in dtype_names
176
- ]
177
-
178
- if "dot" in metric_families:
179
- yield from for_dtypes(
180
- "numpy.dot",
181
- ["float64", "float32", "float16", "int8", "complex64", "complex128"],
182
- np.dot,
183
- lambda A, B: np.sum(A * B, axis=1),
184
- lambda A, B: np.dot(A, B.T),
185
- simd.dot,
186
- lambda A, B: simd.cdist(A, B, metric="dot"),
187
- )
188
- yield from for_dtypes(
189
- "numpy.dot",
190
- ["complex32"],
191
- lambda A, B: raise_(NotImplementedError("Not implemented for complex32")),
192
- lambda A, B: raise_(NotImplementedError("Not implemented for complex32")),
193
- lambda A, B: raise_(NotImplementedError("Not implemented for complex32")),
194
- lambda A, B: simd.dot(A, B, "complex32"),
195
- lambda A, B: simd.cdist(A, B, "complex32", metric="dot"),
196
- )
197
- yield from for_dtypes(
198
- "numpy.dot",
199
- ["bfloat16"],
200
- lambda A, B: raise_(NotImplementedError("Not implemented for bfloat16")),
201
- lambda A, B: raise_(NotImplementedError("Not implemented for bfloat16")),
202
- lambda A, B: raise_(NotImplementedError("Not implemented for bfloat16")),
203
- lambda A, B: simd.dot(A, B, "bfloat16"),
204
- lambda A, B: simd.cdist(A, B, "bfloat16", metric="dot"),
205
- )
206
- yield from for_dtypes(
207
- "numpy.vdot",
208
- ["complex64", "complex128"],
209
- np.vdot,
210
- wrap_rows_batch_calls(np.vdot),
211
- wrap_rows_all_pairs_calls(np.vdot),
212
- simd.vdot,
213
- lambda A, B: simd.cdist(A, B, metric="vdot"),
214
- )
215
- if "spatial" in metric_families:
216
- yield from for_dtypes(
217
- "serial.cosine",
218
- ["float64", "float32", "float16", "int8"],
219
- serial_cosine,
220
- wrap_rows_batch_calls(serial_cosine),
221
- lambda A, B: spd.cdist(A, B, "cosine"),
222
- simd.cosine,
223
- lambda A, B: simd.cdist(A, B, metric="cosine"),
224
- )
225
- yield from for_dtypes(
226
- "serial.sqeuclidean",
227
- ["float64", "float32", "float16", "int8"],
228
- serial_sqeuclidean,
229
- wrap_rows_batch_calls(serial_sqeuclidean),
230
- lambda A, B: spd.cdist(A, B, "sqeuclidean"),
231
- simd.sqeuclidean,
232
- lambda A, B: simd.cdist(A, B, metric="sqeuclidean"),
233
- )
234
- if "spatial" in metric_families and include_scipy:
235
- yield from for_dtypes(
236
- "scipy.cosine",
237
- ["float64", "float32", "float16", "int8"],
238
- spd.cosine,
239
- wrap_rows_batch_calls(spd.cosine),
240
- lambda A, B: spd.cdist(A, B, "cosine"),
241
- simd.cosine,
242
- lambda A, B: simd.cdist(A, B, metric="cosine"),
243
- )
244
- yield from for_dtypes(
245
- "scipy.cosine",
246
- ["bfloat16"],
247
- lambda A, B: raise_(NotImplementedError(f"Not implemented for bfloat16")),
248
- lambda A, B: raise_(NotImplementedError(f"Not implemented for bfloat16")),
249
- lambda A, B: raise_(NotImplementedError(f"Not implemented for bfloat16")),
250
- lambda A, B: simd.cosine(A, B, "bfloat16"),
251
- lambda A, B: simd.cdist(A, B, "bfloat16", metric="cosine"),
252
- )
253
- yield from for_dtypes(
254
- "scipy.sqeuclidean",
255
- ["float64", "float32", "float16", "int8"],
256
- spd.sqeuclidean,
257
- wrap_rows_batch_calls(spd.sqeuclidean),
258
- lambda A, B: spd.cdist(A, B, "sqeuclidean"),
259
- simd.sqeuclidean,
260
- lambda A, B: simd.cdist(A, B, metric="sqeuclidean"),
261
- )
262
-
263
- if "probability" in metric_families and include_scipy:
264
- yield from for_dtypes(
265
- "scipy.jensenshannon",
266
- ["float64", "float32", "float16"],
267
- spd.jensenshannon,
268
- wrap_rows_batch_calls(spd.jensenshannon),
269
- lambda A, B: spd.cdist(A, B, "jensenshannon"),
270
- simd.jensenshannon,
271
- lambda A, B: simd.cdist(A, B, metric="jensenshannon"),
272
- )
273
- yield from for_dtypes(
274
- "scipy.kl_div",
275
- ["float64", "float32", "float16"],
276
- scs.kl_div,
277
- wrap_rows_batch_calls(scs.kl_div),
278
- wrap_rows_all_pairs_calls(scs.kl_div),
279
- simd.kullbackleibler,
280
- lambda A, B: simd.cdist(A, B, metric="kullbackleibler"),
281
- )
282
- if "binary" in metric_families and include_scipy:
283
- yield from for_dtypes(
284
- "scipy.hamming",
285
- ["bin8"],
286
- spd.hamming,
287
- wrap_rows_batch_calls(spd.hamming),
288
- lambda A, B: spd.cdist(A, B, "hamming"),
289
- lambda A, B: simd.hamming(A, B, "bin8"),
290
- lambda A, B: simd.cdist(A, B, "bin8", metric="hamming"),
291
- )
292
- yield from for_dtypes(
293
- "scipy.jaccard",
294
- ["bin8"],
295
- spd.jaccard,
296
- wrap_rows_batch_calls(spd.jaccard),
297
- lambda A, B: spd.cdist(A, B, "jaccard"),
298
- lambda A, B: simd.jaccard(A, B, "bin8"),
299
- lambda A, B: simd.cdist(A, B, "bin8", metric="jaccard"),
300
- )
301
- if "spatial" in metric_families and include_scikit:
302
- yield from for_dtypes(
303
- "sklearn.cosine_similarity",
304
- ["float64", "float32", "float16", "int8"],
305
- lambda A, B: skp.cosine_similarity(A.reshape(1, len(A)), B.reshape(1, len(B))),
306
- lambda A, B: raise_(NotImplementedError("Not implemented for many-to-many")),
307
- skp.paired_cosine_distances,
308
- simd.cosine,
309
- lambda A, B: simd.cdist(A, B, metric="cosine"),
310
- )
311
- yield from for_dtypes(
312
- "sklearn.euclidean_distances",
313
- ["float64", "float32", "float16", "int8"],
314
- lambda A, B: skp.euclidean_distances(A.reshape(1, len(A)), B.reshape(1, len(B))),
315
- lambda A, B: raise_(NotImplementedError("Not implemented for many-to-many")),
316
- skp.paired_euclidean_distances,
317
- simd.sqeuclidean,
318
- lambda A, B: simd.cdist(A, B, metric="sqeuclidean"),
319
- )
320
- if "dot" in metric_families and include_tf:
321
- yield from for_dtypes(
322
- "tensorflow.tensordot",
323
- ["float64", "float32", "float16", "int8"],
324
- lambda A, B: tf.tensordot(A, B, axes=1).numpy(),
325
- lambda A, B: tf.reduce_sum(tf.multiply(A, B), axis=1).numpy(),
326
- lambda A, B: tf.tensordot(A, B.T, axes=1).numpy(),
327
- simd.dot,
328
- lambda A, B: simd.cdist(A, B, metric="dot"),
329
- tf.convert_to_tensor,
330
- )
331
- if "dot" in metric_families and include_jax:
332
- yield from for_dtypes(
333
- "jax.numpy.dot",
334
- ["float64", "float32", "float16", "int8"],
335
- lambda A, B: jnp.dot(A, B).block_until_ready(),
336
- lambda A, B: jnp.einsum("ij,ij->i", A, B).block_until_ready(),
337
- lambda A, B: jnp.dot(A, B.T).block_until_ready(),
338
- simd.dot,
339
- lambda A, B: simd.cdist(A, B, metric="dot"),
340
- jnp.array,
341
- )
342
- if "dot" in metric_families and include_torch:
343
- yield from for_dtypes(
344
- "torch.dot",
345
- ["float64", "float32", "float16", "int8"],
346
- lambda A, B: torch.dot(A, B).item(),
347
- lambda A, B: torch.bmm(A.unsqueeze(1), B.unsqueeze(2)).squeeze(),
348
- lambda A, B: torch.dot(A, B.T).item(),
349
- simd.dot,
350
- lambda A, B: simd.cdist(A, B, metric="dot"),
351
- torch.tensor,
352
- )
353
-
354
-
355
- @dataclass
356
- class Result:
357
- dtype: str
358
- name: str
359
- baseline_seconds: Union[float, Exception]
360
- simsimd_seconds: Union[float, Exception]
361
- bytes_per_vector: int
362
- distance_calculations: int
363
-
364
-
365
- def random_matrix(count: int, ndim: int, dtype: str) -> np.ndarray:
366
- if dtype == "complex128":
367
- return (
368
- np.random.randn(count, ndim // 2).astype(np.float64)
369
- + 1j * np.random.randn(count, ndim // 2).astype(np.float64)
370
- ).view(np.complex128)
371
- if dtype == "complex64":
372
- return (
373
- np.random.randn(count, ndim // 2).astype(np.float32)
374
- + 1j * np.random.randn(count, ndim // 2).astype(np.float32)
375
- ).view(np.complex64)
376
- if dtype == "complex32":
377
- return np.random.randn(count, ndim).astype(np.float16)
378
- if dtype == "float64":
379
- return np.random.randn(count, ndim).astype(np.float64)
380
- if dtype == "float32":
381
- return np.random.randn(count, ndim).astype(np.float32)
382
- if dtype == "float16":
383
- return np.random.randn(count, ndim).astype(np.float16)
384
- if dtype == "bfloat16":
385
- return np.random.randint(0, high=256, size=(count, ndim), dtype=np.int16)
386
- if dtype == "int8":
387
- return np.random.randint(-100, high=100, size=(count, ndim), dtype=np.int8)
388
- if dtype == "bin8":
389
- return np.packbits(np.random.randint(0, high=2, size=(count, ndim), dtype=np.uint8), axis=0)
390
-
391
-
392
- def latency(func, A, B, iterations: int = 1, warmup: int = 0) -> float:
393
- """Time the amount of time it takes to run a function and return the average time per run in seconds."""
394
- while warmup > 0:
395
- func(A, B)
396
- warmup -= 1
397
- start_time = time.time_ns()
398
- while iterations > 0:
399
- func(A, B)
400
- iterations -= 1
401
- end_time = time.time_ns()
402
- return (end_time - start_time) / 1e9
403
-
404
-
405
- def yield_batch_results(
406
- count_vectors_per_matrix: int,
407
- ndim: int,
408
- kernels: List[Kernel],
409
- warmup: int = 0,
410
- ) -> Generator[Result, None, None]:
411
- # For each of the present data types, we may want to pre-generate several random matrices
412
- count_matrices_per_dtype = 16
413
- count_repetitions_per_matrix = 3 # This helps dampen the effect of time-measurement itself
414
- matrices_per_dtype = {}
415
- for kernel in kernels:
416
- if kernel.dtype in matrices_per_dtype:
417
- continue
418
- matrices = [
419
- random_matrix(count_vectors_per_matrix, ndim, kernel.dtype) for _ in range(count_matrices_per_dtype)
420
- ]
421
- if count_vectors_per_matrix == 1:
422
- matrices = [m.flatten() for m in matrices]
423
- matrices_per_dtype[kernel.dtype] = matrices
424
-
425
- # For each kernel, repeat benchmarks for each data type
426
- for kernel in kernels:
427
- matrices_numpy = matrices_per_dtype[kernel.dtype]
428
- matrices_converted = [kernel.tensor_type(m) for m in matrices_numpy]
429
- baseline_one_to_one_func = (
430
- kernel.baseline_one_to_one_func if count_vectors_per_matrix == 1 else kernel.baseline_many_to_many_func
431
- )
432
- simsimd_func = kernel.simsimd_func
433
- result = Result(
434
- kernel.dtype,
435
- kernel.name,
436
- baseline_seconds=0,
437
- simsimd_seconds=0,
438
- bytes_per_vector=matrices_numpy[0].nbytes // count_vectors_per_matrix,
439
- distance_calculations=count_vectors_per_matrix * count_matrices_per_dtype * count_repetitions_per_matrix,
440
- )
441
-
442
- # Try obtaining the baseline measurements
443
- try:
444
- for i in range(1, count_matrices_per_dtype):
445
- result.baseline_seconds += latency(
446
- baseline_one_to_one_func,
447
- matrices_converted[i - 1],
448
- matrices_converted[i],
449
- count_repetitions_per_matrix,
450
- warmup,
451
- )
452
- except NotImplementedError as e:
453
- result.baseline_seconds = e
454
- except ValueError as e:
455
- result.baseline_seconds = e #! This happens often during overflows
456
- except RuntimeError as e:
457
- result.baseline_seconds = e #! This happens often during overflows
458
- except Exception as e:
459
- # This is an unexpected exception... once you face it, please report it
460
- raise RuntimeError(str(e) + " for %s(%s)" % (kernel.name, str(kernel.dtype))) from e
461
-
462
- # Try obtaining the SimSIMD measurements
463
- try:
464
- for i in range(1, count_matrices_per_dtype):
465
- result.simsimd_seconds += latency(
466
- simsimd_func,
467
- matrices_numpy[i - 1],
468
- matrices_numpy[i],
469
- count_repetitions_per_matrix,
470
- warmup,
471
- )
472
- except NotImplementedError as e:
473
- result.simsimd_seconds = e
474
- except Exception as e:
475
- # This is an unexpected exception... once you face it, please report it
476
- raise RuntimeError(str(e) + " for %s(%s)" % (kernel.name, str(kernel.dtype))) from e
477
-
478
- yield result
479
-
480
-
481
- def yield_all_pairs_results(
482
- count_vectors_per_matrix: int,
483
- ndim: int,
484
- kernels: List[Kernel],
485
- warmup: int = 0,
486
- ) -> Generator[Result, None, None]:
487
- # For each of the present data types, we may want to pre-generate several random matrices
488
- count_matrices_per_dtype = 16
489
- count_repetitions_per_matrix = 3 # This helps dampen the effect of time-measurement itself
490
- matrices_per_dtype = {}
491
- for kernel in kernels:
492
- if kernel.dtype in matrices_per_dtype:
493
- continue
494
- matrices = [
495
- random_matrix(count_vectors_per_matrix, ndim, kernel.dtype) for _ in range(count_matrices_per_dtype)
496
- ]
497
- matrices_per_dtype[kernel.dtype] = matrices
498
-
499
- # For each kernel, repeat benchmarks for each data type
500
- for kernel in kernels:
501
- matrices_numpy = matrices_per_dtype[kernel.dtype]
502
- matrices_converted = [kernel.tensor_type(m) for m in matrices_numpy]
503
- baseline_one_to_one_func = kernel.baseline_all_pairs_func
504
- simsimd_func = kernel.simsimd_all_pairs_func
505
- result = Result(
506
- kernel.dtype,
507
- kernel.name,
508
- baseline_seconds=0,
509
- simsimd_seconds=0,
510
- bytes_per_vector=matrices_numpy[0].nbytes // count_vectors_per_matrix,
511
- distance_calculations=(count_vectors_per_matrix**2)
512
- * count_matrices_per_dtype
513
- * count_repetitions_per_matrix,
514
- )
515
-
516
- # Try obtaining the baseline measurements
517
- try:
518
- for i in range(1, count_matrices_per_dtype):
519
- result.baseline_seconds += latency(
520
- baseline_one_to_one_func,
521
- matrices_converted[i - 1],
522
- matrices_converted[i],
523
- count_repetitions_per_matrix,
524
- warmup,
525
- )
526
- except NotImplementedError as e:
527
- result.baseline_seconds = e
528
- except ValueError as e:
529
- result.baseline_seconds = e #! This happens often during overflows
530
- except RuntimeError as e:
531
- result.baseline_seconds = e #! This happens often during overflows
532
- except Exception as e:
533
- # This is an unexpected exception... once you face it, please report it
534
- raise RuntimeError(str(e) + " for %s(%s)" % (kernel.name, str(kernel.dtype))) from e
535
-
536
- # Try obtaining the SimSIMD measurements
537
- try:
538
- for i in range(1, count_matrices_per_dtype):
539
- result.simsimd_seconds += latency(
540
- simsimd_func,
541
- matrices_numpy[i - 1],
542
- matrices_numpy[i],
543
- count_repetitions_per_matrix,
544
- warmup,
545
- )
546
- except NotImplementedError as e:
547
- result.simsimd_seconds = e
548
- except Exception as e:
549
- # This is an unexpected exception... once you face it, please report it
550
- raise RuntimeError(str(e) + " for %s(%s)" % (kernel.name, str(kernel.dtype))) from e
551
-
552
- yield result
553
-
554
-
555
- def result_to_row(result: Result) -> List[str]:
556
- dtype_cell = f"`{result.dtype}`"
557
- name_cell = f"`{result.name}`"
558
- baseline_cell = "💥"
559
- simsimd_cell = "💥"
560
- improvement_cell = "🤷"
561
-
562
- if isinstance(result.baseline_seconds, float):
563
- ops_per_second = result.distance_calculations / result.baseline_seconds
564
- gbs_per_second = result.bytes_per_vector * ops_per_second / 1e9
565
- baseline_cell = f"{ops_per_second:,.0f} ops/s, {gbs_per_second:,.3f} GB/s"
566
- if isinstance(result.simsimd_seconds, float):
567
- ops_per_second = result.distance_calculations / result.simsimd_seconds
568
- gbs_per_second = result.bytes_per_vector * ops_per_second / 1e9
569
- simsimd_cell = f"{ops_per_second:,.0f} ops/s, {gbs_per_second:,.3f} GB/s"
570
- if isinstance(result.baseline_seconds, float) and isinstance(result.simsimd_seconds, float):
571
- improvement_cell = f"{result.baseline_seconds / result.simsimd_seconds:,.2f} x"
572
-
573
- return [dtype_cell, name_cell, baseline_cell, simsimd_cell, improvement_cell]
574
-
575
-
576
- def main():
577
- # Argument parsing
578
- parser = argparse.ArgumentParser(description="Benchmark SimSIMD and other libraries")
579
- parser.add_argument(
580
- "--ndim",
581
- type=int,
582
- default=1536,
583
- help="""
584
- Number of dimensions in vectors (default: 1536)
585
-
586
- For binary vectors (e.g., Hamming, Jaccard), this is the number of bits.
587
- In case of SimSIMD, the inputs will be treated at the bit-level.
588
- Other packages will be matching/comparing 8-bit integers.
589
- The volume of exchanged data will be identical, but the results will differ.
590
- """,
591
- )
592
- parser.add_argument(
593
- "-n",
594
- "--count",
595
- type=int,
596
- default=1,
597
- help="""
598
- Number of vectors per batch (default: 1)
599
-
600
- By default, when set to 1 the latency will generate many vectors of size (ndim, )
601
- and call the functions on pairs of single vectors: both directly, and through `cdist`.
602
- Alternatively, for larger batch sizes the latency will generate two matrices of
603
- size (n, ndim) and compute:
604
-
605
- - batch mode: (n) distances between vectors in identical rows of the two matrices,
606
- - all-pairs mode: (n^2) distances between all pairs of vectors in the two matrices via `cdist`.
607
- """,
608
- )
609
- parser.add_argument(
610
- "--mode",
611
- choices=["batch", "all-pairs"],
612
- default="batch",
613
- help="""Choose between 'batch' and 'all-pairs' mode (default: batch)
614
-
615
- In 'batch' mode, the latency will generate two matrices of size (n, ndim)
616
- and compute (n) distances between vectors in identical rows of the two matrices.
617
- In 'all-pairs' mode, the latency will generate two matrices of size (n, ndim)
618
- and compute (n^2) distances between all pairs of vectors in the two matrices via `cdist`.
619
- """,
620
- )
621
- parser.add_argument(
622
- "--metric",
623
- choices=["all", *metric_families],
624
- default="all",
625
- help="Distance metric to use, profiles everything by default",
626
- )
627
- parser.add_argument(
628
- "--dtype",
629
- choices=["all", *dtype_names],
630
- default="all",
631
- help="Defines numeric types to latency, profiles everything by default",
632
- )
633
- parser.add_argument("--scipy", action="store_true", help="Profile SciPy, must be installed")
634
- parser.add_argument("--scikit", action="store_true", help="Profile scikit-learn, must be installed")
635
- parser.add_argument("--torch", action="store_true", help="Profile PyTorch, must be installed")
636
- parser.add_argument("--tf", action="store_true", help="Profile TensorFlow, must be installed")
637
- parser.add_argument("--jax", action="store_true", help="Profile JAX, must be installed")
638
- parser.add_argument(
639
- "--time-limit",
640
- type=float,
641
- default=1.0,
642
- help="Maximum time in seconds to run each latency (default: 1.0)",
643
- )
644
- parser.add_argument(
645
- "--warmup",
646
- type=int,
647
- default=0,
648
- help="""
649
- Number of warm-up runs before timing (default: 0)
650
-
651
- This will greatly affect the results for all heavy libraries relying on JIT compilation
652
- or lazy computational graphs (e.g., TensorFlow, PyTorch, JAX).
653
- """,
654
- )
655
- args = parser.parse_args()
656
- assert args.count > 0, "Number of vectors per batch must be greater than 0"
657
- assert args.ndim > 0, "Number of dimensions must be greater than 0"
658
-
659
- count = args.count
660
- ndim = args.ndim
661
- dtypes_profiled = set([args.dtype] if args.dtype != "all" else dtype_names)
662
- metric_families_profiled = set([args.metric] if args.metric != "all" else metric_families)
663
-
664
- print("# Benchmarking SimSIMD")
665
- print("- Vector dimensions:", ndim)
666
- print("- Vectors count:", count)
667
- print("- Metrics:", ", ".join(metric_families_profiled))
668
- print("- Datatypes:", ", ".join(dtypes_profiled))
669
- try:
670
- caps = [cap for cap, enabled in simd.get_capabilities().items() if enabled]
671
- print("- Hardware capabilities:", ", ".join(caps))
672
-
673
- # Log versions of SimSIMD, NumPy, SciPy, and scikit-learn
674
- print(f"- SimSIMD version: {simd.__version__}")
675
- print(f"- NumPy version: {np.__version__}")
676
-
677
- if args.scipy:
678
- import scipy as sp
679
-
680
- print(f"- SciPy version: {sp.__version__}")
681
- if args.scikit:
682
- import sklearn as sk
683
-
684
- print(f"- scikit-learn version: {sk.__version__}")
685
- if args.torch:
686
- import torch
687
-
688
- print(f"- PyTorch version: {torch.__version__}")
689
- if args.tf:
690
- import tensorflow as tf
691
-
692
- print(f"- TensorFlow version: {tf.__version__}")
693
- if args.jax:
694
- import jax
695
-
696
- print(f"- JAX version: {jax.__version__}")
697
-
698
- deps: dict = np.show_config(mode="dicts").get("Build Dependencies")
699
- print("-- NumPy BLAS dependency:", deps["blas"]["name"])
700
- print("-- NumPy LAPACK dependency:", deps["lapack"]["name"])
701
- except Exception as e:
702
- print(f"An error occurred: {e}")
703
-
704
- kernels: List[Kernel] = list(
705
- yield_kernels(
706
- metric_families_profiled,
707
- dtypes_profiled,
708
- include_scipy=args.scipy,
709
- include_scikit=args.scikit,
710
- include_torch=args.torch,
711
- include_tf=args.tf,
712
- include_jax=args.jax,
713
- )
714
- )
715
-
716
- results: Generator[Result, None, None] = []
717
- if args.mode == "batch":
718
- print("## Between Vectors in Two Matrices, Batch Size: {:,}".format(count))
719
- results = yield_batch_results(count, ndim, kernels)
720
- else:
721
- print("## Between All Pairs of Vectors (`cdist`), Batch Size: {:,}".format(count))
722
- results = yield_all_pairs_results(count, ndim, kernels)
723
-
724
- columns_headers = ["Data Type", "Method", "Baseline", "SimSIMD", "Improvement"]
725
- results_rows = []
726
- for result in results:
727
- result_row = result_to_row(result)
728
- results_rows.append(result_row)
729
-
730
- print(tabulate.tabulate(results_rows, headers=columns_headers))
731
-
732
-
733
- if __name__ == "__main__":
734
- main()