usearch 2.21.3 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/binding.gyp +15 -37
- package/c/CMakeLists.txt +4 -5
- package/c/README.md +7 -7
- package/c/lib.cpp +32 -14
- package/c/test.c +83 -1
- package/c/usearch.h +24 -3
- package/cpp/CMakeLists.txt +4 -0
- package/cpp/README.md +5 -5
- package/cpp/bench.cpp +97 -116
- package/cpp/test.cpp +117 -20
- package/include/usearch/index.hpp +235 -52
- package/include/usearch/index_dense.hpp +105 -40
- package/include/usearch/index_plugins.hpp +1387 -204
- package/javascript/dist/cjs/usearch.d.ts +8 -3
- package/javascript/dist/cjs/usearch.js +12 -4
- package/javascript/dist/esm/usearch.d.ts +8 -3
- package/javascript/dist/esm/usearch.js +12 -4
- package/javascript/lib.cpp +17 -0
- package/javascript/usearch.ts +14 -6
- package/numkong/.clang-tidy +30 -0
- package/{simsimd → numkong}/.cmake-format.py +18 -0
- package/numkong/.editorconfig +12 -0
- package/numkong/.git-blame-ignore-revs +123 -0
- package/numkong/.mailmap +15 -0
- package/numkong/.spi.yml +11 -0
- package/numkong/.swift-format +14 -0
- package/numkong/CITATION.cff +81 -0
- package/numkong/CONTRIBUTING.md +500 -0
- package/numkong/Cargo.toml +54 -0
- package/numkong/MANIFEST.in +8 -0
- package/numkong/Package.swift +84 -0
- package/numkong/README.md +569 -0
- package/numkong/bench/README.md +217 -0
- package/numkong/bench/bench-browser.html +323 -0
- package/numkong/bench/bench.cpp +344 -0
- package/numkong/bench/bench.hpp +816 -0
- package/numkong/bench/bench.js +148 -0
- package/numkong/bench/bench.mjs +616 -0
- package/numkong/bench/bench_attention.cpp +113 -0
- package/numkong/bench/bench_cast.cpp +264 -0
- package/numkong/bench/bench_cross_amx.cpp +62 -0
- package/numkong/bench/bench_cross_arm.cpp +245 -0
- package/numkong/bench/bench_cross_blas.cpp +309 -0
- package/numkong/bench/bench_cross_loongarch.cpp +106 -0
- package/numkong/bench/bench_cross_power.cpp +84 -0
- package/numkong/bench/bench_cross_rvv.cpp +121 -0
- package/numkong/bench/bench_cross_serial.cpp +151 -0
- package/numkong/bench/bench_cross_sme.cpp +163 -0
- package/numkong/bench/bench_cross_wasm.cpp +142 -0
- package/numkong/bench/bench_cross_x86.cpp +455 -0
- package/numkong/bench/bench_curved.cpp +210 -0
- package/numkong/bench/bench_dot.cpp +315 -0
- package/numkong/bench/bench_each.cpp +503 -0
- package/numkong/bench/bench_geospatial.cpp +112 -0
- package/numkong/bench/bench_maxsim.cpp +154 -0
- package/numkong/bench/bench_mesh.cpp +148 -0
- package/numkong/bench/bench_probability.cpp +60 -0
- package/numkong/bench/bench_reduce.cpp +371 -0
- package/numkong/bench/bench_set.cpp +73 -0
- package/numkong/bench/bench_sparse.cpp +198 -0
- package/numkong/bench/bench_spatial.cpp +347 -0
- package/numkong/bench/bench_trigonometry.cpp +137 -0
- package/numkong/bench/swift/Bench.swift +506 -0
- package/numkong/binding.gyp +169 -0
- package/numkong/build.rs +484 -0
- package/numkong/c/dispatch.h +512 -0
- package/numkong/c/dispatch_bf16.c +447 -0
- package/numkong/c/dispatch_bf16c.c +52 -0
- package/numkong/c/dispatch_e2m3.c +296 -0
- package/numkong/c/dispatch_e3m2.c +284 -0
- package/numkong/c/dispatch_e4m3.c +318 -0
- package/numkong/c/dispatch_e5m2.c +316 -0
- package/numkong/c/dispatch_f16.c +452 -0
- package/numkong/c/dispatch_f16c.c +58 -0
- package/numkong/c/dispatch_f32.c +434 -0
- package/numkong/c/dispatch_f32c.c +99 -0
- package/numkong/c/dispatch_f64.c +348 -0
- package/numkong/c/dispatch_f64c.c +98 -0
- package/numkong/c/dispatch_i16.c +96 -0
- package/numkong/c/dispatch_i32.c +89 -0
- package/numkong/c/dispatch_i4.c +153 -0
- package/numkong/c/dispatch_i64.c +86 -0
- package/numkong/c/dispatch_i8.c +348 -0
- package/numkong/c/dispatch_other.c +348 -0
- package/numkong/c/dispatch_u1.c +193 -0
- package/numkong/c/dispatch_u16.c +124 -0
- package/numkong/c/dispatch_u32.c +118 -0
- package/numkong/c/dispatch_u4.c +153 -0
- package/numkong/c/dispatch_u64.c +102 -0
- package/numkong/c/dispatch_u8.c +364 -0
- package/numkong/c/numkong.c +940 -0
- package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
- package/numkong/cmake/nk_isa_probe.cmake +90 -0
- package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
- package/numkong/cmake/nk_math_lib.cmake +46 -0
- package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
- package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
- package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
- package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
- package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
- package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
- package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
- package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
- package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
- package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
- package/numkong/cmake/toolchain-wasi.cmake +77 -0
- package/numkong/cmake/toolchain-wasm.cmake +70 -0
- package/numkong/cmake/toolchain-wasm64.cmake +62 -0
- package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
- package/numkong/include/README.md +643 -0
- package/numkong/include/module.modulemap +129 -0
- package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
- package/numkong/include/numkong/attention/sme.h +2075 -0
- package/numkong/include/numkong/attention.h +49 -0
- package/numkong/include/numkong/capabilities.h +930 -0
- package/numkong/include/numkong/cast/README.md +262 -0
- package/numkong/include/numkong/cast/diamond.h +64 -0
- package/numkong/include/numkong/cast/haswell.h +823 -0
- package/numkong/include/numkong/cast/icelake.h +475 -0
- package/numkong/include/numkong/cast/loongsonasx.h +252 -0
- package/numkong/include/numkong/cast/neon.h +1174 -0
- package/numkong/include/numkong/cast/powervsx.h +449 -0
- package/numkong/include/numkong/cast/rvv.h +970 -0
- package/numkong/include/numkong/cast/sapphire.h +262 -0
- package/numkong/include/numkong/cast/serial.h +2336 -0
- package/numkong/include/numkong/cast/skylake.h +915 -0
- package/numkong/include/numkong/cast/v128relaxed.h +537 -0
- package/numkong/include/numkong/cast.h +254 -0
- package/numkong/include/numkong/cast.hpp +44 -0
- package/numkong/include/numkong/curved/README.md +223 -0
- package/numkong/include/numkong/curved/genoa.h +182 -0
- package/numkong/include/numkong/curved/haswell.h +276 -0
- package/numkong/include/numkong/curved/neon.h +329 -0
- package/numkong/include/numkong/curved/neonbfdot.h +211 -0
- package/numkong/include/numkong/curved/rvv.h +305 -0
- package/numkong/include/numkong/curved/serial.h +207 -0
- package/numkong/include/numkong/curved/skylake.h +457 -0
- package/numkong/include/numkong/curved/smef64.h +530 -0
- package/numkong/include/numkong/curved.h +513 -0
- package/numkong/include/numkong/curved.hpp +144 -0
- package/numkong/include/numkong/dot/README.md +442 -0
- package/numkong/include/numkong/dot/alder.h +563 -0
- package/numkong/include/numkong/dot/diamond.h +158 -0
- package/numkong/include/numkong/dot/genoa.h +289 -0
- package/numkong/include/numkong/dot/haswell.h +1723 -0
- package/numkong/include/numkong/dot/icelake.h +997 -0
- package/numkong/include/numkong/dot/loongsonasx.h +671 -0
- package/numkong/include/numkong/dot/neon.h +869 -0
- package/numkong/include/numkong/dot/neonbfdot.h +243 -0
- package/numkong/include/numkong/dot/neonfhm.h +358 -0
- package/numkong/include/numkong/dot/neonfp8.h +323 -0
- package/numkong/include/numkong/dot/neonsdot.h +622 -0
- package/numkong/include/numkong/dot/powervsx.h +752 -0
- package/numkong/include/numkong/dot/rvv.h +722 -0
- package/numkong/include/numkong/dot/rvvbb.h +72 -0
- package/numkong/include/numkong/dot/rvvbf16.h +123 -0
- package/numkong/include/numkong/dot/rvvhalf.h +129 -0
- package/numkong/include/numkong/dot/sapphire.h +141 -0
- package/numkong/include/numkong/dot/serial.h +874 -0
- package/numkong/include/numkong/dot/sierra.h +405 -0
- package/numkong/include/numkong/dot/skylake.h +1116 -0
- package/numkong/include/numkong/dot/sve.h +420 -0
- package/numkong/include/numkong/dot/svebfdot.h +75 -0
- package/numkong/include/numkong/dot/svehalf.h +168 -0
- package/numkong/include/numkong/dot/svesdot.h +90 -0
- package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
- package/numkong/include/numkong/dot.h +1136 -0
- package/numkong/include/numkong/dot.hpp +94 -0
- package/numkong/include/numkong/dots/README.md +496 -0
- package/numkong/include/numkong/dots/alder.h +117 -0
- package/numkong/include/numkong/dots/diamond.h +86 -0
- package/numkong/include/numkong/dots/genoa.h +100 -0
- package/numkong/include/numkong/dots/graniteamx.h +733 -0
- package/numkong/include/numkong/dots/haswell.h +310 -0
- package/numkong/include/numkong/dots/icelake.h +180 -0
- package/numkong/include/numkong/dots/loongsonasx.h +176 -0
- package/numkong/include/numkong/dots/neon.h +123 -0
- package/numkong/include/numkong/dots/neonbfdot.h +59 -0
- package/numkong/include/numkong/dots/neonfhm.h +96 -0
- package/numkong/include/numkong/dots/neonfp8.h +99 -0
- package/numkong/include/numkong/dots/neonsdot.h +144 -0
- package/numkong/include/numkong/dots/powervsx.h +194 -0
- package/numkong/include/numkong/dots/rvv.h +2593 -0
- package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
- package/numkong/include/numkong/dots/serial.h +2867 -0
- package/numkong/include/numkong/dots/sierra.h +100 -0
- package/numkong/include/numkong/dots/skylake.h +207 -0
- package/numkong/include/numkong/dots/sme.h +5041 -0
- package/numkong/include/numkong/dots/smebi32.h +477 -0
- package/numkong/include/numkong/dots/smef64.h +1328 -0
- package/numkong/include/numkong/dots/smehalf.h +47 -0
- package/numkong/include/numkong/dots/v128relaxed.h +317 -0
- package/numkong/include/numkong/dots.h +3110 -0
- package/numkong/include/numkong/dots.hpp +641 -0
- package/numkong/include/numkong/each/README.md +465 -0
- package/numkong/include/numkong/each/haswell.h +1658 -0
- package/numkong/include/numkong/each/icelake.h +272 -0
- package/numkong/include/numkong/each/neon.h +1138 -0
- package/numkong/include/numkong/each/neonbfdot.h +211 -0
- package/numkong/include/numkong/each/neonhalf.h +318 -0
- package/numkong/include/numkong/each/rvv.h +1121 -0
- package/numkong/include/numkong/each/sapphire.h +343 -0
- package/numkong/include/numkong/each/serial.h +282 -0
- package/numkong/include/numkong/each/skylake.h +1562 -0
- package/numkong/include/numkong/each/v128relaxed.h +562 -0
- package/numkong/include/numkong/each.h +2232 -0
- package/numkong/include/numkong/each.hpp +434 -0
- package/numkong/include/numkong/geospatial/README.md +147 -0
- package/numkong/include/numkong/geospatial/haswell.h +633 -0
- package/numkong/include/numkong/geospatial/neon.h +615 -0
- package/numkong/include/numkong/geospatial/rvv.h +701 -0
- package/numkong/include/numkong/geospatial/serial.h +309 -0
- package/numkong/include/numkong/geospatial/skylake.h +613 -0
- package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
- package/numkong/include/numkong/geospatial.h +453 -0
- package/numkong/include/numkong/geospatial.hpp +235 -0
- package/numkong/include/numkong/matrix.hpp +336 -0
- package/numkong/include/numkong/maxsim/README.md +187 -0
- package/numkong/include/numkong/maxsim/alder.h +511 -0
- package/numkong/include/numkong/maxsim/genoa.h +115 -0
- package/numkong/include/numkong/maxsim/haswell.h +553 -0
- package/numkong/include/numkong/maxsim/icelake.h +480 -0
- package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
- package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
- package/numkong/include/numkong/maxsim/serial.h +490 -0
- package/numkong/include/numkong/maxsim/sme.h +993 -0
- package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
- package/numkong/include/numkong/maxsim.h +571 -0
- package/numkong/include/numkong/maxsim.hpp +133 -0
- package/numkong/include/numkong/mesh/README.md +219 -0
- package/numkong/include/numkong/mesh/haswell.h +2013 -0
- package/numkong/include/numkong/mesh/neon.h +1821 -0
- package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
- package/numkong/include/numkong/mesh/rvv.h +936 -0
- package/numkong/include/numkong/mesh/serial.h +721 -0
- package/numkong/include/numkong/mesh/skylake.h +2344 -0
- package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
- package/numkong/include/numkong/mesh.h +666 -0
- package/numkong/include/numkong/mesh.hpp +701 -0
- package/numkong/include/numkong/numkong.h +78 -0
- package/numkong/include/numkong/numkong.hpp +58 -0
- package/numkong/include/numkong/probability/README.md +177 -0
- package/numkong/include/numkong/probability/haswell.h +267 -0
- package/numkong/include/numkong/probability/neon.h +255 -0
- package/numkong/include/numkong/probability/rvv.h +414 -0
- package/numkong/include/numkong/probability/serial.h +181 -0
- package/numkong/include/numkong/probability/skylake.h +324 -0
- package/numkong/include/numkong/probability.h +380 -0
- package/numkong/include/numkong/probability.hpp +120 -0
- package/numkong/include/numkong/random.h +50 -0
- package/numkong/include/numkong/random.hpp +285 -0
- package/numkong/include/numkong/reduce/README.md +552 -0
- package/numkong/include/numkong/reduce/alder.h +636 -0
- package/numkong/include/numkong/reduce/genoa.h +201 -0
- package/numkong/include/numkong/reduce/haswell.h +3785 -0
- package/numkong/include/numkong/reduce/icelake.h +549 -0
- package/numkong/include/numkong/reduce/neon.h +3980 -0
- package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
- package/numkong/include/numkong/reduce/neonfhm.h +293 -0
- package/numkong/include/numkong/reduce/neonsdot.h +357 -0
- package/numkong/include/numkong/reduce/rvv.h +3533 -0
- package/numkong/include/numkong/reduce/serial.h +753 -0
- package/numkong/include/numkong/reduce/sierra.h +338 -0
- package/numkong/include/numkong/reduce/skylake.h +3794 -0
- package/numkong/include/numkong/reduce/sve.h +52 -0
- package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
- package/numkong/include/numkong/reduce.h +1582 -0
- package/numkong/include/numkong/reduce.hpp +778 -0
- package/numkong/include/numkong/scalar/README.md +89 -0
- package/numkong/include/numkong/scalar/haswell.h +122 -0
- package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
- package/numkong/include/numkong/scalar/neon.h +122 -0
- package/numkong/include/numkong/scalar/neonhalf.h +70 -0
- package/numkong/include/numkong/scalar/powervsx.h +96 -0
- package/numkong/include/numkong/scalar/rvv.h +211 -0
- package/numkong/include/numkong/scalar/sapphire.h +74 -0
- package/numkong/include/numkong/scalar/serial.h +332 -0
- package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
- package/numkong/include/numkong/scalar.h +696 -0
- package/numkong/include/numkong/set/README.md +179 -0
- package/numkong/include/numkong/set/haswell.h +334 -0
- package/numkong/include/numkong/set/icelake.h +485 -0
- package/numkong/include/numkong/set/loongsonasx.h +181 -0
- package/numkong/include/numkong/set/neon.h +363 -0
- package/numkong/include/numkong/set/powervsx.h +326 -0
- package/numkong/include/numkong/set/rvv.h +226 -0
- package/numkong/include/numkong/set/rvvbb.h +117 -0
- package/numkong/include/numkong/set/serial.h +174 -0
- package/numkong/include/numkong/set/sve.h +187 -0
- package/numkong/include/numkong/set/v128relaxed.h +240 -0
- package/numkong/include/numkong/set.h +471 -0
- package/numkong/include/numkong/set.hpp +114 -0
- package/numkong/include/numkong/sets/README.md +149 -0
- package/numkong/include/numkong/sets/haswell.h +63 -0
- package/numkong/include/numkong/sets/icelake.h +66 -0
- package/numkong/include/numkong/sets/loongsonasx.h +52 -0
- package/numkong/include/numkong/sets/neon.h +61 -0
- package/numkong/include/numkong/sets/powervsx.h +65 -0
- package/numkong/include/numkong/sets/serial.h +43 -0
- package/numkong/include/numkong/sets/smebi32.h +1135 -0
- package/numkong/include/numkong/sets/v128relaxed.h +58 -0
- package/numkong/include/numkong/sets.h +382 -0
- package/numkong/include/numkong/sparse/README.md +156 -0
- package/numkong/include/numkong/sparse/icelake.h +463 -0
- package/numkong/include/numkong/sparse/neon.h +288 -0
- package/numkong/include/numkong/sparse/serial.h +117 -0
- package/numkong/include/numkong/sparse/sve2.h +504 -0
- package/numkong/include/numkong/sparse/turin.h +322 -0
- package/numkong/include/numkong/sparse.h +363 -0
- package/numkong/include/numkong/sparse.hpp +113 -0
- package/numkong/include/numkong/spatial/README.md +439 -0
- package/numkong/include/numkong/spatial/alder.h +604 -0
- package/numkong/include/numkong/spatial/diamond.h +240 -0
- package/numkong/include/numkong/spatial/genoa.h +222 -0
- package/numkong/include/numkong/spatial/haswell.h +979 -0
- package/numkong/include/numkong/spatial/icelake.h +1067 -0
- package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
- package/numkong/include/numkong/spatial/neon.h +846 -0
- package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
- package/numkong/include/numkong/spatial/neonfp8.h +258 -0
- package/numkong/include/numkong/spatial/neonsdot.h +429 -0
- package/numkong/include/numkong/spatial/powervsx.h +738 -0
- package/numkong/include/numkong/spatial/rvv.h +991 -0
- package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
- package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
- package/numkong/include/numkong/spatial/serial.h +347 -0
- package/numkong/include/numkong/spatial/sierra.h +516 -0
- package/numkong/include/numkong/spatial/skylake.h +605 -0
- package/numkong/include/numkong/spatial/sve.h +246 -0
- package/numkong/include/numkong/spatial/svebfdot.h +125 -0
- package/numkong/include/numkong/spatial/svehalf.h +136 -0
- package/numkong/include/numkong/spatial/svesdot.h +143 -0
- package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
- package/numkong/include/numkong/spatial.h +1681 -0
- package/numkong/include/numkong/spatial.hpp +183 -0
- package/numkong/include/numkong/spatials/README.md +580 -0
- package/numkong/include/numkong/spatials/alder.h +94 -0
- package/numkong/include/numkong/spatials/diamond.h +82 -0
- package/numkong/include/numkong/spatials/genoa.h +94 -0
- package/numkong/include/numkong/spatials/graniteamx.h +173 -0
- package/numkong/include/numkong/spatials/haswell.h +219 -0
- package/numkong/include/numkong/spatials/icelake.h +113 -0
- package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
- package/numkong/include/numkong/spatials/neon.h +109 -0
- package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
- package/numkong/include/numkong/spatials/neonfhm.h +92 -0
- package/numkong/include/numkong/spatials/neonfp8.h +111 -0
- package/numkong/include/numkong/spatials/neonsdot.h +143 -0
- package/numkong/include/numkong/spatials/powervsx.h +153 -0
- package/numkong/include/numkong/spatials/rvv.h +1976 -0
- package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
- package/numkong/include/numkong/spatials/serial.h +248 -0
- package/numkong/include/numkong/spatials/sierra.h +96 -0
- package/numkong/include/numkong/spatials/skylake.h +184 -0
- package/numkong/include/numkong/spatials/sme.h +1927 -0
- package/numkong/include/numkong/spatials/smef64.h +483 -0
- package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
- package/numkong/include/numkong/spatials.h +3374 -0
- package/numkong/include/numkong/spatials.hpp +509 -0
- package/numkong/include/numkong/tensor.hpp +1981 -0
- package/numkong/include/numkong/trigonometry/README.md +184 -0
- package/numkong/include/numkong/trigonometry/haswell.h +653 -0
- package/numkong/include/numkong/trigonometry/neon.h +638 -0
- package/numkong/include/numkong/trigonometry/rvv.h +700 -0
- package/numkong/include/numkong/trigonometry/serial.h +703 -0
- package/numkong/include/numkong/trigonometry/skylake.h +725 -0
- package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
- package/numkong/include/numkong/trigonometry.h +467 -0
- package/numkong/include/numkong/trigonometry.hpp +166 -0
- package/numkong/include/numkong/types.h +1695 -0
- package/numkong/include/numkong/types.hpp +6027 -0
- package/numkong/include/numkong/vector.hpp +766 -0
- package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
- package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
- package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
- package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
- package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
- package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
- package/numkong/javascript/README.md +254 -0
- package/numkong/javascript/node-gyp-build.d.ts +4 -0
- package/numkong/javascript/numkong-browser.ts +40 -0
- package/numkong/javascript/numkong-wasm.ts +750 -0
- package/numkong/javascript/numkong.c +712 -0
- package/numkong/javascript/numkong.ts +613 -0
- package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
- package/numkong/javascript/tsconfig-cjs.json +13 -0
- package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
- package/numkong/javascript/types.ts +784 -0
- package/numkong/numkong.gypi +104 -0
- package/numkong/package.json +108 -0
- package/numkong/probes/arm_neon.c +8 -0
- package/numkong/probes/arm_neon_bfdot.c +9 -0
- package/numkong/probes/arm_neon_fhm.c +9 -0
- package/numkong/probes/arm_neon_half.c +8 -0
- package/numkong/probes/arm_neon_sdot.c +9 -0
- package/numkong/probes/arm_neonfp8.c +9 -0
- package/numkong/probes/arm_sme.c +16 -0
- package/numkong/probes/arm_sme2.c +16 -0
- package/numkong/probes/arm_sme2p1.c +16 -0
- package/numkong/probes/arm_sme_bf16.c +16 -0
- package/numkong/probes/arm_sme_bi32.c +16 -0
- package/numkong/probes/arm_sme_f64.c +16 -0
- package/numkong/probes/arm_sme_fa64.c +14 -0
- package/numkong/probes/arm_sme_half.c +16 -0
- package/numkong/probes/arm_sme_lut2.c +15 -0
- package/numkong/probes/arm_sve.c +18 -0
- package/numkong/probes/arm_sve2.c +20 -0
- package/numkong/probes/arm_sve2p1.c +18 -0
- package/numkong/probes/arm_sve_bfdot.c +20 -0
- package/numkong/probes/arm_sve_half.c +18 -0
- package/numkong/probes/arm_sve_sdot.c +21 -0
- package/numkong/probes/loongarch_lasx.c +12 -0
- package/numkong/probes/power_vsx.c +12 -0
- package/numkong/probes/probe.js +127 -0
- package/numkong/probes/riscv_rvv.c +14 -0
- package/numkong/probes/riscv_rvv_bb.c +15 -0
- package/numkong/probes/riscv_rvv_bf16.c +17 -0
- package/numkong/probes/riscv_rvv_half.c +14 -0
- package/numkong/probes/wasm_v128relaxed.c +11 -0
- package/numkong/probes/x86_alder.c +17 -0
- package/numkong/probes/x86_diamond.c +17 -0
- package/numkong/probes/x86_genoa.c +17 -0
- package/numkong/probes/x86_graniteamx.c +19 -0
- package/numkong/probes/x86_haswell.c +11 -0
- package/numkong/probes/x86_icelake.c +17 -0
- package/numkong/probes/x86_sapphire.c +16 -0
- package/numkong/probes/x86_sapphireamx.c +18 -0
- package/numkong/probes/x86_sierra.c +17 -0
- package/numkong/probes/x86_skylake.c +15 -0
- package/numkong/probes/x86_turin.c +17 -0
- package/numkong/rust/README.md +698 -0
- package/numkong/rust/capabilities.rs +96 -0
- package/numkong/rust/cast.rs +314 -0
- package/numkong/rust/curved.rs +391 -0
- package/numkong/rust/each.rs +2721 -0
- package/numkong/rust/geospatial.rs +343 -0
- package/numkong/rust/matrix.rs +5424 -0
- package/numkong/rust/maxsim.rs +540 -0
- package/numkong/rust/mesh.rs +837 -0
- package/numkong/rust/numkong.rs +409 -0
- package/numkong/rust/probability.rs +272 -0
- package/numkong/rust/reduce.rs +1249 -0
- package/numkong/rust/set.rs +194 -0
- package/numkong/rust/sparse.rs +513 -0
- package/numkong/rust/spatial.rs +1815 -0
- package/numkong/rust/tensor.rs +7565 -0
- package/numkong/rust/types.rs +3666 -0
- package/numkong/rust/vector.rs +1899 -0
- package/numkong/rustfmt.toml +2 -0
- package/numkong/swift/Matrix.swift +1388 -0
- package/numkong/swift/MaxSim.swift +151 -0
- package/numkong/swift/NumKong.swift +283 -0
- package/numkong/swift/Numerics.swift +329 -0
- package/numkong/swift/README.md +433 -0
- package/numkong/swift/Scalar.swift +741 -0
- package/numkong/swift/Tensor.swift +209 -0
- package/numkong/test/README.md +315 -0
- package/numkong/test/playwright.config.ts +16 -0
- package/numkong/test/swift/Test.swift +534 -0
- package/numkong/test/test-browser-bundle-runner.mjs +36 -0
- package/numkong/test/test-browser-bundle.html +188 -0
- package/numkong/test/test-browser-runner.mjs +43 -0
- package/numkong/test/test-browser.html +305 -0
- package/numkong/test/test-dtypes.mjs +453 -0
- package/numkong/test/test-wasm.mjs +267 -0
- package/numkong/test/test.cpp +442 -0
- package/numkong/test/test.hpp +580 -0
- package/numkong/test/test.mjs +363 -0
- package/numkong/test/test_base.py +1041 -0
- package/numkong/test/test_cast.cpp +242 -0
- package/numkong/test/test_cross.hpp +551 -0
- package/numkong/test/test_cross.py +467 -0
- package/numkong/test/test_cross_amx.cpp +50 -0
- package/numkong/test/test_cross_arm.cpp +225 -0
- package/numkong/test/test_cross_blas.cpp +354 -0
- package/numkong/test/test_cross_loongarch.cpp +90 -0
- package/numkong/test/test_cross_power.cpp +73 -0
- package/numkong/test/test_cross_rvv.cpp +109 -0
- package/numkong/test/test_cross_serial.cpp +181 -0
- package/numkong/test/test_cross_sme.cpp +148 -0
- package/numkong/test/test_cross_wasm.cpp +141 -0
- package/numkong/test/test_cross_x86.cpp +442 -0
- package/numkong/test/test_curved.cpp +182 -0
- package/numkong/test/test_curved.py +207 -0
- package/numkong/test/test_dot.cpp +353 -0
- package/numkong/test/test_dot.py +296 -0
- package/numkong/test/test_each.cpp +437 -0
- package/numkong/test/test_each.py +756 -0
- package/numkong/test/test_geospatial.cpp +155 -0
- package/numkong/test/test_geospatial.py +241 -0
- package/numkong/test/test_maxsim.cpp +138 -0
- package/numkong/test/test_maxsim.py +209 -0
- package/numkong/test/test_mesh.cpp +203 -0
- package/numkong/test/test_mesh.py +394 -0
- package/numkong/test/test_probability.cpp +136 -0
- package/numkong/test/test_probability.py +166 -0
- package/numkong/test/test_reduce.cpp +563 -0
- package/numkong/test/test_reduce.py +781 -0
- package/numkong/test/test_set.cpp +151 -0
- package/numkong/test/test_set.py +120 -0
- package/numkong/test/test_similarities.py +579 -0
- package/numkong/test/test_sparse.cpp +121 -0
- package/numkong/test/test_sparse.py +118 -0
- package/numkong/test/test_spatial.cpp +518 -0
- package/numkong/test/test_spatial.py +269 -0
- package/numkong/test/test_tensor.cpp +884 -0
- package/numkong/test/test_tensor.py +1417 -0
- package/numkong/test/test_trigonometry.cpp +156 -0
- package/numkong/test/test_trigonometry.py +180 -0
- package/package.json +7 -8
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/fp16/CMakeLists.txt +0 -176
- package/fp16/LICENSE +0 -11
- package/fp16/README.md +0 -20
- package/fp16/bench/alt-element.cc +0 -89
- package/fp16/bench/from-alt-array.cc +0 -175
- package/fp16/bench/from-ieee-array.cc +0 -399
- package/fp16/bench/ieee-element.cc +0 -272
- package/fp16/bench/to-alt-array.cc +0 -91
- package/fp16/bench/to-ieee-array.cc +0 -303
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
- package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
- package/fp16/cmake/DownloadPSimd.cmake +0 -15
- package/fp16/configure.py +0 -65
- package/fp16/confu.yaml +0 -8
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +0 -50
- package/fp16/include/fp16/avx2.py +0 -53
- package/fp16/include/fp16/bitcasts.h +0 -92
- package/fp16/include/fp16/fp16.h +0 -451
- package/fp16/include/fp16/psimd.h +0 -131
- package/fp16/include/fp16.h +0 -11
- package/fp16/jni/Android.mk +0 -6
- package/fp16/jni/Application.mk +0 -4
- package/fp16/test/alt-from-fp32-value.cc +0 -498
- package/fp16/test/alt-to-fp32-bits.cc +0 -263
- package/fp16/test/alt-to-fp32-psimd.cc +0 -145
- package/fp16/test/alt-to-fp32-value.cc +0 -348
- package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
- package/fp16/test/bitcasts.cc +0 -56
- package/fp16/test/ieee-from-fp32-value.cc +0 -523
- package/fp16/test/ieee-to-fp32-bits.cc +0 -333
- package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
- package/fp16/test/ieee-to-fp32-value.cc +0 -420
- package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
- package/fp16/test/peachpy/stubs.py +0 -38
- package/fp16/test/tables.cc +0 -530
- package/fp16/test/tables.h +0 -13
- package/fp16/third-party/THHalf.h +0 -92
- package/fp16/third-party/eigen-half.h +0 -170
- package/fp16/third-party/float16-compressor.h +0 -80
- package/fp16/third-party/half.hpp +0 -2916
- package/fp16/third-party/npy-halffloat.h +0 -328
- package/simsimd/.git-blame-ignore-revs +0 -2
- package/simsimd/CONTRIBUTING.md +0 -321
- package/simsimd/Cargo.toml +0 -49
- package/simsimd/MANIFEST.in +0 -4
- package/simsimd/Package.swift +0 -28
- package/simsimd/README.md +0 -1493
- package/simsimd/binding.gyp +0 -35
- package/simsimd/build.rs +0 -70
- package/simsimd/c/lib.c +0 -374
- package/simsimd/include/module.modulemap +0 -4
- package/simsimd/include/simsimd/binary.h +0 -486
- package/simsimd/include/simsimd/curved.h +0 -1541
- package/simsimd/include/simsimd/dot.h +0 -1853
- package/simsimd/include/simsimd/elementwise.h +0 -2465
- package/simsimd/include/simsimd/geospatial.h +0 -43
- package/simsimd/include/simsimd/mesh.h +0 -69
- package/simsimd/include/simsimd/probability.h +0 -606
- package/simsimd/include/simsimd/simsimd.h +0 -2567
- package/simsimd/include/simsimd/sparse.h +0 -1384
- package/simsimd/include/simsimd/spatial.h +0 -2335
- package/simsimd/include/simsimd/types.h +0 -666
- package/simsimd/javascript/fallback.ts +0 -233
- package/simsimd/javascript/lib.c +0 -125
- package/simsimd/javascript/node-gyp-build.d.ts +0 -1
- package/simsimd/javascript/simsimd.ts +0 -179
- package/simsimd/javascript/tsconfig-cjs.json +0 -8
- package/simsimd/package-lock.json +0 -1761
- package/simsimd/package.json +0 -61
- package/simsimd/rust/lib.rs +0 -1821
- package/simsimd/scripts/bench.cxx +0 -1170
- package/simsimd/scripts/bench.ipynb +0 -187
- package/simsimd/scripts/bench.js +0 -127
- package/simsimd/scripts/bench.rs +0 -876
- package/simsimd/scripts/bench_vectors.py +0 -734
- package/simsimd/scripts/bench_vectors_live.py +0 -213
- package/simsimd/scripts/test.c +0 -187
- package/simsimd/scripts/test.mjs +0 -220
- package/simsimd/scripts/test.py +0 -1505
- package/simsimd/swift/SimSIMD.swift +0 -149
- package/simsimd/swift/Test.swift +0 -128
- /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
- /package/{simsimd → numkong}/LICENSE +0 -0
- /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
- /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()
|