usearch 2.21.4 → 2.25.1

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 (604) hide show
  1. package/README.md +65 -69
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +8 -8
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +124 -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/README.md +1 -1
  16. package/javascript/dist/cjs/usearch.d.ts +8 -3
  17. package/javascript/dist/cjs/usearch.js +12 -4
  18. package/javascript/dist/esm/usearch.d.ts +8 -3
  19. package/javascript/dist/esm/usearch.js +12 -4
  20. package/javascript/lib.cpp +17 -0
  21. package/javascript/usearch.test.js +117 -94
  22. package/javascript/usearch.ts +14 -6
  23. package/numkong/.clang-tidy +30 -0
  24. package/{simsimd → numkong}/.cmake-format.py +18 -0
  25. package/numkong/.editorconfig +12 -0
  26. package/numkong/.git-blame-ignore-revs +123 -0
  27. package/numkong/.mailmap +15 -0
  28. package/numkong/.spi.yml +11 -0
  29. package/numkong/.swift-format +14 -0
  30. package/numkong/CITATION.cff +81 -0
  31. package/numkong/CONTRIBUTING.md +500 -0
  32. package/numkong/Cargo.toml +54 -0
  33. package/numkong/MANIFEST.in +8 -0
  34. package/numkong/Package.swift +84 -0
  35. package/numkong/README.md +569 -0
  36. package/numkong/bench/README.md +217 -0
  37. package/numkong/bench/bench-browser.html +323 -0
  38. package/numkong/bench/bench.cpp +344 -0
  39. package/numkong/bench/bench.hpp +816 -0
  40. package/numkong/bench/bench.js +148 -0
  41. package/numkong/bench/bench.mjs +616 -0
  42. package/numkong/bench/bench_attention.cpp +113 -0
  43. package/numkong/bench/bench_cast.cpp +264 -0
  44. package/numkong/bench/bench_cross_amx.cpp +62 -0
  45. package/numkong/bench/bench_cross_arm.cpp +245 -0
  46. package/numkong/bench/bench_cross_blas.cpp +309 -0
  47. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  48. package/numkong/bench/bench_cross_power.cpp +84 -0
  49. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  50. package/numkong/bench/bench_cross_serial.cpp +151 -0
  51. package/numkong/bench/bench_cross_sme.cpp +163 -0
  52. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  53. package/numkong/bench/bench_cross_x86.cpp +455 -0
  54. package/numkong/bench/bench_curved.cpp +210 -0
  55. package/numkong/bench/bench_dot.cpp +315 -0
  56. package/numkong/bench/bench_each.cpp +503 -0
  57. package/numkong/bench/bench_geospatial.cpp +112 -0
  58. package/numkong/bench/bench_maxsim.cpp +154 -0
  59. package/numkong/bench/bench_mesh.cpp +148 -0
  60. package/numkong/bench/bench_probability.cpp +60 -0
  61. package/numkong/bench/bench_reduce.cpp +371 -0
  62. package/numkong/bench/bench_set.cpp +73 -0
  63. package/numkong/bench/bench_sparse.cpp +198 -0
  64. package/numkong/bench/bench_spatial.cpp +347 -0
  65. package/numkong/bench/bench_trigonometry.cpp +137 -0
  66. package/numkong/bench/swift/Bench.swift +506 -0
  67. package/numkong/binding.gyp +169 -0
  68. package/numkong/build.rs +484 -0
  69. package/numkong/c/dispatch.h +512 -0
  70. package/numkong/c/dispatch_bf16.c +447 -0
  71. package/numkong/c/dispatch_bf16c.c +52 -0
  72. package/numkong/c/dispatch_e2m3.c +296 -0
  73. package/numkong/c/dispatch_e3m2.c +284 -0
  74. package/numkong/c/dispatch_e4m3.c +318 -0
  75. package/numkong/c/dispatch_e5m2.c +316 -0
  76. package/numkong/c/dispatch_f16.c +452 -0
  77. package/numkong/c/dispatch_f16c.c +58 -0
  78. package/numkong/c/dispatch_f32.c +434 -0
  79. package/numkong/c/dispatch_f32c.c +99 -0
  80. package/numkong/c/dispatch_f64.c +348 -0
  81. package/numkong/c/dispatch_f64c.c +98 -0
  82. package/numkong/c/dispatch_i16.c +96 -0
  83. package/numkong/c/dispatch_i32.c +89 -0
  84. package/numkong/c/dispatch_i4.c +153 -0
  85. package/numkong/c/dispatch_i64.c +86 -0
  86. package/numkong/c/dispatch_i8.c +348 -0
  87. package/numkong/c/dispatch_other.c +348 -0
  88. package/numkong/c/dispatch_u1.c +193 -0
  89. package/numkong/c/dispatch_u16.c +124 -0
  90. package/numkong/c/dispatch_u32.c +118 -0
  91. package/numkong/c/dispatch_u4.c +153 -0
  92. package/numkong/c/dispatch_u64.c +102 -0
  93. package/numkong/c/dispatch_u8.c +364 -0
  94. package/numkong/c/numkong.c +940 -0
  95. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  96. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  97. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_math_lib.cmake +46 -0
  99. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  100. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  101. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  102. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  103. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  104. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  105. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  106. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  107. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  108. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  109. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  110. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  111. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  112. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  113. package/numkong/include/README.md +643 -0
  114. package/numkong/include/module.modulemap +129 -0
  115. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  116. package/numkong/include/numkong/attention/sme.h +2075 -0
  117. package/numkong/include/numkong/attention.h +49 -0
  118. package/numkong/include/numkong/capabilities.h +930 -0
  119. package/numkong/include/numkong/cast/README.md +262 -0
  120. package/numkong/include/numkong/cast/diamond.h +64 -0
  121. package/numkong/include/numkong/cast/haswell.h +823 -0
  122. package/numkong/include/numkong/cast/icelake.h +475 -0
  123. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  124. package/numkong/include/numkong/cast/neon.h +1174 -0
  125. package/numkong/include/numkong/cast/powervsx.h +449 -0
  126. package/numkong/include/numkong/cast/rvv.h +970 -0
  127. package/numkong/include/numkong/cast/sapphire.h +262 -0
  128. package/numkong/include/numkong/cast/serial.h +2336 -0
  129. package/numkong/include/numkong/cast/skylake.h +915 -0
  130. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  131. package/numkong/include/numkong/cast.h +254 -0
  132. package/numkong/include/numkong/cast.hpp +44 -0
  133. package/numkong/include/numkong/curved/README.md +223 -0
  134. package/numkong/include/numkong/curved/genoa.h +182 -0
  135. package/numkong/include/numkong/curved/haswell.h +276 -0
  136. package/numkong/include/numkong/curved/neon.h +329 -0
  137. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  138. package/numkong/include/numkong/curved/rvv.h +305 -0
  139. package/numkong/include/numkong/curved/serial.h +207 -0
  140. package/numkong/include/numkong/curved/skylake.h +457 -0
  141. package/numkong/include/numkong/curved/smef64.h +530 -0
  142. package/numkong/include/numkong/curved.h +513 -0
  143. package/numkong/include/numkong/curved.hpp +144 -0
  144. package/numkong/include/numkong/dot/README.md +442 -0
  145. package/numkong/include/numkong/dot/alder.h +563 -0
  146. package/numkong/include/numkong/dot/diamond.h +158 -0
  147. package/numkong/include/numkong/dot/genoa.h +289 -0
  148. package/numkong/include/numkong/dot/haswell.h +1723 -0
  149. package/numkong/include/numkong/dot/icelake.h +997 -0
  150. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  151. package/numkong/include/numkong/dot/neon.h +869 -0
  152. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  153. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  154. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  155. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  156. package/numkong/include/numkong/dot/powervsx.h +752 -0
  157. package/numkong/include/numkong/dot/rvv.h +722 -0
  158. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  159. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  160. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  161. package/numkong/include/numkong/dot/sapphire.h +141 -0
  162. package/numkong/include/numkong/dot/serial.h +874 -0
  163. package/numkong/include/numkong/dot/sierra.h +405 -0
  164. package/numkong/include/numkong/dot/skylake.h +1116 -0
  165. package/numkong/include/numkong/dot/sve.h +420 -0
  166. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  167. package/numkong/include/numkong/dot/svehalf.h +168 -0
  168. package/numkong/include/numkong/dot/svesdot.h +90 -0
  169. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  170. package/numkong/include/numkong/dot.h +1136 -0
  171. package/numkong/include/numkong/dot.hpp +94 -0
  172. package/numkong/include/numkong/dots/README.md +496 -0
  173. package/numkong/include/numkong/dots/alder.h +117 -0
  174. package/numkong/include/numkong/dots/diamond.h +86 -0
  175. package/numkong/include/numkong/dots/genoa.h +100 -0
  176. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  177. package/numkong/include/numkong/dots/haswell.h +310 -0
  178. package/numkong/include/numkong/dots/icelake.h +180 -0
  179. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  180. package/numkong/include/numkong/dots/neon.h +123 -0
  181. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  182. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  183. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  184. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  185. package/numkong/include/numkong/dots/powervsx.h +194 -0
  186. package/numkong/include/numkong/dots/rvv.h +2593 -0
  187. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  188. package/numkong/include/numkong/dots/serial.h +2867 -0
  189. package/numkong/include/numkong/dots/sierra.h +100 -0
  190. package/numkong/include/numkong/dots/skylake.h +207 -0
  191. package/numkong/include/numkong/dots/sme.h +5041 -0
  192. package/numkong/include/numkong/dots/smebi32.h +477 -0
  193. package/numkong/include/numkong/dots/smef64.h +1328 -0
  194. package/numkong/include/numkong/dots/smehalf.h +47 -0
  195. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  196. package/numkong/include/numkong/dots.h +3110 -0
  197. package/numkong/include/numkong/dots.hpp +641 -0
  198. package/numkong/include/numkong/each/README.md +465 -0
  199. package/numkong/include/numkong/each/haswell.h +1658 -0
  200. package/numkong/include/numkong/each/icelake.h +272 -0
  201. package/numkong/include/numkong/each/neon.h +1138 -0
  202. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  203. package/numkong/include/numkong/each/neonhalf.h +318 -0
  204. package/numkong/include/numkong/each/rvv.h +1121 -0
  205. package/numkong/include/numkong/each/sapphire.h +343 -0
  206. package/numkong/include/numkong/each/serial.h +282 -0
  207. package/numkong/include/numkong/each/skylake.h +1562 -0
  208. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  209. package/numkong/include/numkong/each.h +2232 -0
  210. package/numkong/include/numkong/each.hpp +434 -0
  211. package/numkong/include/numkong/geospatial/README.md +147 -0
  212. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  213. package/numkong/include/numkong/geospatial/neon.h +615 -0
  214. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  215. package/numkong/include/numkong/geospatial/serial.h +309 -0
  216. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  217. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  218. package/numkong/include/numkong/geospatial.h +453 -0
  219. package/numkong/include/numkong/geospatial.hpp +235 -0
  220. package/numkong/include/numkong/matrix.hpp +336 -0
  221. package/numkong/include/numkong/maxsim/README.md +187 -0
  222. package/numkong/include/numkong/maxsim/alder.h +511 -0
  223. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  224. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  225. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  226. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  227. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  228. package/numkong/include/numkong/maxsim/serial.h +490 -0
  229. package/numkong/include/numkong/maxsim/sme.h +993 -0
  230. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  231. package/numkong/include/numkong/maxsim.h +571 -0
  232. package/numkong/include/numkong/maxsim.hpp +133 -0
  233. package/numkong/include/numkong/mesh/README.md +219 -0
  234. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  235. package/numkong/include/numkong/mesh/neon.h +1821 -0
  236. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  237. package/numkong/include/numkong/mesh/rvv.h +936 -0
  238. package/numkong/include/numkong/mesh/serial.h +721 -0
  239. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  240. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  241. package/numkong/include/numkong/mesh.h +666 -0
  242. package/numkong/include/numkong/mesh.hpp +701 -0
  243. package/numkong/include/numkong/numkong.h +78 -0
  244. package/numkong/include/numkong/numkong.hpp +58 -0
  245. package/numkong/include/numkong/probability/README.md +177 -0
  246. package/numkong/include/numkong/probability/haswell.h +267 -0
  247. package/numkong/include/numkong/probability/neon.h +255 -0
  248. package/numkong/include/numkong/probability/rvv.h +414 -0
  249. package/numkong/include/numkong/probability/serial.h +181 -0
  250. package/numkong/include/numkong/probability/skylake.h +324 -0
  251. package/numkong/include/numkong/probability.h +380 -0
  252. package/numkong/include/numkong/probability.hpp +120 -0
  253. package/numkong/include/numkong/random.h +50 -0
  254. package/numkong/include/numkong/random.hpp +285 -0
  255. package/numkong/include/numkong/reduce/README.md +552 -0
  256. package/numkong/include/numkong/reduce/alder.h +636 -0
  257. package/numkong/include/numkong/reduce/genoa.h +201 -0
  258. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  259. package/numkong/include/numkong/reduce/icelake.h +549 -0
  260. package/numkong/include/numkong/reduce/neon.h +3980 -0
  261. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  262. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  263. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  264. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  265. package/numkong/include/numkong/reduce/serial.h +753 -0
  266. package/numkong/include/numkong/reduce/sierra.h +338 -0
  267. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  268. package/numkong/include/numkong/reduce/sve.h +52 -0
  269. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  270. package/numkong/include/numkong/reduce.h +1582 -0
  271. package/numkong/include/numkong/reduce.hpp +778 -0
  272. package/numkong/include/numkong/scalar/README.md +89 -0
  273. package/numkong/include/numkong/scalar/haswell.h +122 -0
  274. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  275. package/numkong/include/numkong/scalar/neon.h +122 -0
  276. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  277. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  278. package/numkong/include/numkong/scalar/rvv.h +211 -0
  279. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  280. package/numkong/include/numkong/scalar/serial.h +332 -0
  281. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  282. package/numkong/include/numkong/scalar.h +696 -0
  283. package/numkong/include/numkong/set/README.md +179 -0
  284. package/numkong/include/numkong/set/haswell.h +334 -0
  285. package/numkong/include/numkong/set/icelake.h +485 -0
  286. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  287. package/numkong/include/numkong/set/neon.h +363 -0
  288. package/numkong/include/numkong/set/powervsx.h +326 -0
  289. package/numkong/include/numkong/set/rvv.h +226 -0
  290. package/numkong/include/numkong/set/rvvbb.h +117 -0
  291. package/numkong/include/numkong/set/serial.h +174 -0
  292. package/numkong/include/numkong/set/sve.h +187 -0
  293. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  294. package/numkong/include/numkong/set.h +471 -0
  295. package/numkong/include/numkong/set.hpp +114 -0
  296. package/numkong/include/numkong/sets/README.md +149 -0
  297. package/numkong/include/numkong/sets/haswell.h +63 -0
  298. package/numkong/include/numkong/sets/icelake.h +66 -0
  299. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  300. package/numkong/include/numkong/sets/neon.h +61 -0
  301. package/numkong/include/numkong/sets/powervsx.h +65 -0
  302. package/numkong/include/numkong/sets/serial.h +43 -0
  303. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  304. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  305. package/numkong/include/numkong/sets.h +382 -0
  306. package/numkong/include/numkong/sparse/README.md +156 -0
  307. package/numkong/include/numkong/sparse/icelake.h +463 -0
  308. package/numkong/include/numkong/sparse/neon.h +288 -0
  309. package/numkong/include/numkong/sparse/serial.h +117 -0
  310. package/numkong/include/numkong/sparse/sve2.h +504 -0
  311. package/numkong/include/numkong/sparse/turin.h +322 -0
  312. package/numkong/include/numkong/sparse.h +363 -0
  313. package/numkong/include/numkong/sparse.hpp +113 -0
  314. package/numkong/include/numkong/spatial/README.md +439 -0
  315. package/numkong/include/numkong/spatial/alder.h +604 -0
  316. package/numkong/include/numkong/spatial/diamond.h +240 -0
  317. package/numkong/include/numkong/spatial/genoa.h +222 -0
  318. package/numkong/include/numkong/spatial/haswell.h +979 -0
  319. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  320. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  321. package/numkong/include/numkong/spatial/neon.h +846 -0
  322. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  323. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  324. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  325. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  326. package/numkong/include/numkong/spatial/rvv.h +991 -0
  327. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  328. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  329. package/numkong/include/numkong/spatial/serial.h +347 -0
  330. package/numkong/include/numkong/spatial/sierra.h +516 -0
  331. package/numkong/include/numkong/spatial/skylake.h +605 -0
  332. package/numkong/include/numkong/spatial/sve.h +246 -0
  333. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  334. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  335. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  336. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  337. package/numkong/include/numkong/spatial.h +1681 -0
  338. package/numkong/include/numkong/spatial.hpp +183 -0
  339. package/numkong/include/numkong/spatials/README.md +580 -0
  340. package/numkong/include/numkong/spatials/alder.h +94 -0
  341. package/numkong/include/numkong/spatials/diamond.h +82 -0
  342. package/numkong/include/numkong/spatials/genoa.h +94 -0
  343. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  344. package/numkong/include/numkong/spatials/haswell.h +219 -0
  345. package/numkong/include/numkong/spatials/icelake.h +113 -0
  346. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  347. package/numkong/include/numkong/spatials/neon.h +109 -0
  348. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  349. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  350. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  351. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  352. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  353. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  354. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  355. package/numkong/include/numkong/spatials/serial.h +248 -0
  356. package/numkong/include/numkong/spatials/sierra.h +96 -0
  357. package/numkong/include/numkong/spatials/skylake.h +184 -0
  358. package/numkong/include/numkong/spatials/sme.h +1927 -0
  359. package/numkong/include/numkong/spatials/smef64.h +483 -0
  360. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  361. package/numkong/include/numkong/spatials.h +3374 -0
  362. package/numkong/include/numkong/spatials.hpp +509 -0
  363. package/numkong/include/numkong/tensor.hpp +1981 -0
  364. package/numkong/include/numkong/trigonometry/README.md +184 -0
  365. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  366. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  367. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  368. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  369. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  370. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  371. package/numkong/include/numkong/trigonometry.h +467 -0
  372. package/numkong/include/numkong/trigonometry.hpp +166 -0
  373. package/numkong/include/numkong/types.h +1695 -0
  374. package/numkong/include/numkong/types.hpp +6027 -0
  375. package/numkong/include/numkong/vector.hpp +766 -0
  376. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  377. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  378. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  380. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  381. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  382. package/numkong/javascript/README.md +254 -0
  383. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  384. package/numkong/javascript/numkong-browser.ts +40 -0
  385. package/numkong/javascript/numkong-wasm.ts +750 -0
  386. package/numkong/javascript/numkong.c +712 -0
  387. package/numkong/javascript/numkong.ts +613 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  389. package/numkong/javascript/tsconfig-cjs.json +13 -0
  390. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  391. package/numkong/javascript/types.ts +784 -0
  392. package/numkong/numkong.gypi +104 -0
  393. package/numkong/package.json +108 -0
  394. package/numkong/probes/arm_neon.c +8 -0
  395. package/numkong/probes/arm_neon_bfdot.c +9 -0
  396. package/numkong/probes/arm_neon_fhm.c +9 -0
  397. package/numkong/probes/arm_neon_half.c +8 -0
  398. package/numkong/probes/arm_neon_sdot.c +9 -0
  399. package/numkong/probes/arm_neonfp8.c +9 -0
  400. package/numkong/probes/arm_sme.c +16 -0
  401. package/numkong/probes/arm_sme2.c +16 -0
  402. package/numkong/probes/arm_sme2p1.c +16 -0
  403. package/numkong/probes/arm_sme_bf16.c +16 -0
  404. package/numkong/probes/arm_sme_bi32.c +16 -0
  405. package/numkong/probes/arm_sme_f64.c +16 -0
  406. package/numkong/probes/arm_sme_fa64.c +14 -0
  407. package/numkong/probes/arm_sme_half.c +16 -0
  408. package/numkong/probes/arm_sme_lut2.c +15 -0
  409. package/numkong/probes/arm_sve.c +18 -0
  410. package/numkong/probes/arm_sve2.c +20 -0
  411. package/numkong/probes/arm_sve2p1.c +18 -0
  412. package/numkong/probes/arm_sve_bfdot.c +20 -0
  413. package/numkong/probes/arm_sve_half.c +18 -0
  414. package/numkong/probes/arm_sve_sdot.c +21 -0
  415. package/numkong/probes/loongarch_lasx.c +12 -0
  416. package/numkong/probes/power_vsx.c +12 -0
  417. package/numkong/probes/probe.js +127 -0
  418. package/numkong/probes/riscv_rvv.c +14 -0
  419. package/numkong/probes/riscv_rvv_bb.c +15 -0
  420. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  421. package/numkong/probes/riscv_rvv_half.c +14 -0
  422. package/numkong/probes/wasm_v128relaxed.c +11 -0
  423. package/numkong/probes/x86_alder.c +17 -0
  424. package/numkong/probes/x86_diamond.c +17 -0
  425. package/numkong/probes/x86_genoa.c +17 -0
  426. package/numkong/probes/x86_graniteamx.c +19 -0
  427. package/numkong/probes/x86_haswell.c +11 -0
  428. package/numkong/probes/x86_icelake.c +17 -0
  429. package/numkong/probes/x86_sapphire.c +16 -0
  430. package/numkong/probes/x86_sapphireamx.c +18 -0
  431. package/numkong/probes/x86_sierra.c +17 -0
  432. package/numkong/probes/x86_skylake.c +15 -0
  433. package/numkong/probes/x86_turin.c +17 -0
  434. package/numkong/rust/README.md +698 -0
  435. package/numkong/rust/capabilities.rs +96 -0
  436. package/numkong/rust/cast.rs +314 -0
  437. package/numkong/rust/curved.rs +391 -0
  438. package/numkong/rust/each.rs +2721 -0
  439. package/numkong/rust/geospatial.rs +343 -0
  440. package/numkong/rust/matrix.rs +5424 -0
  441. package/numkong/rust/maxsim.rs +540 -0
  442. package/numkong/rust/mesh.rs +837 -0
  443. package/numkong/rust/numkong.rs +409 -0
  444. package/numkong/rust/probability.rs +272 -0
  445. package/numkong/rust/reduce.rs +1249 -0
  446. package/numkong/rust/set.rs +194 -0
  447. package/numkong/rust/sparse.rs +513 -0
  448. package/numkong/rust/spatial.rs +1815 -0
  449. package/numkong/rust/tensor.rs +7565 -0
  450. package/numkong/rust/types.rs +3666 -0
  451. package/numkong/rust/vector.rs +1899 -0
  452. package/numkong/rustfmt.toml +2 -0
  453. package/numkong/swift/Matrix.swift +1388 -0
  454. package/numkong/swift/MaxSim.swift +151 -0
  455. package/numkong/swift/NumKong.swift +283 -0
  456. package/numkong/swift/Numerics.swift +329 -0
  457. package/numkong/swift/README.md +433 -0
  458. package/numkong/swift/Scalar.swift +741 -0
  459. package/numkong/swift/Tensor.swift +209 -0
  460. package/numkong/test/README.md +315 -0
  461. package/numkong/test/playwright.config.ts +16 -0
  462. package/numkong/test/swift/Test.swift +534 -0
  463. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  464. package/numkong/test/test-browser-bundle.html +188 -0
  465. package/numkong/test/test-browser-runner.mjs +43 -0
  466. package/numkong/test/test-browser.html +305 -0
  467. package/numkong/test/test-dtypes.mjs +453 -0
  468. package/numkong/test/test-wasm.mjs +267 -0
  469. package/numkong/test/test.cpp +442 -0
  470. package/numkong/test/test.hpp +580 -0
  471. package/numkong/test/test.mjs +363 -0
  472. package/numkong/test/test_base.py +1041 -0
  473. package/numkong/test/test_cast.cpp +242 -0
  474. package/numkong/test/test_cross.hpp +551 -0
  475. package/numkong/test/test_cross.py +467 -0
  476. package/numkong/test/test_cross_amx.cpp +50 -0
  477. package/numkong/test/test_cross_arm.cpp +225 -0
  478. package/numkong/test/test_cross_blas.cpp +354 -0
  479. package/numkong/test/test_cross_loongarch.cpp +90 -0
  480. package/numkong/test/test_cross_power.cpp +73 -0
  481. package/numkong/test/test_cross_rvv.cpp +109 -0
  482. package/numkong/test/test_cross_serial.cpp +181 -0
  483. package/numkong/test/test_cross_sme.cpp +148 -0
  484. package/numkong/test/test_cross_wasm.cpp +141 -0
  485. package/numkong/test/test_cross_x86.cpp +442 -0
  486. package/numkong/test/test_curved.cpp +182 -0
  487. package/numkong/test/test_curved.py +207 -0
  488. package/numkong/test/test_dot.cpp +353 -0
  489. package/numkong/test/test_dot.py +296 -0
  490. package/numkong/test/test_each.cpp +437 -0
  491. package/numkong/test/test_each.py +756 -0
  492. package/numkong/test/test_geospatial.cpp +155 -0
  493. package/numkong/test/test_geospatial.py +241 -0
  494. package/numkong/test/test_maxsim.cpp +138 -0
  495. package/numkong/test/test_maxsim.py +209 -0
  496. package/numkong/test/test_mesh.cpp +203 -0
  497. package/numkong/test/test_mesh.py +394 -0
  498. package/numkong/test/test_probability.cpp +136 -0
  499. package/numkong/test/test_probability.py +166 -0
  500. package/numkong/test/test_reduce.cpp +563 -0
  501. package/numkong/test/test_reduce.py +781 -0
  502. package/numkong/test/test_set.cpp +151 -0
  503. package/numkong/test/test_set.py +120 -0
  504. package/numkong/test/test_similarities.py +579 -0
  505. package/numkong/test/test_sparse.cpp +121 -0
  506. package/numkong/test/test_sparse.py +118 -0
  507. package/numkong/test/test_spatial.cpp +518 -0
  508. package/numkong/test/test_spatial.py +269 -0
  509. package/numkong/test/test_tensor.cpp +884 -0
  510. package/numkong/test/test_tensor.py +1417 -0
  511. package/numkong/test/test_trigonometry.cpp +156 -0
  512. package/numkong/test/test_trigonometry.py +180 -0
  513. package/package.json +7 -8
  514. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  515. package/prebuilds/linux-arm64/usearch.node +0 -0
  516. package/prebuilds/linux-x64/usearch.node +0 -0
  517. package/fp16/CMakeLists.txt +0 -176
  518. package/fp16/LICENSE +0 -11
  519. package/fp16/README.md +0 -20
  520. package/fp16/bench/alt-element.cc +0 -89
  521. package/fp16/bench/from-alt-array.cc +0 -175
  522. package/fp16/bench/from-ieee-array.cc +0 -399
  523. package/fp16/bench/ieee-element.cc +0 -272
  524. package/fp16/bench/to-alt-array.cc +0 -91
  525. package/fp16/bench/to-ieee-array.cc +0 -303
  526. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  527. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  528. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  529. package/fp16/configure.py +0 -65
  530. package/fp16/confu.yaml +0 -8
  531. package/fp16/include/fp16/__init__.py +0 -0
  532. package/fp16/include/fp16/avx.py +0 -50
  533. package/fp16/include/fp16/avx2.py +0 -53
  534. package/fp16/include/fp16/bitcasts.h +0 -92
  535. package/fp16/include/fp16/fp16.h +0 -451
  536. package/fp16/include/fp16/psimd.h +0 -131
  537. package/fp16/include/fp16.h +0 -11
  538. package/fp16/jni/Android.mk +0 -6
  539. package/fp16/jni/Application.mk +0 -4
  540. package/fp16/test/alt-from-fp32-value.cc +0 -498
  541. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  542. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  543. package/fp16/test/alt-to-fp32-value.cc +0 -348
  544. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  545. package/fp16/test/bitcasts.cc +0 -56
  546. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  547. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  548. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  549. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  550. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  551. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  552. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  553. package/fp16/test/peachpy/stubs.py +0 -38
  554. package/fp16/test/tables.cc +0 -530
  555. package/fp16/test/tables.h +0 -13
  556. package/fp16/third-party/THHalf.h +0 -92
  557. package/fp16/third-party/eigen-half.h +0 -170
  558. package/fp16/third-party/float16-compressor.h +0 -80
  559. package/fp16/third-party/half.hpp +0 -2916
  560. package/fp16/third-party/npy-halffloat.h +0 -328
  561. package/simsimd/.git-blame-ignore-revs +0 -2
  562. package/simsimd/CONTRIBUTING.md +0 -321
  563. package/simsimd/Cargo.toml +0 -49
  564. package/simsimd/MANIFEST.in +0 -4
  565. package/simsimd/Package.swift +0 -28
  566. package/simsimd/README.md +0 -1493
  567. package/simsimd/binding.gyp +0 -35
  568. package/simsimd/build.rs +0 -70
  569. package/simsimd/c/lib.c +0 -374
  570. package/simsimd/include/module.modulemap +0 -4
  571. package/simsimd/include/simsimd/binary.h +0 -486
  572. package/simsimd/include/simsimd/curved.h +0 -1541
  573. package/simsimd/include/simsimd/dot.h +0 -1853
  574. package/simsimd/include/simsimd/elementwise.h +0 -2465
  575. package/simsimd/include/simsimd/geospatial.h +0 -43
  576. package/simsimd/include/simsimd/mesh.h +0 -69
  577. package/simsimd/include/simsimd/probability.h +0 -606
  578. package/simsimd/include/simsimd/simsimd.h +0 -2567
  579. package/simsimd/include/simsimd/sparse.h +0 -1384
  580. package/simsimd/include/simsimd/spatial.h +0 -2335
  581. package/simsimd/include/simsimd/types.h +0 -666
  582. package/simsimd/javascript/fallback.ts +0 -233
  583. package/simsimd/javascript/lib.c +0 -125
  584. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  585. package/simsimd/javascript/simsimd.ts +0 -179
  586. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  587. package/simsimd/package-lock.json +0 -1761
  588. package/simsimd/package.json +0 -61
  589. package/simsimd/rust/lib.rs +0 -1821
  590. package/simsimd/scripts/bench.cxx +0 -1170
  591. package/simsimd/scripts/bench.ipynb +0 -187
  592. package/simsimd/scripts/bench.js +0 -127
  593. package/simsimd/scripts/bench.rs +0 -876
  594. package/simsimd/scripts/bench_vectors.py +0 -734
  595. package/simsimd/scripts/bench_vectors_live.py +0 -213
  596. package/simsimd/scripts/test.c +0 -187
  597. package/simsimd/scripts/test.mjs +0 -220
  598. package/simsimd/scripts/test.py +0 -1505
  599. package/simsimd/swift/SimSIMD.swift +0 -149
  600. package/simsimd/swift/Test.swift +0 -128
  601. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  602. /package/{simsimd → numkong}/LICENSE +0 -0
  603. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  604. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,194 @@
