usearch 2.21.4 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +224 -48
- 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
package/simsimd/rust/lib.rs
DELETED
|
@@ -1,1821 +0,0 @@
|
|
|
1
|
-
//! # SpatialSimilarity - Hardware-Accelerated Similarity Metrics and Distance Functions
|
|
2
|
-
//!
|
|
3
|
-
//! * Targets ARM NEON, SVE, x86 AVX2, AVX-512 (VNNI, FP16) hardware backends.
|
|
4
|
-
//! * Handles `f64` double- and `f32` single-precision, integral, and binary vectors.
|
|
5
|
-
//! * Exposes half-precision (`f16`) and brain floating point (`bf16`) types.
|
|
6
|
-
//! * Zero-dependency header-only C 99 library with bindings for Rust and other languages.
|
|
7
|
-
//!
|
|
8
|
-
//! ## Implemented distance functions include:
|
|
9
|
-
//!
|
|
10
|
-
//! * Euclidean (L2), inner product, and cosine (angular) spatial distances.
|
|
11
|
-
//! * Hamming (~ Manhattan) and Jaccard (~ Tanimoto) binary distances.
|
|
12
|
-
//! * Kullback-Leibler and Jensen-Shannon divergences for probability distributions.
|
|
13
|
-
//!
|
|
14
|
-
//! ## Example
|
|
15
|
-
//!
|
|
16
|
-
//! ```rust
|
|
17
|
-
//! use simsimd::SpatialSimilarity;
|
|
18
|
-
//!
|
|
19
|
-
//! let a = &[1, 2, 3];
|
|
20
|
-
//! let b = &[4, 5, 6];
|
|
21
|
-
//!
|
|
22
|
-
//! // Compute cosine distance
|
|
23
|
-
//! let cos_dist = i8::cos(a, b);
|
|
24
|
-
//!
|
|
25
|
-
//! // Compute dot product distance
|
|
26
|
-
//! let dot_product = i8::dot(a, b);
|
|
27
|
-
//!
|
|
28
|
-
//! // Compute squared Euclidean distance
|
|
29
|
-
//! let l2sq_dist = i8::l2sq(a, b);
|
|
30
|
-
//!
|
|
31
|
-
//! // Optimize performance by flushing denormals
|
|
32
|
-
//! simsimd::capabilities::flush_denormals();
|
|
33
|
-
//! ```
|
|
34
|
-
//!
|
|
35
|
-
//! ## Mixed Precision Support
|
|
36
|
-
//!
|
|
37
|
-
//! ```rust
|
|
38
|
-
//! use simsimd::{SpatialSimilarity, f16, bf16};
|
|
39
|
-
//!
|
|
40
|
-
//! // Work with half-precision floats
|
|
41
|
-
//! let half_a: Vec<f16> = vec![1.0, 2.0, 3.0].iter().map(|&x| f16::from_f32(x)).collect();
|
|
42
|
-
//! let half_b: Vec<f16> = vec![4.0, 5.0, 6.0].iter().map(|&x| f16::from_f32(x)).collect();
|
|
43
|
-
//! let half_cos_dist = f16::cos(&half_a, &half_b);
|
|
44
|
-
//!
|
|
45
|
-
//! // Work with brain floats
|
|
46
|
-
//! let brain_a: Vec<bf16> = vec![1.0, 2.0, 3.0].iter().map(|&x| bf16::from_f32(x)).collect();
|
|
47
|
-
//! let brain_b: Vec<bf16> = vec![4.0, 5.0, 6.0].iter().map(|&x| bf16::from_f32(x)).collect();
|
|
48
|
-
//! let brain_cos_dist = bf16::cos(&brain_a, &brain_b);
|
|
49
|
-
//!
|
|
50
|
-
//! // Direct bit manipulation
|
|
51
|
-
//! let half = f16::from_f32(3.14);
|
|
52
|
-
//! let bits = half.0; // Access raw u16 representation
|
|
53
|
-
//! let reconstructed = f16(bits);
|
|
54
|
-
//! ```
|
|
55
|
-
//!
|
|
56
|
-
//! ## Traits
|
|
57
|
-
//!
|
|
58
|
-
//! The `SpatialSimilarity` trait covers following methods:
|
|
59
|
-
//!
|
|
60
|
-
//! - `cosine(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes cosine distance (1 - similarity) between two slices.
|
|
61
|
-
//! - `dot(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes dot product distance between two slices.
|
|
62
|
-
//! - `sqeuclidean(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes squared Euclidean distance between two slices.
|
|
63
|
-
//!
|
|
64
|
-
//! The `BinarySimilarity` trait covers following methods:
|
|
65
|
-
//!
|
|
66
|
-
//! - `hamming(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes Hamming distance between two slices.
|
|
67
|
-
//! - `jaccard(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes Jaccard distance between two slices.
|
|
68
|
-
//!
|
|
69
|
-
//! The `ProbabilitySimilarity` trait covers following methods:
|
|
70
|
-
//!
|
|
71
|
-
//! - `jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes Jensen-Shannon divergence between two slices.
|
|
72
|
-
//! - `kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance>`: Computes Kullback-Leibler divergence between two slices.
|
|
73
|
-
//!
|
|
74
|
-
#![allow(non_camel_case_types)]
|
|
75
|
-
#![cfg_attr(not(test), no_std)]
|
|
76
|
-
|
|
77
|
-
pub type Distance = f64;
|
|
78
|
-
pub type ComplexProduct = (f64, f64);
|
|
79
|
-
|
|
80
|
-
/// Compatibility function for pre 1.85 Rust versions lacking `f32::abs`.
|
|
81
|
-
#[inline(always)]
|
|
82
|
-
fn f32_abs_compat(x: f32) -> f32 {
|
|
83
|
-
f32::from_bits(x.to_bits() & 0x7FFF_FFFF)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
#[link(name = "simsimd")]
|
|
87
|
-
extern "C" {
|
|
88
|
-
|
|
89
|
-
fn simsimd_dot_i8(a: *const i8, b: *const i8, c: usize, d: *mut Distance);
|
|
90
|
-
fn simsimd_dot_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
91
|
-
fn simsimd_dot_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
92
|
-
fn simsimd_dot_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
93
|
-
fn simsimd_dot_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
94
|
-
|
|
95
|
-
fn simsimd_dot_f16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
96
|
-
fn simsimd_dot_bf16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
97
|
-
fn simsimd_dot_f32c(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
98
|
-
fn simsimd_dot_f64c(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
99
|
-
|
|
100
|
-
fn simsimd_vdot_f16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
101
|
-
fn simsimd_vdot_bf16c(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
102
|
-
fn simsimd_vdot_f32c(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
103
|
-
fn simsimd_vdot_f64c(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
104
|
-
|
|
105
|
-
fn simsimd_cos_i8(a: *const i8, b: *const i8, c: usize, d: *mut Distance);
|
|
106
|
-
fn simsimd_cos_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
107
|
-
fn simsimd_cos_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
108
|
-
fn simsimd_cos_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
109
|
-
fn simsimd_cos_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
110
|
-
|
|
111
|
-
fn simsimd_l2sq_i8(a: *const i8, b: *const i8, c: usize, d: *mut Distance);
|
|
112
|
-
fn simsimd_l2sq_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
113
|
-
fn simsimd_l2sq_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
114
|
-
fn simsimd_l2sq_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
115
|
-
fn simsimd_l2sq_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
116
|
-
|
|
117
|
-
fn simsimd_l2_i8(a: *const i8, b: *const i8, c: usize, d: *mut Distance);
|
|
118
|
-
fn simsimd_l2_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
119
|
-
fn simsimd_l2_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
120
|
-
fn simsimd_l2_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
121
|
-
fn simsimd_l2_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
122
|
-
|
|
123
|
-
fn simsimd_hamming_b8(a: *const u8, b: *const u8, c: usize, d: *mut Distance);
|
|
124
|
-
fn simsimd_jaccard_b8(a: *const u8, b: *const u8, c: usize, d: *mut Distance);
|
|
125
|
-
|
|
126
|
-
fn simsimd_js_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
127
|
-
fn simsimd_js_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
128
|
-
fn simsimd_js_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
129
|
-
fn simsimd_js_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
130
|
-
|
|
131
|
-
fn simsimd_kl_f16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
132
|
-
fn simsimd_kl_bf16(a: *const u16, b: *const u16, c: usize, d: *mut Distance);
|
|
133
|
-
fn simsimd_kl_f32(a: *const f32, b: *const f32, c: usize, d: *mut Distance);
|
|
134
|
-
fn simsimd_kl_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
|
|
135
|
-
|
|
136
|
-
fn simsimd_intersect_u16(
|
|
137
|
-
a: *const u16,
|
|
138
|
-
b: *const u16,
|
|
139
|
-
a_length: usize,
|
|
140
|
-
b_length: usize,
|
|
141
|
-
d: *mut Distance,
|
|
142
|
-
);
|
|
143
|
-
fn simsimd_intersect_u32(
|
|
144
|
-
a: *const u32,
|
|
145
|
-
b: *const u32,
|
|
146
|
-
a_length: usize,
|
|
147
|
-
b_length: usize,
|
|
148
|
-
d: *mut Distance,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
fn simsimd_uses_neon() -> i32;
|
|
152
|
-
fn simsimd_uses_neon_f16() -> i32;
|
|
153
|
-
fn simsimd_uses_neon_bf16() -> i32;
|
|
154
|
-
fn simsimd_uses_neon_i8() -> i32;
|
|
155
|
-
fn simsimd_uses_sve() -> i32;
|
|
156
|
-
fn simsimd_uses_sve_f16() -> i32;
|
|
157
|
-
fn simsimd_uses_sve_bf16() -> i32;
|
|
158
|
-
fn simsimd_uses_sve_i8() -> i32;
|
|
159
|
-
fn simsimd_uses_haswell() -> i32;
|
|
160
|
-
fn simsimd_uses_skylake() -> i32;
|
|
161
|
-
fn simsimd_uses_ice() -> i32;
|
|
162
|
-
fn simsimd_uses_genoa() -> i32;
|
|
163
|
-
fn simsimd_uses_sapphire() -> i32;
|
|
164
|
-
fn simsimd_uses_turin() -> i32;
|
|
165
|
-
fn simsimd_uses_sierra() -> i32;
|
|
166
|
-
|
|
167
|
-
fn simsimd_flush_denormals() -> i32;
|
|
168
|
-
fn simsimd_uses_dynamic_dispatch() -> i32;
|
|
169
|
-
|
|
170
|
-
fn simsimd_f32_to_f16(f32_value: f32, result_ptr: *mut u16);
|
|
171
|
-
fn simsimd_f16_to_f32(f16_ptr: *const u16) -> f32;
|
|
172
|
-
fn simsimd_f32_to_bf16(f32_value: f32, result_ptr: *mut u16);
|
|
173
|
-
fn simsimd_bf16_to_f32(bf16_ptr: *const u16) -> f32;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/// A half-precision (16-bit) floating point number.
|
|
177
|
-
///
|
|
178
|
-
/// This type represents IEEE 754 half-precision binary floating-point format.
|
|
179
|
-
/// It provides conversion methods to and from f32, and the underlying u16
|
|
180
|
-
/// representation is publicly accessible for direct bit manipulation.
|
|
181
|
-
///
|
|
182
|
-
/// # Examples
|
|
183
|
-
///
|
|
184
|
-
/// ```
|
|
185
|
-
/// use simsimd::f16;
|
|
186
|
-
///
|
|
187
|
-
/// // Create from f32
|
|
188
|
-
/// let half = f16::from_f32(3.14);
|
|
189
|
-
///
|
|
190
|
-
/// // Convert back to f32
|
|
191
|
-
/// let float = half.to_f32();
|
|
192
|
-
///
|
|
193
|
-
/// // Direct access to bits
|
|
194
|
-
/// let bits = half.0;
|
|
195
|
-
/// ```
|
|
196
|
-
#[repr(transparent)]
|
|
197
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
198
|
-
pub struct f16(pub u16);
|
|
199
|
-
|
|
200
|
-
impl f16 {
|
|
201
|
-
/// Positive zero.
|
|
202
|
-
pub const ZERO: Self = f16(0);
|
|
203
|
-
|
|
204
|
-
/// Positive one.
|
|
205
|
-
pub const ONE: Self = f16(0x3C00);
|
|
206
|
-
|
|
207
|
-
/// Negative one.
|
|
208
|
-
pub const NEG_ONE: Self = f16(0xBC00);
|
|
209
|
-
|
|
210
|
-
/// Converts an f32 to f16 representation.
|
|
211
|
-
///
|
|
212
|
-
/// # Examples
|
|
213
|
-
///
|
|
214
|
-
/// ```
|
|
215
|
-
/// use simsimd::f16;
|
|
216
|
-
/// let half = f16::from_f32(3.14159);
|
|
217
|
-
/// ```
|
|
218
|
-
#[inline(always)]
|
|
219
|
-
pub fn from_f32(value: f32) -> Self {
|
|
220
|
-
let mut result: u16 = 0;
|
|
221
|
-
unsafe { simsimd_f32_to_f16(value, &mut result) };
|
|
222
|
-
f16(result)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/// Converts the f16 to an f32.
|
|
226
|
-
///
|
|
227
|
-
/// # Examples
|
|
228
|
-
///
|
|
229
|
-
/// ```
|
|
230
|
-
/// use simsimd::f16;
|
|
231
|
-
/// let half = f16::from_f32(3.14159);
|
|
232
|
-
/// let float = half.to_f32();
|
|
233
|
-
/// ```
|
|
234
|
-
#[inline(always)]
|
|
235
|
-
pub fn to_f32(self) -> f32 {
|
|
236
|
-
unsafe { simsimd_f16_to_f32(&self.0) }
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/// Returns true if this value is NaN.
|
|
240
|
-
#[inline(always)]
|
|
241
|
-
pub fn is_nan(self) -> bool {
|
|
242
|
-
self.to_f32().is_nan()
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/// Returns true if this value is positive or negative infinity.
|
|
246
|
-
#[inline(always)]
|
|
247
|
-
pub fn is_infinite(self) -> bool {
|
|
248
|
-
self.to_f32().is_infinite()
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/// Returns true if this number is neither infinite nor NaN.
|
|
252
|
-
#[inline(always)]
|
|
253
|
-
pub fn is_finite(self) -> bool {
|
|
254
|
-
self.to_f32().is_finite()
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/// Returns the absolute value of self.
|
|
258
|
-
#[inline(always)]
|
|
259
|
-
pub fn abs(self) -> Self {
|
|
260
|
-
Self::from_f32(f32_abs_compat(self.to_f32()))
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/// Returns the largest integer less than or equal to a number.
|
|
264
|
-
///
|
|
265
|
-
/// This method is only available when the `std` feature is enabled.
|
|
266
|
-
#[cfg(feature = "std")]
|
|
267
|
-
#[inline(always)]
|
|
268
|
-
pub fn floor(self) -> Self {
|
|
269
|
-
Self::from_f32(self.to_f32().floor())
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/// Returns the smallest integer greater than or equal to a number.
|
|
273
|
-
///
|
|
274
|
-
/// This method is only available when the `std` feature is enabled.
|
|
275
|
-
#[cfg(feature = "std")]
|
|
276
|
-
#[inline(always)]
|
|
277
|
-
pub fn ceil(self) -> Self {
|
|
278
|
-
Self::from_f32(self.to_f32().ceil())
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/// Returns the nearest integer to a number. Round half-way cases away from 0.0.
|
|
282
|
-
///
|
|
283
|
-
/// This method is only available when the `std` feature is enabled.
|
|
284
|
-
#[cfg(feature = "std")]
|
|
285
|
-
#[inline(always)]
|
|
286
|
-
pub fn round(self) -> Self {
|
|
287
|
-
Self::from_f32(self.to_f32().round())
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
#[cfg(feature = "std")]
|
|
292
|
-
impl std::fmt::Display for f16 {
|
|
293
|
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
294
|
-
write!(f, "{}", self.to_f32())
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
impl core::ops::Add for f16 {
|
|
299
|
-
type Output = Self;
|
|
300
|
-
|
|
301
|
-
#[inline(always)]
|
|
302
|
-
fn add(self, rhs: Self) -> Self::Output {
|
|
303
|
-
Self::from_f32(self.to_f32() + rhs.to_f32())
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
impl core::ops::Sub for f16 {
|
|
308
|
-
type Output = Self;
|
|
309
|
-
|
|
310
|
-
#[inline(always)]
|
|
311
|
-
fn sub(self, rhs: Self) -> Self::Output {
|
|
312
|
-
Self::from_f32(self.to_f32() - rhs.to_f32())
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
impl core::ops::Mul for f16 {
|
|
317
|
-
type Output = Self;
|
|
318
|
-
|
|
319
|
-
#[inline(always)]
|
|
320
|
-
fn mul(self, rhs: Self) -> Self::Output {
|
|
321
|
-
Self::from_f32(self.to_f32() * rhs.to_f32())
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
impl core::ops::Div for f16 {
|
|
326
|
-
type Output = Self;
|
|
327
|
-
|
|
328
|
-
#[inline(always)]
|
|
329
|
-
fn div(self, rhs: Self) -> Self::Output {
|
|
330
|
-
Self::from_f32(self.to_f32() / rhs.to_f32())
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
impl core::ops::Neg for f16 {
|
|
335
|
-
type Output = Self;
|
|
336
|
-
|
|
337
|
-
#[inline(always)]
|
|
338
|
-
fn neg(self) -> Self::Output {
|
|
339
|
-
Self::from_f32(-self.to_f32())
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
impl core::cmp::PartialOrd for f16 {
|
|
344
|
-
#[inline(always)]
|
|
345
|
-
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
|
346
|
-
self.to_f32().partial_cmp(&other.to_f32())
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/// A brain floating point (bfloat16) number.
|
|
351
|
-
///
|
|
352
|
-
/// This type represents Google's bfloat16 format, which truncates IEEE 754
|
|
353
|
-
/// single-precision to 16 bits by keeping the exponent bits but reducing
|
|
354
|
-
/// the mantissa. This provides a wider range than f16 but lower precision.
|
|
355
|
-
///
|
|
356
|
-
/// # Examples
|
|
357
|
-
///
|
|
358
|
-
/// ```
|
|
359
|
-
/// use simsimd::bf16;
|
|
360
|
-
///
|
|
361
|
-
/// // Create from f32
|
|
362
|
-
/// let brain_half = bf16::from_f32(3.14);
|
|
363
|
-
///
|
|
364
|
-
/// // Convert back to f32
|
|
365
|
-
/// let float = brain_half.to_f32();
|
|
366
|
-
///
|
|
367
|
-
/// // Direct access to bits
|
|
368
|
-
/// let bits = brain_half.0;
|
|
369
|
-
/// ```
|
|
370
|
-
#[repr(transparent)]
|
|
371
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
372
|
-
pub struct bf16(pub u16);
|
|
373
|
-
|
|
374
|
-
impl bf16 {
|
|
375
|
-
/// Positive zero.
|
|
376
|
-
pub const ZERO: Self = bf16(0);
|
|
377
|
-
|
|
378
|
-
/// Positive one.
|
|
379
|
-
pub const ONE: Self = bf16(0x3F80);
|
|
380
|
-
|
|
381
|
-
/// Negative one.
|
|
382
|
-
pub const NEG_ONE: Self = bf16(0xBF80);
|
|
383
|
-
|
|
384
|
-
/// Converts an f32 to bf16 representation.
|
|
385
|
-
///
|
|
386
|
-
/// # Examples
|
|
387
|
-
///
|
|
388
|
-
/// ```
|
|
389
|
-
/// use simsimd::bf16;
|
|
390
|
-
/// let brain_half = bf16::from_f32(3.14159);
|
|
391
|
-
/// ```
|
|
392
|
-
#[inline(always)]
|
|
393
|
-
pub fn from_f32(value: f32) -> Self {
|
|
394
|
-
let mut result: u16 = 0;
|
|
395
|
-
unsafe { simsimd_f32_to_bf16(value, &mut result) };
|
|
396
|
-
bf16(result)
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/// Converts the bf16 to an f32.
|
|
400
|
-
///
|
|
401
|
-
/// # Examples
|
|
402
|
-
///
|
|
403
|
-
/// ```
|
|
404
|
-
/// use simsimd::bf16;
|
|
405
|
-
/// let brain_half = bf16::from_f32(3.14159);
|
|
406
|
-
/// let float = brain_half.to_f32();
|
|
407
|
-
/// ```
|
|
408
|
-
#[inline(always)]
|
|
409
|
-
pub fn to_f32(self) -> f32 {
|
|
410
|
-
unsafe { simsimd_bf16_to_f32(&self.0) }
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/// Returns true if this value is NaN.
|
|
414
|
-
#[inline(always)]
|
|
415
|
-
pub fn is_nan(self) -> bool {
|
|
416
|
-
self.to_f32().is_nan()
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/// Returns true if this value is positive or negative infinity.
|
|
420
|
-
#[inline(always)]
|
|
421
|
-
pub fn is_infinite(self) -> bool {
|
|
422
|
-
self.to_f32().is_infinite()
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/// Returns true if this number is neither infinite nor NaN.
|
|
426
|
-
#[inline(always)]
|
|
427
|
-
pub fn is_finite(self) -> bool {
|
|
428
|
-
self.to_f32().is_finite()
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/// Returns the absolute value of self.
|
|
432
|
-
#[inline(always)]
|
|
433
|
-
pub fn abs(self) -> Self {
|
|
434
|
-
Self::from_f32(f32_abs_compat(self.to_f32()))
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/// Returns the largest integer less than or equal to a number.
|
|
438
|
-
///
|
|
439
|
-
/// This method is only available when the `std` feature is enabled.
|
|
440
|
-
#[cfg(feature = "std")]
|
|
441
|
-
#[inline(always)]
|
|
442
|
-
pub fn floor(self) -> Self {
|
|
443
|
-
Self::from_f32(self.to_f32().floor())
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/// Returns the smallest integer greater than or equal to a number.
|
|
447
|
-
///
|
|
448
|
-
/// This method is only available when the `std` feature is enabled.
|
|
449
|
-
#[cfg(feature = "std")]
|
|
450
|
-
#[inline(always)]
|
|
451
|
-
pub fn ceil(self) -> Self {
|
|
452
|
-
Self::from_f32(self.to_f32().ceil())
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/// Returns the nearest integer to a number. Round half-way cases away from 0.0.
|
|
456
|
-
///
|
|
457
|
-
/// This method is only available when the `std` feature is enabled.
|
|
458
|
-
#[cfg(feature = "std")]
|
|
459
|
-
#[inline(always)]
|
|
460
|
-
pub fn round(self) -> Self {
|
|
461
|
-
Self::from_f32(self.to_f32().round())
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
#[cfg(feature = "std")]
|
|
466
|
-
impl std::fmt::Display for bf16 {
|
|
467
|
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
468
|
-
write!(f, "{}", self.to_f32())
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
impl core::ops::Add for bf16 {
|
|
473
|
-
type Output = Self;
|
|
474
|
-
|
|
475
|
-
#[inline(always)]
|
|
476
|
-
fn add(self, rhs: Self) -> Self::Output {
|
|
477
|
-
Self::from_f32(self.to_f32() + rhs.to_f32())
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
impl core::ops::Sub for bf16 {
|
|
482
|
-
type Output = Self;
|
|
483
|
-
|
|
484
|
-
#[inline(always)]
|
|
485
|
-
fn sub(self, rhs: Self) -> Self::Output {
|
|
486
|
-
Self::from_f32(self.to_f32() - rhs.to_f32())
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
impl core::ops::Mul for bf16 {
|
|
491
|
-
type Output = Self;
|
|
492
|
-
|
|
493
|
-
#[inline(always)]
|
|
494
|
-
fn mul(self, rhs: Self) -> Self::Output {
|
|
495
|
-
Self::from_f32(self.to_f32() * rhs.to_f32())
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
impl core::ops::Div for bf16 {
|
|
500
|
-
type Output = Self;
|
|
501
|
-
|
|
502
|
-
#[inline(always)]
|
|
503
|
-
fn div(self, rhs: Self) -> Self::Output {
|
|
504
|
-
Self::from_f32(self.to_f32() / rhs.to_f32())
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
impl core::ops::Neg for bf16 {
|
|
509
|
-
type Output = Self;
|
|
510
|
-
|
|
511
|
-
#[inline(always)]
|
|
512
|
-
fn neg(self) -> Self::Output {
|
|
513
|
-
Self::from_f32(-self.to_f32())
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
impl core::cmp::PartialOrd for bf16 {
|
|
518
|
-
#[inline(always)]
|
|
519
|
-
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
|
520
|
-
self.to_f32().partial_cmp(&other.to_f32())
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/// The `capabilities` module provides functions for detecting the hardware features
|
|
525
|
-
/// available on the current system.
|
|
526
|
-
pub mod capabilities {
|
|
527
|
-
|
|
528
|
-
pub fn uses_neon() -> bool {
|
|
529
|
-
unsafe { crate::simsimd_uses_neon() != 0 }
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
pub fn uses_neon_f16() -> bool {
|
|
533
|
-
unsafe { crate::simsimd_uses_neon_f16() != 0 }
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
pub fn uses_neon_bf16() -> bool {
|
|
537
|
-
unsafe { crate::simsimd_uses_neon_bf16() != 0 }
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
pub fn uses_neon_i8() -> bool {
|
|
541
|
-
unsafe { crate::simsimd_uses_neon_i8() != 0 }
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
pub fn uses_sve() -> bool {
|
|
545
|
-
unsafe { crate::simsimd_uses_sve() != 0 }
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
pub fn uses_sve_f16() -> bool {
|
|
549
|
-
unsafe { crate::simsimd_uses_sve_f16() != 0 }
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
pub fn uses_sve_bf16() -> bool {
|
|
553
|
-
unsafe { crate::simsimd_uses_sve_bf16() != 0 }
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
pub fn uses_sve_i8() -> bool {
|
|
557
|
-
unsafe { crate::simsimd_uses_sve_i8() != 0 }
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
pub fn uses_haswell() -> bool {
|
|
561
|
-
unsafe { crate::simsimd_uses_haswell() != 0 }
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
pub fn uses_skylake() -> bool {
|
|
565
|
-
unsafe { crate::simsimd_uses_skylake() != 0 }
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
pub fn uses_ice() -> bool {
|
|
569
|
-
unsafe { crate::simsimd_uses_ice() != 0 }
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
pub fn uses_genoa() -> bool {
|
|
573
|
-
unsafe { crate::simsimd_uses_genoa() != 0 }
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
pub fn uses_sapphire() -> bool {
|
|
577
|
-
unsafe { crate::simsimd_uses_sapphire() != 0 }
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
pub fn uses_turin() -> bool {
|
|
581
|
-
unsafe { crate::simsimd_uses_turin() != 0 }
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
pub fn uses_sierra() -> bool {
|
|
585
|
-
unsafe { crate::simsimd_uses_sierra() != 0 }
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
/// Flushes denormalized numbers to zero on the current CPU architecture.
|
|
589
|
-
///
|
|
590
|
-
/// This function should be called on each thread before any SIMD operations
|
|
591
|
-
/// to avoid performance penalties. When facing denormalized values,
|
|
592
|
-
/// Fused-Multiply-Add (FMA) operations can be up to 30x slower.
|
|
593
|
-
///
|
|
594
|
-
/// # Returns
|
|
595
|
-
///
|
|
596
|
-
/// Returns `true` if the operation was successful, `false` otherwise.
|
|
597
|
-
pub fn flush_denormals() -> bool {
|
|
598
|
-
unsafe { crate::simsimd_flush_denormals() != 0 }
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
/// Checks if the library is using dynamic dispatch for function selection.
|
|
602
|
-
///
|
|
603
|
-
/// # Returns
|
|
604
|
-
///
|
|
605
|
-
/// Returns `true` when the C backend is compiled with dynamic dispatch
|
|
606
|
-
/// (default for this crate via `build.rs`), otherwise `false`.
|
|
607
|
-
pub fn uses_dynamic_dispatch() -> bool {
|
|
608
|
-
unsafe { crate::simsimd_uses_dynamic_dispatch() != 0 }
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
/// `SpatialSimilarity` provides a set of trait methods for computing similarity
|
|
613
|
-
/// or distance between spatial data vectors in SIMD (Single Instruction, Multiple Data) context.
|
|
614
|
-
/// These methods can be used to calculate metrics like cosine distance, dot product,
|
|
615
|
-
/// and squared Euclidean distance between two slices of data.
|
|
616
|
-
///
|
|
617
|
-
/// Each method takes two slices of data (a and b) and returns an Option<Distance>.
|
|
618
|
-
/// The result is `None` if the slices are not of the same length, as these operations
|
|
619
|
-
/// require one-to-one correspondence between the elements of the slices.
|
|
620
|
-
/// Otherwise, it returns the computed similarity or distance as `Some(f64)`.
|
|
621
|
-
/// Convenience methods like `cosine`/`sqeuclidean` delegate to the core methods
|
|
622
|
-
/// `cos`/`l2sq` implemented by this trait.
|
|
623
|
-
pub trait SpatialSimilarity
|
|
624
|
-
where
|
|
625
|
-
Self: Sized,
|
|
626
|
-
{
|
|
627
|
-
/// Computes the cosine distance between two slices.
|
|
628
|
-
/// The cosine distance is 1 minus the cosine similarity between two non-zero vectors
|
|
629
|
-
/// of an dot product space that measures the cosine of the angle between them.
|
|
630
|
-
fn cos(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
631
|
-
|
|
632
|
-
/// Computes the inner product (also known as dot product) between two slices.
|
|
633
|
-
/// The dot product is the sum of the products of the corresponding entries
|
|
634
|
-
/// of the two sequences of numbers.
|
|
635
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
636
|
-
|
|
637
|
-
/// Computes the squared Euclidean distance between two slices.
|
|
638
|
-
/// The squared Euclidean distance is the sum of the squared differences
|
|
639
|
-
/// between corresponding elements of the two slices.
|
|
640
|
-
fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
641
|
-
|
|
642
|
-
/// Computes the Euclidean distance between two slices.
|
|
643
|
-
/// The Euclidean distance is the square root of
|
|
644
|
-
// sum of the squared differences between corresponding
|
|
645
|
-
/// elements of the two slices.
|
|
646
|
-
fn l2(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
647
|
-
|
|
648
|
-
/// Computes the squared Euclidean distance between two slices.
|
|
649
|
-
/// The squared Euclidean distance is the sum of the squared differences
|
|
650
|
-
/// between corresponding elements of the two slices.
|
|
651
|
-
fn sqeuclidean(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
652
|
-
SpatialSimilarity::l2sq(a, b)
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
/// Computes the Euclidean distance between two slices.
|
|
656
|
-
/// The Euclidean distance is the square root of the
|
|
657
|
-
/// sum of the squared differences between corresponding
|
|
658
|
-
/// elements of the two slices.
|
|
659
|
-
fn euclidean(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
660
|
-
SpatialSimilarity::l2(a, b)
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/// Computes the squared Euclidean distance between two slices.
|
|
664
|
-
/// The squared Euclidean distance is the sum of the squared differences
|
|
665
|
-
/// between corresponding elements of the two slices.
|
|
666
|
-
fn inner(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
667
|
-
SpatialSimilarity::dot(a, b)
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
/// Computes the cosine distance between two slices.
|
|
671
|
-
/// The cosine distance is 1 minus the cosine similarity between two non-zero vectors
|
|
672
|
-
/// of an dot product space that measures the cosine of the angle between them.
|
|
673
|
-
fn cosine(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
674
|
-
SpatialSimilarity::cos(a, b)
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/// `BinarySimilarity` provides trait methods for computing similarity metrics
|
|
679
|
-
/// that are commonly used with binary data vectors, such as Hamming distance
|
|
680
|
-
/// and Jaccard index.
|
|
681
|
-
///
|
|
682
|
-
/// The methods accept two slices of binary data and return an Option<Distance>
|
|
683
|
-
/// indicating the computed similarity or distance, with `None` returned if the
|
|
684
|
-
/// slices differ in length.
|
|
685
|
-
pub trait BinarySimilarity
|
|
686
|
-
where
|
|
687
|
-
Self: Sized,
|
|
688
|
-
{
|
|
689
|
-
/// Computes the Hamming distance between two binary data slices.
|
|
690
|
-
/// The Hamming distance between two strings of equal length is the number of
|
|
691
|
-
/// bits at which the corresponding values are different.
|
|
692
|
-
fn hamming(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
693
|
-
|
|
694
|
-
/// Computes the Jaccard index between two bitsets represented by binary data slices.
|
|
695
|
-
/// The Jaccard index, also known as the Jaccard similarity coefficient, is a statistic
|
|
696
|
-
/// used for gauging the similarity and diversity of sample sets.
|
|
697
|
-
fn jaccard(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
/// `ProbabilitySimilarity` provides trait methods for computing similarity or divergence
|
|
701
|
-
/// measures between probability distributions, such as the Jensen-Shannon divergence
|
|
702
|
-
/// and the Kullback-Leibler divergence.
|
|
703
|
-
///
|
|
704
|
-
/// These methods are particularly useful in contexts such as information theory and
|
|
705
|
-
/// machine learning, where one often needs to measure how one probability distribution
|
|
706
|
-
/// differs from a second, reference probability distribution.
|
|
707
|
-
pub trait ProbabilitySimilarity
|
|
708
|
-
where
|
|
709
|
-
Self: Sized,
|
|
710
|
-
{
|
|
711
|
-
/// Computes the Jensen-Shannon divergence between two probability distributions.
|
|
712
|
-
/// The Jensen-Shannon divergence is a method of measuring the similarity between
|
|
713
|
-
/// two probability distributions. It is based on the Kullback-Leibler divergence,
|
|
714
|
-
/// but is symmetric and always has a finite value.
|
|
715
|
-
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
716
|
-
|
|
717
|
-
/// Computes the Kullback-Leibler divergence between two probability distributions.
|
|
718
|
-
/// The Kullback-Leibler divergence is a measure of how one probability distribution
|
|
719
|
-
/// diverges from a second, expected probability distribution.
|
|
720
|
-
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
/// `ComplexProducts` provides trait methods for computing products between
|
|
724
|
-
/// complex number vectors. This includes standard and Hermitian dot products.
|
|
725
|
-
pub trait ComplexProducts
|
|
726
|
-
where
|
|
727
|
-
Self: Sized,
|
|
728
|
-
{
|
|
729
|
-
/// Computes the dot product between two complex number vectors.
|
|
730
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct>;
|
|
731
|
-
|
|
732
|
-
/// Computes the Hermitian dot product (conjugate dot product) between two complex number vectors.
|
|
733
|
-
fn vdot(a: &[Self], b: &[Self]) -> Option<ComplexProduct>;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
/// `Sparse` provides trait methods for sparse vectors.
|
|
737
|
-
pub trait Sparse
|
|
738
|
-
where
|
|
739
|
-
Self: Sized,
|
|
740
|
-
{
|
|
741
|
-
/// Computes the number of common elements between two sparse vectors.
|
|
742
|
-
/// both vectors must be sorted in ascending order.
|
|
743
|
-
fn intersect(a: &[Self], b: &[Self]) -> Option<Distance>;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
impl BinarySimilarity for u8 {
|
|
747
|
-
fn hamming(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
748
|
-
if a.len() != b.len() {
|
|
749
|
-
return None;
|
|
750
|
-
}
|
|
751
|
-
let mut distance_value: Distance = 0.0;
|
|
752
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
753
|
-
unsafe { simsimd_hamming_b8(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
754
|
-
Some(distance_value)
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
fn jaccard(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
758
|
-
if a.len() != b.len() {
|
|
759
|
-
return None;
|
|
760
|
-
}
|
|
761
|
-
let mut distance_value: Distance = 0.0;
|
|
762
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
763
|
-
unsafe { simsimd_jaccard_b8(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
764
|
-
Some(distance_value)
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
impl SpatialSimilarity for i8 {
|
|
769
|
-
fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
770
|
-
if a.len() != b.len() {
|
|
771
|
-
return None;
|
|
772
|
-
}
|
|
773
|
-
let mut distance_value: Distance = 0.0;
|
|
774
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
775
|
-
unsafe { simsimd_cos_i8(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
776
|
-
Some(distance_value)
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
780
|
-
if a.len() != b.len() {
|
|
781
|
-
return None;
|
|
782
|
-
}
|
|
783
|
-
let mut distance_value: Distance = 0.0;
|
|
784
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
785
|
-
unsafe { simsimd_dot_i8(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
786
|
-
Some(distance_value)
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
790
|
-
if a.len() != b.len() {
|
|
791
|
-
return None;
|
|
792
|
-
}
|
|
793
|
-
let mut distance_value: Distance = 0.0;
|
|
794
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
795
|
-
unsafe { simsimd_l2sq_i8(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
796
|
-
Some(distance_value)
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
fn l2(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
800
|
-
if a.len() != b.len() {
|
|
801
|
-
return None;
|
|
802
|
-
}
|
|
803
|
-
let mut distance_value: Distance = 0.0;
|
|
804
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
805
|
-
unsafe { simsimd_l2_i8(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
806
|
-
Some(distance_value)
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
impl Sparse for u16 {
|
|
811
|
-
fn intersect(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
812
|
-
let mut distance_value: Distance = 0.0;
|
|
813
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
814
|
-
unsafe { simsimd_intersect_u16(a.as_ptr(), b.as_ptr(), a.len(), b.len(), distance_ptr) };
|
|
815
|
-
Some(distance_value)
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
impl Sparse for u32 {
|
|
820
|
-
fn intersect(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
821
|
-
let mut distance_value: Distance = 0.0;
|
|
822
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
823
|
-
unsafe { simsimd_intersect_u32(a.as_ptr(), b.as_ptr(), a.len(), b.len(), distance_ptr) };
|
|
824
|
-
Some(distance_value)
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
impl SpatialSimilarity for f16 {
|
|
829
|
-
fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
830
|
-
if a.len() != b.len() {
|
|
831
|
-
return None;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
835
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
836
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
837
|
-
let mut distance_value: Distance = 0.0;
|
|
838
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
839
|
-
unsafe { simsimd_cos_f16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
840
|
-
Some(distance_value)
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
844
|
-
if a.len() != b.len() {
|
|
845
|
-
return None;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
849
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
850
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
851
|
-
let mut distance_value: Distance = 0.0;
|
|
852
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
853
|
-
unsafe { simsimd_dot_f16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
854
|
-
Some(distance_value)
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
858
|
-
if a.len() != b.len() {
|
|
859
|
-
return None;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
863
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
864
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
865
|
-
let mut distance_value: Distance = 0.0;
|
|
866
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
867
|
-
unsafe { simsimd_l2sq_f16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
868
|
-
Some(distance_value)
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
fn l2(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
872
|
-
if a.len() != b.len() {
|
|
873
|
-
return None;
|
|
874
|
-
}
|
|
875
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
876
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
877
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
878
|
-
let mut distance_value: Distance = 0.0;
|
|
879
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
880
|
-
unsafe { simsimd_l2_f16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
881
|
-
Some(distance_value)
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
impl SpatialSimilarity for bf16 {
|
|
886
|
-
fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
887
|
-
if a.len() != b.len() {
|
|
888
|
-
return None;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
892
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
893
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
894
|
-
let mut distance_value: Distance = 0.0;
|
|
895
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
896
|
-
unsafe { simsimd_cos_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
897
|
-
Some(distance_value)
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
901
|
-
if a.len() != b.len() {
|
|
902
|
-
return None;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
906
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
907
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
908
|
-
let mut distance_value: Distance = 0.0;
|
|
909
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
910
|
-
unsafe { simsimd_dot_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
911
|
-
Some(distance_value)
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
915
|
-
if a.len() != b.len() {
|
|
916
|
-
return None;
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
920
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
921
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
922
|
-
let mut distance_value: Distance = 0.0;
|
|
923
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
924
|
-
unsafe { simsimd_l2sq_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
925
|
-
Some(distance_value)
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
fn l2(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
929
|
-
if a.len() != b.len() {
|
|
930
|
-
return None;
|
|
931
|
-
}
|
|
932
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
933
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
934
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
935
|
-
let mut distance_value: Distance = 0.0;
|
|
936
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
937
|
-
unsafe { simsimd_l2_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
938
|
-
Some(distance_value)
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
impl SpatialSimilarity for f32 {
|
|
943
|
-
fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
944
|
-
if a.len() != b.len() {
|
|
945
|
-
return None;
|
|
946
|
-
}
|
|
947
|
-
let mut distance_value: Distance = 0.0;
|
|
948
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
949
|
-
unsafe { simsimd_cos_f32(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
950
|
-
Some(distance_value)
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
954
|
-
if a.len() != b.len() {
|
|
955
|
-
return None;
|
|
956
|
-
}
|
|
957
|
-
let mut distance_value: Distance = 0.0;
|
|
958
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
959
|
-
unsafe { simsimd_dot_f32(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
960
|
-
Some(distance_value)
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
964
|
-
if a.len() != b.len() {
|
|
965
|
-
return None;
|
|
966
|
-
}
|
|
967
|
-
let mut distance_value: Distance = 0.0;
|
|
968
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
969
|
-
unsafe { simsimd_l2sq_f32(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
970
|
-
Some(distance_value)
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
fn l2(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
974
|
-
if a.len() != b.len() {
|
|
975
|
-
return None;
|
|
976
|
-
}
|
|
977
|
-
let mut distance_value: Distance = 0.0;
|
|
978
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
979
|
-
unsafe { simsimd_l2_f32(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
980
|
-
Some(distance_value)
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
impl SpatialSimilarity for f64 {
|
|
985
|
-
fn cos(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
986
|
-
if a.len() != b.len() {
|
|
987
|
-
return None;
|
|
988
|
-
}
|
|
989
|
-
let mut distance_value: Distance = 0.0;
|
|
990
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
991
|
-
unsafe { simsimd_cos_f64(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
992
|
-
Some(distance_value)
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
996
|
-
if a.len() != b.len() {
|
|
997
|
-
return None;
|
|
998
|
-
}
|
|
999
|
-
let mut distance_value: Distance = 0.0;
|
|
1000
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1001
|
-
unsafe { simsimd_dot_f64(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1002
|
-
Some(distance_value)
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
fn l2sq(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1006
|
-
if a.len() != b.len() {
|
|
1007
|
-
return None;
|
|
1008
|
-
}
|
|
1009
|
-
let mut distance_value: Distance = 0.0;
|
|
1010
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1011
|
-
unsafe { simsimd_l2sq_f64(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1012
|
-
Some(distance_value)
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
fn l2(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1016
|
-
if a.len() != b.len() {
|
|
1017
|
-
return None;
|
|
1018
|
-
}
|
|
1019
|
-
let mut distance_value: Distance = 0.0;
|
|
1020
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1021
|
-
unsafe { simsimd_l2_f64(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1022
|
-
Some(distance_value)
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
impl ProbabilitySimilarity for f16 {
|
|
1027
|
-
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1028
|
-
if a.len() != b.len() {
|
|
1029
|
-
return None;
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
1033
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1034
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1035
|
-
let mut distance_value: Distance = 0.0;
|
|
1036
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1037
|
-
unsafe { simsimd_js_f16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
1038
|
-
Some(distance_value)
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1042
|
-
if a.len() != b.len() {
|
|
1043
|
-
return None;
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
1047
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1048
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1049
|
-
let mut distance_value: Distance = 0.0;
|
|
1050
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1051
|
-
unsafe { simsimd_kl_f16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
1052
|
-
Some(distance_value)
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
impl ProbabilitySimilarity for bf16 {
|
|
1057
|
-
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1058
|
-
if a.len() != b.len() {
|
|
1059
|
-
return None;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
1063
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1064
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1065
|
-
let mut distance_value: Distance = 0.0;
|
|
1066
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1067
|
-
unsafe { simsimd_js_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
1068
|
-
Some(distance_value)
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1072
|
-
if a.len() != b.len() {
|
|
1073
|
-
return None;
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
1077
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1078
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1079
|
-
let mut distance_value: Distance = 0.0;
|
|
1080
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1081
|
-
unsafe { simsimd_kl_bf16(a_ptr, b_ptr, a.len(), distance_ptr) };
|
|
1082
|
-
Some(distance_value)
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
impl ProbabilitySimilarity for f32 {
|
|
1087
|
-
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1088
|
-
if a.len() != b.len() {
|
|
1089
|
-
return None;
|
|
1090
|
-
}
|
|
1091
|
-
let mut distance_value: Distance = 0.0;
|
|
1092
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1093
|
-
unsafe { simsimd_js_f32(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1094
|
-
Some(distance_value)
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1098
|
-
if a.len() != b.len() {
|
|
1099
|
-
return None;
|
|
1100
|
-
}
|
|
1101
|
-
let mut distance_value: Distance = 0.0;
|
|
1102
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1103
|
-
unsafe { simsimd_kl_f32(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1104
|
-
Some(distance_value)
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
impl ProbabilitySimilarity for f64 {
|
|
1109
|
-
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1110
|
-
if a.len() != b.len() {
|
|
1111
|
-
return None;
|
|
1112
|
-
}
|
|
1113
|
-
let mut distance_value: Distance = 0.0;
|
|
1114
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1115
|
-
unsafe { simsimd_js_f64(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1116
|
-
Some(distance_value)
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Distance> {
|
|
1120
|
-
if a.len() != b.len() {
|
|
1121
|
-
return None;
|
|
1122
|
-
}
|
|
1123
|
-
let mut distance_value: Distance = 0.0;
|
|
1124
|
-
let distance_ptr: *mut Distance = &mut distance_value as *mut Distance;
|
|
1125
|
-
unsafe { simsimd_kl_f64(a.as_ptr(), b.as_ptr(), a.len(), distance_ptr) };
|
|
1126
|
-
Some(distance_value)
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
impl ComplexProducts for f16 {
|
|
1131
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1132
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1133
|
-
return None;
|
|
1134
|
-
}
|
|
1135
|
-
// Prepare the output array where the real and imaginary parts will be stored
|
|
1136
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1137
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1138
|
-
// Explicitly cast `*const f16` to `*const u16`
|
|
1139
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1140
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1141
|
-
// The C function expects the number of complex pairs, not the total number of f16 elements
|
|
1142
|
-
unsafe { simsimd_dot_f16c(a_ptr, b_ptr, a.len() / 2, product_ptr) };
|
|
1143
|
-
Some((product[0], product[1]))
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
fn vdot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1147
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1148
|
-
return None;
|
|
1149
|
-
}
|
|
1150
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1151
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1152
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1153
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1154
|
-
// The C function expects the number of complex pairs, not the total number of f16 elements
|
|
1155
|
-
unsafe { simsimd_vdot_f16c(a_ptr, b_ptr, a.len() / 2, product_ptr) };
|
|
1156
|
-
Some((product[0], product[1]))
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
impl ComplexProducts for bf16 {
|
|
1161
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1162
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1163
|
-
return None;
|
|
1164
|
-
}
|
|
1165
|
-
// Prepare the output array where the real and imaginary parts will be stored
|
|
1166
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1167
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1168
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
1169
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1170
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1171
|
-
// The C function expects the number of complex pairs, not the total number of bf16 elements
|
|
1172
|
-
unsafe { simsimd_dot_bf16c(a_ptr, b_ptr, a.len() / 2, product_ptr) };
|
|
1173
|
-
Some((product[0], product[1]))
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
fn vdot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1177
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1178
|
-
return None;
|
|
1179
|
-
}
|
|
1180
|
-
// Prepare the output array where the real and imaginary parts will be stored
|
|
1181
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1182
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1183
|
-
// Explicitly cast `*const bf16` to `*const u16`
|
|
1184
|
-
let a_ptr = a.as_ptr() as *const u16;
|
|
1185
|
-
let b_ptr = b.as_ptr() as *const u16;
|
|
1186
|
-
// The C function expects the number of complex pairs, not the total number of bf16 elements
|
|
1187
|
-
unsafe { simsimd_vdot_bf16c(a_ptr, b_ptr, a.len() / 2, product_ptr) };
|
|
1188
|
-
Some((product[0], product[1]))
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
impl ComplexProducts for f32 {
|
|
1193
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1194
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1195
|
-
return None;
|
|
1196
|
-
}
|
|
1197
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1198
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1199
|
-
// The C function expects the number of complex pairs, not the total number of floats
|
|
1200
|
-
unsafe { simsimd_dot_f32c(a.as_ptr(), b.as_ptr(), a.len() / 2, product_ptr) };
|
|
1201
|
-
Some((product[0], product[1]))
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
fn vdot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1205
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1206
|
-
return None;
|
|
1207
|
-
}
|
|
1208
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1209
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1210
|
-
// The C function expects the number of complex pairs, not the total number of floats
|
|
1211
|
-
unsafe { simsimd_vdot_f32c(a.as_ptr(), b.as_ptr(), a.len() / 2, product_ptr) };
|
|
1212
|
-
Some((product[0], product[1]))
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
impl ComplexProducts for f64 {
|
|
1217
|
-
fn dot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1218
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1219
|
-
return None;
|
|
1220
|
-
}
|
|
1221
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1222
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1223
|
-
// The C function expects the number of complex pairs, not the total number of floats
|
|
1224
|
-
unsafe { simsimd_dot_f64c(a.as_ptr(), b.as_ptr(), a.len() / 2, product_ptr) };
|
|
1225
|
-
Some((product[0], product[1]))
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
fn vdot(a: &[Self], b: &[Self]) -> Option<ComplexProduct> {
|
|
1229
|
-
if a.len() != b.len() || a.len() % 2 != 0 {
|
|
1230
|
-
return None;
|
|
1231
|
-
}
|
|
1232
|
-
let mut product: [Distance; 2] = [0.0, 0.0];
|
|
1233
|
-
let product_ptr: *mut Distance = &mut product[0] as *mut _;
|
|
1234
|
-
// The C function expects the number of complex pairs, not the total number of floats
|
|
1235
|
-
unsafe { simsimd_vdot_f64c(a.as_ptr(), b.as_ptr(), a.len() / 2, product_ptr) };
|
|
1236
|
-
Some((product[0], product[1]))
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
#[cfg(test)]
|
|
1241
|
-
mod tests {
|
|
1242
|
-
use super::*;
|
|
1243
|
-
use half::bf16 as HalfBF16;
|
|
1244
|
-
use half::f16 as HalfF16;
|
|
1245
|
-
|
|
1246
|
-
#[test]
|
|
1247
|
-
fn hardware_features_detection() {
|
|
1248
|
-
let uses_arm = capabilities::uses_neon() || capabilities::uses_sve();
|
|
1249
|
-
let uses_x86 = capabilities::uses_haswell()
|
|
1250
|
-
|| capabilities::uses_skylake()
|
|
1251
|
-
|| capabilities::uses_ice()
|
|
1252
|
-
|| capabilities::uses_genoa()
|
|
1253
|
-
|| capabilities::uses_sapphire()
|
|
1254
|
-
|| capabilities::uses_turin();
|
|
1255
|
-
|
|
1256
|
-
// The CPU can't simultaneously support ARM and x86 SIMD extensions
|
|
1257
|
-
if uses_arm {
|
|
1258
|
-
assert!(!uses_x86);
|
|
1259
|
-
}
|
|
1260
|
-
if uses_x86 {
|
|
1261
|
-
assert!(!uses_arm);
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
println!("- uses_neon: {}", capabilities::uses_neon());
|
|
1265
|
-
println!("- uses_neon_f16: {}", capabilities::uses_neon_f16());
|
|
1266
|
-
println!("- uses_neon_bf16: {}", capabilities::uses_neon_bf16());
|
|
1267
|
-
println!("- uses_neon_i8: {}", capabilities::uses_neon_i8());
|
|
1268
|
-
println!("- uses_sve: {}", capabilities::uses_sve());
|
|
1269
|
-
println!("- uses_sve_f16: {}", capabilities::uses_sve_f16());
|
|
1270
|
-
println!("- uses_sve_bf16: {}", capabilities::uses_sve_bf16());
|
|
1271
|
-
println!("- uses_sve_i8: {}", capabilities::uses_sve_i8());
|
|
1272
|
-
println!("- uses_haswell: {}", capabilities::uses_haswell());
|
|
1273
|
-
println!("- uses_skylake: {}", capabilities::uses_skylake());
|
|
1274
|
-
println!("- uses_ice: {}", capabilities::uses_ice());
|
|
1275
|
-
println!("- uses_genoa: {}", capabilities::uses_genoa());
|
|
1276
|
-
println!("- uses_sapphire: {}", capabilities::uses_sapphire());
|
|
1277
|
-
println!("- uses_turin: {}", capabilities::uses_turin());
|
|
1278
|
-
println!("- uses_sierra: {}", capabilities::uses_sierra());
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
//
|
|
1282
|
-
fn assert_almost_equal(left: Distance, right: Distance, tolerance: Distance) {
|
|
1283
|
-
let lower = right - tolerance;
|
|
1284
|
-
let upper = right + tolerance;
|
|
1285
|
-
|
|
1286
|
-
assert!(left >= lower && left <= upper);
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
#[test]
|
|
1290
|
-
fn cos_i8() {
|
|
1291
|
-
let a = &[3, 97, 127];
|
|
1292
|
-
let b = &[3, 97, 127];
|
|
1293
|
-
|
|
1294
|
-
if let Some(result) = SpatialSimilarity::cosine(a, b) {
|
|
1295
|
-
assert_almost_equal(0.00012027938, result, 0.01);
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
#[test]
|
|
1300
|
-
fn cos_f32() {
|
|
1301
|
-
let a = &[1.0, 2.0, 3.0];
|
|
1302
|
-
let b = &[4.0, 5.0, 6.0];
|
|
1303
|
-
|
|
1304
|
-
if let Some(result) = SpatialSimilarity::cosine(a, b) {
|
|
1305
|
-
assert_almost_equal(0.025, result, 0.01);
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
#[test]
|
|
1310
|
-
fn dot_i8() {
|
|
1311
|
-
let a = &[1, 2, 3];
|
|
1312
|
-
let b = &[4, 5, 6];
|
|
1313
|
-
|
|
1314
|
-
if let Some(result) = SpatialSimilarity::dot(a, b) {
|
|
1315
|
-
assert_almost_equal(32.0, result, 0.01);
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
#[test]
|
|
1320
|
-
fn dot_f32() {
|
|
1321
|
-
let a = &[1.0, 2.0, 3.0];
|
|
1322
|
-
let b = &[4.0, 5.0, 6.0];
|
|
1323
|
-
|
|
1324
|
-
if let Some(result) = SpatialSimilarity::dot(a, b) {
|
|
1325
|
-
assert_almost_equal(32.0, result, 0.01);
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
#[test]
|
|
1330
|
-
fn dot_f32_complex() {
|
|
1331
|
-
// Let's consider these as complex numbers where every pair is (real, imaginary)
|
|
1332
|
-
let a: &[f32; 4] = &[1.0, 2.0, 3.0, 4.0]; // Represents two complex numbers: 1+2i, 3+4i
|
|
1333
|
-
let b: &[f32; 4] = &[5.0, 6.0, 7.0, 8.0]; // Represents two complex numbers: 5+6i, 7+8i
|
|
1334
|
-
|
|
1335
|
-
if let Some((real, imag)) = ComplexProducts::dot(a, b) {
|
|
1336
|
-
assert_almost_equal(-18.0, real, 0.01);
|
|
1337
|
-
assert_almost_equal(68.0, imag, 0.01);
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
#[test]
|
|
1342
|
-
fn vdot_f32_complex() {
|
|
1343
|
-
// Here we're assuming a similar setup to the previous test, but for the Hermitian (conjugate) dot product
|
|
1344
|
-
let a: &[f32; 4] = &[1.0, 2.0, 3.0, 4.0]; // Represents two complex numbers: 1+2i, 3+4i
|
|
1345
|
-
let b: &[f32; 4] = &[5.0, 6.0, 7.0, 8.0]; // Represents two complex numbers: 5+6i, 7+8i
|
|
1346
|
-
|
|
1347
|
-
if let Some((real, imag)) = ComplexProducts::vdot(a, b) {
|
|
1348
|
-
assert_almost_equal(70.0, real, 0.01);
|
|
1349
|
-
assert_almost_equal(-8.0, imag, 0.01);
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
#[test]
|
|
1354
|
-
fn l2sq_i8() {
|
|
1355
|
-
let a = &[1, 2, 3];
|
|
1356
|
-
let b = &[4, 5, 6];
|
|
1357
|
-
|
|
1358
|
-
if let Some(result) = SpatialSimilarity::sqeuclidean(a, b) {
|
|
1359
|
-
assert_almost_equal(27.0, result, 0.01);
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
#[test]
|
|
1364
|
-
fn l2sq_f32() {
|
|
1365
|
-
let a = &[1.0, 2.0, 3.0];
|
|
1366
|
-
let b = &[4.0, 5.0, 6.0];
|
|
1367
|
-
|
|
1368
|
-
if let Some(result) = SpatialSimilarity::sqeuclidean(a, b) {
|
|
1369
|
-
assert_almost_equal(27.0, result, 0.01);
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
#[test]
|
|
1374
|
-
fn l2_f32() {
|
|
1375
|
-
let a: &[f32; 3] = &[1.0, 2.0, 3.0];
|
|
1376
|
-
let b: &[f32; 3] = &[4.0, 5.0, 6.0];
|
|
1377
|
-
if let Some(result) = SpatialSimilarity::euclidean(a, b) {
|
|
1378
|
-
assert_almost_equal(5.2, result, 0.01);
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1382
|
-
#[test]
|
|
1383
|
-
fn l2_f64() {
|
|
1384
|
-
let a: &[f64; 3] = &[1.0, 2.0, 3.0];
|
|
1385
|
-
let b: &[f64; 3] = &[4.0, 5.0, 6.0];
|
|
1386
|
-
if let Some(result) = SpatialSimilarity::euclidean(a, b) {
|
|
1387
|
-
assert_almost_equal(5.2, result, 0.01);
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
#[test]
|
|
1392
|
-
fn l2_f16() {
|
|
1393
|
-
let a_half: Vec<HalfF16> = vec![1.0, 2.0, 3.0]
|
|
1394
|
-
.iter()
|
|
1395
|
-
.map(|&x| HalfF16::from_f32(x))
|
|
1396
|
-
.collect();
|
|
1397
|
-
let b_half: Vec<HalfF16> = vec![4.0, 5.0, 6.0]
|
|
1398
|
-
.iter()
|
|
1399
|
-
.map(|&x| HalfF16::from_f32(x))
|
|
1400
|
-
.collect();
|
|
1401
|
-
|
|
1402
|
-
let a_simsimd: &[f16] =
|
|
1403
|
-
unsafe { std::slice::from_raw_parts(a_half.as_ptr() as *const f16, a_half.len()) };
|
|
1404
|
-
let b_simsimd: &[f16] =
|
|
1405
|
-
unsafe { std::slice::from_raw_parts(b_half.as_ptr() as *const f16, b_half.len()) };
|
|
1406
|
-
|
|
1407
|
-
if let Some(result) = SpatialSimilarity::euclidean(&a_simsimd, &b_simsimd) {
|
|
1408
|
-
assert_almost_equal(5.2, result, 0.01);
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
#[test]
|
|
1413
|
-
fn l2_i8() {
|
|
1414
|
-
let a = &[1, 2, 3];
|
|
1415
|
-
let b = &[4, 5, 6];
|
|
1416
|
-
|
|
1417
|
-
if let Some(result) = SpatialSimilarity::euclidean(a, b) {
|
|
1418
|
-
assert_almost_equal(5.2, result, 0.01);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
// Adding new tests for bit-level distances
|
|
1422
|
-
#[test]
|
|
1423
|
-
fn hamming_u8() {
|
|
1424
|
-
let a = &[0b01010101, 0b11110000, 0b10101010];
|
|
1425
|
-
let b = &[0b01010101, 0b11110000, 0b10101010];
|
|
1426
|
-
|
|
1427
|
-
if let Some(result) = BinarySimilarity::hamming(a, b) {
|
|
1428
|
-
assert_almost_equal(0.0, result, 0.01);
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
#[test]
|
|
1433
|
-
fn jaccard_u8() {
|
|
1434
|
-
// For binary data, treat each byte as a set of bits
|
|
1435
|
-
let a = &[0b11110000, 0b00001111, 0b10101010];
|
|
1436
|
-
let b = &[0b11110000, 0b00001111, 0b01010101];
|
|
1437
|
-
|
|
1438
|
-
if let Some(result) = BinarySimilarity::jaccard(a, b) {
|
|
1439
|
-
assert_almost_equal(0.5, result, 0.01);
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// Adding new tests for probability similarities
|
|
1444
|
-
#[test]
|
|
1445
|
-
fn js_f32() {
|
|
1446
|
-
let a: &[f32; 3] = &[0.1, 0.9, 0.0];
|
|
1447
|
-
let b: &[f32; 3] = &[0.2, 0.8, 0.0];
|
|
1448
|
-
|
|
1449
|
-
if let Some(result) = ProbabilitySimilarity::jensenshannon(a, b) {
|
|
1450
|
-
assert_almost_equal(0.099, result, 0.01);
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
#[test]
|
|
1455
|
-
fn kl_f32() {
|
|
1456
|
-
let a: &[f32; 3] = &[0.1, 0.9, 0.0];
|
|
1457
|
-
let b: &[f32; 3] = &[0.2, 0.8, 0.0];
|
|
1458
|
-
|
|
1459
|
-
if let Some(result) = ProbabilitySimilarity::kullbackleibler(a, b) {
|
|
1460
|
-
assert_almost_equal(0.036, result, 0.01);
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
#[test]
|
|
1465
|
-
fn cos_f16_same() {
|
|
1466
|
-
// Assuming these u16 values represent f16 bit patterns, and they are identical
|
|
1467
|
-
let a_u16: &[u16] = &[15360, 16384, 17408]; // Corresponding to some f16 values
|
|
1468
|
-
let b_u16: &[u16] = &[15360, 16384, 17408]; // Same as above for simplicity
|
|
1469
|
-
|
|
1470
|
-
// Reinterpret cast from &[u16] to &[f16]
|
|
1471
|
-
let a_f16: &[f16] =
|
|
1472
|
-
unsafe { std::slice::from_raw_parts(a_u16.as_ptr() as *const f16, a_u16.len()) };
|
|
1473
|
-
let b_f16: &[f16] =
|
|
1474
|
-
unsafe { std::slice::from_raw_parts(b_u16.as_ptr() as *const f16, b_u16.len()) };
|
|
1475
|
-
|
|
1476
|
-
if let Some(result) = SpatialSimilarity::cosine(a_f16, b_f16) {
|
|
1477
|
-
assert_almost_equal(0.0, result, 0.01);
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
#[test]
|
|
1482
|
-
fn cos_bf16_same() {
|
|
1483
|
-
// Assuming these u16 values represent bf16 bit patterns, and they are identical
|
|
1484
|
-
let a_u16: &[u16] = &[15360, 16384, 17408]; // Corresponding to some bf16 values
|
|
1485
|
-
let b_u16: &[u16] = &[15360, 16384, 17408]; // Same as above for simplicity
|
|
1486
|
-
|
|
1487
|
-
// Reinterpret cast from &[u16] to &[bf16]
|
|
1488
|
-
let a_bf16: &[bf16] =
|
|
1489
|
-
unsafe { std::slice::from_raw_parts(a_u16.as_ptr() as *const bf16, a_u16.len()) };
|
|
1490
|
-
let b_bf16: &[bf16] =
|
|
1491
|
-
unsafe { std::slice::from_raw_parts(b_u16.as_ptr() as *const bf16, b_u16.len()) };
|
|
1492
|
-
|
|
1493
|
-
if let Some(result) = SpatialSimilarity::cosine(a_bf16, b_bf16) {
|
|
1494
|
-
assert_almost_equal(0.0, result, 0.01);
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
#[test]
|
|
1499
|
-
fn cos_f16_interop() {
|
|
1500
|
-
let a_half: Vec<HalfF16> = vec![1.0, 2.0, 3.0]
|
|
1501
|
-
.iter()
|
|
1502
|
-
.map(|&x| HalfF16::from_f32(x))
|
|
1503
|
-
.collect();
|
|
1504
|
-
let b_half: Vec<HalfF16> = vec![4.0, 5.0, 6.0]
|
|
1505
|
-
.iter()
|
|
1506
|
-
.map(|&x| HalfF16::from_f32(x))
|
|
1507
|
-
.collect();
|
|
1508
|
-
|
|
1509
|
-
// SAFETY: This is safe as long as the memory representations are guaranteed to be identical,
|
|
1510
|
-
// which they are due to both being #[repr(transparent)] wrappers around u16.
|
|
1511
|
-
let a_simsimd: &[f16] =
|
|
1512
|
-
unsafe { std::slice::from_raw_parts(a_half.as_ptr() as *const f16, a_half.len()) };
|
|
1513
|
-
let b_simsimd: &[f16] =
|
|
1514
|
-
unsafe { std::slice::from_raw_parts(b_half.as_ptr() as *const f16, b_half.len()) };
|
|
1515
|
-
|
|
1516
|
-
// Use the reinterpret-casted slices with your SpatialSimilarity implementation
|
|
1517
|
-
if let Some(result) = SpatialSimilarity::cosine(a_simsimd, b_simsimd) {
|
|
1518
|
-
assert_almost_equal(0.025, result, 0.01);
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
#[test]
|
|
1523
|
-
fn cos_bf16_interop() {
|
|
1524
|
-
let a_half: Vec<HalfBF16> = vec![1.0, 2.0, 3.0]
|
|
1525
|
-
.iter()
|
|
1526
|
-
.map(|&x| HalfBF16::from_f32(x))
|
|
1527
|
-
.collect();
|
|
1528
|
-
let b_half: Vec<HalfBF16> = vec![4.0, 5.0, 6.0]
|
|
1529
|
-
.iter()
|
|
1530
|
-
.map(|&x| HalfBF16::from_f32(x))
|
|
1531
|
-
.collect();
|
|
1532
|
-
|
|
1533
|
-
// SAFETY: This is safe as long as the memory representations are guaranteed to be identical,
|
|
1534
|
-
// which they are due to both being #[repr(transparent)] wrappers around u16.
|
|
1535
|
-
let a_simsimd: &[bf16] =
|
|
1536
|
-
unsafe { std::slice::from_raw_parts(a_half.as_ptr() as *const bf16, a_half.len()) };
|
|
1537
|
-
let b_simsimd: &[bf16] =
|
|
1538
|
-
unsafe { std::slice::from_raw_parts(b_half.as_ptr() as *const bf16, b_half.len()) };
|
|
1539
|
-
|
|
1540
|
-
// Use the reinterpret-casted slices with your SpatialSimilarity implementation
|
|
1541
|
-
if let Some(result) = SpatialSimilarity::cosine(a_simsimd, b_simsimd) {
|
|
1542
|
-
assert_almost_equal(0.025, result, 0.01);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
#[test]
|
|
1547
|
-
fn intersect_u16() {
|
|
1548
|
-
{
|
|
1549
|
-
let a_u16: &[u16] = &[153, 16384, 17408];
|
|
1550
|
-
let b_u16: &[u16] = &[7408, 15360, 16384];
|
|
1551
|
-
|
|
1552
|
-
if let Some(result) = Sparse::intersect(a_u16, b_u16) {
|
|
1553
|
-
assert_almost_equal(1.0, result, 0.0001);
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
{
|
|
1558
|
-
let a_u16: &[u16] = &[8, 153, 11638];
|
|
1559
|
-
let b_u16: &[u16] = &[7408, 15360, 16384];
|
|
1560
|
-
|
|
1561
|
-
if let Some(result) = Sparse::intersect(a_u16, b_u16) {
|
|
1562
|
-
assert_almost_equal(0.0, result, 0.0001);
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
#[test]
|
|
1568
|
-
fn intersect_u32() {
|
|
1569
|
-
{
|
|
1570
|
-
let a_u32: &[u32] = &[11, 153];
|
|
1571
|
-
let b_u32: &[u32] = &[11, 153, 7408, 16384];
|
|
1572
|
-
|
|
1573
|
-
if let Some(result) = Sparse::intersect(a_u32, b_u32) {
|
|
1574
|
-
assert_almost_equal(2.0, result, 0.0001);
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
{
|
|
1579
|
-
let a_u32: &[u32] = &[153, 7408, 11638];
|
|
1580
|
-
let b_u32: &[u32] = &[153, 7408, 11638];
|
|
1581
|
-
|
|
1582
|
-
if let Some(result) = Sparse::intersect(a_u32, b_u32) {
|
|
1583
|
-
assert_almost_equal(3.0, result, 0.0001);
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
|
-
/// Reference implementation of set intersection using Rust's standard library
|
|
1589
|
-
fn reference_intersect<T: Ord>(a: &[T], b: &[T]) -> usize {
|
|
1590
|
-
let mut a_iter = a.iter();
|
|
1591
|
-
let mut b_iter = b.iter();
|
|
1592
|
-
let mut a_current = a_iter.next();
|
|
1593
|
-
let mut b_current = b_iter.next();
|
|
1594
|
-
let mut count = 0;
|
|
1595
|
-
|
|
1596
|
-
while let (Some(a_val), Some(b_val)) = (a_current, b_current) {
|
|
1597
|
-
match a_val.cmp(b_val) {
|
|
1598
|
-
core::cmp::Ordering::Less => a_current = a_iter.next(),
|
|
1599
|
-
core::cmp::Ordering::Greater => b_current = b_iter.next(),
|
|
1600
|
-
core::cmp::Ordering::Equal => {
|
|
1601
|
-
count += 1;
|
|
1602
|
-
a_current = a_iter.next();
|
|
1603
|
-
b_current = b_iter.next();
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
count
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
/// Generate test arrays with various sizes and patterns for intersection testing
|
|
1611
|
-
/// Includes empty, small, medium, large arrays with different overlap characteristics
|
|
1612
|
-
fn generate_intersection_test_arrays<T>() -> Vec<Vec<T>>
|
|
1613
|
-
where
|
|
1614
|
-
T: core::convert::TryFrom<u32> + Copy,
|
|
1615
|
-
<T as core::convert::TryFrom<u32>>::Error: core::fmt::Debug,
|
|
1616
|
-
{
|
|
1617
|
-
vec![
|
|
1618
|
-
// Empty array
|
|
1619
|
-
vec![],
|
|
1620
|
-
// Single element
|
|
1621
|
-
vec![T::try_from(42).unwrap()],
|
|
1622
|
-
// Very small arrays (< 16 elements) - tests serial fallback
|
|
1623
|
-
vec![
|
|
1624
|
-
T::try_from(1).unwrap(),
|
|
1625
|
-
T::try_from(5).unwrap(),
|
|
1626
|
-
T::try_from(10).unwrap(),
|
|
1627
|
-
],
|
|
1628
|
-
vec![
|
|
1629
|
-
T::try_from(2).unwrap(),
|
|
1630
|
-
T::try_from(4).unwrap(),
|
|
1631
|
-
T::try_from(6).unwrap(),
|
|
1632
|
-
T::try_from(8).unwrap(),
|
|
1633
|
-
T::try_from(10).unwrap(),
|
|
1634
|
-
T::try_from(12).unwrap(),
|
|
1635
|
-
T::try_from(14).unwrap(),
|
|
1636
|
-
],
|
|
1637
|
-
// Small arrays (< 32 elements) - boundary case for Turin
|
|
1638
|
-
(0..14).map(|x| T::try_from(x * 10).unwrap()).collect(),
|
|
1639
|
-
(5..20).map(|x| T::try_from(x * 10).unwrap()).collect(),
|
|
1640
|
-
// Medium arrays (32-64 elements) - tests one or two SIMD iterations
|
|
1641
|
-
(0..40).map(|x| T::try_from(x * 2).unwrap()).collect(),
|
|
1642
|
-
(10..50).map(|x| T::try_from(x * 2).unwrap()).collect(), // 50% overlap with previous
|
|
1643
|
-
(0..45).map(|x| T::try_from(x * 3).unwrap()).collect(), // Different stride
|
|
1644
|
-
// Large arrays (> 64 elements) - tests main SIMD loop
|
|
1645
|
-
(0..100).map(|x| T::try_from(x * 2).unwrap()).collect(),
|
|
1646
|
-
(50..150).map(|x| T::try_from(x * 2).unwrap()).collect(), // 50% overlap
|
|
1647
|
-
(0..100).map(|x| T::try_from(x * 5).unwrap()).collect(), // Sparse overlap
|
|
1648
|
-
(0..150)
|
|
1649
|
-
.filter(|x| x % 7 == 0)
|
|
1650
|
-
.map(|x| T::try_from(x).unwrap())
|
|
1651
|
-
.collect(),
|
|
1652
|
-
// Very large arrays (> 256 elements) - stress test
|
|
1653
|
-
(0..500).map(|x| T::try_from(x * 3).unwrap()).collect(),
|
|
1654
|
-
(100..600).map(|x| T::try_from(x * 3).unwrap()).collect(), // Large overlap
|
|
1655
|
-
(0..600).map(|x| T::try_from(x * 7).unwrap()).collect(), // Minimal overlap
|
|
1656
|
-
// Edge cases: no overlap at all
|
|
1657
|
-
(0..50).map(|x| T::try_from(x * 2).unwrap()).collect(),
|
|
1658
|
-
(1000..1050).map(|x| T::try_from(x * 2).unwrap()).collect(), // Completely disjoint
|
|
1659
|
-
// Dense arrays at boundaries
|
|
1660
|
-
(0..16).map(|x| T::try_from(x).unwrap()).collect(), // Exactly 16 elements
|
|
1661
|
-
(0..32).map(|x| T::try_from(x).unwrap()).collect(), // Exactly 32 elements
|
|
1662
|
-
(0..64).map(|x| T::try_from(x).unwrap()).collect(), // Exactly 64 elements
|
|
1663
|
-
]
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
#[test]
|
|
1667
|
-
fn intersect_u32_comprehensive() {
|
|
1668
|
-
let test_arrays: Vec<Vec<u32>> = generate_intersection_test_arrays();
|
|
1669
|
-
|
|
1670
|
-
for (i, array_a) in test_arrays.iter().enumerate() {
|
|
1671
|
-
for (j, array_b) in test_arrays.iter().enumerate() {
|
|
1672
|
-
let expected = reference_intersect(array_a, array_b);
|
|
1673
|
-
let result =
|
|
1674
|
-
Sparse::intersect(array_a.as_slice(), array_b.as_slice()).unwrap() as usize;
|
|
1675
|
-
|
|
1676
|
-
assert_eq!(
|
|
1677
|
-
expected,
|
|
1678
|
-
result,
|
|
1679
|
-
"Intersection mismatch for arrays[{}] (len={}) and arrays[{}] (len={})",
|
|
1680
|
-
i,
|
|
1681
|
-
array_a.len(),
|
|
1682
|
-
j,
|
|
1683
|
-
array_b.len()
|
|
1684
|
-
);
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
#[test]
|
|
1690
|
-
fn intersect_u16_comprehensive() {
|
|
1691
|
-
let test_arrays: Vec<Vec<u16>> = generate_intersection_test_arrays();
|
|
1692
|
-
|
|
1693
|
-
for (i, array_a) in test_arrays.iter().enumerate() {
|
|
1694
|
-
for (j, array_b) in test_arrays.iter().enumerate() {
|
|
1695
|
-
let expected = reference_intersect(array_a, array_b);
|
|
1696
|
-
let result =
|
|
1697
|
-
Sparse::intersect(array_a.as_slice(), array_b.as_slice()).unwrap() as usize;
|
|
1698
|
-
|
|
1699
|
-
assert_eq!(
|
|
1700
|
-
expected,
|
|
1701
|
-
result,
|
|
1702
|
-
"Intersection mismatch for arrays[{}] (len={}) and arrays[{}] (len={})",
|
|
1703
|
-
i,
|
|
1704
|
-
array_a.len(),
|
|
1705
|
-
j,
|
|
1706
|
-
array_b.len()
|
|
1707
|
-
);
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
#[test]
|
|
1713
|
-
fn intersect_edge_cases() {
|
|
1714
|
-
// Test empty arrays
|
|
1715
|
-
let empty: &[u32] = &[];
|
|
1716
|
-
let non_empty: &[u32] = &[1, 2, 3];
|
|
1717
|
-
assert_eq!(Sparse::intersect(empty, empty), Some(0.0));
|
|
1718
|
-
assert_eq!(Sparse::intersect(empty, non_empty), Some(0.0));
|
|
1719
|
-
assert_eq!(Sparse::intersect(non_empty, empty), Some(0.0));
|
|
1720
|
-
|
|
1721
|
-
// Test single element matches
|
|
1722
|
-
assert_eq!(Sparse::intersect(&[42u32], &[42u32]), Some(1.0));
|
|
1723
|
-
assert_eq!(Sparse::intersect(&[42u32], &[43u32]), Some(0.0));
|
|
1724
|
-
|
|
1725
|
-
// Test no overlap
|
|
1726
|
-
let a: &[u32] = &[1, 2, 3, 4, 5];
|
|
1727
|
-
let b: &[u32] = &[10, 20, 30, 40, 50];
|
|
1728
|
-
assert_eq!(Sparse::intersect(a, b), Some(0.0));
|
|
1729
|
-
|
|
1730
|
-
// Test complete overlap
|
|
1731
|
-
let c: &[u32] = &[10, 20, 30, 40, 50];
|
|
1732
|
-
assert_eq!(Sparse::intersect(c, c), Some(5.0));
|
|
1733
|
-
|
|
1734
|
-
// Test one element at boundary (exactly at 16, 32, 64 element boundaries)
|
|
1735
|
-
let boundary_16: Vec<u32> = (0..16).collect();
|
|
1736
|
-
let boundary_32: Vec<u32> = (0..32).collect();
|
|
1737
|
-
let boundary_64: Vec<u32> = (0..64).collect();
|
|
1738
|
-
|
|
1739
|
-
assert_eq!(Sparse::intersect(&boundary_16, &boundary_16), Some(16.0));
|
|
1740
|
-
assert_eq!(Sparse::intersect(&boundary_32, &boundary_32), Some(32.0));
|
|
1741
|
-
assert_eq!(Sparse::intersect(&boundary_64, &boundary_64), Some(64.0));
|
|
1742
|
-
|
|
1743
|
-
// Test partial overlap at boundaries
|
|
1744
|
-
let first_half: Vec<u32> = (0..32).collect();
|
|
1745
|
-
let second_half: Vec<u32> = (16..48).collect();
|
|
1746
|
-
assert_eq!(Sparse::intersect(&first_half, &second_half), Some(16.0));
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
#[test]
|
|
1750
|
-
fn f16_arithmetic() {
|
|
1751
|
-
let a = f16::from_f32(3.5);
|
|
1752
|
-
let b = f16::from_f32(2.0);
|
|
1753
|
-
|
|
1754
|
-
// Test basic arithmetic
|
|
1755
|
-
assert!((a + b).to_f32() - 5.5 < 0.01);
|
|
1756
|
-
assert!((a - b).to_f32() - 1.5 < 0.01);
|
|
1757
|
-
assert!((a * b).to_f32() - 7.0 < 0.01);
|
|
1758
|
-
assert!((a / b).to_f32() - 1.75 < 0.01);
|
|
1759
|
-
assert!((-a).to_f32() + 3.5 < 0.01);
|
|
1760
|
-
|
|
1761
|
-
// Test constants
|
|
1762
|
-
assert!(f16::ZERO.to_f32() == 0.0);
|
|
1763
|
-
assert!((f16::ONE.to_f32() - 1.0).abs() < 0.01);
|
|
1764
|
-
assert!((f16::NEG_ONE.to_f32() + 1.0).abs() < 0.01);
|
|
1765
|
-
|
|
1766
|
-
// Test comparisons
|
|
1767
|
-
assert!(a > b);
|
|
1768
|
-
assert!(!(a < b));
|
|
1769
|
-
assert!(a == a);
|
|
1770
|
-
|
|
1771
|
-
// Test utility methods
|
|
1772
|
-
assert!((-a).abs().to_f32() - 3.5 < 0.01);
|
|
1773
|
-
assert!(a.is_finite());
|
|
1774
|
-
assert!(!a.is_nan());
|
|
1775
|
-
assert!(!a.is_infinite());
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
#[test]
|
|
1779
|
-
fn bf16_arithmetic() {
|
|
1780
|
-
let a = bf16::from_f32(3.5);
|
|
1781
|
-
let b = bf16::from_f32(2.0);
|
|
1782
|
-
|
|
1783
|
-
// Test basic arithmetic
|
|
1784
|
-
assert!((a + b).to_f32() - 5.5 < 0.1);
|
|
1785
|
-
assert!((a - b).to_f32() - 1.5 < 0.1);
|
|
1786
|
-
assert!((a * b).to_f32() - 7.0 < 0.1);
|
|
1787
|
-
assert!((a / b).to_f32() - 1.75 < 0.1);
|
|
1788
|
-
assert!((-a).to_f32() + 3.5 < 0.1);
|
|
1789
|
-
|
|
1790
|
-
// Test constants
|
|
1791
|
-
assert!(bf16::ZERO.to_f32() == 0.0);
|
|
1792
|
-
assert!((bf16::ONE.to_f32() - 1.0).abs() < 0.01);
|
|
1793
|
-
assert!((bf16::NEG_ONE.to_f32() + 1.0).abs() < 0.01);
|
|
1794
|
-
|
|
1795
|
-
// Test comparisons
|
|
1796
|
-
assert!(a > b);
|
|
1797
|
-
assert!(!(a < b));
|
|
1798
|
-
assert!(a == a);
|
|
1799
|
-
|
|
1800
|
-
// Test utility methods
|
|
1801
|
-
assert!((-a).abs().to_f32() - 3.5 < 0.1);
|
|
1802
|
-
assert!(a.is_finite());
|
|
1803
|
-
assert!(!a.is_nan());
|
|
1804
|
-
assert!(!a.is_infinite());
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
#[test]
|
|
1808
|
-
fn bf16_dot() {
|
|
1809
|
-
let brain_a: Vec<bf16> = vec![1.0, 2.0, 3.0, 1.0, 2.0]
|
|
1810
|
-
.iter()
|
|
1811
|
-
.map(|&x| bf16::from_f32(x))
|
|
1812
|
-
.collect();
|
|
1813
|
-
let brain_b: Vec<bf16> = vec![4.0, 5.0, 6.0, 4.0, 5.0]
|
|
1814
|
-
.iter()
|
|
1815
|
-
.map(|&x| bf16::from_f32(x))
|
|
1816
|
-
.collect();
|
|
1817
|
-
if let Some(result) = <bf16 as SpatialSimilarity>::dot(&brain_a, &brain_b) {
|
|
1818
|
-
assert_eq!(46.0, result);
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
}
|