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,698 @@
|
|
|
1
|
+
# NumKong for Rust
|
|
2
|
+
|
|
3
|
+
NumKong's Rust crate keeps most of the native kernel surface while expressing it in Rust-native terms.
|
|
4
|
+
Rust is a natural fit for NumKong when you want static typing, explicit ownership, and strong container APIs without giving up mixed precision.
|
|
5
|
+
Traits cover scalar metric families.
|
|
6
|
+
`Tensor`, `Vector`, and packed matrix types cover the higher-level workflows.
|
|
7
|
+
Custom allocators, low-precision storage wrappers, and explicit row-contiguity checks stay visible instead of being hidden behind a dynamic runtime.
|
|
8
|
+
The crate makes the storage policy and result promotion visible.
|
|
9
|
+
That matters for fp16, bf16, fp8, packed bits, and strided reductions.
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```rust
|
|
14
|
+
use numkong::{configure_thread, Dot};
|
|
15
|
+
|
|
16
|
+
fn main() {
|
|
17
|
+
configure_thread();
|
|
18
|
+
let a = [1.0_f32, 2.0, 3.0];
|
|
19
|
+
let b = [4.0_f32, 5.0, 6.0];
|
|
20
|
+
let dot = f32::dot(&a, &b).unwrap();
|
|
21
|
+
println!("dot={dot}");
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Highlights
|
|
26
|
+
|
|
27
|
+
This is the most fully featured high-level SDK after Python.
|
|
28
|
+
It is a good fit if you want most of the native breadth without dropping into a manual FFI layer.
|
|
29
|
+
|
|
30
|
+
__Trait-first scalar API.__
|
|
31
|
+
`Type::operation(&a, &b)` stays compact and predictable.
|
|
32
|
+
__Allocator-aware tensors.__
|
|
33
|
+
`Tensor`, `PackedMatrix`, and `MaxSimPackedMatrix` can use custom allocators.
|
|
34
|
+
__Storage-first low precision.__
|
|
35
|
+
`f16`, `bf16`, fp8, fp6, and packed integer wrappers are first-class types.
|
|
36
|
+
__Matrix kernels with explicit contracts.__
|
|
37
|
+
Packed and symmetric kernels validate shapes and row contiguity.
|
|
38
|
+
__No hidden thread pool.__
|
|
39
|
+
Parallel helpers remain host-controlled.
|
|
40
|
+
__Fork Union support.__
|
|
41
|
+
The `parallel` feature is the intended native orchestration layer.
|
|
42
|
+
|
|
43
|
+
## Ecosystem Comparison
|
|
44
|
+
|
|
45
|
+
| Feature | NumKong | [nalgebra](https://github.com/dimforge/nalgebra) | [ndarray](https://github.com/rust-ndarray/ndarray) |
|
|
46
|
+
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------- |
|
|
47
|
+
| Operation families | dots, distances, binary, probability, geospatial, curved, mesh, sparse, MaxSim, elementwise, reductions, cast, trig | linear algebra, decompositions | general n-dimensional arithmetic |
|
|
48
|
+
| Precision | BFloat16 through sub-byte; automatic widening; Kahan summation; 0 ULP in Float32/Float64 | Float32/Float64 only; no widening; standard accuracy | Float32/Float64 only; no widening; standard accuracy |
|
|
49
|
+
| Runtime SIMD dispatch | auto-selects best ISA per-thread at runtime across x86, ARM, RISC-V | none | none |
|
|
50
|
+
| Packed matrix, GEMM-like | pack once, reuse across query batches | standard matmul; no persistent packing | `dot` for matmul; no persistent packing |
|
|
51
|
+
| Symmetric kernels, SYRK-like | skip duplicate pairs, up to 2x speedup for self-distance | no duplicate-pair skipping | no duplicate-pair skipping |
|
|
52
|
+
| Memory model | Caller-owned; `Tensor`/`PackedMatrix` support custom allocators | Heap-allocated matrices; custom storage trait | Heap-allocated; no custom allocator support |
|
|
53
|
+
| Host-side parallelism | row-range partitioning via reusable `ThreadPool`; no hidden threads | Rayon-based parallelism possible | Rayon-based parallelism possible |
|
|
54
|
+
|
|
55
|
+
NumKong validates `f16` and `bf16` interop against the `half` crate in its own test suite.
|
|
56
|
+
That lets you move between ecosystem-standard half types and NumKong's kernel-facing wrappers without ambiguity.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
Minimal:
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
[dependencies]
|
|
64
|
+
numkong = "7"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
With host-side parallel helpers:
|
|
68
|
+
|
|
69
|
+
```toml
|
|
70
|
+
[dependencies]
|
|
71
|
+
numkong = { version = "7", features = ["parallel", "std"] }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Compilation and Backend Selection
|
|
75
|
+
|
|
76
|
+
The crate uses the `cc` build system to compile the C backend with `NK_DYNAMIC_DISPATCH=1` automatically.
|
|
77
|
+
All supported backends for the target architecture are compiled into a single binary and selected at runtime.
|
|
78
|
+
|
|
79
|
+
The two Cargo features are `std`, which enables standard library support, and `parallel`, which adds host-side orchestration via ForkUnion and implies `std`.
|
|
80
|
+
|
|
81
|
+
Backend selection follows the target architecture.
|
|
82
|
+
ARM gets NEON, SVE, and SME, with SME available on Linux, FreeBSD, and macOS.
|
|
83
|
+
x86-64 gets Haswell (AVX2), Skylake/Icelake/Sapphire Rapids AVX-512 variants, and AMX on Linux and Windows only.
|
|
84
|
+
RISC-V gets RVV backends on Linux and FreeBSD.
|
|
85
|
+
WASM gets relaxed v128.
|
|
86
|
+
|
|
87
|
+
Individual backends can be disabled through environment variables.
|
|
88
|
+
Any `NK_TARGET_*` variable set to `0` or `false` disables that backend.
|
|
89
|
+
Backends not explicitly disabled are enabled by default for the target platform.
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
NK_TARGET_NEON=0 cargo build
|
|
93
|
+
NK_TARGET_SVE=0 NK_TARGET_SME=0 cargo build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
If a backend fails to compile, the build system automatically disables it and retries with the remaining backends.
|
|
97
|
+
A warning is emitted for each disabled backend.
|
|
98
|
+
|
|
99
|
+
## Dynamic Dispatch and Capabilities
|
|
100
|
+
|
|
101
|
+
`configure_thread` enables CPU-specific acceleration features such as Intel AMX.
|
|
102
|
+
It must be called once per thread before using AMX operations.
|
|
103
|
+
|
|
104
|
+
```rust
|
|
105
|
+
use numkong::{available, configure_thread, cap};
|
|
106
|
+
|
|
107
|
+
let caps = available();
|
|
108
|
+
configure_thread();
|
|
109
|
+
|
|
110
|
+
if caps & cap::SAPPHIREAMX != 0 {
|
|
111
|
+
println!("AMX available");
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Call `configure_thread` at the start of every thread that will use AMX operations.
|
|
116
|
+
In a thread-pool setting, each worker thread needs its own call.
|
|
117
|
+
The function is idempotent and cheap to call more than once on the same thread.
|
|
118
|
+
|
|
119
|
+
## Core Traits
|
|
120
|
+
|
|
121
|
+
The crate root re-exports the main metric families:
|
|
122
|
+
|
|
123
|
+
- `Dot`, `VDot`, `Angular`, `Euclidean`
|
|
124
|
+
- `Hamming`, `Jaccard`
|
|
125
|
+
- `KullbackLeibler`, `JensenShannon`
|
|
126
|
+
- `Haversine`, `Vincenty`
|
|
127
|
+
- `Bilinear`, `Mahalanobis`
|
|
128
|
+
- `ReduceMoments`, `ReduceMinMax`
|
|
129
|
+
- `EachScale`, `EachSum`, `EachBlend`, `EachFMA`
|
|
130
|
+
|
|
131
|
+
The standard call shape is:
|
|
132
|
+
|
|
133
|
+
```rust
|
|
134
|
+
use numkong::{Dot, JensenShannon, Jaccard, u1x8};
|
|
135
|
+
|
|
136
|
+
let a = [1.0_f32, 2.0, 3.0];
|
|
137
|
+
let b = [4.0_f32, 5.0, 6.0];
|
|
138
|
+
let dot = f32::dot(&a, &b).unwrap();
|
|
139
|
+
|
|
140
|
+
let bits_a = [u1x8(0b11110000), u1x8(0b00001111)];
|
|
141
|
+
let bits_b = [u1x8(0b11110000), u1x8(0b11110000)];
|
|
142
|
+
let jaccard = u1x8::jaccard(&bits_a, &bits_b).unwrap();
|
|
143
|
+
|
|
144
|
+
let p = [0.2_f32, 0.3, 0.5];
|
|
145
|
+
let q = [0.1_f32, 0.3, 0.6];
|
|
146
|
+
let jsd = f32::jensenshannon(&p, &q).unwrap();
|
|
147
|
+
|
|
148
|
+
println!("{dot} {jaccard} {jsd}");
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Dot Products
|
|
152
|
+
|
|
153
|
+
Dot products span real, complex, quantized, and packed storage types.
|
|
154
|
+
|
|
155
|
+
```rust
|
|
156
|
+
use numkong::{Dot, VDot, f32c};
|
|
157
|
+
|
|
158
|
+
let a = [f32c { re: 1.0, im: 2.0 }, f32c { re: 3.0, im: 4.0 }];
|
|
159
|
+
let b = [f32c { re: 5.0, im: 6.0 }, f32c { re: 7.0, im: 8.0 }];
|
|
160
|
+
|
|
161
|
+
let dot = f32c::dot(&a, &b).unwrap();
|
|
162
|
+
let vdot = f32c::vdot(&a, &b).unwrap(); // like numpy.vdot, conjugated
|
|
163
|
+
|
|
164
|
+
println!("{dot:?} {vdot:?}");
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Dense Distances
|
|
168
|
+
|
|
169
|
+
The dense spatial family covers `sqeuclidean`, `euclidean`, and `angular`.
|
|
170
|
+
The main value over naive loops is the combination of SIMD and safer accumulation policy.
|
|
171
|
+
|
|
172
|
+
```rust
|
|
173
|
+
use numkong::Euclidean;
|
|
174
|
+
|
|
175
|
+
let a = [1_i8, 2, 3, 4];
|
|
176
|
+
let b = [4_i8, 3, 2, 1];
|
|
177
|
+
|
|
178
|
+
let distance = i8::euclidean(&a, &b).unwrap(); // widened output, not int8
|
|
179
|
+
println!("{distance}");
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Scalar Types and Promotions
|
|
183
|
+
|
|
184
|
+
The scalar wrappers are storage-first types.
|
|
185
|
+
They are not decorative aliases over `f32`.
|
|
186
|
+
|
|
187
|
+
| Type | Layout | Bytes | Range | Inf | NaN |
|
|
188
|
+
| ------ | ------------- | ----- | ------------ | --- | --- |
|
|
189
|
+
| `f16` | 1+5+10 | 2 | ±65504 | yes | yes |
|
|
190
|
+
| `bf16` | 1+8+7 | 2 | ±3.4×10³⁸ | yes | yes |
|
|
191
|
+
| `e4m3` | 1+4+3 | 1 | ±448 | no | yes |
|
|
192
|
+
| `e5m2` | 1+5+2 | 1 | ±57344 | yes | yes |
|
|
193
|
+
| `e2m3` | 1+2+3 (6 bit) | 1 | ±7.5 | no | no |
|
|
194
|
+
| `e3m2` | 1+3+2 (6 bit) | 1 | ±28 | no | no |
|
|
195
|
+
| `u1x8` | 8 packed bits | 1 | 0–1 per bit | — | — |
|
|
196
|
+
| `u4x2` | 2×4-bit uint | 1 | 0–15 per nib | — | — |
|
|
197
|
+
| `i4x2` | 2×4-bit int | 1 | −8–7 per nib | — | — |
|
|
198
|
+
|
|
199
|
+
The trait hierarchy documents intent:
|
|
200
|
+
|
|
201
|
+
- `StorageElement` — raw storable element type.
|
|
202
|
+
- `NumberLike` — adds numeric conversion and ordering.
|
|
203
|
+
- `FloatConvertible` — adds unpacking and float-domain conversion.
|
|
204
|
+
|
|
205
|
+
The output type is intentionally wider than the storage type for many operations.
|
|
206
|
+
For example, `i8::dot` returns `i32`.
|
|
207
|
+
`f32::dot` returns a wider accumulator type.
|
|
208
|
+
Moments reductions widen even more aggressively.
|
|
209
|
+
|
|
210
|
+
## Set Similarity
|
|
211
|
+
|
|
212
|
+
Packed-binary metrics work on packed words instead of boolean slices.
|
|
213
|
+
That is the right model once the workload is "semantic hash" rather than "array of booleans".
|
|
214
|
+
|
|
215
|
+
```rust
|
|
216
|
+
use numkong::{Hamming, Jaccard, u1x8};
|
|
217
|
+
|
|
218
|
+
let a = [u1x8(0b10101010), u1x8(0b11110000)];
|
|
219
|
+
let b = [u1x8(0b10101110), u1x8(0b11000000)];
|
|
220
|
+
let hamming = u1x8::hamming(&a, &b).unwrap();
|
|
221
|
+
let jaccard = u1x8::jaccard(&a, &b).unwrap();
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Integer set Jaccard works on sorted arrays of integer identifiers.
|
|
225
|
+
|
|
226
|
+
```rust
|
|
227
|
+
let set_a = [1_u32, 3, 5, 7, 9];
|
|
228
|
+
let set_b = [3_u32, 5, 8, 9, 10];
|
|
229
|
+
let jaccard_sets = u32::jaccard(&set_a, &set_b).unwrap();
|
|
230
|
+
assert!(jaccard_sets > 0.0 && jaccard_sets < 1.0); // |A ∩ B| / |A ∪ B|
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Probability Metrics
|
|
234
|
+
|
|
235
|
+
```rust
|
|
236
|
+
use numkong::{JensenShannon, KullbackLeibler};
|
|
237
|
+
|
|
238
|
+
let p = [0.2_f32, 0.3, 0.5], q = [0.1_f32, 0.3, 0.6];
|
|
239
|
+
let kl_forward = f32::kullbackleibler(&p, &q).unwrap();
|
|
240
|
+
let kl_reverse = f32::kullbackleibler(&q, &p).unwrap();
|
|
241
|
+
assert!(kl_forward != kl_reverse); // KLD is asymmetric
|
|
242
|
+
|
|
243
|
+
let js_forward = f32::jensenshannon(&p, &q).unwrap();
|
|
244
|
+
let js_reverse = f32::jensenshannon(&q, &p).unwrap();
|
|
245
|
+
assert!((js_forward - js_reverse).abs() < 1e-6, "JSD is symmetric");
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Geospatial Metrics
|
|
249
|
+
|
|
250
|
+
Inputs are latitudes and longitudes in radians.
|
|
251
|
+
Outputs are meters.
|
|
252
|
+
|
|
253
|
+
```rust
|
|
254
|
+
use numkong::{Haversine, Vincenty};
|
|
255
|
+
|
|
256
|
+
// Statue of Liberty (40.6892°N, 74.0445°W) → Big Ben (51.5007°N, 0.1246°W)
|
|
257
|
+
let liberty_lat = [0.7101605100_f64], liberty_lon = [-1.2923203180_f64];
|
|
258
|
+
let big_ben_lat = [0.8988567821_f64], big_ben_lon = [-0.0021746802_f64];
|
|
259
|
+
let mut distance = [0.0_f64; 1];
|
|
260
|
+
f64::vincenty(&liberty_lat, &liberty_lon, &big_ben_lat, &big_ben_lon, &mut distance).unwrap(); // ≈ 5,589,857 m (ellipsoidal, baseline)
|
|
261
|
+
f64::haversine(&liberty_lat, &liberty_lon, &big_ben_lat, &big_ben_lon, &mut distance).unwrap(); // ≈ 5,543,723 m (spherical, ~46 km less)
|
|
262
|
+
|
|
263
|
+
// Vincenty in f32 — drifts ~2 m from f64
|
|
264
|
+
let liberty_lat32 = [0.7101605100_f32], liberty_lon32 = [-1.2923203180_f32];
|
|
265
|
+
let big_ben_lat32 = [0.8988567821_f32], big_ben_lon32 = [-0.0021746802_f32];
|
|
266
|
+
let mut distance_f32 = [0.0_f32; 1];
|
|
267
|
+
f32::vincenty(&liberty_lat32, &liberty_lon32, &big_ben_lat32, &big_ben_lon32, &mut distance_f32).unwrap(); // ≈ 5,589,859 m (+2 m drift)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Curved Metrics
|
|
271
|
+
|
|
272
|
+
Curved-space kernels combine vectors with an extra metric tensor or covariance inverse.
|
|
273
|
+
|
|
274
|
+
```rust
|
|
275
|
+
use numkong::{Bilinear, Mahalanobis, f32c};
|
|
276
|
+
|
|
277
|
+
// Complex bilinear form: aᴴ M b
|
|
278
|
+
let a = [f32c { re: 1.0, im: 0.0 }; 16];
|
|
279
|
+
let b = [f32c { re: 0.0, im: 1.0 }; 16];
|
|
280
|
+
let metric = [f32c { re: 1.0, im: 0.0 }; 16 * 16];
|
|
281
|
+
let bilinear = f32c::bilinear(&a, &b, &metric).unwrap();
|
|
282
|
+
|
|
283
|
+
// Real Mahalanobis distance: √((a−b)ᵀ M⁻¹ (a−b))
|
|
284
|
+
let x = [1.0_f32; 32];
|
|
285
|
+
let y = [2.0_f32; 32];
|
|
286
|
+
let mut inv_cov = vec![0.0_f32; 32 * 32];
|
|
287
|
+
for i in 0..32 { inv_cov[i * 32 + i] = 1.0; } // identity matrix
|
|
288
|
+
let distance = f32::mahalanobis(&x, &y, &inv_cov).unwrap();
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Vectors, Tensors, Views, and Spans
|
|
292
|
+
|
|
293
|
+
The container model is unusual enough that it needs direct documentation.
|
|
294
|
+
|
|
295
|
+
- `Vector<T>` owns one-dimensional storage.
|
|
296
|
+
- `VectorView<'a, T>` is an immutable borrowed view.
|
|
297
|
+
- `VectorSpan<'a, T>` is a mutable borrowed view.
|
|
298
|
+
- `Tensor<T, A, MAX_RANK>` owns N-dimensional storage and can use a custom allocator.
|
|
299
|
+
- `TensorView` and `TensorSpan` are the borrowed forms.
|
|
300
|
+
- `Matrix<T>` is a rank-2 alias over `Tensor<T, _, 2>`.
|
|
301
|
+
|
|
302
|
+
The allocator story is explicit.
|
|
303
|
+
`Tensor` and `PackedMatrix` default to `Global`.
|
|
304
|
+
The underlying layout uses `SIMD_ALIGNMENT == 64` for owned allocations.
|
|
305
|
+
That does _not_ mean callers must align their source buffers manually.
|
|
306
|
+
It means owned outputs and packed payloads are allocated in a SIMD-friendly way when the crate owns them.
|
|
307
|
+
|
|
308
|
+
```rust
|
|
309
|
+
use numkong::{RangeStep, SliceRange, Tensor};
|
|
310
|
+
|
|
311
|
+
let t = Tensor::<f32>::try_from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], &[3, 3]).unwrap();
|
|
312
|
+
|
|
313
|
+
let col = t.slice((.., 1_usize)).unwrap(); // t[:, 1] — column 1
|
|
314
|
+
let rows = t.slice((0..2_usize, ..)).unwrap(); // t[0:2, :] — first two rows
|
|
315
|
+
let tail = t.slice((-2_isize.., ..)).unwrap(); // t[-2:, :] — last two rows
|
|
316
|
+
let neg = t.slice((.., -2..-1_isize)).unwrap(); // t[:, -2:-1]
|
|
317
|
+
let step = t.slice((.., RangeStep::new(0, 3, 2))).unwrap(); // t[:, ::2]
|
|
318
|
+
|
|
319
|
+
// Explicit &[SliceRange] syntax also works
|
|
320
|
+
let col = t.slice(&[SliceRange::full(), SliceRange::index(1)]).unwrap();
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Tuple elements implement `SliceArg` — each monomorphized with zero runtime dispatch:
|
|
324
|
+
|
|
325
|
+
| Rust syntax | Meaning |
|
|
326
|
+
| ------------------------------- | -------------------------------------- |
|
|
327
|
+
| `..` | all |
|
|
328
|
+
| `0_usize` / `-1_isize` | single index (negative wraps from end) |
|
|
329
|
+
| `1..4_usize` / `-3..-1_isize` | half-open range |
|
|
330
|
+
| `..3_usize` / `..-1_isize` | from start |
|
|
331
|
+
| `1_usize..` / `-2_isize..` | to end |
|
|
332
|
+
| `0..=2_usize` / `-3..=-1_isize` | inclusive range |
|
|
333
|
+
| `RangeStep::new(0, 6, 2)` | stepped (no Rust literal) |
|
|
334
|
+
|
|
335
|
+
Integer literals default to `i32` — use `_usize` / `_isize` suffixes.
|
|
336
|
+
Negative `isize` values wrap from the dimension end, like Python.
|
|
337
|
+
|
|
338
|
+
Iteration works at the logical-dimension level.
|
|
339
|
+
For sub-byte types like `i4x2` (2 nibbles per byte), iterating a 3-element vector yields 6 dimensions.
|
|
340
|
+
Immutable iterators (`iter()`) yield `DimRef<T>`, which dereferences to `T::DimScalar`.
|
|
341
|
+
Mutable iterators (`iter_mut()`) yield `DimMut<T>`, which writes back on drop — the only way to mutate individual nibbles or bits.
|
|
342
|
+
|
|
343
|
+
```rust
|
|
344
|
+
use numkong::{Vector, i4x2};
|
|
345
|
+
|
|
346
|
+
let mut nibbles = Vector::<i4x2>::try_zeros(4).unwrap();
|
|
347
|
+
for (i, mut dim) in nibbles.iter_mut().enumerate() {
|
|
348
|
+
*dim = i as i8;
|
|
349
|
+
}
|
|
350
|
+
assert_eq!(nibbles.try_get(0_usize).unwrap(), 0);
|
|
351
|
+
assert_eq!(nibbles.try_get(3_usize).unwrap(), 3);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Vectors and tensors can be converted between each other without copying:
|
|
355
|
+
|
|
356
|
+
```rust
|
|
357
|
+
use numkong::{Vector, Tensor};
|
|
358
|
+
|
|
359
|
+
let v = Vector::<f32>::try_from_scalars(&[1.0, 2.0, 3.0]).unwrap();
|
|
360
|
+
let t: Tensor<f32, _, 8> = v.try_into_tensor().unwrap();
|
|
361
|
+
assert_eq!(t.shape(), &[3]);
|
|
362
|
+
let v2 = t.try_into_vector().unwrap();
|
|
363
|
+
assert_eq!(v2.dims(), 3);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
The main layout rules are:
|
|
367
|
+
|
|
368
|
+
- General slicing and transposition are supported by views.
|
|
369
|
+
- Elementwise and many reduction kernels accept strided views.
|
|
370
|
+
- Matrix-style kernels require rank-2 inputs with contiguous rows.
|
|
371
|
+
- A tensor can be non-contiguous overall and still have contiguous rows.
|
|
372
|
+
- Some reductions have SIMD kernels for strided lanes.
|
|
373
|
+
- Some backends still fall back depending on alignment and dtype.
|
|
374
|
+
|
|
375
|
+
Sub-byte types (`i4x2`, `u4x2`, `u1x8`) use logical shapes.
|
|
376
|
+
A shape of `[8]` for `i4x2` means 8 nibbles (stored in 4 bytes), not 8 bytes.
|
|
377
|
+
The innermost dimension must be divisible by `dimensions_per_value()` (2 for nibble types, 8 for bit types).
|
|
378
|
+
Transpose and reshape are not supported for sub-byte types — they return `SubByteUnsupported`.
|
|
379
|
+
|
|
380
|
+
## Elementwise Operations
|
|
381
|
+
|
|
382
|
+
Elementwise kernels live on tensors and views.
|
|
383
|
+
They are not a promise that every arbitrary strided view gets the same SIMD path on every backend.
|
|
384
|
+
|
|
385
|
+
```rust
|
|
386
|
+
use numkong::Tensor;
|
|
387
|
+
|
|
388
|
+
let a = Tensor::<f32>::try_from_slice(&[1.0, 2.0, 3.0, 4.0], &[2, 2]).unwrap();
|
|
389
|
+
let b = Tensor::<f32>::try_full(&[2, 2], 2.0).unwrap();
|
|
390
|
+
|
|
391
|
+
let blended = a.view().try_blend_tensor(&b.view(), 0.25, 0.75).unwrap();
|
|
392
|
+
let sines = blended.sin().unwrap();
|
|
393
|
+
|
|
394
|
+
assert_eq!(sines.shape(), &[2, 2]);
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Compound assignment operators work in-place:
|
|
398
|
+
|
|
399
|
+
```rust
|
|
400
|
+
use numkong::Tensor;
|
|
401
|
+
|
|
402
|
+
let mut t = Tensor::<f32>::try_full(&[4], 1.0).unwrap();
|
|
403
|
+
t += 10.0;
|
|
404
|
+
t -= 0.5;
|
|
405
|
+
t *= 2.0;
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Trigonometry
|
|
409
|
+
|
|
410
|
+
The trigonometric kernels share the tensor and view surface.
|
|
411
|
+
They are useful both directly and as a sanity check that the container path is not just about matrix kernels.
|
|
412
|
+
|
|
413
|
+
```rust
|
|
414
|
+
use numkong::Tensor;
|
|
415
|
+
|
|
416
|
+
let a = Tensor::<f32>::try_from_slice(&[0.0, 1.0, 2.0, 3.0], &[2, 2]).unwrap();
|
|
417
|
+
let c = a.cos().unwrap();
|
|
418
|
+
let s = a.sin().unwrap();
|
|
419
|
+
|
|
420
|
+
assert_eq!(c.shape(), &[2, 2]);
|
|
421
|
+
assert_eq!(s.shape(), &[2, 2]);
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
## Moments Reductions
|
|
425
|
+
|
|
426
|
+
Moments reductions return both sum and sum-of-squares.
|
|
427
|
+
That is the right building block for norms and variance-like workflows.
|
|
428
|
+
|
|
429
|
+
```rust
|
|
430
|
+
use numkong::{ReduceMoments, Tensor};
|
|
431
|
+
|
|
432
|
+
let narrow = Tensor::<u8>::try_full(&[1024], 255).unwrap();
|
|
433
|
+
let (sum, sumsq) = narrow.try_moments_all().unwrap();
|
|
434
|
+
|
|
435
|
+
assert!(sum > 255); // a naive u8 accumulation would overflow immediately
|
|
436
|
+
assert!(sumsq > 255u64); // same for sum-of-squares
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
The important documentation point is not just "wider outputs exist".
|
|
440
|
+
It is that the API makes the widened outputs part of the type story.
|
|
441
|
+
|
|
442
|
+
## Min/Max Reductions
|
|
443
|
+
|
|
444
|
+
Min/max reductions return a `MinMaxResult` with both the value and its flat index:
|
|
445
|
+
|
|
446
|
+
```rust
|
|
447
|
+
use numkong::Tensor;
|
|
448
|
+
|
|
449
|
+
let t = Tensor::<f32>::try_from_slice(&[
|
|
450
|
+
3.0, 0.0, 7.0,
|
|
451
|
+
1.0, 2.0, 5.0,
|
|
452
|
+
4.0, -1.0, 6.0,
|
|
453
|
+
], &[3, 3]).unwrap();
|
|
454
|
+
|
|
455
|
+
let second_column = t.slice((.., 1_usize)).unwrap(); // t[:, 1]
|
|
456
|
+
let idx = second_column.try_argmin_all().unwrap();
|
|
457
|
+
|
|
458
|
+
assert_eq!(idx, 2);
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
## Sparse Operations and Intersections
|
|
463
|
+
|
|
464
|
+
Sparse helpers cover both sorted-index intersection and weighted sparse dot products.
|
|
465
|
+
|
|
466
|
+
```rust
|
|
467
|
+
use numkong::{SparseIntersect, SparseDot};
|
|
468
|
+
|
|
469
|
+
let a_idx = [1_u32, 3, 5, 7], b_idx = [3_u32, 4, 5, 8];
|
|
470
|
+
let count = u32::sparse_intersection_size(&a_idx, &b_idx);
|
|
471
|
+
assert_eq!(count, 2); // indices 3 and 5
|
|
472
|
+
|
|
473
|
+
let a_weights = [1.0_f32, 2.0, 3.0, 4.0], b_weights = [5.0_f32, 6.0, 7.0, 8.0];
|
|
474
|
+
let dot = u32::sparse_dot(&a_idx, &b_idx, &a_weights, &b_weights).unwrap();
|
|
475
|
+
assert!(dot > 0.0); // weighted dot over shared indices
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Packed Matrix Kernels for GEMM-Like Workloads
|
|
479
|
+
|
|
480
|
+
Packed kernels are the main "matrix throughput" path in the crate.
|
|
481
|
+
They are `GEMM`-like in workload shape.
|
|
482
|
+
They are not a thin BLAS clone.
|
|
483
|
+
|
|
484
|
+
```rust
|
|
485
|
+
use numkong::{PackedMatrix, Tensor};
|
|
486
|
+
|
|
487
|
+
let a = Tensor::<f32>::try_full(&[1024, 512], 1.0).unwrap();
|
|
488
|
+
let b = Tensor::<f32>::try_full(&[256, 512], 1.0).unwrap();
|
|
489
|
+
|
|
490
|
+
let b_packed = PackedMatrix::try_pack(&b).unwrap();
|
|
491
|
+
let c = a.dots_packed(&b_packed);
|
|
492
|
+
|
|
493
|
+
assert_eq!(c.shape(), &[1024, 256]);
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
The useful economics are:
|
|
497
|
+
|
|
498
|
+
- pack `B` once
|
|
499
|
+
- reuse it across many `A` batches
|
|
500
|
+
- convert or pad once during packing instead of on every multiply
|
|
501
|
+
- reuse precomputed norms for `angulars_packed` and `euclideans_packed`
|
|
502
|
+
|
|
503
|
+
The crate checks row contiguity because these kernels assume contiguous rows.
|
|
504
|
+
Caller-side source alignment is not required.
|
|
505
|
+
The owned packed buffer handles its own aligned allocation internally.
|
|
506
|
+
|
|
507
|
+
## Symmetric Kernels for SYRK-Like Workloads
|
|
508
|
+
|
|
509
|
+
Symmetric kernels are for self-similarity and self-distance.
|
|
510
|
+
They are `SYRK`-like in shape.
|
|
511
|
+
They avoid duplicate `(i, j)` and `(j, i)` work.
|
|
512
|
+
|
|
513
|
+
```rust
|
|
514
|
+
use numkong::Tensor;
|
|
515
|
+
|
|
516
|
+
let vectors = Tensor::<f32>::try_full(&[100, 768], 1.0).unwrap();
|
|
517
|
+
let gram = vectors.view().try_dots_symmetric().unwrap();
|
|
518
|
+
|
|
519
|
+
assert_eq!(gram.shape(), &[100, 100]);
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
This family is also where row-window partitioning becomes the natural parallel model.
|
|
523
|
+
That is structurally different from packed `GEMM`-style work against a shared packed RHS.
|
|
524
|
+
|
|
525
|
+
## MaxSim and ColBERT-Style Late Interaction
|
|
526
|
+
|
|
527
|
+
MaxSim is the late-interaction primitive used by systems such as [ColBERT](https://arxiv.org/abs/2004.12832).
|
|
528
|
+
It is not "just another matrix multiply".
|
|
529
|
+
|
|
530
|
+
```rust
|
|
531
|
+
use numkong::{MaxSimPackedMatrix, Tensor};
|
|
532
|
+
|
|
533
|
+
let queries = Tensor::<f32>::try_full(&[4, 16], 1.0).unwrap();
|
|
534
|
+
let docs = Tensor::<f32>::try_full(&[8, 16], 1.0).unwrap();
|
|
535
|
+
|
|
536
|
+
let queries_packed = queries.view().try_maxsim_pack().unwrap();
|
|
537
|
+
let docs_packed = docs.view().try_maxsim_pack().unwrap();
|
|
538
|
+
let score = queries_packed.score(&docs_packed);
|
|
539
|
+
|
|
540
|
+
assert!(score.is_finite());
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
## Geometric Mesh Alignment
|
|
544
|
+
|
|
545
|
+
Mesh alignment returns transforms, scales, and RMSD values.
|
|
546
|
+
That is a different API shape from the scalar metric families.
|
|
547
|
+
|
|
548
|
+
```rust
|
|
549
|
+
use numkong::MeshAlignment;
|
|
550
|
+
|
|
551
|
+
let source = [[0.0_f32, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];
|
|
552
|
+
let target = [[0.0_f32, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];
|
|
553
|
+
|
|
554
|
+
let result = f32::kabsch(&source, &target).unwrap();
|
|
555
|
+
assert!(result.rmsd < 1e-6);
|
|
556
|
+
assert!((result.scale - 1.0).abs() < 1e-6);
|
|
557
|
+
|
|
558
|
+
// Umeyama with known 2x scaling
|
|
559
|
+
let scaled = [[0.0_f32, 0.0, 0.0], [2.0, 0.0, 0.0], [0.0, 2.0, 0.0]];
|
|
560
|
+
let result = f32::umeyama(&source, &scaled).unwrap();
|
|
561
|
+
assert!(result.rmsd < 1e-6);
|
|
562
|
+
assert!((result.scale - 2.0).abs() < 0.01);
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## Tolerance Comparison
|
|
566
|
+
|
|
567
|
+
Exact floating-point equality is rarely what you want after arithmetic.
|
|
568
|
+
`allclose()` checks every element pair with the formula:
|
|
569
|
+
|
|
570
|
+
$$
|
|
571
|
+
|a - b| \leq \text{atol} + \text{rtol} \cdot |b|
|
|
572
|
+
$$
|
|
573
|
+
|
|
574
|
+
Available on `Vector`, `VectorView`, `VectorSpan`, `Tensor`, `TensorView`, and `TensorSpan`.
|
|
575
|
+
For tensors, `allclose` is provided by the `AllCloseOps` trait — import it if calling on a `TensorRef` implementor.
|
|
576
|
+
Shape mismatch returns `false`.
|
|
577
|
+
The scalar helper `is_close` is re-exported at crate root.
|
|
578
|
+
|
|
579
|
+
```rust
|
|
580
|
+
use numkong::{is_close, Vector, Tensor};
|
|
581
|
+
|
|
582
|
+
// Scalar check
|
|
583
|
+
assert!(is_close(1.0, 1.0 + 1e-8, 1e-6, 0.0));
|
|
584
|
+
|
|
585
|
+
// Vector tolerance check
|
|
586
|
+
let a = Vector::<f32>::try_full(3, 1.0).unwrap();
|
|
587
|
+
let b = Vector::<f32>::try_full(3, 1.0 + 1e-7).unwrap();
|
|
588
|
+
assert!(a.allclose(&b, 1e-6, 0.0));
|
|
589
|
+
|
|
590
|
+
// Tensor tolerance check
|
|
591
|
+
let ta = Tensor::<f32>::try_full(&[2, 3], 1.0).unwrap();
|
|
592
|
+
let tb = Tensor::<f32>::try_full(&[2, 3], 1.0 + 1e-7).unwrap();
|
|
593
|
+
assert!(ta.allclose(&tb, 1e-6, 0.0));
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
## Type Casting
|
|
597
|
+
|
|
598
|
+
The `cast` function performs bulk conversion between contiguous slices.
|
|
599
|
+
Any pair of types that implement `CastDtype` (all `NumberLike` scalars) can be converted.
|
|
600
|
+
|
|
601
|
+
```rust
|
|
602
|
+
use numkong::{cast, f16, bf16};
|
|
603
|
+
|
|
604
|
+
let src: Vec<f32> = vec![1.0, 2.0, 3.0];
|
|
605
|
+
let mut dst: Vec<f16> = vec![f16::from(0.0_f32); 3];
|
|
606
|
+
cast(&src, &mut dst);
|
|
607
|
+
assert!((dst[0].to_f32() - 1.0).abs() < 0.01);
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
`Tensor`, `TensorView`, and `TensorSpan` expose casting via the `CastOps` trait.
|
|
611
|
+
`try_cast_dtype()` allocates a new tensor; `try_cast_dtype_into()` writes into a pre-allocated `TensorSpan`.
|
|
612
|
+
Strided and non-contiguous views are supported: the implementation scans strides from the innermost dimension outward to find the longest contiguous tail, then walks the outer dimensions and casts each contiguous block in a single kernel call.
|
|
613
|
+
|
|
614
|
+
```rust
|
|
615
|
+
use numkong::{Tensor, f16};
|
|
616
|
+
|
|
617
|
+
let src = Tensor::<f32>::try_full(&[4, 4], 1.0).unwrap();
|
|
618
|
+
let mut dst = Tensor::<f16>::try_zeros(&[4, 4]).unwrap();
|
|
619
|
+
src.view().try_cast_dtype_into(&mut dst.span()).unwrap();
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
## Parallelism and ForkUnion
|
|
623
|
+
|
|
624
|
+
NumKong does not own a thread pool.
|
|
625
|
+
The `parallel` feature adds host-side orchestration helpers via [ForkUnion](https://github.com/ashvardanian/ForkUnion), not a hidden scheduler.
|
|
626
|
+
|
|
627
|
+
```rust
|
|
628
|
+
use numkong::{PackedMatrix, Tensor};
|
|
629
|
+
use fork_union::ThreadPool;
|
|
630
|
+
|
|
631
|
+
let a = Tensor::<f32>::try_full(&[4096, 768], 1.0).unwrap();
|
|
632
|
+
let b = Tensor::<f32>::try_full(&[8192, 768], 1.0).unwrap();
|
|
633
|
+
let mut pool = ThreadPool::try_spawn(4).unwrap();
|
|
634
|
+
|
|
635
|
+
// GEMM-like: rows of A partitioned across threads, one shared packed B
|
|
636
|
+
let b_packed = PackedMatrix::try_pack(&b).unwrap();
|
|
637
|
+
let c = a.dots_packed_parallel(&b_packed, &mut pool);
|
|
638
|
+
assert_eq!(c.shape(), &[4096, 8192]);
|
|
639
|
+
|
|
640
|
+
// SYRK-like: row windows of one square output partitioned across threads
|
|
641
|
+
let gram = a.dots_symmetric_parallel(&mut pool);
|
|
642
|
+
assert_eq!(gram.shape(), &[4096, 4096]);
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
Rayon or a manual thread pool can still work if the rest of your application already depends on them.
|
|
646
|
+
|
|
647
|
+
## Addressing External Memory
|
|
648
|
+
|
|
649
|
+
Views wrap raw pointers without ownership, owned containers accept custom allocators, and the scalar trait API works on any `&[T]` regardless of how the memory was allocated.
|
|
650
|
+
|
|
651
|
+
`VectorView::from_raw_parts` and `TensorView::from_raw_parts` wrap device-accessible or externally allocated memory.
|
|
652
|
+
The mutable counterparts `VectorSpan::from_raw_parts` and `TensorSpan::from_raw_parts` work the same way with `*mut T`.
|
|
653
|
+
|
|
654
|
+
```rust
|
|
655
|
+
use numkong::{VectorView, TensorView};
|
|
656
|
+
|
|
657
|
+
let embeddings_ptr: *const f32 = /* from CUDA, mmap, or FFI */;
|
|
658
|
+
let embeddings = unsafe {
|
|
659
|
+
VectorView::from_raw_parts(embeddings_ptr, 1024, std::mem::size_of::<f32>() as isize)
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
let shape = [32, 64];
|
|
663
|
+
let strides = [64 * 4, 4]; // row-major f32
|
|
664
|
+
let matrix = unsafe { TensorView::<f32>::from_raw_parts(embeddings_ptr, &shape, &strides) };
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Owned containers accept any allocator.
|
|
668
|
+
A CUDA unified memory allocator looks like this:
|
|
669
|
+
|
|
670
|
+
```rust
|
|
671
|
+
use std::alloc::{Allocator, AllocError, Layout};
|
|
672
|
+
use std::ptr::NonNull;
|
|
673
|
+
use numkong::Vector;
|
|
674
|
+
|
|
675
|
+
struct CudaAllocator;
|
|
676
|
+
|
|
677
|
+
unsafe impl Allocator for CudaAllocator {
|
|
678
|
+
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
|
|
679
|
+
let raw = unsafe { cuda_malloc_managed(layout.size()) };
|
|
680
|
+
let base = NonNull::new(raw).ok_or(AllocError)?;
|
|
681
|
+
Ok(NonNull::slice_from_raw_parts(base, layout.size()))
|
|
682
|
+
}
|
|
683
|
+
unsafe fn deallocate(&self, block: NonNull<u8>, _layout: Layout) {
|
|
684
|
+
cuda_free(block.as_ptr());
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
let queries = Vector::<f32, CudaAllocator>::try_zeros_in(1024, CudaAllocator).unwrap();
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
The trait-based scalar API works on any `&[T]` — `Vec`, mmap, arena, or pinned buffer:
|
|
692
|
+
|
|
693
|
+
```rust
|
|
694
|
+
use numkong::Dot;
|
|
695
|
+
|
|
696
|
+
let weights: &[f32] = /* any contiguous slice */;
|
|
697
|
+
let similarity = f32::dot(weights, weights).unwrap();
|
|
698
|
+
```
|