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
@@ -0,0 +1,326 @@
1
+ /**
2
+ * @brief SIMD-accelerated Set Similarity Measures for Power ISA VSX.
3
+ * @file include/numkong/set/powervsx.h
4
+ * @author Ash Vardanian
5
+ * @date March 23, 2026
6
+ *
7
+ * @sa include/numkong/set.h
8
+ *
9
+ * @section set_powervsx_instructions Power9 VSX Set Instructions
10
+ *
11
+ * Key Power9 VSX instructions for binary/bitwise operations:
12
+ *
13
+ * Intrinsic Instruction P9
14
+ * vec_popcnt vpopcntb/h/w/d 2cy @ 2p element-wise popcount
15
+ * vec_xor xxlxor 1cy @ 4p
16
+ * vec_and xxland 1cy @ 4p
17
+ * vec_or xxlor 1cy @ 4p
18
+ * vec_cmpne vcmpneb/h/w 2cy @ 2p byte/half/word not-equal
19
+ * vec_xl_len lxvll 6cy @ 1p partial vector load
20
+ *
21
+ * Power9 has native doubleword `vpopcntd` instruction, providing efficient SIMD popcount
22
+ * with minimal data flow complexity. `vec_xl_len` enables branchless tail handling.
23
+ *
24
+ * @section set_powervsx_stateful Stateful Streaming Logic
25
+ *
26
+ * To build memory-optimal tiled algorithms, this file defines:
27
+ *
28
+ * - nk_hamming_u1x128_state_powervsx_t for streaming Hamming distance
29
+ * - nk_jaccard_u1x128_state_powervsx_t for streaming Jaccard similarity
30
+ *
31
+ * @code{c}
32
+ * nk_jaccard_u1x128_state_powervsx_t state_first, state_second, state_third, state_fourth;
33
+ * nk_jaccard_u1x128_init_powervsx(&state_first);
34
+ * // ... stream through packed binary vectors ...
35
+ * nk_jaccard_u1x128_finalize_powervsx(&state_first, &state_second, &state_third, &state_fourth,
36
+ * query_popcount, target_popcount_a, target_popcount_b, target_popcount_c, target_popcount_d,
37
+ * total_dimensions, &results);
38
+ * @endcode
39
+ */
40
+ #ifndef NK_SET_POWERVSX_H
41
+ #define NK_SET_POWERVSX_H
42
+
43
+ #if NK_TARGET_POWER64_
44
+ #if NK_TARGET_POWERVSX
45
+
46
+ #include "numkong/types.h"
47
+ #include "numkong/set/serial.h" // `nk_u1x8_popcount_`
48
+ #include "numkong/dot/powervsx.h" // `nk_hsum_u32x4_powervsx_`, `nk_hsum_u64x2_powervsx_`
49
+
50
+ #if defined(__cplusplus)
51
+ extern "C" {
52
+ #endif
53
+
54
+ #if defined(__clang__)
55
+ #pragma clang attribute push(__attribute__((target("power9-vector"))), apply_to = function)
56
+ #elif defined(__GNUC__)
57
+ #pragma GCC push_options
58
+ #pragma GCC target("power9-vector")
59
+ #endif
60
+
61
+ NK_PUBLIC void nk_hamming_u1_powervsx(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n, nk_u32_t *result) {
62
+ nk_size_t n_bytes = nk_size_divide_round_up_(n, NK_BITS_PER_BYTE);
63
+ nk_vu64x2_t differences_u64x2 = vec_splats((nk_u64_t)0);
64
+ nk_size_t i = 0;
65
+ // Process 16 bytes at a time using doubleword popcount (vpopcntd)
66
+ for (; i + 16 <= n_bytes; i += 16) {
67
+ nk_vu8x16_t a_u8x16 = vec_xl(0, (nk_u8_t const *)(a + i));
68
+ nk_vu8x16_t b_u8x16 = vec_xl(0, (nk_u8_t const *)(b + i));
69
+ nk_vu8x16_t xor_u8x16 = vec_xor(a_u8x16, b_u8x16);
70
+ nk_vu64x2_t popcnt_u64x2 = vec_popcnt((nk_vu64x2_t)xor_u8x16);
71
+ differences_u64x2 = vec_add(differences_u64x2, popcnt_u64x2);
72
+ }
73
+ // Branchless tail: vec_xl_len zero-fills beyond remaining_bytes
74
+ nk_size_t remaining_bytes = n_bytes - i;
75
+ nk_vu8x16_t a_u8x16 = vec_xl_len((nk_u8_t *)(a + i), remaining_bytes);
76
+ nk_vu8x16_t b_u8x16 = vec_xl_len((nk_u8_t *)(b + i), remaining_bytes);
77
+ nk_vu8x16_t xor_u8x16 = vec_xor(a_u8x16, b_u8x16);
78
+ nk_vu64x2_t popcnt_u64x2 = vec_popcnt((nk_vu64x2_t)xor_u8x16);
79
+ differences_u64x2 = vec_add(differences_u64x2, popcnt_u64x2);
80
+ *result = (nk_u32_t)nk_hsum_u64x2_powervsx_(differences_u64x2);
81
+ }
82
+
83
+ NK_PUBLIC void nk_jaccard_u1_powervsx(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n, nk_f32_t *result) {
84
+ nk_size_t n_bytes = nk_size_divide_round_up_(n, NK_BITS_PER_BYTE);
85
+ nk_vu64x2_t intersection_u64x2 = vec_splats((nk_u64_t)0);
86
+ nk_vu64x2_t union_u64x2 = vec_splats((nk_u64_t)0);
87
+ nk_size_t i = 0;
88
+ for (; i + 16 <= n_bytes; i += 16) {
89
+ nk_vu8x16_t a_u8x16 = vec_xl(0, (nk_u8_t const *)(a + i));
90
+ nk_vu8x16_t b_u8x16 = vec_xl(0, (nk_u8_t const *)(b + i));
91
+ nk_vu64x2_t and_popcnt_u64x2 = vec_popcnt((nk_vu64x2_t)vec_and(a_u8x16, b_u8x16));
92
+ nk_vu64x2_t or_popcnt_u64x2 = vec_popcnt((nk_vu64x2_t)vec_or(a_u8x16, b_u8x16));
93
+ intersection_u64x2 = vec_add(intersection_u64x2, and_popcnt_u64x2);
94
+ union_u64x2 = vec_add(union_u64x2, or_popcnt_u64x2);
95
+ }
96
+ // Branchless tail
97
+ nk_size_t remaining_bytes = n_bytes - i;
98
+ nk_vu8x16_t a_u8x16 = vec_xl_len((nk_u8_t *)(a + i), remaining_bytes);
99
+ nk_vu8x16_t b_u8x16 = vec_xl_len((nk_u8_t *)(b + i), remaining_bytes);
100
+ nk_vu64x2_t and_popcnt_u64x2 = vec_popcnt((nk_vu64x2_t)vec_and(a_u8x16, b_u8x16));
101
+ nk_vu64x2_t or_popcnt_u64x2 = vec_popcnt((nk_vu64x2_t)vec_or(a_u8x16, b_u8x16));
102
+ intersection_u64x2 = vec_add(intersection_u64x2, and_popcnt_u64x2);
103
+ union_u64x2 = vec_add(union_u64x2, or_popcnt_u64x2);
104
+ nk_u32_t intersection_count = (nk_u32_t)nk_hsum_u64x2_powervsx_(intersection_u64x2);
105
+ nk_u32_t union_count = (nk_u32_t)nk_hsum_u64x2_powervsx_(union_u64x2);
106
+ *result = (union_count != 0) ? 1.0f - (nk_f32_t)intersection_count / (nk_f32_t)union_count : 0.0f;
107
+ }
108
+
109
+ NK_PUBLIC void nk_hamming_u8_powervsx(nk_u8_t const *a, nk_u8_t const *b, nk_size_t n, nk_u32_t *result) {
110
+ nk_vu32x4_t differences_u32x4 = vec_splats((nk_u32_t)0);
111
+ nk_vu8x16_t ones_u8x16 = vec_splats((nk_u8_t)1);
112
+ nk_size_t i = 0;
113
+ // Process 16 bytes at a time using vec_cmpne
114
+ for (; i + 16 <= n; i += 16) {
115
+ nk_vu8x16_t a_u8x16 = vec_xl(0, (nk_u8_t const *)(a + i));
116
+ nk_vu8x16_t b_u8x16 = vec_xl(0, (nk_u8_t const *)(b + i));
117
+ // vec_cmpne returns 0xFF for not-equal, 0x00 for equal
118
+ // AND with 1 to get 0x01 for not-equal, then sum groups of 4 bytes → u32
119
+ nk_vu8x16_t not_equal_u8x16 = vec_and((nk_vu8x16_t)vec_cmpne(a_u8x16, b_u8x16), ones_u8x16);
120
+ differences_u32x4 = vec_sum4s(not_equal_u8x16, differences_u32x4);
121
+ }
122
+ // Branchless tail
123
+ nk_size_t remaining_bytes = n - i;
124
+ nk_vu8x16_t a_u8x16 = vec_xl_len((nk_u8_t *)(a + i), remaining_bytes);
125
+ nk_vu8x16_t b_u8x16 = vec_xl_len((nk_u8_t *)(b + i), remaining_bytes);
126
+ nk_vu8x16_t not_equal_u8x16 = vec_and((nk_vu8x16_t)vec_cmpne(a_u8x16, b_u8x16), ones_u8x16);
127
+ differences_u32x4 = vec_sum4s(not_equal_u8x16, differences_u32x4);
128
+ *result = nk_hsum_u32x4_powervsx_(differences_u32x4);
129
+ }
130
+
131
+ typedef struct nk_hamming_u1x128_state_powervsx_t {
132
+ nk_vu32x4_t intersection_count_u32x4;
133
+ } nk_hamming_u1x128_state_powervsx_t;
134
+
135
+ NK_INTERNAL void nk_hamming_u1x128_init_powervsx(nk_hamming_u1x128_state_powervsx_t *state) {
136
+ state->intersection_count_u32x4 = vec_splats((nk_u32_t)0);
137
+ }
138
+
139
+ NK_INTERNAL void nk_hamming_u1x128_update_powervsx(nk_hamming_u1x128_state_powervsx_t *state, nk_b128_vec_t a,
140
+ nk_b128_vec_t b, nk_size_t depth_offset,
141
+ nk_size_t active_dimensions) {
142
+ nk_unused_(depth_offset);
143
+ nk_unused_(active_dimensions);
144
+
145
+ // Process one 128-bit chunk (native VSX register size).
146
+ // Uses vector accumulation → horizontal sum deferred to finalize.
147
+ //
148
+ // Power9 VSX instruction characteristics:
149
+ // - `vec_xor`: xxlxor (V, V, V) 1cy, bitwise XOR
150
+ // - `vec_popcnt`: vpopcntw (V.4S, V.4S) 3cy, word popcount
151
+ // - `vec_add`: vadduwm (V.4S, V.4S, V.4S) 2cy, u32 add
152
+ // Total: ~6cy per 128-bit chunk (horizontal sum deferred to finalize)
153
+
154
+ // Step 1: Compute difference bits (A XOR B)
155
+ nk_vu8x16_t a_u8x16 = *(nk_vu8x16_t *)&a;
156
+ nk_vu8x16_t b_u8x16 = *(nk_vu8x16_t *)&b;
157
+ nk_vu8x16_t xor_u8x16 = vec_xor(a_u8x16, b_u8x16);
158
+
159
+ // Step 2: Word popcount → each u32 lane contains set bits for 4 bytes
160
+ nk_vu32x4_t popcnt_u32x4 = vec_popcnt((nk_vu32x4_t)xor_u8x16);
161
+
162
+ // Step 3: Vector accumulation (defers horizontal sum to finalize)
163
+ state->intersection_count_u32x4 = vec_add(state->intersection_count_u32x4, popcnt_u32x4);
164
+ }
165
+
166
+ NK_INTERNAL void nk_hamming_u1x128_finalize_powervsx( //
167
+ nk_hamming_u1x128_state_powervsx_t const *state_a, nk_hamming_u1x128_state_powervsx_t const *state_b,
168
+ nk_hamming_u1x128_state_powervsx_t const *state_c, nk_hamming_u1x128_state_powervsx_t const *state_d,
169
+ nk_size_t total_dimensions, nk_b128_vec_t *result) {
170
+ nk_unused_(total_dimensions);
171
+
172
+ nk_vu32x4_t a_u32x4 = state_a->intersection_count_u32x4, b_u32x4 = state_b->intersection_count_u32x4,
173
+ c_u32x4 = state_c->intersection_count_u32x4, d_u32x4 = state_d->intersection_count_u32x4;
174
+ nk_vu32x4_t transpose_ab_low_u32x4 = vec_mergeh(a_u32x4, b_u32x4);
175
+ nk_vu32x4_t transpose_cd_low_u32x4 = vec_mergeh(c_u32x4, d_u32x4);
176
+ nk_vu32x4_t transpose_ab_high_u32x4 = vec_mergel(a_u32x4, b_u32x4);
177
+ nk_vu32x4_t transpose_cd_high_u32x4 = vec_mergel(c_u32x4, d_u32x4);
178
+ nk_vu32x4_t sum_lane0_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_low_u32x4,
179
+ (nk_vu64x2_t)transpose_cd_low_u32x4, 0);
180
+ nk_vu32x4_t sum_lane1_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_low_u32x4,
181
+ (nk_vu64x2_t)transpose_cd_low_u32x4, 3);
182
+ nk_vu32x4_t sum_lane2_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_high_u32x4,
183
+ (nk_vu64x2_t)transpose_cd_high_u32x4, 0);
184
+ nk_vu32x4_t sum_lane3_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_high_u32x4,
185
+ (nk_vu64x2_t)transpose_cd_high_u32x4, 3);
186
+ result->vu32x4 = vec_add(vec_add(sum_lane0_u32x4, sum_lane1_u32x4), vec_add(sum_lane2_u32x4, sum_lane3_u32x4));
187
+ }
188
+
189
+ typedef struct nk_jaccard_u1x128_state_powervsx_t {
190
+ nk_vu32x4_t intersection_count_u32x4;
191
+ } nk_jaccard_u1x128_state_powervsx_t;
192
+
193
+ NK_INTERNAL void nk_jaccard_u1x128_init_powervsx(nk_jaccard_u1x128_state_powervsx_t *state) {
194
+ state->intersection_count_u32x4 = vec_splats((nk_u32_t)0);
195
+ }
196
+
197
+ NK_INTERNAL void nk_jaccard_u1x128_update_powervsx(nk_jaccard_u1x128_state_powervsx_t *state, nk_b128_vec_t a,
198
+ nk_b128_vec_t b, nk_size_t depth_offset,
199
+ nk_size_t active_dimensions) {
200
+ nk_unused_(depth_offset);
201
+ nk_unused_(active_dimensions);
202
+
203
+ // Process one 128-bit chunk (native VSX register size).
204
+ // Uses vector accumulation → horizontal sum deferred to finalize.
205
+ //
206
+ // Power9 VSX instruction characteristics:
207
+ // - `vec_and`: xxland (V, V, V) 1cy, bitwise AND
208
+ // - `vec_popcnt`: vpopcntw (V.4S, V.4S) 3cy, word popcount
209
+ // - `vec_add`: vadduwm (V.4S, V.4S, V.4S) 2cy, u32 add
210
+ // Total: ~6cy per 128-bit chunk (horizontal sum deferred to finalize)
211
+
212
+ // Step 1: Compute intersection bits (A AND B)
213
+ nk_vu8x16_t a_u8x16 = *(nk_vu8x16_t *)&a;
214
+ nk_vu8x16_t b_u8x16 = *(nk_vu8x16_t *)&b;
215
+ nk_vu8x16_t intersection_u8x16 = vec_and(a_u8x16, b_u8x16);
216
+
217
+ // Step 2: Word popcount → each u32 lane contains set bits for 4 bytes
218
+ nk_vu32x4_t popcnt_u32x4 = vec_popcnt((nk_vu32x4_t)intersection_u8x16);
219
+
220
+ // Step 3: Vector accumulation (defers horizontal sum to finalize)
221
+ state->intersection_count_u32x4 = vec_add(state->intersection_count_u32x4, popcnt_u32x4);
222
+ }
223
+
224
+ NK_INTERNAL void nk_jaccard_u1x128_finalize_powervsx( //
225
+ nk_jaccard_u1x128_state_powervsx_t const *state_a, nk_jaccard_u1x128_state_powervsx_t const *state_b,
226
+ nk_jaccard_u1x128_state_powervsx_t const *state_c, nk_jaccard_u1x128_state_powervsx_t const *state_d,
227
+ nk_f32_t query_popcount, nk_f32_t target_popcount_a, nk_f32_t target_popcount_b, nk_f32_t target_popcount_c,
228
+ nk_f32_t target_popcount_d, nk_size_t total_dimensions, nk_b128_vec_t *result) {
229
+ nk_unused_(total_dimensions);
230
+
231
+ // Transpose-based 4-way horizontal sum of u32x4 intersection counts
232
+ nk_vu32x4_t a_u32x4 = state_a->intersection_count_u32x4, b_u32x4 = state_b->intersection_count_u32x4,
233
+ c_u32x4 = state_c->intersection_count_u32x4, d_u32x4 = state_d->intersection_count_u32x4;
234
+ nk_vu32x4_t transpose_ab_low_u32x4 = vec_mergeh(a_u32x4, b_u32x4);
235
+ nk_vu32x4_t transpose_cd_low_u32x4 = vec_mergeh(c_u32x4, d_u32x4);
236
+ nk_vu32x4_t transpose_ab_high_u32x4 = vec_mergel(a_u32x4, b_u32x4);
237
+ nk_vu32x4_t transpose_cd_high_u32x4 = vec_mergel(c_u32x4, d_u32x4);
238
+ nk_vu32x4_t sum_lane0_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_low_u32x4,
239
+ (nk_vu64x2_t)transpose_cd_low_u32x4, 0);
240
+ nk_vu32x4_t sum_lane1_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_low_u32x4,
241
+ (nk_vu64x2_t)transpose_cd_low_u32x4, 3);
242
+ nk_vu32x4_t sum_lane2_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_high_u32x4,
243
+ (nk_vu64x2_t)transpose_cd_high_u32x4, 0);
244
+ nk_vu32x4_t sum_lane3_u32x4 = (nk_vu32x4_t)vec_xxpermdi((nk_vu64x2_t)transpose_ab_high_u32x4,
245
+ (nk_vu64x2_t)transpose_cd_high_u32x4, 3);
246
+ nk_vu32x4_t intersection_u32x4 = vec_add(vec_add(sum_lane0_u32x4, sum_lane1_u32x4),
247
+ vec_add(sum_lane2_u32x4, sum_lane3_u32x4));
248
+ nk_vf32x4_t intersection_f32x4 = vec_ctf(intersection_u32x4, 0);
249
+
250
+ // Build target popcounts vector via vec_insert
251
+ nk_vf32x4_t targets_f32x4 = vec_splats(0.0f);
252
+ targets_f32x4 = vec_insert(target_popcount_a, targets_f32x4, 0);
253
+ targets_f32x4 = vec_insert(target_popcount_b, targets_f32x4, 1);
254
+ targets_f32x4 = vec_insert(target_popcount_c, targets_f32x4, 2);
255
+ targets_f32x4 = vec_insert(target_popcount_d, targets_f32x4, 3);
256
+ nk_vf32x4_t query_f32x4 = vec_splats(query_popcount);
257
+
258
+ // Compute union using |A union B| = |A| + |B| - |A intersection B|
259
+ nk_vf32x4_t union_f32x4 = vec_sub(vec_add(query_f32x4, targets_f32x4), intersection_f32x4);
260
+
261
+ // Handle zero-union edge case (empty vectors → distance = 0.0)
262
+ nk_vf32x4_t one_f32x4 = vec_splats(1.0f);
263
+ nk_vf32x4_t zero_f32x4 = vec_splats(0.0f);
264
+ nk_vu32x4_t zero_union_mask_u32x4 = (nk_vu32x4_t)vec_cmpeq(union_f32x4, zero_f32x4);
265
+ nk_vf32x4_t safe_union_f32x4 = vec_sel(union_f32x4, one_f32x4, zero_union_mask_u32x4);
266
+
267
+ // Fast reciprocal with Newton-Raphson refinement
268
+ nk_vf32x4_t union_reciprocal_f32x4 = vec_re(safe_union_f32x4);
269
+ // One Newton-Raphson step: reciprocal = reciprocal × (2 - value * reciprocal)
270
+ nk_vf32x4_t two_f32x4 = vec_splats(2.0f);
271
+ union_reciprocal_f32x4 = vec_mul(union_reciprocal_f32x4,
272
+ vec_sub(two_f32x4, vec_mul(safe_union_f32x4, union_reciprocal_f32x4)));
273
+
274
+ // Compute Jaccard distance = 1 - intersection / union
275
+ nk_vf32x4_t ratio_f32x4 = vec_mul(intersection_f32x4, union_reciprocal_f32x4);
276
+ nk_vf32x4_t jaccard_f32x4 = vec_sub(one_f32x4, ratio_f32x4);
277
+ result->vf32x4 = vec_sel(jaccard_f32x4, zero_f32x4, zero_union_mask_u32x4);
278
+ }
279
+
280
+ /** @brief Hamming from_dot: computes pop_a + pop_b - 2 × dot for 4 pairs (Power VSX). */
281
+ NK_INTERNAL void nk_hamming_u32x4_from_dot_powervsx_(nk_b128_vec_t dots, nk_u32_t query_pop, nk_b128_vec_t target_pops,
282
+ nk_b128_vec_t *results) {
283
+ nk_vu32x4_t dots_u32x4 = dots.vu32x4;
284
+ nk_vu32x4_t query_u32x4 = vec_splats(query_pop);
285
+ nk_vu32x4_t target_u32x4 = target_pops.vu32x4;
286
+ nk_vu32x4_t two_dots_u32x4 = vec_add(dots_u32x4, dots_u32x4);
287
+ results->vu32x4 = vec_sub(vec_add(query_u32x4, target_u32x4), two_dots_u32x4);
288
+ }
289
+
290
+ /** @brief Jaccard from_dot: computes 1 - dot / (pop_a + pop_b - dot) for 4 pairs (Power VSX). */
291
+ NK_INTERNAL void nk_jaccard_f32x4_from_dot_powervsx_(nk_b128_vec_t dots, nk_u32_t query_pop, nk_b128_vec_t target_pops,
292
+ nk_b128_vec_t *results) {
293
+ nk_vf32x4_t dot_f32x4 = vec_ctf(dots.vu32x4, 0);
294
+ nk_vf32x4_t query_f32x4 = vec_splats((nk_f32_t)query_pop);
295
+ nk_vf32x4_t target_f32x4 = vec_ctf(target_pops.vu32x4, 0);
296
+ nk_vf32x4_t union_f32x4 = vec_sub(vec_add(query_f32x4, target_f32x4), dot_f32x4);
297
+
298
+ nk_vf32x4_t one_f32x4 = vec_splats(1.0f);
299
+ nk_vf32x4_t zero_f32x4 = vec_splats(0.0f);
300
+ nk_vu32x4_t zero_union_mask_u32x4 = (nk_vu32x4_t)vec_cmpeq(union_f32x4, zero_f32x4);
301
+ nk_vf32x4_t safe_union_f32x4 = vec_sel(union_f32x4, one_f32x4, zero_union_mask_u32x4);
302
+
303
+ // Fast reciprocal with Newton-Raphson
304
+ nk_vf32x4_t union_reciprocal_f32x4 = vec_re(safe_union_f32x4);
305
+ nk_vf32x4_t two_f32x4 = vec_splats(2.0f);
306
+ union_reciprocal_f32x4 = vec_mul(union_reciprocal_f32x4,
307
+ vec_sub(two_f32x4, vec_mul(safe_union_f32x4, union_reciprocal_f32x4)));
308
+
309
+ nk_vf32x4_t ratio_f32x4 = vec_mul(dot_f32x4, union_reciprocal_f32x4);
310
+ nk_vf32x4_t jaccard_f32x4 = vec_sub(one_f32x4, ratio_f32x4);
311
+ results->vf32x4 = vec_sel(jaccard_f32x4, zero_f32x4, zero_union_mask_u32x4);
312
+ }
313
+
314
+ #if defined(__clang__)
315
+ #pragma clang attribute pop
316
+ #elif defined(__GNUC__)
317
+ #pragma GCC pop_options
318
+ #endif
319
+
320
+ #if defined(__cplusplus)
321
+ } // extern "C"
322
+ #endif
323
+
324
+ #endif // NK_TARGET_POWERVSX
325
+ #endif // NK_TARGET_POWER64_
326
+ #endif // NK_SET_POWERVSX_H
@@ -0,0 +1,226 @@
1
+ /**
2
+ * @brief SIMD-accelerated Set Similarity Measures for RISC-V.
3
+ * @file include/numkong/set/rvv.h
4
+ * @author Ash Vardanian
5
+ * @date January 13, 2026
6
+ *
7
+ * @sa include/numkong/set.h
8
+ *
9
+ * SpacemiT K1 and similar chips implement RVA22 profile with base RVV 1.0.
10
+ * This does NOT include the Zvbb extension, so we lack native element-wise popcount (`vcpop.v`).
11
+ *
12
+ * @section rvv_popcount_lut Popcount via vrgather LUT
13
+ *
14
+ * We implement popcount using a 16-entry nibble lookup table with `vrgather`:
15
+ * - Split each byte into high and low nibbles
16
+ * - Use vrgather to look up popcount of each nibble (0-4)
17
+ * - Sum the results (0-8 per byte)
18
+ *
19
+ * This approach is efficient on SpacemiT X60 cores which have optimized vrgather
20
+ * for small indices (LMUL=1 with indices 0-15).
21
+ *
22
+ * @section set_rvv_instructions Key RVV Set Instructions
23
+ *
24
+ * Intrinsic Purpose
25
+ * vxor_vv_u8m1 XOR for Hamming difference
26
+ * vand_vv_u8m1 AND for Jaccard intersection
27
+ * vor_vv_u8m1 OR for Jaccard union
28
+ * vrgather_vv_u8m1 LUT lookup (16-entry nibble table)
29
+ * vsrl_vx_u8m1 Right shift to extract high nibble
30
+ * vwaddu_vx_u16m2 Widen u8 → u16 for accumulation
31
+ * vwredsumu_vs_u16m2_u32m1 Widening reduction sum
32
+ */
33
+ #ifndef NK_SET_RVV_H
34
+ #define NK_SET_RVV_H
35
+
36
+ #if NK_TARGET_RISCV64_
37
+ #if NK_TARGET_RVV
38
+
39
+ #include "numkong/types.h"
40
+ #include "numkong/set/serial.h" // `nk_u1x8_popcount_`
41
+
42
+ #if defined(__clang__)
43
+ #pragma clang attribute push(__attribute__((target("arch=+v"))), apply_to = function)
44
+ #elif defined(__GNUC__)
45
+ #pragma GCC push_options
46
+ #pragma GCC target("arch=+v")
47
+ #endif
48
+
49
+ #if defined(__cplusplus)
50
+ extern "C" {
51
+ #endif
52
+
53
+ #pragma region Binary Sets
54
+
55
+ /**
56
+ * @brief Compute byte-level popcount using arithmetic SWAR.
57
+ *
58
+ * Uses parallel bit counting (Hamming weight) — no vrgather, so scales
59
+ * linearly with LMUL unlike the nibble-LUT approach.
60
+ * Cost: 11 ALU instructions regardless of LMUL.
61
+ *
62
+ * @param[in] v_u8m4 Input vector of bytes
63
+ * @param[in] vector_length Vector length
64
+ * @return Vector where each byte contains its popcount (0-8)
65
+ */
66
+ NK_INTERNAL vuint8m4_t nk_popcount_u8m4_rvv_(vuint8m4_t v_u8m4, nk_size_t vector_length) {
67
+ // Step 1: count pairs — v = (v & 0x55) + ((v >> 1) & 0x55)
68
+ vuint8m4_t t_u8m4 = __riscv_vsrl_vx_u8m4(v_u8m4, 1, vector_length);
69
+ t_u8m4 = __riscv_vand_vx_u8m4(t_u8m4, 0x55, vector_length);
70
+ v_u8m4 = __riscv_vand_vx_u8m4(v_u8m4, 0x55, vector_length);
71
+ v_u8m4 = __riscv_vadd_vv_u8m4(v_u8m4, t_u8m4, vector_length);
72
+ // Step 2: count nibbles — v = (v & 0x33) + ((v >> 2) & 0x33)
73
+ t_u8m4 = __riscv_vsrl_vx_u8m4(v_u8m4, 2, vector_length);
74
+ t_u8m4 = __riscv_vand_vx_u8m4(t_u8m4, 0x33, vector_length);
75
+ v_u8m4 = __riscv_vand_vx_u8m4(v_u8m4, 0x33, vector_length);
76
+ v_u8m4 = __riscv_vadd_vv_u8m4(v_u8m4, t_u8m4, vector_length);
77
+ // Step 3: count bytes — v = (v + (v >> 4)) & 0x0F
78
+ t_u8m4 = __riscv_vsrl_vx_u8m4(v_u8m4, 4, vector_length);
79
+ v_u8m4 = __riscv_vadd_vv_u8m4(v_u8m4, t_u8m4, vector_length);
80
+ return __riscv_vand_vx_u8m4(v_u8m4, 0x0F, vector_length);
81
+ }
82
+
83
+ NK_PUBLIC void nk_hamming_u1_rvv(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n, nk_u32_t *result) {
84
+ nk_size_t count_bytes = nk_size_divide_round_up_(n, NK_BITS_PER_BYTE);
85
+
86
+ // Accumulator for total differences
87
+ vuint32m1_t sum_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
88
+
89
+ nk_size_t i = 0;
90
+ for (nk_size_t vector_length; i + 1 <= count_bytes; i += vector_length) {
91
+ vector_length = __riscv_vsetvl_e8m4(count_bytes - i);
92
+
93
+ // Load and XOR to find differing bits
94
+ vuint8m4_t a_u8m4 = __riscv_vle8_v_u8m4(a + i, vector_length);
95
+ vuint8m4_t b_u8m4 = __riscv_vle8_v_u8m4(b + i, vector_length);
96
+ vuint8m4_t xor_u8m4 = __riscv_vxor_vv_u8m4(a_u8m4, b_u8m4, vector_length);
97
+
98
+ // Popcount each byte (0-8 per byte) using arithmetic SWAR
99
+ vuint8m4_t popcount_u8m4 = nk_popcount_u8m4_rvv_(xor_u8m4, vector_length);
100
+
101
+ // Widen to u16 and accumulate via widening reduction sum
102
+ vuint16m8_t popcount_u16m8 = __riscv_vwaddu_vx_u16m8(popcount_u8m4, 0, vector_length);
103
+ sum_u32m1 = __riscv_vwredsumu_vs_u16m8_u32m1(popcount_u16m8, sum_u32m1, vector_length);
104
+ }
105
+
106
+ *result = __riscv_vmv_x_s_u32m1_u32(sum_u32m1);
107
+ }
108
+
109
+ NK_PUBLIC void nk_jaccard_u1_rvv(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n, nk_f32_t *result) {
110
+ nk_size_t count_bytes = nk_size_divide_round_up_(n, NK_BITS_PER_BYTE);
111
+
112
+ // Accumulators for intersection and union counts
113
+ vuint32m1_t intersection_sum_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
114
+ vuint32m1_t union_sum_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
115
+
116
+ nk_size_t i = 0;
117
+ for (nk_size_t vector_length; i + 1 <= count_bytes; i += vector_length) {
118
+ vector_length = __riscv_vsetvl_e8m4(count_bytes - i);
119
+
120
+ // Load vectors
121
+ vuint8m4_t a_u8m4 = __riscv_vle8_v_u8m4(a + i, vector_length);
122
+ vuint8m4_t b_u8m4 = __riscv_vle8_v_u8m4(b + i, vector_length);
123
+
124
+ // Compute intersection (AND) and union (OR)
125
+ vuint8m4_t intersection_u8m4 = __riscv_vand_vv_u8m4(a_u8m4, b_u8m4, vector_length);
126
+ vuint8m4_t union_u8m4 = __riscv_vor_vv_u8m4(a_u8m4, b_u8m4, vector_length);
127
+
128
+ // Popcount each using arithmetic SWAR
129
+ vuint8m4_t intersection_popcount_u8m4 = nk_popcount_u8m4_rvv_(intersection_u8m4, vector_length);
130
+ vuint8m4_t union_popcount_u8m4 = nk_popcount_u8m4_rvv_(union_u8m4, vector_length);
131
+
132
+ // Widen and accumulate
133
+ vuint16m8_t intersection_popcount_u16m8 = __riscv_vwaddu_vx_u16m8(intersection_popcount_u8m4, 0, vector_length);
134
+ vuint16m8_t union_popcount_u16m8 = __riscv_vwaddu_vx_u16m8(union_popcount_u8m4, 0, vector_length);
135
+ intersection_sum_u32m1 = __riscv_vwredsumu_vs_u16m8_u32m1(intersection_popcount_u16m8, intersection_sum_u32m1,
136
+ vector_length);
137
+ union_sum_u32m1 = __riscv_vwredsumu_vs_u16m8_u32m1(union_popcount_u16m8, union_sum_u32m1, vector_length);
138
+ }
139
+
140
+ nk_u32_t intersection_count_u32 = __riscv_vmv_x_s_u32m1_u32(intersection_sum_u32m1);
141
+ nk_u32_t union_count_u32 = __riscv_vmv_x_s_u32m1_u32(union_sum_u32m1);
142
+ *result = (union_count_u32 != 0) ? 1.0f - (nk_f32_t)intersection_count_u32 / (nk_f32_t)union_count_u32 : 0.0f;
143
+ }
144
+
145
+ #pragma endregion Binary Sets
146
+
147
+ #pragma region Integer Sets
148
+
149
+ NK_PUBLIC void nk_hamming_u8_rvv(nk_u8_t const *a, nk_u8_t const *b, nk_size_t n, nk_u32_t *result) {
150
+ vuint32m1_t difference_count_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
151
+
152
+ nk_size_t i = 0;
153
+ for (nk_size_t vector_length; i + 1 <= n; i += vector_length) {
154
+ vector_length = __riscv_vsetvl_e8m1(n - i);
155
+
156
+ vuint8m1_t a_u8m1 = __riscv_vle8_v_u8m1(a + i, vector_length);
157
+ vuint8m1_t b_u8m1 = __riscv_vle8_v_u8m1(b + i, vector_length);
158
+
159
+ // Compare: mask where a != b
160
+ vbool8_t not_equal_mask_b8 = __riscv_vmsne_vv_u8m1_b8(a_u8m1, b_u8m1, vector_length);
161
+
162
+ // Count set bits in mask via vcpop.m (this IS available in base RVV 1.0)
163
+ nk_u32_t difference_count_u32 = __riscv_vcpop_m_b8(not_equal_mask_b8, vector_length);
164
+
165
+ // Accumulate (scalar addition is fine here, vcpop already reduced)
166
+ difference_count_u32m1 = __riscv_vadd_vx_u32m1(difference_count_u32m1, difference_count_u32, 1);
167
+ }
168
+
169
+ *result = __riscv_vmv_x_s_u32m1_u32(difference_count_u32m1);
170
+ }
171
+
172
+ NK_PUBLIC void nk_jaccard_u32_rvv(nk_u32_t const *a, nk_u32_t const *b, nk_size_t n, nk_f32_t *result) {
173
+ nk_u32_t match_count_u32 = 0;
174
+
175
+ nk_size_t i = 0;
176
+ for (nk_size_t vector_length; i + 1 <= n; i += vector_length) {
177
+ vector_length = __riscv_vsetvl_e32m1(n - i);
178
+
179
+ vuint32m1_t a_u32m1 = __riscv_vle32_v_u32m1(a + i, vector_length);
180
+ vuint32m1_t b_u32m1 = __riscv_vle32_v_u32m1(b + i, vector_length);
181
+
182
+ // Compare: mask where a == b
183
+ vbool32_t equal_mask_b32 = __riscv_vmseq_vv_u32m1_b32(a_u32m1, b_u32m1, vector_length);
184
+
185
+ // Count matches via vcpop.m
186
+ match_count_u32 += __riscv_vcpop_m_b32(equal_mask_b32, vector_length);
187
+ }
188
+
189
+ *result = (n != 0) ? 1.0f - (nk_f32_t)match_count_u32 / (nk_f32_t)n : 0.0f;
190
+ }
191
+
192
+ NK_PUBLIC void nk_jaccard_u16_rvv(nk_u16_t const *a, nk_u16_t const *b, nk_size_t n, nk_f32_t *result) {
193
+ nk_u32_t match_count_u32 = 0;
194
+
195
+ nk_size_t i = 0;
196
+ for (nk_size_t vector_length; i + 1 <= n; i += vector_length) {
197
+ vector_length = __riscv_vsetvl_e16m1(n - i);
198
+
199
+ vuint16m1_t a_u16m1 = __riscv_vle16_v_u16m1(a + i, vector_length);
200
+ vuint16m1_t b_u16m1 = __riscv_vle16_v_u16m1(b + i, vector_length);
201
+
202
+ // Compare: mask where a == b
203
+ vbool16_t equal_mask_b16 = __riscv_vmseq_vv_u16m1_b16(a_u16m1, b_u16m1, vector_length);
204
+
205
+ // Count matches via vcpop.m
206
+ match_count_u32 += __riscv_vcpop_m_b16(equal_mask_b16, vector_length);
207
+ }
208
+
209
+ *result = (n != 0) ? 1.0f - (nk_f32_t)match_count_u32 / (nk_f32_t)n : 0.0f;
210
+ }
211
+
212
+ #pragma endregion Integer Sets
213
+
214
+ #if defined(__cplusplus)
215
+ } // extern "C"
216
+ #endif
217
+
218
+ #if defined(__clang__)
219
+ #pragma clang attribute pop
220
+ #elif defined(__GNUC__)
221
+ #pragma GCC pop_options
222
+ #endif
223
+
224
+ #endif // NK_TARGET_RVV
225
+ #endif // NK_TARGET_RISCV64_
226
+ #endif // NK_SET_RVV_H
@@ -0,0 +1,117 @@
1
+ /**
2
+ * @brief SIMD-accelerated Set Similarity Measures for RISC-V with Zvbb.
3
+ * @file include/numkong/set/rvvbb.h
4
+ * @author Ash Vardanian
5
+ * @date February 9, 2026
6
+ *
7
+ * @sa include/numkong/set.h
8
+ *
9
+ * Zvbb (Vector Basic Bit-manipulation) provides native per-element popcount via `vcpop.v`,
10
+ * replacing the 11-instruction SWAR approach in set/rvv.h with a single instruction.
11
+ *
12
+ * Only `nk_hamming_u1` and `nk_jaccard_u1` benefit from Zvbb (they need byte-level popcount).
13
+ * Integer set operations (hamming_u8, jaccard_u16, jaccard_u32) use mask-level vcpop.m
14
+ * which is already available in base RVV 1.0.
15
+ *
16
+ * Requires: RVV 1.0 + Zvbb extension (GCC 14+ or Clang 18+)
17
+ */
18
+ #ifndef NK_SET_RVVBB_H
19
+ #define NK_SET_RVVBB_H
20
+
21
+ #if NK_TARGET_RISCV64_
22
+ #if NK_TARGET_RVVBB
23
+
24
+ #include "numkong/types.h"
25
+
26
+ #if defined(__clang__)
27
+ #pragma clang attribute push(__attribute__((target("arch=+v,+zvbb"))), apply_to = function)
28
+ #elif defined(__GNUC__)
29
+ #pragma GCC push_options
30
+ #pragma GCC target("arch=+v,+zvbb")
31
+ #endif
32
+
33
+ #if defined(__cplusplus)
34
+ extern "C" {
35
+ #endif
36
+
37
+ /**
38
+ * @brief Native per-element popcount using Zvbb vcpop.v (1 instruction).
39
+ *
40
+ * Replaces the 11-instruction SWAR approach in nk_popcount_u8m4_rvv_.
41
+ */
42
+ NK_INTERNAL vuint8m4_t nk_popcount_u8m4_rvvbb_(vuint8m4_t v_u8m4) {
43
+ vuint8m4_t result_u8m4;
44
+ __asm__ volatile("vcpop.v %0, %1" : "=vr"(result_u8m4) : "vr"(v_u8m4));
45
+ return result_u8m4;
46
+ }
47
+
48
+ NK_PUBLIC void nk_hamming_u1_rvvbb(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n, nk_u32_t *result) {
49
+ nk_size_t count_bytes = nk_size_divide_round_up_(n, NK_BITS_PER_BYTE);
50
+
51
+ vuint32m1_t sum_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
52
+
53
+ nk_size_t i = 0;
54
+ for (nk_size_t vector_length; i + 1 <= count_bytes; i += vector_length) {
55
+ vector_length = __riscv_vsetvl_e8m4(count_bytes - i);
56
+
57
+ vuint8m4_t a_u8m4 = __riscv_vle8_v_u8m4(a + i, vector_length);
58
+ vuint8m4_t b_u8m4 = __riscv_vle8_v_u8m4(b + i, vector_length);
59
+ vuint8m4_t xor_u8m4 = __riscv_vxor_vv_u8m4(a_u8m4, b_u8m4, vector_length);
60
+
61
+ // Native per-element popcount via Zvbb (1 instruction vs 11 SWAR)
62
+ vuint8m4_t popcount_u8m4 = nk_popcount_u8m4_rvvbb_(xor_u8m4);
63
+
64
+ // Widen to u16 and accumulate via widening reduction sum
65
+ vuint16m8_t popcount_u16m8 = __riscv_vwaddu_vx_u16m8(popcount_u8m4, 0, vector_length);
66
+ sum_u32m1 = __riscv_vwredsumu_vs_u16m8_u32m1(popcount_u16m8, sum_u32m1, vector_length);
67
+ }
68
+
69
+ *result = __riscv_vmv_x_s_u32m1_u32(sum_u32m1);
70
+ }
71
+
72
+ NK_PUBLIC void nk_jaccard_u1_rvvbb(nk_u1x8_t const *a, nk_u1x8_t const *b, nk_size_t n, nk_f32_t *result) {
73
+ nk_size_t count_bytes = nk_size_divide_round_up_(n, NK_BITS_PER_BYTE);
74
+
75
+ vuint32m1_t intersection_sum_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
76
+ vuint32m1_t union_sum_u32m1 = __riscv_vmv_v_x_u32m1(0, 1);
77
+
78
+ nk_size_t i = 0;
79
+ for (nk_size_t vector_length; i + 1 <= count_bytes; i += vector_length) {
80
+ vector_length = __riscv_vsetvl_e8m4(count_bytes - i);
81
+
82
+ vuint8m4_t a_u8m4 = __riscv_vle8_v_u8m4(a + i, vector_length);
83
+ vuint8m4_t b_u8m4 = __riscv_vle8_v_u8m4(b + i, vector_length);
84
+
85
+ vuint8m4_t intersection_u8m4 = __riscv_vand_vv_u8m4(a_u8m4, b_u8m4, vector_length);
86
+ vuint8m4_t union_u8m4 = __riscv_vor_vv_u8m4(a_u8m4, b_u8m4, vector_length);
87
+
88
+ // Native per-element popcount via Zvbb
89
+ vuint8m4_t intersection_popcount_u8m4 = nk_popcount_u8m4_rvvbb_(intersection_u8m4);
90
+ vuint8m4_t union_popcount_u8m4 = nk_popcount_u8m4_rvvbb_(union_u8m4);
91
+
92
+ // Widen and accumulate
93
+ vuint16m8_t intersection_popcount_u16m8 = __riscv_vwaddu_vx_u16m8(intersection_popcount_u8m4, 0, vector_length);
94
+ vuint16m8_t union_popcount_u16m8 = __riscv_vwaddu_vx_u16m8(union_popcount_u8m4, 0, vector_length);
95
+ intersection_sum_u32m1 = __riscv_vwredsumu_vs_u16m8_u32m1(intersection_popcount_u16m8, intersection_sum_u32m1,
96
+ vector_length);
97
+ union_sum_u32m1 = __riscv_vwredsumu_vs_u16m8_u32m1(union_popcount_u16m8, union_sum_u32m1, vector_length);
98
+ }
99
+
100
+ nk_u32_t intersection_count_u32 = __riscv_vmv_x_s_u32m1_u32(intersection_sum_u32m1);
101
+ nk_u32_t union_count_u32 = __riscv_vmv_x_s_u32m1_u32(union_sum_u32m1);
102
+ *result = (union_count_u32 != 0) ? 1.0f - (nk_f32_t)intersection_count_u32 / (nk_f32_t)union_count_u32 : 0.0f;
103
+ }
104
+
105
+ #if defined(__cplusplus)
106
+ } // extern "C"
107
+ #endif
108
+
109
+ #if defined(__clang__)
110
+ #pragma clang attribute pop
111
+ #elif defined(__GNUC__)
112
+ #pragma GCC pop_options
113
+ #endif
114
+
115
+ #endif // NK_TARGET_RVVBB
116
+ #endif // NK_TARGET_RISCV64_
117
+ #endif // NK_SET_RVVBB_H