usearch 2.21.4 → 2.25.0

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