1
+ //! Binary set similarity: Hamming and Jaccard distances.
2
+ //!
3
+ //! This module provides:
4
+ //!
5
+ //! - [`Hamming`]: Bit-level or byte-level Hamming distance
6
+ //! - [`Jaccard`]: Jaccard distance (1 - intersection/union)
7
+ //! - [`BinarySimilarity`]: Blanket trait combining `Hamming + Jaccard`
8
+
9
+ use crate::types::{u1x8, StorageElement};
10
+
11
+ #[link(name = "numkong")]
12
+ extern "C" {
13
+ fn nk_hamming_u1(a: *const u8, b: *const u8, c: usize, d: *mut u32);
14
+ fn nk_jaccard_u1(a: *const u8, b: *const u8, c: usize, d: *mut f32);
15
+ fn nk_hamming_u8(a: *const u8, b: *const u8, n: usize, result: *mut u32);
16
+ fn nk_jaccard_u16(a: *const u16, b: *const u16, n: usize, result: *mut f32);
17
+ fn nk_jaccard_u32(a: *const u32, b: *const u32, n: usize, result: *mut f32);
18
+ }
19
+
20
+ // region: Hamming
21
+
22
+ /// Computes the **Hamming distance** between two binary vectors.
23
+ ///
24
+ /// Counts differing bits (for `u1x8`) or differing bytes (for `u8`).
25
+ ///
26
+ /// Range: \[0, n\]. Returns `None` if lengths differ.
27
+ ///
28
+ /// Implemented for: `u1x8`, `u8`.
29
+ pub trait Hamming: StorageElement {
30
+ type Output;
31
+ fn hamming(a: &[Self], b: &[Self]) -> Option<Self::Output>;
32
+ }
33
+
34
+ impl Hamming for u1x8 {
35
+ type Output = u32;
36
+ fn hamming(a: &[Self], b: &[Self]) -> Option<Self::Output> {
37
+ if a.len() != b.len() {
38
+ return None;
39
+ }
40
+ let mut result: Self::Output = 0;
41
+ let n_bits = a.len() * 8; // Each u1x8 contains 8 bits
42
+ unsafe {
43
+ nk_hamming_u1(
44
+ a.as_ptr() as *const u8,
45
+ b.as_ptr() as *const u8,
46
+ n_bits,
47
+ &mut result,
48
+ )
49
+ };
50
+ Some(result)
51
+ }
52
+ }
53
+
54
+ impl Hamming for u8 {
55
+ type Output = u32;
56
+ fn hamming(a: &[Self], b: &[Self]) -> Option<Self::Output> {
57
+ if a.len() != b.len() {
58
+ return None;
59
+ }
60
+ let mut result: Self::Output = 0;
61
+ unsafe { nk_hamming_u8(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
62
+ Some(result)
63
+ }
64
+ }
65
+
66
+ // endregion: Hamming
67
+
68
+ // region: Jaccard
69
+
70
+ /// Computes the **Jaccard distance** between two sets represented as bit/integer vectors.
71
+ ///
72
+ /// d = 1 − |A ∩ B| / |A ∪ B|
73
+ ///
74
+ /// Range: \[0, 1\]. Returns `None` if lengths differ.
75
+ ///
76
+ /// Implemented for: `u1x8`, `u16`, `u32`.
77
+ pub trait Jaccard: StorageElement {
78
+ type Output;
79
+ fn jaccard(a: &[Self], b: &[Self]) -> Option<Self::Output>;
80
+ }
81
+
82
+ impl Jaccard for u1x8 {
83
+ type Output = f32;
84
+ fn jaccard(a: &[Self], b: &[Self]) -> Option<Self::Output> {
85
+ if a.len() != b.len() {
86
+ return None;
87
+ }
88
+ let mut result: Self::Output = 0.0;
89
+ let n_bits = a.len() * 8; // Each u1x8 contains 8 bits
90
+ unsafe {
91
+ nk_jaccard_u1(
92
+ a.as_ptr() as *const u8,
93
+ b.as_ptr() as *const u8,
94
+ n_bits,
95
+ &mut result,
96
+ )
97
+ };
98
+ Some(result)
99
+ }
100
+ }
101
+
102
+ impl Jaccard for u16 {
103
+ type Output = f32;
104
+ fn jaccard(a: &[Self], b: &[Self]) -> Option<Self::Output> {
105
+ if a.len() != b.len() {
106
+ return None;
107
+ }
108
+ let mut result: Self::Output = 0.0;
109
+ unsafe { nk_jaccard_u16(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
110
+ Some(result)
111
+ }
112
+ }
113
+
114
+ impl Jaccard for u32 {
115
+ type Output = f32;
116
+ fn jaccard(a: &[Self], b: &[Self]) -> Option<Self::Output> {
117
+ if a.len() != b.len() {
118
+ return None;
119
+ }
120
+ let mut result: Self::Output = 0.0;
121
+ unsafe { nk_jaccard_u32(a.as_ptr(), b.as_ptr(), a.len(), &mut result) };
122
+ Some(result)
123
+ }
124
+ }
125
+
126
+ // endregion: Jaccard
127
+
128
+ /// `BinarySimilarity` bundles binary distance metrics: Hamming and Jaccard.
129
+ pub trait BinarySimilarity: Hamming + Jaccard {}
130
+ impl<Scalar: Hamming + Jaccard> BinarySimilarity for Scalar {}
131
+
132
+ #[cfg(test)]
133
+ mod tests {
134
+ use super::*;
135
+ use crate::types::{assert_close, u1x8};
136
+
137
+ #[test]
138
+ fn hamming() {
139
+ // u1x8
140
+ let left = vec![u1x8(0b11110000), u1x8(0b10101010)];
141
+ let right = vec![u1x8(0b00001111), u1x8(0b01010101)];
142
+ assert_eq!(u1x8::hamming(&left, &right).unwrap(), 16);
143
+
144
+ // u8
145
+ let left: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7];
146
+ let right: Vec<u8> = vec![0, 1, 2, 3, 0, 0, 0, 0];
147
+ assert_eq!(u8::hamming(&left, &right).unwrap(), 4);
148
+ }
149
+
150
+ #[test]
151
+ fn jaccard() {
152
+ // u1x8 — identical
153
+ let left = vec![u1x8(0b11110000), u1x8(0b10101010)];
154
+ let right = vec![u1x8(0b11110000), u1x8(0b10101010)];
155
+ assert_close(
156
+ u1x8::jaccard(&left, &right).unwrap() as f64,
157
+ 0.0,
158
+ 0.01,
159
+ 0.0,
160
+ "jaccard_u1x8",
161
+ );
162
+
163
+ // u16 — identical
164
+ let left: Vec<u16> = vec![1, 2, 3, 4];
165
+ let right: Vec<u16> = vec![1, 2, 3, 4];
166
+ assert_close(
167
+ u16::jaccard(&left, &right).unwrap() as f64,
168
+ 0.0,
169
+ 0.01,
170
+ 0.0,
171
+ "jaccard_u16 identical",
172
+ );
173
+ // u16 — disjoint
174
+ let disjoint: Vec<u16> = vec![5, 6, 7, 8];
175
+ assert_close(
176
+ u16::jaccard(&left, &disjoint).unwrap() as f64,
177
+ 1.0,
178
+ 0.01,
179
+ 0.0,
180
+ "jaccard_u16 disjoint",
181
+ );
182
+
183
+ // u32 — partial overlap
184
+ let left: Vec<u32> = vec![1, 2, 3, 4];
185
+ let right: Vec<u32> = vec![1, 2, 5, 6];
186
+ assert_close(
187
+ u32::jaccard(&left, &right).unwrap() as f64,
188
+ 0.5,
189
+ 0.01,
190
+ 0.0,
191
+ "jaccard_u32",
192
+ );
193
+ }
194
+ }
@@ -0,0 +1,513 @@
1
+ //! Sparse set intersection and weighted dot products.
2
+ //!
3
+ //! This module provides:
4
+ //!
5
+ //! - [`SparseIntersect`]: Sorted-set intersection of index arrays
6
+ //! - [`SparseDot`]: Weighted dot product over sparse index-value pairs
7
+ //!
8
+ //! # Sorted-Index Assumption
9
+ //!
10
+ //! Every sparse routine in this module assumes that the index arrays are **strictly
11
+ //! ascending** (sorted with no duplicates) — for example `[1, 3, 5, 7]`. The
12
+ //! underlying SIMD kernels use galloping / merge-style advancement that is only
13
+ //! correct on sorted input; feeding unsorted indices silently produces wrong results
14
+ //! (typically an undercounted intersection).
15
+ //!
16
+ //! For [`SparseDot`], the paired `weights` slice must mirror the index layout: entry
17
+ //! `weights[i]` is the weight at `indices[i]`. The dot product sums
18
+ //! `a_weights[i] × b_weights[j]` over all pairs `i, j` where
19
+ //! `a_indices[i] == b_indices[j]` — i.e., the intersection's co-indexed weights.
20
+ //!
21
+ //! Callers with unsorted sparse vectors should sort (e.g., via `slice::sort_unstable`)
22
+ //! and deduplicate before calling these kernels.
23
+
24
+ use crate::types::bf16;
25
+
26
+ #[link(name = "numkong")]
27
+ extern "C" {
28
+ fn nk_sparse_intersect_u16(
29
+ a: *const u16,
30
+ b: *const u16,
31
+ a_length: usize,
32
+ b_length: usize,
33
+ result: *mut u16,
34
+ count: *mut usize,
35
+ );
36
+ fn nk_sparse_intersect_u32(
37
+ a: *const u32,
38
+ b: *const u32,
39
+ a_length: usize,
40
+ b_length: usize,
41
+ result: *mut u32,
42
+ count: *mut usize,
43
+ );
44
+ fn nk_sparse_intersect_u64(
45
+ a: *const u64,
46
+ b: *const u64,
47
+ a_length: usize,
48
+ b_length: usize,
49
+ result: *mut u64,
50
+ count: *mut usize,
51
+ );
52
+ fn nk_sparse_dot_u16bf16(
53
+ a: *const u16,
54
+ b: *const u16,
55
+ a_weights: *const u16,
56
+ b_weights: *const u16,
57
+ a_length: usize,
58
+ b_length: usize,
59
+ product: *mut f32,
60
+ );
61
+ fn nk_sparse_dot_u32f32(
62
+ a: *const u32,
63
+ b: *const u32,
64
+ a_weights: *const f32,
65
+ b_weights: *const f32,
66
+ a_length: usize,
67
+ b_length: usize,
68
+ product: *mut f64,
69
+ );
70
+ }
71
+
72
+ // region: SparseIntersect
73
+
74
+ /// Computes set operations on sorted sparse vectors.
75
+ pub trait SparseIntersect: Sized {
76
+ /// Returns the intersection size between two sorted sparse vectors.
77
+ fn sparse_intersection_size(a: &[Self], b: &[Self]) -> usize;
78
+
79
+ /// Computes intersection and writes matching elements to output buffer.
80
+ /// Buffer must be at least `min(a.len(), b.len())` in size.
81
+ /// Returns `Some(count)` with number of elements written, or `None` if buffer too small.
82
+ fn sparse_intersect_into(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<usize>;
83
+ }
84
+
85
+ impl SparseIntersect for u16 {
86
+ fn sparse_intersection_size(a: &[Self], b: &[Self]) -> usize {
87
+ let mut count: usize = 0;
88
+ unsafe {
89
+ nk_sparse_intersect_u16(
90
+ a.as_ptr(),
91
+ b.as_ptr(),
92
+ a.len(),
93
+ b.len(),
94
+ core::ptr::null_mut(),
95
+ &mut count,
96
+ )
97
+ };
98
+ count
99
+ }
100
+
101
+ fn sparse_intersect_into(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<usize> {
102
+ let min_len = a.len().min(b.len());
103
+ if result.len() < min_len {
104
+ return None;
105
+ }
106
+ let mut count: usize = 0;
107
+ unsafe {
108
+ nk_sparse_intersect_u16(
109
+ a.as_ptr(),
110
+ b.as_ptr(),
111
+ a.len(),
112
+ b.len(),
113
+ result.as_mut_ptr(),
114
+ &mut count,
115
+ )
116
+ };
117
+ Some(count)
118
+ }
119
+ }
120
+
121
+ impl SparseIntersect for u32 {
122
+ fn sparse_intersection_size(a: &[Self], b: &[Self]) -> usize {
123
+ let mut count: usize = 0;
124
+ unsafe {
125
+ nk_sparse_intersect_u32(
126
+ a.as_ptr(),
127
+ b.as_ptr(),
128
+ a.len(),
129
+ b.len(),
130
+ core::ptr::null_mut(),
131
+ &mut count,
132
+ )
133
+ };
134
+ count
135
+ }
136
+
137
+ fn sparse_intersect_into(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<usize> {
138
+ let min_len = a.len().min(b.len());
139
+ if result.len() < min_len {
140
+ return None;
141
+ }
142
+ let mut count: usize = 0;
143
+ unsafe {
144
+ nk_sparse_intersect_u32(
145
+ a.as_ptr(),
146
+ b.as_ptr(),
147
+ a.len(),
148
+ b.len(),
149
+ result.as_mut_ptr(),
150
+ &mut count,
151
+ )
152
+ };
153
+ Some(count)
154
+ }
155
+ }
156
+
157
+ impl SparseIntersect for u64 {
158
+ fn sparse_intersection_size(a: &[Self], b: &[Self]) -> usize {
159
+ let mut count: usize = 0;
160
+ unsafe {
161
+ nk_sparse_intersect_u64(
162
+ a.as_ptr(),
163
+ b.as_ptr(),
164
+ a.len(),
165
+ b.len(),
166
+ core::ptr::null_mut(),
167
+ &mut count,
168
+ )
169
+ };
170
+ count
171
+ }
172
+
173
+ fn sparse_intersect_into(a: &[Self], b: &[Self], result: &mut [Self]) -> Option<usize> {
174
+ let min_len = a.len().min(b.len());
175
+ if result.len() < min_len {
176
+ return None;
177
+ }
178
+ let mut count: usize = 0;
179
+ unsafe {
180
+ nk_sparse_intersect_u64(
181
+ a.as_ptr(),
182
+ b.as_ptr(),
183
+ a.len(),
184
+ b.len(),
185
+ result.as_mut_ptr(),
186
+ &mut count,
187
+ )
188
+ };
189
+ Some(count)
190
+ }
191
+ }
192
+
193
+ // endregion: SparseIntersect
194
+
195
+ // region: SparseDot
196
+
197
+ /// Computes sparse dot product between two sorted sparse vectors with weights.
198
+ ///
199
+ /// Each vector consists of sorted indices and corresponding weights. The dot product
200
+ /// is computed over the intersection of indices, summing the products of weights.
201
+ pub trait SparseDot: Sized {
202
+ /// Weight type for this sparse dot product.
203
+ type Weight;
204
+ /// Output type for this sparse dot product.
205
+ type Output;
206
+
207
+ /// Computes sparse dot product.
208
+ ///
209
+ /// Returns the sum of `a_weights[i] × b_weights[j]` for all pairs where `a_indices[i] == b_indices[j]`.
210
+ fn sparse_dot(
211
+ a_indices: &[Self],
212
+ b_indices: &[Self],
213
+ a_weights: &[Self::Weight],
214
+ b_weights: &[Self::Weight],
215
+ ) -> Self::Output;
216
+ }
217
+
218
+ impl SparseDot for u16 {
219
+ type Weight = bf16;
220
+ type Output = f32;
221
+
222
+ fn sparse_dot(
223
+ a_indices: &[Self],
224
+ b_indices: &[Self],
225
+ a_weights: &[bf16],
226
+ b_weights: &[bf16],
227
+ ) -> Self::Output {
228
+ let mut product: f32 = 0.0;
229
+ unsafe {
230
+ nk_sparse_dot_u16bf16(
231
+ a_indices.as_ptr(),
232
+ b_indices.as_ptr(),
233
+ a_weights.as_ptr() as *const u16,
234
+ b_weights.as_ptr() as *const u16,
235
+ a_indices.len(),
236
+ b_indices.len(),
237
+ &mut product,
238
+ );
239
+ }
240
+ product
241
+ }
242
+ }
243
+
244
+ impl SparseDot for u32 {
245
+ type Weight = f32;
246
+ type Output = f64;
247
+
248
+ fn sparse_dot(
249
+ a_indices: &[Self],
250
+ b_indices: &[Self],
251
+ a_weights: &[f32],
252
+ b_weights: &[f32],
253
+ ) -> Self::Output {
254
+ let mut product: f64 = 0.0;
255
+ unsafe {
256
+ nk_sparse_dot_u32f32(
257
+ a_indices.as_ptr(),
258
+ b_indices.as_ptr(),
259
+ a_weights.as_ptr(),
260
+ b_weights.as_ptr(),
261
+ a_indices.len(),
262
+ b_indices.len(),
263
+ &mut product,
264
+ );
265
+ }
266
+ product
267
+ }
268
+ }
269
+
270
+ // endregion: SparseDot
271
+
272
+ #[cfg(test)]
273
+ mod tests {
274
+ use super::*;
275
+ use crate::types::bf16;
276
+
277
+ // region: Sparse Intersections
278
+
279
+ #[test]
280
+ fn sparse_intersection() {
281
+ // u16 — intersection size
282
+ let left: Vec<u16> = vec![1, 3, 5, 7, 9];
283
+ let right: Vec<u16> = vec![2, 3, 5, 8, 9];
284
+ assert_eq!(u16::sparse_intersection_size(&left, &right), 3);
285
+
286
+ // u16 — intersect into buffer
287
+ let mut result: Vec<u16> = vec![0; 5];
288
+ let count = u16::sparse_intersect_into(&left, &right, &mut result).unwrap();
289
+ assert_eq!(count, 3);
290
+ assert_eq!(&result[..count], &[3, 5, 9]);
291
+
292
+ // u32 — intersect into buffer
293
+ let left: Vec<u32> = vec![10, 20, 30, 40];
294
+ let right: Vec<u32> = vec![15, 20, 30, 45];
295
+ let mut result: Vec<u32> = vec![0; 4];
296
+ let count = u32::sparse_intersect_into(&left, &right, &mut result).unwrap();
297
+ assert_eq!(count, 2);
298
+ assert_eq!(&result[..count], &[20, 30]);
299
+
300
+ // u64 — intersection size
301
+ let left: Vec<u64> = vec![100, 200, 300];
302
+ let right: Vec<u64> = vec![200, 300, 400];
303
+ assert_eq!(u64::sparse_intersection_size(&left, &right), 2);
304
+ }
305
+
306
+ #[test]
307
+ fn sparse_intersect_into_buffer_too_small() {
308
+ let left: Vec<u16> = vec![1, 2, 3, 4, 5];
309
+ let right: Vec<u16> = vec![3, 4, 5, 6, 7];
310
+ let mut result: Vec<u16> = vec![0; 2];
311
+ assert!(u16::sparse_intersect_into(&left, &right, &mut result).is_none());
312
+ }
313
+
314
+ // endregion
315
+
316
+ // region: Intersection Tests
317
+
318
+ fn reference_intersect<Scalar: Ord>(a: &[Scalar], b: &[Scalar]) -> usize {
319
+ let mut a_iter = a.iter();
320
+ let mut b_iter = b.iter();
321
+ let mut a_current = a_iter.next();
322
+ let mut b_current = b_iter.next();
323
+ let mut count = 0;
324
+ while let (Some(a_val), Some(b_val)) = (a_current, b_current) {
325
+ match a_val.cmp(b_val) {
326
+ core::cmp::Ordering::Less => a_current = a_iter.next(),
327
+ core::cmp::Ordering::Greater => b_current = b_iter.next(),
328
+ core::cmp::Ordering::Equal => {
329
+ count += 1;
330
+ a_current = a_iter.next();
331
+ b_current = b_iter.next();
332
+ }
333
+ }
334
+ }
335
+ count
336
+ }
337
+
338
+ fn generate_intersection_test_arrays<Scalar>() -> Vec<Vec<Scalar>>
339
+ where
340
+ Scalar: core::convert::TryFrom<u32> + Copy,
341
+ <Scalar as core::convert::TryFrom<u32>>::Error: core::fmt::Debug,
342
+ {
343
+ vec![
344
+ vec![],
345
+ vec![Scalar::try_from(42).unwrap()],
346
+ vec![
347
+ Scalar::try_from(1).unwrap(),
348
+ Scalar::try_from(5).unwrap(),
349
+ Scalar::try_from(10).unwrap(),
350
+ ],
351
+ vec![
352
+ Scalar::try_from(2).unwrap(),
353
+ Scalar::try_from(4).unwrap(),
354
+ Scalar::try_from(6).unwrap(),
355
+ Scalar::try_from(8).unwrap(),
356
+ Scalar::try_from(10).unwrap(),
357
+ Scalar::try_from(12).unwrap(),
358
+ Scalar::try_from(14).unwrap(),
359
+ ],
360
+ (0..14).map(|x| Scalar::try_from(x * 10).unwrap()).collect(),
361
+ (5..20).map(|x| Scalar::try_from(x * 10).unwrap()).collect(),
362
+ (0..40).map(|x| Scalar::try_from(x * 2).unwrap()).collect(),
363
+ (10..50).map(|x| Scalar::try_from(x * 2).unwrap()).collect(),
364
+ (0..45).map(|x| Scalar::try_from(x * 3).unwrap()).collect(),
365
+ (0..100).map(|x| Scalar::try_from(x * 2).unwrap()).collect(),
366
+ (50..150)
367
+ .map(|x| Scalar::try_from(x * 2).unwrap())
368
+ .collect(),
369
+ (0..100).map(|x| Scalar::try_from(x * 5).unwrap()).collect(),
370
+ (0..150)
371
+ .filter(|x| x % 7 == 0)
372
+ .map(|x| Scalar::try_from(x).unwrap())
373
+ .collect(),
374
+ (0..500).map(|x| Scalar::try_from(x * 3).unwrap()).collect(),
375
+ (100..600)
376
+ .map(|x| Scalar::try_from(x * 3).unwrap())
377
+ .collect(),
378
+ (0..600).map(|x| Scalar::try_from(x * 7).unwrap()).collect(),
379
+ (0..50).map(|x| Scalar::try_from(x * 2).unwrap()).collect(),
380
+ (1000..1050)
381
+ .map(|x| Scalar::try_from(x * 2).unwrap())
382
+ .collect(),
383
+ (0..16).map(|x| Scalar::try_from(x).unwrap()).collect(),
384
+ (0..32).map(|x| Scalar::try_from(x).unwrap()).collect(),
385
+ (0..64).map(|x| Scalar::try_from(x).unwrap()).collect(),
386
+ ]
387
+ }
388
+
389
+ #[test]
390
+ fn intersect_u32_comprehensive() {
391
+ let test_arrays: Vec<Vec<u32>> = generate_intersection_test_arrays();
392
+ for (i, array_a) in test_arrays.iter().enumerate() {
393
+ for (j, array_b) in test_arrays.iter().enumerate() {
394
+ let expected = reference_intersect(array_a, array_b);
395
+ let result = u32::sparse_intersection_size(array_a.as_slice(), array_b.as_slice());
396
+ assert_eq!(
397
+ expected,
398
+ result,
399
+ "Intersection mismatch for arrays[{}] (len={}) and arrays[{}] (len={})",
400
+ i,
401
+ array_a.len(),
402
+ j,
403
+ array_b.len()
404
+ );
405
+ }
406
+ }
407
+ }
408
+
409
+ #[test]
410
+ fn intersect_u16_comprehensive() {
411
+ let test_arrays: Vec<Vec<u16>> = generate_intersection_test_arrays();
412
+ for (i, array_a) in test_arrays.iter().enumerate() {
413
+ for (j, array_b) in test_arrays.iter().enumerate() {
414
+ let expected = reference_intersect(array_a, array_b);
415
+ let result = u16::sparse_intersection_size(array_a.as_slice(), array_b.as_slice());
416
+ assert_eq!(
417
+ expected,
418
+ result,
419
+ "Intersection mismatch for arrays[{}] (len={}) and arrays[{}] (len={})",
420
+ i,
421
+ array_a.len(),
422
+ j,
423
+ array_b.len()
424
+ );
425
+ }
426
+ }
427
+ }
428
+
429
+ #[test]
430
+ fn intersect_edge_cases() {
431
+ let empty: &[u32] = &[];
432
+ let non_empty: &[u32] = &[1, 2, 3];
433
+ assert_eq!(u32::sparse_intersection_size(empty, empty), 0);
434
+ assert_eq!(u32::sparse_intersection_size(empty, non_empty), 0);
435
+ assert_eq!(u32::sparse_intersection_size(non_empty, empty), 0);
436
+
437
+ assert_eq!(u32::sparse_intersection_size(&[42u32], &[42u32]), 1);
438
+ assert_eq!(u32::sparse_intersection_size(&[42u32], &[43u32]), 0);
439
+
440
+ let a: &[u32] = &[1, 2, 3, 4, 5];
441
+ let b: &[u32] = &[10, 20, 30, 40, 50];
442
+ assert_eq!(u32::sparse_intersection_size(a, b), 0);
443
+
444
+ let c: &[u32] = &[10, 20, 30, 40, 50];
445
+ assert_eq!(u32::sparse_intersection_size(c, c), 5);
446
+
447
+ let boundary_16: Vec<u32> = (0..16).collect();
448
+ let boundary_32: Vec<u32> = (0..32).collect();
449
+ let boundary_64: Vec<u32> = (0..64).collect();
450
+ assert_eq!(
451
+ u32::sparse_intersection_size(&boundary_16, &boundary_16),
452
+ 16
453
+ );
454
+ assert_eq!(
455
+ u32::sparse_intersection_size(&boundary_32, &boundary_32),
456
+ 32
457
+ );
458
+ assert_eq!(
459
+ u32::sparse_intersection_size(&boundary_64, &boundary_64),
460
+ 64
461
+ );
462
+
463
+ let first_half: Vec<u32> = (0..32).collect();
464
+ let second_half: Vec<u32> = (16..48).collect();
465
+ assert_eq!(u32::sparse_intersection_size(&first_half, &second_half), 16);
466
+ }
467
+
468
+ // endregion
469
+
470
+ // region: SparseDot
471
+
472
+ #[test]
473
+ fn sparse_dot() {
474
+ // u32 indices with f32 weights
475
+ let first_indices: Vec<u32> = vec![1, 3, 5];
476
+ let second_indices: Vec<u32> = vec![2, 3, 5, 7];
477
+ let first_weights: Vec<f32> = vec![1.0, 2.0, 3.0];
478
+ let second_weights: Vec<f32> = vec![4.0, 5.0, 6.0, 7.0];
479
+ // Overlap at indices 3 and 5: 2.0*5.0 + 3.0*6.0 = 28.0
480
+ let result = u32::sparse_dot(
481
+ &first_indices,
482
+ &second_indices,
483
+ &first_weights,
484
+ &second_weights,
485
+ );
486
+ assert!((result - 28.0).abs() < 0.01, "sparse_dot u32f32: {result}");
487
+
488
+ // u16 indices with bf16 weights
489
+ let first_indices_u16: Vec<u16> = vec![1, 3, 5];
490
+ let second_indices_u16: Vec<u16> = vec![2, 3, 5, 7];
491
+ let first_weights_bf16: Vec<bf16> = vec![1.0, 2.0, 3.0]
492
+ .iter()
493
+ .map(|&value| bf16::from_f32(value))
494
+ .collect();
495
+ let second_weights_bf16: Vec<bf16> = vec![4.0, 5.0, 6.0, 7.0]
496
+ .iter()
497
+ .map(|&value| bf16::from_f32(value))
498
+ .collect();
499
+ let result = u16::sparse_dot(
500
+ &first_indices_u16,
501
+ &second_indices_u16,
502
+ &first_weights_bf16,
503
+ &second_weights_bf16,
504
+ );
505
+ assert!((result - 28.0).abs() < 1.0, "sparse_dot u16bf16: {result}");
506
+
507
+ // Disjoint sets → 0
508
+ let result = u32::sparse_dot(&[1, 2], &[3, 4], &[1.0, 1.0], &[1.0, 1.0]);
509
+ assert!(result.abs() < 0.01, "sparse_dot disjoint: {result}");
510
+ }
511
+
512
+ // endregion
513
+ }