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
@@ -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()