usearch 2.21.3 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/binding.gyp +15 -37
- package/c/CMakeLists.txt +4 -5
- package/c/README.md +7 -7
- package/c/lib.cpp +32 -14
- package/c/test.c +83 -1
- package/c/usearch.h +24 -3
- package/cpp/CMakeLists.txt +4 -0
- package/cpp/README.md +5 -5
- package/cpp/bench.cpp +97 -116
- package/cpp/test.cpp +117 -20
- package/include/usearch/index.hpp +235 -52
- package/include/usearch/index_dense.hpp +105 -40
- package/include/usearch/index_plugins.hpp +1387 -204
- package/javascript/dist/cjs/usearch.d.ts +8 -3
- package/javascript/dist/cjs/usearch.js +12 -4
- package/javascript/dist/esm/usearch.d.ts +8 -3
- package/javascript/dist/esm/usearch.js +12 -4
- package/javascript/lib.cpp +17 -0
- package/javascript/usearch.ts +14 -6
- package/numkong/.clang-tidy +30 -0
- package/{simsimd → numkong}/.cmake-format.py +18 -0
- package/numkong/.editorconfig +12 -0
- package/numkong/.git-blame-ignore-revs +123 -0
- package/numkong/.mailmap +15 -0
- package/numkong/.spi.yml +11 -0
- package/numkong/.swift-format +14 -0
- package/numkong/CITATION.cff +81 -0
- package/numkong/CONTRIBUTING.md +500 -0
- package/numkong/Cargo.toml +54 -0
- package/numkong/MANIFEST.in +8 -0
- package/numkong/Package.swift +84 -0
- package/numkong/README.md +569 -0
- package/numkong/bench/README.md +217 -0
- package/numkong/bench/bench-browser.html +323 -0
- package/numkong/bench/bench.cpp +344 -0
- package/numkong/bench/bench.hpp +816 -0
- package/numkong/bench/bench.js +148 -0
- package/numkong/bench/bench.mjs +616 -0
- package/numkong/bench/bench_attention.cpp +113 -0
- package/numkong/bench/bench_cast.cpp +264 -0
- package/numkong/bench/bench_cross_amx.cpp +62 -0
- package/numkong/bench/bench_cross_arm.cpp +245 -0
- package/numkong/bench/bench_cross_blas.cpp +309 -0
- package/numkong/bench/bench_cross_loongarch.cpp +106 -0
- package/numkong/bench/bench_cross_power.cpp +84 -0
- package/numkong/bench/bench_cross_rvv.cpp +121 -0
- package/numkong/bench/bench_cross_serial.cpp +151 -0
- package/numkong/bench/bench_cross_sme.cpp +163 -0
- package/numkong/bench/bench_cross_wasm.cpp +142 -0
- package/numkong/bench/bench_cross_x86.cpp +455 -0
- package/numkong/bench/bench_curved.cpp +210 -0
- package/numkong/bench/bench_dot.cpp +315 -0
- package/numkong/bench/bench_each.cpp +503 -0
- package/numkong/bench/bench_geospatial.cpp +112 -0
- package/numkong/bench/bench_maxsim.cpp +154 -0
- package/numkong/bench/bench_mesh.cpp +148 -0
- package/numkong/bench/bench_probability.cpp +60 -0
- package/numkong/bench/bench_reduce.cpp +371 -0
- package/numkong/bench/bench_set.cpp +73 -0
- package/numkong/bench/bench_sparse.cpp +198 -0
- package/numkong/bench/bench_spatial.cpp +347 -0
- package/numkong/bench/bench_trigonometry.cpp +137 -0
- package/numkong/bench/swift/Bench.swift +506 -0
- package/numkong/binding.gyp +169 -0
- package/numkong/build.rs +484 -0
- package/numkong/c/dispatch.h +512 -0
- package/numkong/c/dispatch_bf16.c +447 -0
- package/numkong/c/dispatch_bf16c.c +52 -0
- package/numkong/c/dispatch_e2m3.c +296 -0
- package/numkong/c/dispatch_e3m2.c +284 -0
- package/numkong/c/dispatch_e4m3.c +318 -0
- package/numkong/c/dispatch_e5m2.c +316 -0
- package/numkong/c/dispatch_f16.c +452 -0
- package/numkong/c/dispatch_f16c.c +58 -0
- package/numkong/c/dispatch_f32.c +434 -0
- package/numkong/c/dispatch_f32c.c +99 -0
- package/numkong/c/dispatch_f64.c +348 -0
- package/numkong/c/dispatch_f64c.c +98 -0
- package/numkong/c/dispatch_i16.c +96 -0
- package/numkong/c/dispatch_i32.c +89 -0
- package/numkong/c/dispatch_i4.c +153 -0
- package/numkong/c/dispatch_i64.c +86 -0
- package/numkong/c/dispatch_i8.c +348 -0
- package/numkong/c/dispatch_other.c +348 -0
- package/numkong/c/dispatch_u1.c +193 -0
- package/numkong/c/dispatch_u16.c +124 -0
- package/numkong/c/dispatch_u32.c +118 -0
- package/numkong/c/dispatch_u4.c +153 -0
- package/numkong/c/dispatch_u64.c +102 -0
- package/numkong/c/dispatch_u8.c +364 -0
- package/numkong/c/numkong.c +940 -0
- package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
- package/numkong/cmake/nk_isa_probe.cmake +90 -0
- package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
- package/numkong/cmake/nk_math_lib.cmake +46 -0
- package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
- package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
- package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
- package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
- package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
- package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
- package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
- package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
- package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
- package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
- package/numkong/cmake/toolchain-wasi.cmake +77 -0
- package/numkong/cmake/toolchain-wasm.cmake +70 -0
- package/numkong/cmake/toolchain-wasm64.cmake +62 -0
- package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
- package/numkong/include/README.md +643 -0
- package/numkong/include/module.modulemap +129 -0
- package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
- package/numkong/include/numkong/attention/sme.h +2075 -0
- package/numkong/include/numkong/attention.h +49 -0
- package/numkong/include/numkong/capabilities.h +930 -0
- package/numkong/include/numkong/cast/README.md +262 -0
- package/numkong/include/numkong/cast/diamond.h +64 -0
- package/numkong/include/numkong/cast/haswell.h +823 -0
- package/numkong/include/numkong/cast/icelake.h +475 -0
- package/numkong/include/numkong/cast/loongsonasx.h +252 -0
- package/numkong/include/numkong/cast/neon.h +1174 -0
- package/numkong/include/numkong/cast/powervsx.h +449 -0
- package/numkong/include/numkong/cast/rvv.h +970 -0
- package/numkong/include/numkong/cast/sapphire.h +262 -0
- package/numkong/include/numkong/cast/serial.h +2336 -0
- package/numkong/include/numkong/cast/skylake.h +915 -0
- package/numkong/include/numkong/cast/v128relaxed.h +537 -0
- package/numkong/include/numkong/cast.h +254 -0
- package/numkong/include/numkong/cast.hpp +44 -0
- package/numkong/include/numkong/curved/README.md +223 -0
- package/numkong/include/numkong/curved/genoa.h +182 -0
- package/numkong/include/numkong/curved/haswell.h +276 -0
- package/numkong/include/numkong/curved/neon.h +329 -0
- package/numkong/include/numkong/curved/neonbfdot.h +211 -0
- package/numkong/include/numkong/curved/rvv.h +305 -0
- package/numkong/include/numkong/curved/serial.h +207 -0
- package/numkong/include/numkong/curved/skylake.h +457 -0
- package/numkong/include/numkong/curved/smef64.h +530 -0
- package/numkong/include/numkong/curved.h +513 -0
- package/numkong/include/numkong/curved.hpp +144 -0
- package/numkong/include/numkong/dot/README.md +442 -0
- package/numkong/include/numkong/dot/alder.h +563 -0
- package/numkong/include/numkong/dot/diamond.h +158 -0
- package/numkong/include/numkong/dot/genoa.h +289 -0
- package/numkong/include/numkong/dot/haswell.h +1723 -0
- package/numkong/include/numkong/dot/icelake.h +997 -0
- package/numkong/include/numkong/dot/loongsonasx.h +671 -0
- package/numkong/include/numkong/dot/neon.h +869 -0
- package/numkong/include/numkong/dot/neonbfdot.h +243 -0
- package/numkong/include/numkong/dot/neonfhm.h +358 -0
- package/numkong/include/numkong/dot/neonfp8.h +323 -0
- package/numkong/include/numkong/dot/neonsdot.h +622 -0
- package/numkong/include/numkong/dot/powervsx.h +752 -0
- package/numkong/include/numkong/dot/rvv.h +722 -0
- package/numkong/include/numkong/dot/rvvbb.h +72 -0
- package/numkong/include/numkong/dot/rvvbf16.h +123 -0
- package/numkong/include/numkong/dot/rvvhalf.h +129 -0
- package/numkong/include/numkong/dot/sapphire.h +141 -0
- package/numkong/include/numkong/dot/serial.h +874 -0
- package/numkong/include/numkong/dot/sierra.h +405 -0
- package/numkong/include/numkong/dot/skylake.h +1116 -0
- package/numkong/include/numkong/dot/sve.h +420 -0
- package/numkong/include/numkong/dot/svebfdot.h +75 -0
- package/numkong/include/numkong/dot/svehalf.h +168 -0
- package/numkong/include/numkong/dot/svesdot.h +90 -0
- package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
- package/numkong/include/numkong/dot.h +1136 -0
- package/numkong/include/numkong/dot.hpp +94 -0
- package/numkong/include/numkong/dots/README.md +496 -0
- package/numkong/include/numkong/dots/alder.h +117 -0
- package/numkong/include/numkong/dots/diamond.h +86 -0
- package/numkong/include/numkong/dots/genoa.h +100 -0
- package/numkong/include/numkong/dots/graniteamx.h +733 -0
- package/numkong/include/numkong/dots/haswell.h +310 -0
- package/numkong/include/numkong/dots/icelake.h +180 -0
- package/numkong/include/numkong/dots/loongsonasx.h +176 -0
- package/numkong/include/numkong/dots/neon.h +123 -0
- package/numkong/include/numkong/dots/neonbfdot.h +59 -0
- package/numkong/include/numkong/dots/neonfhm.h +96 -0
- package/numkong/include/numkong/dots/neonfp8.h +99 -0
- package/numkong/include/numkong/dots/neonsdot.h +144 -0
- package/numkong/include/numkong/dots/powervsx.h +194 -0
- package/numkong/include/numkong/dots/rvv.h +2593 -0
- package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
- package/numkong/include/numkong/dots/serial.h +2867 -0
- package/numkong/include/numkong/dots/sierra.h +100 -0
- package/numkong/include/numkong/dots/skylake.h +207 -0
- package/numkong/include/numkong/dots/sme.h +5041 -0
- package/numkong/include/numkong/dots/smebi32.h +477 -0
- package/numkong/include/numkong/dots/smef64.h +1328 -0
- package/numkong/include/numkong/dots/smehalf.h +47 -0
- package/numkong/include/numkong/dots/v128relaxed.h +317 -0
- package/numkong/include/numkong/dots.h +3110 -0
- package/numkong/include/numkong/dots.hpp +641 -0
- package/numkong/include/numkong/each/README.md +465 -0
- package/numkong/include/numkong/each/haswell.h +1658 -0
- package/numkong/include/numkong/each/icelake.h +272 -0
- package/numkong/include/numkong/each/neon.h +1138 -0
- package/numkong/include/numkong/each/neonbfdot.h +211 -0
- package/numkong/include/numkong/each/neonhalf.h +318 -0
- package/numkong/include/numkong/each/rvv.h +1121 -0
- package/numkong/include/numkong/each/sapphire.h +343 -0
- package/numkong/include/numkong/each/serial.h +282 -0
- package/numkong/include/numkong/each/skylake.h +1562 -0
- package/numkong/include/numkong/each/v128relaxed.h +562 -0
- package/numkong/include/numkong/each.h +2232 -0
- package/numkong/include/numkong/each.hpp +434 -0
- package/numkong/include/numkong/geospatial/README.md +147 -0
- package/numkong/include/numkong/geospatial/haswell.h +633 -0
- package/numkong/include/numkong/geospatial/neon.h +615 -0
- package/numkong/include/numkong/geospatial/rvv.h +701 -0
- package/numkong/include/numkong/geospatial/serial.h +309 -0
- package/numkong/include/numkong/geospatial/skylake.h +613 -0
- package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
- package/numkong/include/numkong/geospatial.h +453 -0
- package/numkong/include/numkong/geospatial.hpp +235 -0
- package/numkong/include/numkong/matrix.hpp +336 -0
- package/numkong/include/numkong/maxsim/README.md +187 -0
- package/numkong/include/numkong/maxsim/alder.h +511 -0
- package/numkong/include/numkong/maxsim/genoa.h +115 -0
- package/numkong/include/numkong/maxsim/haswell.h +553 -0
- package/numkong/include/numkong/maxsim/icelake.h +480 -0
- package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
- package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
- package/numkong/include/numkong/maxsim/serial.h +490 -0
- package/numkong/include/numkong/maxsim/sme.h +993 -0
- package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
- package/numkong/include/numkong/maxsim.h +571 -0
- package/numkong/include/numkong/maxsim.hpp +133 -0
- package/numkong/include/numkong/mesh/README.md +219 -0
- package/numkong/include/numkong/mesh/haswell.h +2013 -0
- package/numkong/include/numkong/mesh/neon.h +1821 -0
- package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
- package/numkong/include/numkong/mesh/rvv.h +936 -0
- package/numkong/include/numkong/mesh/serial.h +721 -0
- package/numkong/include/numkong/mesh/skylake.h +2344 -0
- package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
- package/numkong/include/numkong/mesh.h +666 -0
- package/numkong/include/numkong/mesh.hpp +701 -0
- package/numkong/include/numkong/numkong.h +78 -0
- package/numkong/include/numkong/numkong.hpp +58 -0
- package/numkong/include/numkong/probability/README.md +177 -0
- package/numkong/include/numkong/probability/haswell.h +267 -0
- package/numkong/include/numkong/probability/neon.h +255 -0
- package/numkong/include/numkong/probability/rvv.h +414 -0
- package/numkong/include/numkong/probability/serial.h +181 -0
- package/numkong/include/numkong/probability/skylake.h +324 -0
- package/numkong/include/numkong/probability.h +380 -0
- package/numkong/include/numkong/probability.hpp +120 -0
- package/numkong/include/numkong/random.h +50 -0
- package/numkong/include/numkong/random.hpp +285 -0
- package/numkong/include/numkong/reduce/README.md +552 -0
- package/numkong/include/numkong/reduce/alder.h +636 -0
- package/numkong/include/numkong/reduce/genoa.h +201 -0
- package/numkong/include/numkong/reduce/haswell.h +3785 -0
- package/numkong/include/numkong/reduce/icelake.h +549 -0
- package/numkong/include/numkong/reduce/neon.h +3980 -0
- package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
- package/numkong/include/numkong/reduce/neonfhm.h +293 -0
- package/numkong/include/numkong/reduce/neonsdot.h +357 -0
- package/numkong/include/numkong/reduce/rvv.h +3533 -0
- package/numkong/include/numkong/reduce/serial.h +753 -0
- package/numkong/include/numkong/reduce/sierra.h +338 -0
- package/numkong/include/numkong/reduce/skylake.h +3794 -0
- package/numkong/include/numkong/reduce/sve.h +52 -0
- package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
- package/numkong/include/numkong/reduce.h +1582 -0
- package/numkong/include/numkong/reduce.hpp +778 -0
- package/numkong/include/numkong/scalar/README.md +89 -0
- package/numkong/include/numkong/scalar/haswell.h +122 -0
- package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
- package/numkong/include/numkong/scalar/neon.h +122 -0
- package/numkong/include/numkong/scalar/neonhalf.h +70 -0
- package/numkong/include/numkong/scalar/powervsx.h +96 -0
- package/numkong/include/numkong/scalar/rvv.h +211 -0
- package/numkong/include/numkong/scalar/sapphire.h +74 -0
- package/numkong/include/numkong/scalar/serial.h +332 -0
- package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
- package/numkong/include/numkong/scalar.h +696 -0
- package/numkong/include/numkong/set/README.md +179 -0
- package/numkong/include/numkong/set/haswell.h +334 -0
- package/numkong/include/numkong/set/icelake.h +485 -0
- package/numkong/include/numkong/set/loongsonasx.h +181 -0
- package/numkong/include/numkong/set/neon.h +363 -0
- package/numkong/include/numkong/set/powervsx.h +326 -0
- package/numkong/include/numkong/set/rvv.h +226 -0
- package/numkong/include/numkong/set/rvvbb.h +117 -0
- package/numkong/include/numkong/set/serial.h +174 -0
- package/numkong/include/numkong/set/sve.h +187 -0
- package/numkong/include/numkong/set/v128relaxed.h +240 -0
- package/numkong/include/numkong/set.h +471 -0
- package/numkong/include/numkong/set.hpp +114 -0
- package/numkong/include/numkong/sets/README.md +149 -0
- package/numkong/include/numkong/sets/haswell.h +63 -0
- package/numkong/include/numkong/sets/icelake.h +66 -0
- package/numkong/include/numkong/sets/loongsonasx.h +52 -0
- package/numkong/include/numkong/sets/neon.h +61 -0
- package/numkong/include/numkong/sets/powervsx.h +65 -0
- package/numkong/include/numkong/sets/serial.h +43 -0
- package/numkong/include/numkong/sets/smebi32.h +1135 -0
- package/numkong/include/numkong/sets/v128relaxed.h +58 -0
- package/numkong/include/numkong/sets.h +382 -0
- package/numkong/include/numkong/sparse/README.md +156 -0
- package/numkong/include/numkong/sparse/icelake.h +463 -0
- package/numkong/include/numkong/sparse/neon.h +288 -0
- package/numkong/include/numkong/sparse/serial.h +117 -0
- package/numkong/include/numkong/sparse/sve2.h +504 -0
- package/numkong/include/numkong/sparse/turin.h +322 -0
- package/numkong/include/numkong/sparse.h +363 -0
- package/numkong/include/numkong/sparse.hpp +113 -0
- package/numkong/include/numkong/spatial/README.md +439 -0
- package/numkong/include/numkong/spatial/alder.h +604 -0
- package/numkong/include/numkong/spatial/diamond.h +240 -0
- package/numkong/include/numkong/spatial/genoa.h +222 -0
- package/numkong/include/numkong/spatial/haswell.h +979 -0
- package/numkong/include/numkong/spatial/icelake.h +1067 -0
- package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
- package/numkong/include/numkong/spatial/neon.h +846 -0
- package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
- package/numkong/include/numkong/spatial/neonfp8.h +258 -0
- package/numkong/include/numkong/spatial/neonsdot.h +429 -0
- package/numkong/include/numkong/spatial/powervsx.h +738 -0
- package/numkong/include/numkong/spatial/rvv.h +991 -0
- package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
- package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
- package/numkong/include/numkong/spatial/serial.h +347 -0
- package/numkong/include/numkong/spatial/sierra.h +516 -0
- package/numkong/include/numkong/spatial/skylake.h +605 -0
- package/numkong/include/numkong/spatial/sve.h +246 -0
- package/numkong/include/numkong/spatial/svebfdot.h +125 -0
- package/numkong/include/numkong/spatial/svehalf.h +136 -0
- package/numkong/include/numkong/spatial/svesdot.h +143 -0
- package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
- package/numkong/include/numkong/spatial.h +1681 -0
- package/numkong/include/numkong/spatial.hpp +183 -0
- package/numkong/include/numkong/spatials/README.md +580 -0
- package/numkong/include/numkong/spatials/alder.h +94 -0
- package/numkong/include/numkong/spatials/diamond.h +82 -0
- package/numkong/include/numkong/spatials/genoa.h +94 -0
- package/numkong/include/numkong/spatials/graniteamx.h +173 -0
- package/numkong/include/numkong/spatials/haswell.h +219 -0
- package/numkong/include/numkong/spatials/icelake.h +113 -0
- package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
- package/numkong/include/numkong/spatials/neon.h +109 -0
- package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
- package/numkong/include/numkong/spatials/neonfhm.h +92 -0
- package/numkong/include/numkong/spatials/neonfp8.h +111 -0
- package/numkong/include/numkong/spatials/neonsdot.h +143 -0
- package/numkong/include/numkong/spatials/powervsx.h +153 -0
- package/numkong/include/numkong/spatials/rvv.h +1976 -0
- package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
- package/numkong/include/numkong/spatials/serial.h +248 -0
- package/numkong/include/numkong/spatials/sierra.h +96 -0
- package/numkong/include/numkong/spatials/skylake.h +184 -0
- package/numkong/include/numkong/spatials/sme.h +1927 -0
- package/numkong/include/numkong/spatials/smef64.h +483 -0
- package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
- package/numkong/include/numkong/spatials.h +3374 -0
- package/numkong/include/numkong/spatials.hpp +509 -0
- package/numkong/include/numkong/tensor.hpp +1981 -0
- package/numkong/include/numkong/trigonometry/README.md +184 -0
- package/numkong/include/numkong/trigonometry/haswell.h +653 -0
- package/numkong/include/numkong/trigonometry/neon.h +638 -0
- package/numkong/include/numkong/trigonometry/rvv.h +700 -0
- package/numkong/include/numkong/trigonometry/serial.h +703 -0
- package/numkong/include/numkong/trigonometry/skylake.h +725 -0
- package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
- package/numkong/include/numkong/trigonometry.h +467 -0
- package/numkong/include/numkong/trigonometry.hpp +166 -0
- package/numkong/include/numkong/types.h +1695 -0
- package/numkong/include/numkong/types.hpp +6027 -0
- package/numkong/include/numkong/vector.hpp +766 -0
- package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
- package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
- package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
- package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
- package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
- package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
- package/numkong/javascript/README.md +254 -0
- package/numkong/javascript/node-gyp-build.d.ts +4 -0
- package/numkong/javascript/numkong-browser.ts +40 -0
- package/numkong/javascript/numkong-wasm.ts +750 -0
- package/numkong/javascript/numkong.c +712 -0
- package/numkong/javascript/numkong.ts +613 -0
- package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
- package/numkong/javascript/tsconfig-cjs.json +13 -0
- package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
- package/numkong/javascript/types.ts +784 -0
- package/numkong/numkong.gypi +104 -0
- package/numkong/package.json +108 -0
- package/numkong/probes/arm_neon.c +8 -0
- package/numkong/probes/arm_neon_bfdot.c +9 -0
- package/numkong/probes/arm_neon_fhm.c +9 -0
- package/numkong/probes/arm_neon_half.c +8 -0
- package/numkong/probes/arm_neon_sdot.c +9 -0
- package/numkong/probes/arm_neonfp8.c +9 -0
- package/numkong/probes/arm_sme.c +16 -0
- package/numkong/probes/arm_sme2.c +16 -0
- package/numkong/probes/arm_sme2p1.c +16 -0
- package/numkong/probes/arm_sme_bf16.c +16 -0
- package/numkong/probes/arm_sme_bi32.c +16 -0
- package/numkong/probes/arm_sme_f64.c +16 -0
- package/numkong/probes/arm_sme_fa64.c +14 -0
- package/numkong/probes/arm_sme_half.c +16 -0
- package/numkong/probes/arm_sme_lut2.c +15 -0
- package/numkong/probes/arm_sve.c +18 -0
- package/numkong/probes/arm_sve2.c +20 -0
- package/numkong/probes/arm_sve2p1.c +18 -0
- package/numkong/probes/arm_sve_bfdot.c +20 -0
- package/numkong/probes/arm_sve_half.c +18 -0
- package/numkong/probes/arm_sve_sdot.c +21 -0
- package/numkong/probes/loongarch_lasx.c +12 -0
- package/numkong/probes/power_vsx.c +12 -0
- package/numkong/probes/probe.js +127 -0
- package/numkong/probes/riscv_rvv.c +14 -0
- package/numkong/probes/riscv_rvv_bb.c +15 -0
- package/numkong/probes/riscv_rvv_bf16.c +17 -0
- package/numkong/probes/riscv_rvv_half.c +14 -0
- package/numkong/probes/wasm_v128relaxed.c +11 -0
- package/numkong/probes/x86_alder.c +17 -0
- package/numkong/probes/x86_diamond.c +17 -0
- package/numkong/probes/x86_genoa.c +17 -0
- package/numkong/probes/x86_graniteamx.c +19 -0
- package/numkong/probes/x86_haswell.c +11 -0
- package/numkong/probes/x86_icelake.c +17 -0
- package/numkong/probes/x86_sapphire.c +16 -0
- package/numkong/probes/x86_sapphireamx.c +18 -0
- package/numkong/probes/x86_sierra.c +17 -0
- package/numkong/probes/x86_skylake.c +15 -0
- package/numkong/probes/x86_turin.c +17 -0
- package/numkong/rust/README.md +698 -0
- package/numkong/rust/capabilities.rs +96 -0
- package/numkong/rust/cast.rs +314 -0
- package/numkong/rust/curved.rs +391 -0
- package/numkong/rust/each.rs +2721 -0
- package/numkong/rust/geospatial.rs +343 -0
- package/numkong/rust/matrix.rs +5424 -0
- package/numkong/rust/maxsim.rs +540 -0
- package/numkong/rust/mesh.rs +837 -0
- package/numkong/rust/numkong.rs +409 -0
- package/numkong/rust/probability.rs +272 -0
- package/numkong/rust/reduce.rs +1249 -0
- package/numkong/rust/set.rs +194 -0
- package/numkong/rust/sparse.rs +513 -0
- package/numkong/rust/spatial.rs +1815 -0
- package/numkong/rust/tensor.rs +7565 -0
- package/numkong/rust/types.rs +3666 -0
- package/numkong/rust/vector.rs +1899 -0
- package/numkong/rustfmt.toml +2 -0
- package/numkong/swift/Matrix.swift +1388 -0
- package/numkong/swift/MaxSim.swift +151 -0
- package/numkong/swift/NumKong.swift +283 -0
- package/numkong/swift/Numerics.swift +329 -0
- package/numkong/swift/README.md +433 -0
- package/numkong/swift/Scalar.swift +741 -0
- package/numkong/swift/Tensor.swift +209 -0
- package/numkong/test/README.md +315 -0
- package/numkong/test/playwright.config.ts +16 -0
- package/numkong/test/swift/Test.swift +534 -0
- package/numkong/test/test-browser-bundle-runner.mjs +36 -0
- package/numkong/test/test-browser-bundle.html +188 -0
- package/numkong/test/test-browser-runner.mjs +43 -0
- package/numkong/test/test-browser.html +305 -0
- package/numkong/test/test-dtypes.mjs +453 -0
- package/numkong/test/test-wasm.mjs +267 -0
- package/numkong/test/test.cpp +442 -0
- package/numkong/test/test.hpp +580 -0
- package/numkong/test/test.mjs +363 -0
- package/numkong/test/test_base.py +1041 -0
- package/numkong/test/test_cast.cpp +242 -0
- package/numkong/test/test_cross.hpp +551 -0
- package/numkong/test/test_cross.py +467 -0
- package/numkong/test/test_cross_amx.cpp +50 -0
- package/numkong/test/test_cross_arm.cpp +225 -0
- package/numkong/test/test_cross_blas.cpp +354 -0
- package/numkong/test/test_cross_loongarch.cpp +90 -0
- package/numkong/test/test_cross_power.cpp +73 -0
- package/numkong/test/test_cross_rvv.cpp +109 -0
- package/numkong/test/test_cross_serial.cpp +181 -0
- package/numkong/test/test_cross_sme.cpp +148 -0
- package/numkong/test/test_cross_wasm.cpp +141 -0
- package/numkong/test/test_cross_x86.cpp +442 -0
- package/numkong/test/test_curved.cpp +182 -0
- package/numkong/test/test_curved.py +207 -0
- package/numkong/test/test_dot.cpp +353 -0
- package/numkong/test/test_dot.py +296 -0
- package/numkong/test/test_each.cpp +437 -0
- package/numkong/test/test_each.py +756 -0
- package/numkong/test/test_geospatial.cpp +155 -0
- package/numkong/test/test_geospatial.py +241 -0
- package/numkong/test/test_maxsim.cpp +138 -0
- package/numkong/test/test_maxsim.py +209 -0
- package/numkong/test/test_mesh.cpp +203 -0
- package/numkong/test/test_mesh.py +394 -0
- package/numkong/test/test_probability.cpp +136 -0
- package/numkong/test/test_probability.py +166 -0
- package/numkong/test/test_reduce.cpp +563 -0
- package/numkong/test/test_reduce.py +781 -0
- package/numkong/test/test_set.cpp +151 -0
- package/numkong/test/test_set.py +120 -0
- package/numkong/test/test_similarities.py +579 -0
- package/numkong/test/test_sparse.cpp +121 -0
- package/numkong/test/test_sparse.py +118 -0
- package/numkong/test/test_spatial.cpp +518 -0
- package/numkong/test/test_spatial.py +269 -0
- package/numkong/test/test_tensor.cpp +884 -0
- package/numkong/test/test_tensor.py +1417 -0
- package/numkong/test/test_trigonometry.cpp +156 -0
- package/numkong/test/test_trigonometry.py +180 -0
- package/package.json +7 -8
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/fp16/CMakeLists.txt +0 -176
- package/fp16/LICENSE +0 -11
- package/fp16/README.md +0 -20
- package/fp16/bench/alt-element.cc +0 -89
- package/fp16/bench/from-alt-array.cc +0 -175
- package/fp16/bench/from-ieee-array.cc +0 -399
- package/fp16/bench/ieee-element.cc +0 -272
- package/fp16/bench/to-alt-array.cc +0 -91
- package/fp16/bench/to-ieee-array.cc +0 -303
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
- package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
- package/fp16/cmake/DownloadPSimd.cmake +0 -15
- package/fp16/configure.py +0 -65
- package/fp16/confu.yaml +0 -8
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +0 -50
- package/fp16/include/fp16/avx2.py +0 -53
- package/fp16/include/fp16/bitcasts.h +0 -92
- package/fp16/include/fp16/fp16.h +0 -451
- package/fp16/include/fp16/psimd.h +0 -131
- package/fp16/include/fp16.h +0 -11
- package/fp16/jni/Android.mk +0 -6
- package/fp16/jni/Application.mk +0 -4
- package/fp16/test/alt-from-fp32-value.cc +0 -498
- package/fp16/test/alt-to-fp32-bits.cc +0 -263
- package/fp16/test/alt-to-fp32-psimd.cc +0 -145
- package/fp16/test/alt-to-fp32-value.cc +0 -348
- package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
- package/fp16/test/bitcasts.cc +0 -56
- package/fp16/test/ieee-from-fp32-value.cc +0 -523
- package/fp16/test/ieee-to-fp32-bits.cc +0 -333
- package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
- package/fp16/test/ieee-to-fp32-value.cc +0 -420
- package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
- package/fp16/test/peachpy/stubs.py +0 -38
- package/fp16/test/tables.cc +0 -530
- package/fp16/test/tables.h +0 -13
- package/fp16/third-party/THHalf.h +0 -92
- package/fp16/third-party/eigen-half.h +0 -170
- package/fp16/third-party/float16-compressor.h +0 -80
- package/fp16/third-party/half.hpp +0 -2916
- package/fp16/third-party/npy-halffloat.h +0 -328
- package/simsimd/.git-blame-ignore-revs +0 -2
- package/simsimd/CONTRIBUTING.md +0 -321
- package/simsimd/Cargo.toml +0 -49
- package/simsimd/MANIFEST.in +0 -4
- package/simsimd/Package.swift +0 -28
- package/simsimd/README.md +0 -1493
- package/simsimd/binding.gyp +0 -35
- package/simsimd/build.rs +0 -70
- package/simsimd/c/lib.c +0 -374
- package/simsimd/include/module.modulemap +0 -4
- package/simsimd/include/simsimd/binary.h +0 -486
- package/simsimd/include/simsimd/curved.h +0 -1541
- package/simsimd/include/simsimd/dot.h +0 -1853
- package/simsimd/include/simsimd/elementwise.h +0 -2465
- package/simsimd/include/simsimd/geospatial.h +0 -43
- package/simsimd/include/simsimd/mesh.h +0 -69
- package/simsimd/include/simsimd/probability.h +0 -606
- package/simsimd/include/simsimd/simsimd.h +0 -2567
- package/simsimd/include/simsimd/sparse.h +0 -1384
- package/simsimd/include/simsimd/spatial.h +0 -2335
- package/simsimd/include/simsimd/types.h +0 -666
- package/simsimd/javascript/fallback.ts +0 -233
- package/simsimd/javascript/lib.c +0 -125
- package/simsimd/javascript/node-gyp-build.d.ts +0 -1
- package/simsimd/javascript/simsimd.ts +0 -179
- package/simsimd/javascript/tsconfig-cjs.json +0 -8
- package/simsimd/package-lock.json +0 -1761
- package/simsimd/package.json +0 -61
- package/simsimd/rust/lib.rs +0 -1821
- package/simsimd/scripts/bench.cxx +0 -1170
- package/simsimd/scripts/bench.ipynb +0 -187
- package/simsimd/scripts/bench.js +0 -127
- package/simsimd/scripts/bench.rs +0 -876
- package/simsimd/scripts/bench_vectors.py +0 -734
- package/simsimd/scripts/bench_vectors_live.py +0 -213
- package/simsimd/scripts/test.c +0 -187
- package/simsimd/scripts/test.mjs +0 -220
- package/simsimd/scripts/test.py +0 -1505
- package/simsimd/swift/SimSIMD.swift +0 -149
- package/simsimd/swift/Test.swift +0 -128
- /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
- /package/{simsimd → numkong}/LICENSE +0 -0
- /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
- /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
//! # NumKong - Hardware-Accelerated Numerics
|
|
2
|
+
//!
|
|
3
|
+
//! Provides SIMD-accelerated distance metrics, elementwise operations, and tensor algebra
|
|
4
|
+
//! targeting ARM NEON/SVE/SME and x86 AVX2/AVX-512 backends.
|
|
5
|
+
//!
|
|
6
|
+
//! ## Modules
|
|
7
|
+
//!
|
|
8
|
+
//! - [`types`]: Mixed-precision scalar types (`f16`, `bf16`, FP8, packed integers) and [`FloatLike`] trait
|
|
9
|
+
//! - [`spatial`]: Dot products, angular (cosine), and Euclidean distances
|
|
10
|
+
//! - [`each`]: Elementwise operations and trigonometry
|
|
11
|
+
//! - [`reduce`]: Statistical reductions (moments, min/max)
|
|
12
|
+
//! - [`set`]: Binary set similarity (Hamming, Jaccard)
|
|
13
|
+
//! - [`probability`]: Probability divergences (KL, JS)
|
|
14
|
+
//! - [`curved`]: Curved metric spaces (Bilinear, Mahalanobis)
|
|
15
|
+
//! - [`mesh`]: Mesh alignment (Kabsch, Umeyama, RMSD)
|
|
16
|
+
//! - [`geospatial`]: Geospatial distances (Haversine, Vincenty)
|
|
17
|
+
//! - [`sparse`]: Sparse set operations
|
|
18
|
+
//! - [`cast`]: Type casting between scalar formats
|
|
19
|
+
//! - [`capabilities`]: Runtime SIMD feature detection
|
|
20
|
+
//! - [`matrix`]: Batch matrix operations (GEMM, packed spatial distances)
|
|
21
|
+
//! - [`tensor`]: N-dimensional tensors with elementwise/reduction operations
|
|
22
|
+
//!
|
|
23
|
+
//! ## Implemented operations include:
|
|
24
|
+
//!
|
|
25
|
+
//! * Euclidean (L2), inner product, and angular (cosine) spatial distances.
|
|
26
|
+
//! * Hamming and Jaccard binary distances.
|
|
27
|
+
//! * Kullback-Leibler divergence and Jensen-Shannon distance.
|
|
28
|
+
//! * Elementwise scale, sum, blend, and FMA operations.
|
|
29
|
+
//! * Trigonometric functions (sin, cos, atan).
|
|
30
|
+
//! * Type casting between all scalar formats.
|
|
31
|
+
//! * Matrix multiplication with pre-packing (GEMM).
|
|
32
|
+
//!
|
|
33
|
+
//! ## Example
|
|
34
|
+
//!
|
|
35
|
+
//! ```rust
|
|
36
|
+
//! use numkong::{Dot, Angular, Euclidean};
|
|
37
|
+
//!
|
|
38
|
+
//! let a = &[1.0_f32, 2.0, 3.0];
|
|
39
|
+
//! let b = &[4.0_f32, 5.0, 6.0];
|
|
40
|
+
//!
|
|
41
|
+
//! let dot_product = f32::dot(a, b);
|
|
42
|
+
//! let angular_dist = f32::angular(a, b);
|
|
43
|
+
//! let l2sq_dist = f32::sqeuclidean(a, b);
|
|
44
|
+
//!
|
|
45
|
+
//! // Enable AMX and other platform-specific SIMD features
|
|
46
|
+
//! numkong::capabilities::configure_thread();
|
|
47
|
+
//! ```
|
|
48
|
+
//!
|
|
49
|
+
//! ## Mixed Precision Support
|
|
50
|
+
//!
|
|
51
|
+
//! ```rust
|
|
52
|
+
//! use numkong::{Angular, f16, bf16};
|
|
53
|
+
//!
|
|
54
|
+
//! // Work with half-precision floats
|
|
55
|
+
//! let half_a: Vec<f16> = vec![1.0, 2.0, 3.0].iter().map(|&x| f16::from_f32(x)).collect();
|
|
56
|
+
//! let half_b: Vec<f16> = vec![4.0, 5.0, 6.0].iter().map(|&x| f16::from_f32(x)).collect();
|
|
57
|
+
//! let half_angular_dist = f16::angular(&half_a, &half_b);
|
|
58
|
+
//!
|
|
59
|
+
//! // Work with brain floats
|
|
60
|
+
//! let brain_a: Vec<bf16> = vec![1.0, 2.0, 3.0].iter().map(|&x| bf16::from_f32(x)).collect();
|
|
61
|
+
//! let brain_b: Vec<bf16> = vec![4.0, 5.0, 6.0].iter().map(|&x| bf16::from_f32(x)).collect();
|
|
62
|
+
//! let brain_angular_dist = bf16::angular(&brain_a, &brain_b);
|
|
63
|
+
//!
|
|
64
|
+
//! // Direct bit manipulation
|
|
65
|
+
//! let half = f16::from_f32(3.14);
|
|
66
|
+
//! let bits = half.0; // Access raw u16 representation
|
|
67
|
+
//! let reconstructed = f16(bits);
|
|
68
|
+
//! ```
|
|
69
|
+
//!
|
|
70
|
+
//! ## Traits
|
|
71
|
+
//!
|
|
72
|
+
//! The `SpatialSimilarity` trait (combining `Dot`, `Angular`, `Euclidean`) covers:
|
|
73
|
+
//!
|
|
74
|
+
//! - `dot(a, b)`: Computes dot product between two slices.
|
|
75
|
+
//! - `angular(a, b)` / `cosine(a, b)`: Computes angular distance (1 − cosine similarity).
|
|
76
|
+
//! - `sqeuclidean(a, b)`: Computes squared Euclidean distance.
|
|
77
|
+
//! - `euclidean(a, b)`: Computes Euclidean distance.
|
|
78
|
+
//!
|
|
79
|
+
//! The `BinarySimilarity` trait (combining `Hamming`, `Jaccard`) covers:
|
|
80
|
+
//!
|
|
81
|
+
//! - `hamming(a, b)`: Computes Hamming distance between two slices.
|
|
82
|
+
//! - `jaccard(a, b)`: Computes Jaccard distance between two slices.
|
|
83
|
+
//!
|
|
84
|
+
//! The `ProbabilitySimilarity` trait (combining `KullbackLeibler`, `JensenShannon`) covers:
|
|
85
|
+
//!
|
|
86
|
+
//! - `jensenshannon(a, b)`: Computes Jensen-Shannon distance.
|
|
87
|
+
//! - `kullbackleibler(a, b)`: Computes Kullback-Leibler divergence.
|
|
88
|
+
//!
|
|
89
|
+
//! The elementwise traits (including `EachScale`, `EachSum`, `EachBlend`, `EachFMA`) covers:
|
|
90
|
+
//!
|
|
91
|
+
//! - `scale(a, alpha, beta, result)`: Element-wise `result[i] = α × a[i] + β`.
|
|
92
|
+
//! - `sum(a, b, result)`: Element-wise `result[i] = a[i] + b[i]`.
|
|
93
|
+
//! - `blend(a, b, alpha, beta, result)`: Blend `result[i] = α × a[i] + β × b[i]`.
|
|
94
|
+
//! - `fma(a, b, c, alpha, beta, result)`: Fused multiply-add `result[i] = α × a[i] × b[i] + β × c[i]`.
|
|
95
|
+
//!
|
|
96
|
+
//! The `Trigonometry` trait (combining `EachSin`, `EachCos`, `EachATan`) covers:
|
|
97
|
+
//!
|
|
98
|
+
//! - `sin(input, result)`: Element-wise sine.
|
|
99
|
+
//! - `cos(input, result)`: Element-wise cosine.
|
|
100
|
+
//! - `atan(input, result)`: Element-wise arctangent.
|
|
101
|
+
//!
|
|
102
|
+
//! Additional traits: `VDot`, `Roots`, `SparseIntersect`, `SparseDot`.
|
|
103
|
+
//!
|
|
104
|
+
#![allow(non_camel_case_types)]
|
|
105
|
+
#![allow(clippy::too_many_arguments)]
|
|
106
|
+
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
|
|
107
|
+
|
|
108
|
+
// Domain modules
|
|
109
|
+
pub mod capabilities;
|
|
110
|
+
pub mod cast;
|
|
111
|
+
pub mod curved;
|
|
112
|
+
pub mod each;
|
|
113
|
+
pub mod geospatial;
|
|
114
|
+
pub mod maxsim;
|
|
115
|
+
pub mod mesh;
|
|
116
|
+
pub mod probability;
|
|
117
|
+
pub mod reduce;
|
|
118
|
+
pub mod set;
|
|
119
|
+
pub mod sparse;
|
|
120
|
+
pub mod spatial;
|
|
121
|
+
|
|
122
|
+
// Containers
|
|
123
|
+
pub mod matrix;
|
|
124
|
+
pub mod tensor;
|
|
125
|
+
pub mod types;
|
|
126
|
+
pub mod vector;
|
|
127
|
+
|
|
128
|
+
// Re-export scalar types at crate root
|
|
129
|
+
pub use types::{
|
|
130
|
+
bf16, bf16c, e2m3, e3m2, e4m3, e5m2, f16, f16c, f32c, f64c, i4x2, is_close, u1x8, u4x2, DimMut,
|
|
131
|
+
DimRef, FloatConvertible, FloatLike, NumberLike, StorageElement,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Re-export spatial traits
|
|
135
|
+
pub use spatial::{Angular, Dot, Euclidean, Roots, SpatialSimilarity, VDot};
|
|
136
|
+
|
|
137
|
+
// Re-export set traits
|
|
138
|
+
pub use set::{BinarySimilarity, Hamming, Jaccard};
|
|
139
|
+
|
|
140
|
+
// Re-export probability traits
|
|
141
|
+
pub use probability::{JensenShannon, KullbackLeibler, ProbabilitySimilarity};
|
|
142
|
+
|
|
143
|
+
// Re-export elementwise and trig traits
|
|
144
|
+
pub use each::{EachATan, EachBlend, EachCos, EachFMA, EachScale, EachSin, EachSum, Trigonometry};
|
|
145
|
+
|
|
146
|
+
// Re-export reduction traits
|
|
147
|
+
pub use reduce::{ReduceMinMax, ReduceMoments, Reductions};
|
|
148
|
+
|
|
149
|
+
// Re-export curved metric traits
|
|
150
|
+
pub use curved::{Bilinear, Mahalanobis};
|
|
151
|
+
|
|
152
|
+
// Re-export mesh alignment
|
|
153
|
+
pub use mesh::{MeshAlignment, MeshAlignmentResult};
|
|
154
|
+
|
|
155
|
+
// Re-export geospatial
|
|
156
|
+
pub use geospatial::{Geospatial, Haversine, Vincenty};
|
|
157
|
+
|
|
158
|
+
// Re-export sparse
|
|
159
|
+
pub use sparse::{SparseDot, SparseIntersect};
|
|
160
|
+
|
|
161
|
+
// Re-export cast operations
|
|
162
|
+
pub use cast::{cast, CastDtype};
|
|
163
|
+
|
|
164
|
+
// Re-export capabilities
|
|
165
|
+
pub use capabilities::cap;
|
|
166
|
+
pub use capabilities::{available, configure_thread, uses_dynamic_dispatch};
|
|
167
|
+
|
|
168
|
+
// Re-export tensor types
|
|
169
|
+
pub use tensor::{
|
|
170
|
+
AllCloseOps, Allocator, AxisIterator, AxisIteratorMut, BlendOps, CastOps, FmaOps, Global,
|
|
171
|
+
Matrix, MatrixSpan, MatrixView, MinMaxOps, MinMaxResult, MomentsOps, RangeStep, ScaleOps,
|
|
172
|
+
SliceArg, SliceRange, SliceSpec, SumOps, Tensor, TensorDims, TensorError, TensorIterator,
|
|
173
|
+
TensorMut, TensorRef, TensorSpan, TensorSpanDims, TensorSpanIterator, TensorView,
|
|
174
|
+
TensorViewDims, TensorViewIterator, TrigAtanOps, TrigCosOps, TrigSinOps, DEFAULT_MAX_RANK,
|
|
175
|
+
SIMD_ALIGNMENT,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Re-export matrix types
|
|
179
|
+
pub use matrix::{
|
|
180
|
+
Angulars, Dots, Euclideans, Hammings, Jaccards, PackedMatrix, SymmetricAngulars, SymmetricDots,
|
|
181
|
+
SymmetricEuclideans, SymmetricHammings, SymmetricJaccards,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Re-export vector types
|
|
185
|
+
pub use vector::{
|
|
186
|
+
Vector, VectorIndex, VectorIterator, VectorSpan, VectorSpanIterator, VectorView,
|
|
187
|
+
VectorViewIterator,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Re-export maxsim types
|
|
191
|
+
pub use maxsim::{MaxSim, MaxSimPackedMatrix};
|
|
192
|
+
|
|
193
|
+
// region: Tests
|
|
194
|
+
|
|
195
|
+
#[cfg(test)]
|
|
196
|
+
mod tests {
|
|
197
|
+
use super::*;
|
|
198
|
+
|
|
199
|
+
#[test]
|
|
200
|
+
fn dot_smoke() {
|
|
201
|
+
let first = [1.0_f32, 2.0, 3.0];
|
|
202
|
+
let second = [4.0_f32, 5.0, 6.0];
|
|
203
|
+
assert!((<f32 as Dot>::dot(&first, &second).unwrap() - 32.0).abs() < 0.01);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
#[test]
|
|
207
|
+
fn angular_smoke() {
|
|
208
|
+
let first = [1.0_f32, 0.0];
|
|
209
|
+
let second = [0.0_f32, 1.0];
|
|
210
|
+
// Orthogonal vectors → angular distance = 1.0
|
|
211
|
+
assert!((f32::angular(&first, &second).unwrap() - 1.0).abs() < 0.01);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
#[test]
|
|
215
|
+
fn euclidean_smoke() {
|
|
216
|
+
let first = [0.0_f32, 0.0, 0.0];
|
|
217
|
+
let second = [3.0_f32, 4.0, 0.0];
|
|
218
|
+
assert!((f32::euclidean(&first, &second).unwrap() - 5.0).abs() < 0.1);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
#[test]
|
|
222
|
+
fn maxsim_smoke() {
|
|
223
|
+
capabilities::configure_thread();
|
|
224
|
+
let queries = Tensor::<f32>::try_full(&[4, 16], 1.0).unwrap();
|
|
225
|
+
let documents = Tensor::<f32>::try_full(&[8, 16], 1.0).unwrap();
|
|
226
|
+
let queries_view = queries.view();
|
|
227
|
+
let docs_view = documents.view();
|
|
228
|
+
let queries_packed = MaxSimPackedMatrix::try_pack(&queries_view).unwrap();
|
|
229
|
+
let docs_packed = MaxSimPackedMatrix::try_pack(&docs_view).unwrap();
|
|
230
|
+
assert_eq!(queries_packed.dims(), (4, 16));
|
|
231
|
+
assert_eq!(docs_packed.dims(), (8, 16));
|
|
232
|
+
let score = queries_packed.score(&docs_packed);
|
|
233
|
+
assert!(
|
|
234
|
+
score.is_finite(),
|
|
235
|
+
"MaxSim score must be finite, got {score}"
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#[test]
|
|
240
|
+
fn tensor_dots_smoke() {
|
|
241
|
+
capabilities::configure_thread();
|
|
242
|
+
let queries = Tensor::<f32>::try_full(&[2, 4], 1.0).unwrap();
|
|
243
|
+
let targets = Tensor::<f32>::try_full(&[3, 4], 1.0).unwrap();
|
|
244
|
+
let packed_targets = PackedMatrix::try_pack(&targets).unwrap();
|
|
245
|
+
let products = queries.dots_packed(&packed_targets);
|
|
246
|
+
assert_eq!(products.shape(), &[2, 3]);
|
|
247
|
+
assert!((products.as_slice()[0] - 4.0).abs() < 0.01);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// endregion: Tests
|
|
252
|
+
|
|
253
|
+
// region: WASM Runtime Tests
|
|
254
|
+
|
|
255
|
+
/// WASM runtime integration tests using Wasmtime
|
|
256
|
+
/// These tests validate that WASI builds work correctly with standalone runtimes
|
|
257
|
+
#[cfg(all(test, feature = "wasm-runtime"))]
|
|
258
|
+
mod wasm_runtime_tests {
|
|
259
|
+
use std::fs;
|
|
260
|
+
use std::path::Path;
|
|
261
|
+
use wasmtime::{
|
|
262
|
+
Config, Engine, Extern, ExternType, Linker, Memory, MemoryType, Module, SharedMemory, Store,
|
|
263
|
+
};
|
|
264
|
+
use wasmtime_wasi::WasiCtx;
|
|
265
|
+
|
|
266
|
+
fn resolve_wasi_module() -> Option<String> {
|
|
267
|
+
if let Ok(path) = std::env::var("NK_WASI_MODULE") {
|
|
268
|
+
if Path::new(&path).exists() {
|
|
269
|
+
return Some(path);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if Path::new("build-wasi/nk_test.wasm").exists() {
|
|
273
|
+
Some("build-wasi/nk_test.wasm".to_string())
|
|
274
|
+
} else if Path::new("build-wasi/test.wasm").exists() {
|
|
275
|
+
Some("build-wasi/test.wasm".to_string())
|
|
276
|
+
} else {
|
|
277
|
+
None
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/// Test that WASI WASM module can be loaded and executed with Wasmtime
|
|
282
|
+
/// This validates the dual-path capability detection (EM_ASM vs WASI imports)
|
|
283
|
+
#[test]
|
|
284
|
+
fn wasi_with_wasmtime() -> wasmtime::Result<()> {
|
|
285
|
+
// Check if WASI build exists
|
|
286
|
+
let Some(wasm_path) = resolve_wasi_module() else {
|
|
287
|
+
eprintln!("WASI build not found. Run:");
|
|
288
|
+
eprintln!(" export WASI_SDK_PATH=~/wasi-sdk");
|
|
289
|
+
eprintln!(" cmake -B build-wasi -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-wasi.cmake -DNK_BUILD_TEST=ON");
|
|
290
|
+
eprintln!(" cmake --build build-wasi --target nk_test");
|
|
291
|
+
return Ok(()); // Skip test if build doesn't exist
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
println!("Loading WASI module from {}", wasm_path);
|
|
295
|
+
|
|
296
|
+
let mut config = Config::new();
|
|
297
|
+
config.wasm_simd(true);
|
|
298
|
+
config.wasm_relaxed_simd(true);
|
|
299
|
+
config.wasm_threads(true);
|
|
300
|
+
config.shared_memory(true);
|
|
301
|
+
|
|
302
|
+
// Create Wasmtime engine and linker
|
|
303
|
+
let engine = Engine::new(&config)?;
|
|
304
|
+
let mut linker = Linker::new(&engine);
|
|
305
|
+
|
|
306
|
+
// Create WASI context (Wasmtime 41+ API)
|
|
307
|
+
// Don't inherit_args() — cargo's test filter args would confuse the WASM test binary.
|
|
308
|
+
let wasi = WasiCtx::builder().inherit_stdio().inherit_env().build_p1();
|
|
309
|
+
let mut store = Store::new(&engine, wasi);
|
|
310
|
+
|
|
311
|
+
// Add WASI support (Wasmtime 41+ requires p1 module)
|
|
312
|
+
wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |s| s)?;
|
|
313
|
+
|
|
314
|
+
// Provide capability detection imports (required for WASI build)
|
|
315
|
+
// These functions are called from nk_capabilities_v128relaxed_() in C code
|
|
316
|
+
linker.func_wrap("env", "nk_has_v128", || -> i32 {
|
|
317
|
+
// Return 1 (true) - assume SIMD128 is available in Wasmtime
|
|
318
|
+
println!(" nk_has_v128() called from WASM -> returning 1");
|
|
319
|
+
1
|
|
320
|
+
})?;
|
|
321
|
+
|
|
322
|
+
linker.func_wrap("env", "nk_has_relaxed", || -> i32 {
|
|
323
|
+
// Return 1 (true) - assume Relaxed SIMD is available in Wasmtime
|
|
324
|
+
println!(" nk_has_relaxed() called from WASM -> returning 1");
|
|
325
|
+
1
|
|
326
|
+
})?;
|
|
327
|
+
|
|
328
|
+
linker.func_wrap("wasi", "thread-spawn", |_start_arg: i32| -> i32 { -1 })?;
|
|
329
|
+
|
|
330
|
+
// Load WASM module
|
|
331
|
+
let wasm_bytes = fs::read(&wasm_path)?;
|
|
332
|
+
let module = Module::new(&engine, wasm_bytes)?;
|
|
333
|
+
|
|
334
|
+
for import in module.imports() {
|
|
335
|
+
if import.module() != "env" || import.name() != "memory" {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
let ExternType::Memory(memory_ty) = import.ty() else {
|
|
340
|
+
continue;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
let minimum = u32::try_from(memory_ty.minimum()).map_err(|_| {
|
|
344
|
+
wasmtime::Error::msg(format!(
|
|
345
|
+
"memory minimum {} does not fit in u32",
|
|
346
|
+
memory_ty.minimum()
|
|
347
|
+
))
|
|
348
|
+
})?;
|
|
349
|
+
let maximum = memory_ty
|
|
350
|
+
.maximum()
|
|
351
|
+
.ok_or_else(|| wasmtime::Error::msg("shared memory import is missing a maximum"))?;
|
|
352
|
+
let maximum = u32::try_from(maximum).map_err(|_| {
|
|
353
|
+
wasmtime::Error::msg(format!("memory maximum {maximum} does not fit in u32"))
|
|
354
|
+
})?;
|
|
355
|
+
|
|
356
|
+
if memory_ty.is_shared() {
|
|
357
|
+
let memory = SharedMemory::new(&engine, MemoryType::shared(minimum, maximum))?;
|
|
358
|
+
linker.define(&store, "env", "memory", Extern::from(memory))?;
|
|
359
|
+
} else {
|
|
360
|
+
let memory = Memory::new(&mut store, MemoryType::new(minimum, Some(maximum)))?;
|
|
361
|
+
linker.define(&store, "env", "memory", Extern::from(memory))?;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Instantiate module
|
|
366
|
+
println!("Instantiating WASM module...");
|
|
367
|
+
let instance = linker.instantiate(&mut store, &module)?;
|
|
368
|
+
|
|
369
|
+
// Get _start entry point (WASI convention; exit code comes via proc_exit trap)
|
|
370
|
+
let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?;
|
|
371
|
+
|
|
372
|
+
// Run tests — _start calls exit(0) which triggers proc_exit(0).
|
|
373
|
+
// Wasmtime reports proc_exit as an I32Exit error; exit code 0 means success.
|
|
374
|
+
println!("Running WASM tests...");
|
|
375
|
+
match start.call(&mut store, ()) {
|
|
376
|
+
Ok(()) => {}
|
|
377
|
+
Err(e) => {
|
|
378
|
+
if let Some(exit) = e.downcast_ref::<wasmtime_wasi::I32Exit>() {
|
|
379
|
+
assert_eq!(exit.0, 0, "WASI tests failed with exit code {}", exit.0);
|
|
380
|
+
} else {
|
|
381
|
+
return Err(e);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
println!("WASM tests completed successfully");
|
|
387
|
+
Ok(())
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/// Test capability detection mechanism works in WASI environment
|
|
391
|
+
#[test]
|
|
392
|
+
fn capability_imports() -> wasmtime::Result<()> {
|
|
393
|
+
println!("Testing capability import mechanism...");
|
|
394
|
+
|
|
395
|
+
// Create minimal engine for import testing
|
|
396
|
+
let engine = Engine::default();
|
|
397
|
+
let mut linker = Linker::<()>::new(&engine);
|
|
398
|
+
|
|
399
|
+
// Test that we can define the required imports
|
|
400
|
+
linker.func_wrap("env", "nk_has_v128", || -> i32 { 1 })?;
|
|
401
|
+
linker.func_wrap("env", "nk_has_relaxed", || -> i32 { 0 })?;
|
|
402
|
+
|
|
403
|
+
println!(" ✓ Capability imports defined successfully");
|
|
404
|
+
|
|
405
|
+
Ok(())
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// endregion: WASM Runtime Tests
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
//! Probability measures: Kullback-Leibler divergence and Jensen-Shannon distance.
|
|
2
|
+
//!
|
|
3
|
+
//! This module provides:
|
|
4
|
+
//!
|
|
5
|
+
//! - [`KullbackLeibler`]: KL divergence between two distributions
|
|
6
|
+
//! - [`JensenShannon`]: Jensen-Shannon distance (symmetric metric)
|
|
7
|
+
//! - [`ProbabilitySimilarity`]: Blanket trait combining `KullbackLeibler + JensenShannon`
|
|
8
|
+
|
|
9
|
+
use crate::types::{bf16, f16};
|
|
10
|
+
|
|
11
|
+
#[link(name = "numkong")]
|
|
12
|
+
extern "C" {
|
|
13
|
+
fn nk_jsd_f16(a: *const u16, b: *const u16, c: usize, d: *mut f32);
|
|
14
|
+
fn nk_jsd_bf16(a: *const u16, b: *const u16, c: usize, d: *mut f32);
|
|
15
|
+
fn nk_jsd_f32(a: *const f32, b: *const f32, c: usize, d: *mut f64);
|
|
16
|
+
fn nk_jsd_f64(a: *const f64, b: *const f64, c: usize, d: *mut f64);
|
|
17
|
+
|
|
18
|
+
fn nk_kld_f16(a: *const u16, b: *const u16, c: usize, d: *mut f32);
|
|
19
|
+
fn nk_kld_bf16(a: *const u16, b: *const u16, c: usize, d: *mut f32);
|
|
20
|
+
fn nk_kld_f32(a: *const f32, b: *const f32, c: usize, d: *mut f64);
|
|
21
|
+
fn nk_kld_f64(a: *const f64, b: *const f64, c: usize, d: *mut f64);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// region: KullbackLeibler
|
|
25
|
+
|
|
26
|
+
/// Computes the **Kullback-Leibler divergence** between two probability distributions.
|
|
27
|
+
///
|
|
28
|
+
/// D_KL(P‖Q) = ∑ᵢ pᵢ × ln(pᵢ / qᵢ)
|
|
29
|
+
///
|
|
30
|
+
/// Range: \[0, ∞). Not symmetric. Returns `None` if lengths differ.
|
|
31
|
+
///
|
|
32
|
+
/// Implemented for: `f64`, `f32`, `f16`, `bf16`.
|
|
33
|
+
pub trait KullbackLeibler: Sized {
|
|
34
|
+
type Output;
|
|
35
|
+
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Self::Output>;
|
|
36
|
+
|
|
37
|
+
/// Alias for `kullbackleibler`.
|
|
38
|
+
fn kl(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
39
|
+
Self::kullbackleibler(a, b)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl KullbackLeibler for f64 {
|
|
44
|
+
type Output = f64;
|
|
45
|
+
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
46
|
+
if a.len() != b.len() {
|
|
47
|
+
return None;
|
|
48
|
+
}
|
|
49
|
+
let mut result: Self::Output = 0.0;
|
|
50
|
+
unsafe { nk_kld_f64(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
|
|
51
|
+
Some(result)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
impl KullbackLeibler for f32 {
|
|
56
|
+
type Output = f64;
|
|
57
|
+
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
58
|
+
if a.len() != b.len() {
|
|
59
|
+
return None;
|
|
60
|
+
}
|
|
61
|
+
let mut result: Self::Output = 0.0;
|
|
62
|
+
unsafe { nk_kld_f32(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
|
|
63
|
+
Some(result)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
impl KullbackLeibler for f16 {
|
|
68
|
+
type Output = f32;
|
|
69
|
+
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
70
|
+
if a.len() != b.len() {
|
|
71
|
+
return None;
|
|
72
|
+
}
|
|
73
|
+
let mut result: Self::Output = 0.0;
|
|
74
|
+
unsafe {
|
|
75
|
+
nk_kld_f16(
|
|
76
|
+
a.as_ptr() as *const u16,
|
|
77
|
+
b.as_ptr() as *const u16,
|
|
78
|
+
a.len(),
|
|
79
|
+
&mut result,
|
|
80
|
+
)
|
|
81
|
+
};
|
|
82
|
+
Some(result)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
impl KullbackLeibler for bf16 {
|
|
87
|
+
type Output = f32;
|
|
88
|
+
fn kullbackleibler(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
89
|
+
if a.len() != b.len() {
|
|
90
|
+
return None;
|
|
91
|
+
}
|
|
92
|
+
let mut result: Self::Output = 0.0;
|
|
93
|
+
unsafe {
|
|
94
|
+
nk_kld_bf16(
|
|
95
|
+
a.as_ptr() as *const u16,
|
|
96
|
+
b.as_ptr() as *const u16,
|
|
97
|
+
a.len(),
|
|
98
|
+
&mut result,
|
|
99
|
+
)
|
|
100
|
+
};
|
|
101
|
+
Some(result)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// endregion: KullbackLeibler
|
|
106
|
+
|
|
107
|
+
// region: JensenShannon
|
|
108
|
+
|
|
109
|
+
/// Computes the **Jensen-Shannon distance** between two probability distributions.
|
|
110
|
+
///
|
|
111
|
+
/// d_JS(P, Q) = √(½(D_KL(P‖M) + D_KL(Q‖M))), where M = (P + Q) / 2
|
|
112
|
+
///
|
|
113
|
+
/// Range: \[0, √ln2\]. Symmetric. Returns `None` if lengths differ.
|
|
114
|
+
///
|
|
115
|
+
/// Implemented for: `f64`, `f32`, `f16`, `bf16`.
|
|
116
|
+
pub trait JensenShannon: Sized {
|
|
117
|
+
type Output;
|
|
118
|
+
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Self::Output>;
|
|
119
|
+
|
|
120
|
+
/// Alias for `jensenshannon`.
|
|
121
|
+
fn js(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
122
|
+
Self::jensenshannon(a, b)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
impl JensenShannon for f64 {
|
|
127
|
+
type Output = f64;
|
|
128
|
+
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
129
|
+
if a.len() != b.len() {
|
|
130
|
+
return None;
|
|
131
|
+
}
|
|
132
|
+
let mut result: Self::Output = 0.0;
|
|
133
|
+
unsafe { nk_jsd_f64(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
|
|
134
|
+
Some(result)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
impl JensenShannon for f32 {
|
|
139
|
+
type Output = f64;
|
|
140
|
+
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
141
|
+
if a.len() != b.len() {
|
|
142
|
+
return None;
|
|
143
|
+
}
|
|
144
|
+
let mut result: Self::Output = 0.0;
|
|
145
|
+
unsafe { nk_jsd_f32(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
|
|
146
|
+
Some(result)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
impl JensenShannon for f16 {
|
|
151
|
+
type Output = f32;
|
|
152
|
+
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
153
|
+
if a.len() != b.len() {
|
|
154
|
+
return None;
|
|
155
|
+
}
|
|
156
|
+
let mut result: Self::Output = 0.0;
|
|
157
|
+
unsafe {
|
|
158
|
+
nk_jsd_f16(
|
|
159
|
+
a.as_ptr() as *const u16,
|
|
160
|
+
b.as_ptr() as *const u16,
|
|
161
|
+
a.len(),
|
|
162
|
+
&mut result,
|
|
163
|
+
)
|
|
164
|
+
};
|
|
165
|
+
Some(result)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
impl JensenShannon for bf16 {
|
|
170
|
+
type Output = f32;
|
|
171
|
+
fn jensenshannon(a: &[Self], b: &[Self]) -> Option<Self::Output> {
|
|
172
|
+
if a.len() != b.len() {
|
|
173
|
+
return None;
|
|
174
|
+
}
|
|
175
|
+
let mut result: Self::Output = 0.0;
|
|
176
|
+
unsafe {
|
|
177
|
+
nk_jsd_bf16(
|
|
178
|
+
a.as_ptr() as *const u16,
|
|
179
|
+
b.as_ptr() as *const u16,
|
|
180
|
+
a.len(),
|
|
181
|
+
&mut result,
|
|
182
|
+
)
|
|
183
|
+
};
|
|
184
|
+
Some(result)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// endregion: JensenShannon
|
|
189
|
+
|
|
190
|
+
/// `ProbabilitySimilarity` bundles probability divergence metrics: KullbackLeibler and JensenShannon.
|
|
191
|
+
pub trait ProbabilitySimilarity: KullbackLeibler + JensenShannon {}
|
|
192
|
+
impl<Scalar: KullbackLeibler + JensenShannon> ProbabilitySimilarity for Scalar {}
|
|
193
|
+
|
|
194
|
+
#[cfg(test)]
|
|
195
|
+
mod tests {
|
|
196
|
+
use super::*;
|
|
197
|
+
use crate::types::{assert_close, bf16, f16, FloatLike, NumberLike, TestableType};
|
|
198
|
+
|
|
199
|
+
fn check_kld<Scalar>(distribution_a: &[f32], distribution_b: &[f32], expected: f64)
|
|
200
|
+
where
|
|
201
|
+
Scalar: FloatLike + TestableType + KullbackLeibler,
|
|
202
|
+
Scalar::Output: FloatLike,
|
|
203
|
+
{
|
|
204
|
+
let a_samples: Vec<Scalar> = distribution_a
|
|
205
|
+
.iter()
|
|
206
|
+
.map(|&v| Scalar::from_f32(v))
|
|
207
|
+
.collect();
|
|
208
|
+
let b_samples: Vec<Scalar> = distribution_b
|
|
209
|
+
.iter()
|
|
210
|
+
.map(|&v| Scalar::from_f32(v))
|
|
211
|
+
.collect();
|
|
212
|
+
let result = Scalar::kullbackleibler(&a_samples, &b_samples)
|
|
213
|
+
.unwrap()
|
|
214
|
+
.to_f64();
|
|
215
|
+
// Divergences involve ln() so need wider tolerance than simple dot products
|
|
216
|
+
assert_close(
|
|
217
|
+
result,
|
|
218
|
+
expected,
|
|
219
|
+
Scalar::atol().max(1e-6),
|
|
220
|
+
Scalar::rtol().max(1e-6),
|
|
221
|
+
&format!("kld<{}>", core::any::type_name::<Scalar>()),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
fn check_jsd<Scalar>(distribution_a: &[f32], distribution_b: &[f32], expected: f64)
|
|
226
|
+
where
|
|
227
|
+
Scalar: FloatLike + TestableType + JensenShannon,
|
|
228
|
+
Scalar::Output: FloatLike,
|
|
229
|
+
{
|
|
230
|
+
let a_samples: Vec<Scalar> = distribution_a
|
|
231
|
+
.iter()
|
|
232
|
+
.map(|&v| Scalar::from_f32(v))
|
|
233
|
+
.collect();
|
|
234
|
+
let b_samples: Vec<Scalar> = distribution_b
|
|
235
|
+
.iter()
|
|
236
|
+
.map(|&v| Scalar::from_f32(v))
|
|
237
|
+
.collect();
|
|
238
|
+
let result = Scalar::jensenshannon(&a_samples, &b_samples)
|
|
239
|
+
.unwrap()
|
|
240
|
+
.to_f64();
|
|
241
|
+
// Divergences involve ln() so need wider tolerance than simple dot products
|
|
242
|
+
assert_close(
|
|
243
|
+
result,
|
|
244
|
+
expected,
|
|
245
|
+
Scalar::atol().max(1e-6),
|
|
246
|
+
Scalar::rtol().max(1e-6),
|
|
247
|
+
&format!("jsd<{}>", core::any::type_name::<Scalar>()),
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
#[test]
|
|
252
|
+
fn divergences() {
|
|
253
|
+
let distribution_a = &[0.1_f32, 0.9, 0.0];
|
|
254
|
+
let distribution_b = &[0.2_f32, 0.8, 0.0];
|
|
255
|
+
|
|
256
|
+
// KL(a||b) = 0.1*ln(0.1/0.2) + 0.9*ln(0.9/0.8)
|
|
257
|
+
let kld_expected = 0.1_f64 * (0.1_f64 / 0.2).ln() + 0.9_f64 * (0.9_f64 / 0.8).ln();
|
|
258
|
+
check_kld::<f64>(distribution_a, distribution_b, kld_expected);
|
|
259
|
+
check_kld::<f32>(distribution_a, distribution_b, kld_expected);
|
|
260
|
+
check_kld::<f16>(distribution_a, distribution_b, kld_expected);
|
|
261
|
+
check_kld::<bf16>(distribution_a, distribution_b, kld_expected);
|
|
262
|
+
|
|
263
|
+
// JS distance = sqrt(0.5 * (KL(a||m) + KL(b||m))) where m = (a+b)/2
|
|
264
|
+
let kl_am = 0.1_f64 * (0.1_f64 / 0.15).ln() + 0.9 * (0.9_f64 / 0.85).ln();
|
|
265
|
+
let kl_bm = 0.2_f64 * (0.2_f64 / 0.15).ln() + 0.8 * (0.8_f64 / 0.85).ln();
|
|
266
|
+
let jsd_expected = (0.5 * (kl_am + kl_bm)).sqrt();
|
|
267
|
+
check_jsd::<f64>(distribution_a, distribution_b, jsd_expected);
|
|
268
|
+
check_jsd::<f32>(distribution_a, distribution_b, jsd_expected);
|
|
269
|
+
check_jsd::<f16>(distribution_a, distribution_b, jsd_expected);
|
|
270
|
+
check_jsd::<bf16>(distribution_a, distribution_b, jsd_expected);
|
|
271
|
+
}
|
|
272
|
+
}
|