usearch 2.21.3 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +235 -52
  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
@@ -8,8 +8,8 @@
8
8
  #define UNUM_USEARCH_HPP
9
9
 
10
10
  #define USEARCH_VERSION_MAJOR 2
11
- #define USEARCH_VERSION_MINOR 21
12
- #define USEARCH_VERSION_PATCH 3
11
+ #define USEARCH_VERSION_MINOR 25
12
+ #define USEARCH_VERSION_PATCH 0
13
13
 
14
14
  // Inferring C++ version
15
15
  // https://stackoverflow.com/a/61552074
@@ -72,7 +72,9 @@
72
72
  // OS-specific includes
73
73
  #if defined(USEARCH_DEFINED_WINDOWS)
74
74
  #define _USE_MATH_DEFINES
75
+ #ifndef NOMINMAX
75
76
  #define NOMINMAX
77
+ #endif
76
78
  #include <Windows.h>
77
79
  #include <sys/stat.h> // `fstat` for file size
78
80
  #undef NOMINMAX
@@ -500,7 +502,7 @@ template <typename allocator_at = std::allocator<byte_t>> class bitset_gt {
500
502
 
501
503
  static constexpr std::size_t bits_per_slot() { return sizeof(compressed_slot_t) * CHAR_BIT; }
502
504
  static constexpr compressed_slot_t bits_mask() { return sizeof(compressed_slot_t) * CHAR_BIT - 1; }
503
- static constexpr std::size_t slots(std::size_t bits) { return divide_round_up<bits_per_slot()>(bits); }
505
+ static constexpr std::size_t bits_slots(std::size_t bits) { return divide_round_up<bits_per_slot()>(bits); }
504
506
 
505
507
  compressed_slot_t* slots_{};
506
508
  /// @brief Number of slots.
@@ -524,8 +526,8 @@ template <typename allocator_at = std::allocator<byte_t>> class bitset_gt {
524
526
  }
525
527
 
526
528
  bitset_gt(std::size_t capacity) noexcept
527
- : slots_((compressed_slot_t*)allocator_t{}.allocate(slots(capacity) * sizeof(compressed_slot_t))),
528
- count_(slots_ ? slots(capacity) : 0u) {
529
+ : slots_((compressed_slot_t*)allocator_t{}.allocate(bits_slots(capacity) * sizeof(compressed_slot_t))),
530
+ count_(slots_ ? bits_slots(capacity) : 0u) {
529
531
  clear();
530
532
  }
531
533
 
@@ -595,6 +597,125 @@ template <typename allocator_at = std::allocator<byte_t>> class bitset_gt {
595
597
 
596
598
  using bitset_t = bitset_gt<>;
597
599
 
600
+ /**
601
+ * @brief Cache-line-padded striped spin-lock array for concurrent graph mutations.
602
+ * Maps node slots to lock stripes via Fibonacci hashing, with each stripe
603
+ * occupying its own cache line to eliminate false sharing.
604
+ * The number of stripes is proportional to `threads * connectivity`, not
605
+ * graph size, keeping the lock array comfortably within L2/L3 cache.
606
+ */
607
+ template <typename allocator_at = std::allocator<byte_t>, std::size_t cache_line_ak = 128> //
608
+ class striped_locks_gt {
609
+ using allocator_t = allocator_at;
610
+ using byte_t = typename allocator_t::value_type;
611
+ static_assert(sizeof(byte_t) == 1, "Allocator must allocate separate addressable bytes");
612
+
613
+ static constexpr std::uint64_t fibonacci_k = 0x9E3779B97F4A7C15ull;
614
+
615
+ using atomic_flag_t = std::atomic<std::uint8_t>;
616
+ struct alignas(cache_line_ak) padded_lock_t {
617
+ atomic_flag_t flag{0};
618
+ char padding_[cache_line_ak - sizeof(atomic_flag_t)];
619
+ };
620
+ static_assert(sizeof(padded_lock_t) == cache_line_ak, "Lock stripe must be exactly one cache line");
621
+
622
+ // `padded_lock_t` is `alignas(cache_line_ak)` (128 B by default) which
623
+ // exceeds what a plain allocator guarantees (typically 16 B on x86-64).
624
+ // Rather than demanding an over-aligned allocator, we over-allocate and
625
+ // keep a pointer to the aligned sub-region — `raw_` is what we hand back
626
+ // to the allocator, `stripes_` is the aligned view used for reads/writes.
627
+ byte_t* raw_{};
628
+ std::size_t raw_bytes_{};
629
+ padded_lock_t* stripes_{};
630
+ std::size_t count_{};
631
+ unsigned shift_{};
632
+
633
+ inline std::size_t stripe_for_(std::size_t slot) const noexcept {
634
+ return static_cast<std::size_t>((static_cast<std::uint64_t>(slot) * fibonacci_k) >> shift_);
635
+ }
636
+
637
+ public:
638
+ striped_locks_gt() noexcept {}
639
+ ~striped_locks_gt() noexcept { reset(); }
640
+
641
+ explicit operator bool() const noexcept { return stripes_; }
642
+
643
+ void reset() noexcept {
644
+ if (stripes_)
645
+ for (std::size_t i = 0; i < count_; i++)
646
+ stripes_[i].~padded_lock_t();
647
+ if (raw_)
648
+ allocator_t{}.deallocate(raw_, raw_bytes_);
649
+ raw_ = nullptr;
650
+ raw_bytes_ = 0;
651
+ stripes_ = nullptr;
652
+ count_ = 0;
653
+ shift_ = 64;
654
+ }
655
+
656
+ striped_locks_gt(std::size_t threads, std::size_t connectivity) noexcept {
657
+ std::size_t desired = threads * connectivity * 4;
658
+ if (desired < 256)
659
+ desired = 256;
660
+ count_ = ceil2(desired);
661
+ shift_ = 64;
662
+ for (std::size_t n = count_; n > 1; n >>= 1)
663
+ shift_--;
664
+ // Request one extra stripe's worth of slack so we can always land on a
665
+ // `cache_line_ak`-aligned address inside the allocation, regardless of
666
+ // what the underlying allocator returns.
667
+ constexpr std::size_t alignment_k = alignof(padded_lock_t);
668
+ raw_bytes_ = count_ * sizeof(padded_lock_t) + alignment_k;
669
+ raw_ = allocator_t{}.allocate(raw_bytes_);
670
+ if (!raw_) {
671
+ raw_bytes_ = 0;
672
+ count_ = 0;
673
+ shift_ = 64;
674
+ return;
675
+ }
676
+ auto raw_address = reinterpret_cast<std::uintptr_t>(raw_);
677
+ auto aligned_address = (raw_address + alignment_k - 1) & ~(static_cast<std::uintptr_t>(alignment_k) - 1);
678
+ stripes_ = reinterpret_cast<padded_lock_t*>(aligned_address);
679
+ for (std::size_t i = 0; i < count_; i++)
680
+ new (&stripes_[i]) padded_lock_t();
681
+ }
682
+
683
+ striped_locks_gt(striped_locks_gt&& other) noexcept {
684
+ raw_ = exchange(other.raw_, (byte_t*)nullptr);
685
+ raw_bytes_ = exchange(other.raw_bytes_, std::size_t{0});
686
+ stripes_ = exchange(other.stripes_, nullptr);
687
+ count_ = exchange(other.count_, std::size_t{0});
688
+ shift_ = exchange(other.shift_, unsigned{64});
689
+ }
690
+
691
+ striped_locks_gt& operator=(striped_locks_gt&& other) noexcept {
692
+ std::swap(raw_, other.raw_);
693
+ std::swap(raw_bytes_, other.raw_bytes_);
694
+ std::swap(stripes_, other.stripes_);
695
+ std::swap(count_, other.count_);
696
+ std::swap(shift_, other.shift_);
697
+ return *this;
698
+ }
699
+
700
+ striped_locks_gt(striped_locks_gt const&) = delete;
701
+ striped_locks_gt& operator=(striped_locks_gt const&) = delete;
702
+
703
+ inline bool atomic_set(std::size_t i) noexcept {
704
+ return stripes_[stripe_for_(i)].flag.exchange(1, std::memory_order_acquire);
705
+ }
706
+
707
+ inline void atomic_reset(std::size_t i) noexcept {
708
+ stripes_[stripe_for_(i)].flag.store(0, std::memory_order_release);
709
+ }
710
+
711
+ inline void lock(std::size_t i) noexcept {
712
+ while (atomic_set(i))
713
+ std::this_thread::yield();
714
+ }
715
+
716
+ inline void unlock(std::size_t i) noexcept { atomic_reset(i); }
717
+ };
718
+
598
719
  /**
599
720
  * @brief Similar to `std::priority_queue`, but allows raw access to underlying
600
721
  * memory, in case you want to shuffle it or sort. Good for collections
@@ -726,10 +847,12 @@ class max_heap_gt {
726
847
  */
727
848
  usearch_profiled_m bool reserve(std::size_t new_capacity) noexcept {
728
849
  usearch_profile_name_m(max_heap_reserve);
729
- if (new_capacity < capacity_)
850
+ if (new_capacity <= capacity_)
730
851
  return true;
731
852
 
732
853
  new_capacity = ceil2(new_capacity);
854
+ if (new_capacity == 0)
855
+ return false;
733
856
  new_capacity = (std::max<std::size_t>)(new_capacity, (std::max<std::size_t>)(capacity_ * 2u, 16u));
734
857
  auto allocator = allocator_t{};
735
858
  auto new_elements = allocator.allocate(new_capacity);
@@ -892,10 +1015,12 @@ class sorted_buffer_gt {
892
1015
  inline void clear() noexcept { size_ = 0; }
893
1016
 
894
1017
  bool reserve(std::size_t new_capacity) noexcept {
895
- if (new_capacity < capacity_)
1018
+ if (new_capacity <= capacity_)
896
1019
  return true;
897
1020
 
898
1021
  new_capacity = ceil2(new_capacity);
1022
+ if (new_capacity == 0)
1023
+ return false;
899
1024
  new_capacity = (std::max<std::size_t>)(new_capacity, (std::max<std::size_t>)(capacity_ * 2u, 16u));
900
1025
  auto allocator = allocator_t{};
901
1026
  auto new_elements = allocator.allocate(new_capacity);
@@ -1011,8 +1136,10 @@ class usearch_pack_m uint40_t {
1011
1136
  return result;
1012
1137
  }
1013
1138
 
1014
- inline static uint40_t max() noexcept { return uint40_t{}.broadcast(0xFF); }
1015
- inline static uint40_t min() noexcept { return uint40_t{}.broadcast(0); }
1139
+ /* Parenthesized declarator keeps MSVC's preprocessor from expanding
1140
+ * `max` / `min` against `<windows.h>`'s `max(a,b)` / `min(a,b)` macros. */
1141
+ inline static uint40_t(max)() noexcept { return uint40_t{}.broadcast(0xFF); }
1142
+ inline static uint40_t(min)() noexcept { return uint40_t{}.broadcast(0); }
1016
1143
 
1017
1144
  inline bool operator==(uint40_t const& other) const noexcept { return std::memcmp(octets, other.octets, 5) == 0; }
1018
1145
  inline bool operator!=(uint40_t const& other) const noexcept { return !(*this == other); }
@@ -1044,7 +1171,7 @@ template <typename element_at> struct default_free_value_gt {
1044
1171
  template <typename sfinae_element_at = element_at,
1045
1172
  typename std::enable_if<std::is_integral<sfinae_element_at>::value>::type* = nullptr>
1046
1173
  static sfinae_element_at value() noexcept {
1047
- return std::numeric_limits<element_at>::max();
1174
+ return (std::numeric_limits<element_at>::max)();
1048
1175
  }
1049
1176
  template <typename sfinae_element_at = element_at,
1050
1177
  typename std::enable_if<!std::is_integral<sfinae_element_at>::value>::type* = nullptr>
@@ -1054,7 +1181,7 @@ template <typename element_at> struct default_free_value_gt {
1054
1181
  };
1055
1182
 
1056
1183
  template <> struct default_free_value_gt<uint40_t> {
1057
- static uint40_t value() noexcept { return uint40_t::max(); }
1184
+ static uint40_t value() noexcept { return (uint40_t::max)(); }
1058
1185
  };
1059
1186
 
1060
1187
  template <typename element_at> element_at default_free_value() { return default_free_value_gt<element_at>::value(); }
@@ -1778,7 +1905,7 @@ class memory_mapped_file_t {
1778
1905
  #if defined(USEARCH_DEFINED_WINDOWS)
1779
1906
 
1780
1907
  HANDLE file_handle =
1781
- CreateFile(path_, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1908
+ CreateFileA(path_, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1782
1909
  if (file_handle == INVALID_HANDLE_VALUE)
1783
1910
  return result.failed("Opening file failed!");
1784
1911
 
@@ -2029,8 +2156,8 @@ class index_gt {
2029
2156
  friend inline vector_key_t get_key(member_iterator_gt const& it) noexcept { return it.key(); }
2030
2157
 
2031
2158
  // clang-format off
2032
- member_iterator_gt operator++(int) noexcept { return member_iterator_gt(index_, static_cast<compressed_slot_t>(static_cast<std::size_t>(slot_) + 1)); }
2033
- member_iterator_gt operator--(int) noexcept { return member_iterator_gt(index_, static_cast<compressed_slot_t>(static_cast<std::size_t>(slot_) - 1)); }
2159
+ member_iterator_gt operator++(int) noexcept { member_iterator_gt old(index_, slot_); ++(*this); return old; }
2160
+ member_iterator_gt operator--(int) noexcept { member_iterator_gt old(index_, slot_); --(*this); return old; }
2034
2161
  member_iterator_gt operator+(difference_type d) noexcept { return member_iterator_gt(index_, static_cast<compressed_slot_t>(static_cast<std::size_t>(slot_) + d)); }
2035
2162
  member_iterator_gt operator-(difference_type d) noexcept { return member_iterator_gt(index_, static_cast<compressed_slot_t>(static_cast<std::size_t>(slot_) - d)); }
2036
2163
  member_iterator_gt& operator++() noexcept { slot_ = static_cast<compressed_slot_t>(static_cast<std::size_t>(slot_) + 1); return *this; }
@@ -2084,7 +2211,7 @@ class index_gt {
2084
2211
  */
2085
2212
  static constexpr std::size_t node_head_bytes_() { return sizeof(vector_key_t) + sizeof(level_t); }
2086
2213
 
2087
- using nodes_mutexes_t = bitset_gt<dynamic_allocator_t>;
2214
+ using nodes_mutexes_t = striped_locks_gt<dynamic_allocator_t>;
2088
2215
 
2089
2216
  using visits_hash_set_t = growing_hash_set_gt<compressed_slot_t, hash_gt<compressed_slot_t>, dynamic_allocator_t>;
2090
2217
 
@@ -2189,7 +2316,7 @@ class index_gt {
2189
2316
  misaligned_store<compressed_slot_t>(tape_ + shift(i - removed_count), slot);
2190
2317
  }
2191
2318
  }
2192
- misaligned_store<neighbors_count_t>(tape_, old_count - removed_count);
2319
+ misaligned_store<neighbors_count_t>(tape_, static_cast<neighbors_count_t>(old_count - removed_count));
2193
2320
  return removed_count;
2194
2321
  }
2195
2322
  };
@@ -2507,7 +2634,8 @@ class index_gt {
2507
2634
  return true;
2508
2635
  }
2509
2636
 
2510
- nodes_mutexes_t new_mutexes(limits.members);
2637
+ std::size_t connectivity_max = (std::max)(config_.connectivity_base, config_.connectivity);
2638
+ nodes_mutexes_t new_mutexes(limits.threads(), connectivity_max);
2511
2639
  buffer_gt<node_t, nodes_allocator_t> new_nodes(limits.members);
2512
2640
  buffer_gt<context_t, contexts_allocator_t> new_contexts(limits.threads());
2513
2641
  if (!new_nodes || !new_contexts || !new_mutexes)
@@ -2516,10 +2644,6 @@ class index_gt {
2516
2644
  // Move the nodes info, and deallocate previous buffers.
2517
2645
  if (nodes_)
2518
2646
  std::memcpy(new_nodes.data(), nodes_.data(), sizeof(node_t) * size());
2519
-
2520
- // Pre-reserve the capacity for `top_for_refine`, which always contains at most one more
2521
- // element than the connectivity factors.
2522
- std::size_t connectivity_max = (std::max)(config_.connectivity_base, config_.connectivity);
2523
2647
  for (std::size_t i = 0; i != new_contexts.size(); ++i)
2524
2648
  if (!new_contexts[i].top_for_refine.reserve(connectivity_max + 1))
2525
2649
  return false;
@@ -2567,7 +2691,7 @@ class index_gt {
2567
2691
  member_cref_t member;
2568
2692
  distance_t distance;
2569
2693
 
2570
- inline match_t() noexcept : member({nullptr, 0}), distance(std::numeric_limits<distance_t>::max()) {}
2694
+ inline match_t() noexcept : member({nullptr, 0}), distance((std::numeric_limits<distance_t>::max)()) {}
2571
2695
 
2572
2696
  inline match_t(member_cref_t member, distance_t distance) noexcept : member(member), distance(distance) {}
2573
2697
 
@@ -2624,7 +2748,10 @@ class index_gt {
2624
2748
  inline bool empty() const noexcept { return !count; }
2625
2749
  inline match_t operator[](std::size_t i) const noexcept { return at(i); }
2626
2750
  inline match_t front() const noexcept { return at(0); }
2627
- inline match_t back() const noexcept { return at(count - 1); }
2751
+ inline match_t back() const noexcept {
2752
+ usearch_assert_m(count > 0, "Can't call back() on an empty result set");
2753
+ return at(count - 1);
2754
+ }
2628
2755
  inline bool contains(vector_key_t key) const noexcept {
2629
2756
  for (std::size_t i = 0; i != count; ++i)
2630
2757
  if (at(i).member.key == key)
@@ -2716,7 +2843,7 @@ class index_gt {
2716
2843
  keys[i] = vector_key_t{};
2717
2844
  distances[i] = std::numeric_limits<distance_t>::has_signaling_NaN
2718
2845
  ? std::numeric_limits<distance_t>::signaling_NaN()
2719
- : std::numeric_limits<distance_t>::max();
2846
+ : (std::numeric_limits<distance_t>::max)();
2720
2847
  }
2721
2848
  return initialized_count;
2722
2849
  }
@@ -2783,6 +2910,10 @@ class index_gt {
2783
2910
  callback_at&& callback = callback_at{}, //
2784
2911
  prefetch_at&& prefetch = prefetch_at{}) usearch_noexcept_m {
2785
2912
 
2913
+ // Zero expansion is meaningless, fall back to default
2914
+ if (!config.expansion)
2915
+ config.expansion = default_expansion_add();
2916
+
2786
2917
  add_result_t result;
2787
2918
  if (is_immutable())
2788
2919
  return result.failed("Can't add to an immutable index");
@@ -2987,7 +3118,8 @@ class index_gt {
2987
3118
  }
2988
3119
  form_reverse_links_(metric, updated_slot, closest_view, value, level, context);
2989
3120
  }
2990
- updated_node.key(key);
3121
+ if (static_cast<vector_key_t>(updated_node.key()) != key)
3122
+ updated_node.key(key);
2991
3123
 
2992
3124
  // Normalize stats
2993
3125
  result.computed_distances = context.computed_distances - result.computed_distances;
@@ -3097,6 +3229,9 @@ class index_gt {
3097
3229
  predicate_at&& predicate = predicate_at{}, //
3098
3230
  prefetch_at&& prefetch = prefetch_at{}) const noexcept {
3099
3231
 
3232
+ if (!config.expansion)
3233
+ config.expansion = default_expansion_search();
3234
+
3100
3235
  context_t& context = contexts_[config.thread];
3101
3236
  cluster_result_t result;
3102
3237
  if (!nodes_count_)
@@ -3175,7 +3310,7 @@ class index_gt {
3175
3310
  continue;
3176
3311
 
3177
3312
  ++result.nodes;
3178
- result.edges += neighbors_(node, level).size();
3313
+ result.edges += neighbors_(node, static_cast<level_t>(level)).size();
3179
3314
  result.allocated_bytes += node_head_bytes_() + neighbors_bytes;
3180
3315
  }
3181
3316
 
@@ -3797,12 +3932,11 @@ class index_gt {
3797
3932
  struct node_lock_t {
3798
3933
  nodes_mutexes_t& mutexes;
3799
3934
  std::size_t slot;
3800
- inline ~node_lock_t() noexcept { mutexes.atomic_reset(slot); }
3935
+ inline ~node_lock_t() noexcept { mutexes.unlock(slot); }
3801
3936
  };
3802
3937
 
3803
3938
  inline node_lock_t node_lock_(std::size_t slot) const noexcept {
3804
- while (nodes_mutexes_.atomic_set(slot))
3805
- ;
3939
+ nodes_mutexes_.lock(slot);
3806
3940
  return {nodes_mutexes_, slot};
3807
3941
  }
3808
3942
 
@@ -3810,18 +3944,17 @@ class index_gt {
3810
3944
  nodes_mutexes_t& mutexes;
3811
3945
  std::size_t slot;
3812
3946
  inline ~optional_node_lock_t() noexcept {
3813
- if (slot != std::numeric_limits<std::size_t>::max())
3814
- mutexes.atomic_reset(slot);
3947
+ if (slot != (std::numeric_limits<std::size_t>::max)())
3948
+ mutexes.unlock(slot);
3815
3949
  }
3816
3950
  };
3817
3951
 
3818
3952
  inline optional_node_lock_t optional_node_lock_(std::size_t slot, bool condition) const noexcept {
3819
3953
  if (condition) {
3820
- while (nodes_mutexes_.atomic_set(slot))
3821
- ;
3954
+ nodes_mutexes_.lock(slot);
3822
3955
  return {nodes_mutexes_, slot};
3823
3956
  } else {
3824
- return {nodes_mutexes_, std::numeric_limits<std::size_t>::max()};
3957
+ return {nodes_mutexes_, (std::numeric_limits<std::size_t>::max)()};
3825
3958
  }
3826
3959
  }
3827
3960
 
@@ -3829,15 +3962,19 @@ class index_gt {
3829
3962
  nodes_mutexes_t& mutexes;
3830
3963
  std::size_t slot;
3831
3964
  inline ~node_conditional_lock_t() noexcept {
3832
- if (slot != std::numeric_limits<std::size_t>::max())
3833
- mutexes.atomic_reset(slot);
3965
+ if (slot != (std::numeric_limits<std::size_t>::max)())
3966
+ mutexes.unlock(slot);
3834
3967
  }
3835
3968
  };
3836
3969
 
3837
3970
  inline node_conditional_lock_t node_try_conditional_lock_(std::size_t slot, bool condition,
3838
3971
  bool& failed_to_acquire) const noexcept {
3839
- failed_to_acquire = condition ? nodes_mutexes_.atomic_set(slot) : false;
3840
- return {nodes_mutexes_, failed_to_acquire ? std::numeric_limits<std::size_t>::max() : slot};
3972
+ if (!condition) {
3973
+ failed_to_acquire = false;
3974
+ return {nodes_mutexes_, (std::numeric_limits<std::size_t>::max)()};
3975
+ }
3976
+ failed_to_acquire = nodes_mutexes_.atomic_set(slot);
3977
+ return {nodes_mutexes_, failed_to_acquire ? (std::numeric_limits<std::size_t>::max)() : slot};
3841
3978
  }
3842
3979
 
3843
3980
  template <typename metric_at, bool require_non_empty_ak = false>
@@ -3888,8 +4025,12 @@ class index_gt {
3888
4025
  usearch_assert_m(close_slot != new_slot, "Self-loops are impossible");
3889
4026
  usearch_assert_m(level <= close_node.level(), "Linking to missing level");
3890
4027
 
3891
- // If `new_slot` is already present in the neighboring connections of `close_slot`
3892
- // then no need to modify any connections or run the heuristics.
4028
+ // Skip to prevent duplicate entries in the neighbor list.
4029
+ if (std::find_if(close_header.begin(), close_header.end(),
4030
+ [new_slot](compressed_slot_t slot) { return slot == new_slot; }) != close_header.end()) {
4031
+ continue;
4032
+ }
4033
+
3893
4034
  if (close_header.size() < connectivity_max) {
3894
4035
  close_header.push_back(new_slot);
3895
4036
  continue;
@@ -3904,7 +4045,7 @@ class index_gt {
3904
4045
  // Export the results:
3905
4046
  close_header.clear();
3906
4047
  candidates_view_t top_view = refine_(metric, connectivity_max, top_for_refine, context,
3907
- context.computed_distances_in_reverse_refines);
4048
+ context.computed_distances_in_reverse_refines, new_slot, value);
3908
4049
  usearch_assert_m(top_view.size(), "This would lead to isolated nodes");
3909
4050
  for (std::size_t idx = 0; idx != top_view.size(); idx++)
3910
4051
  close_header.push_back(top_view[idx].slot);
@@ -3952,7 +4093,9 @@ class index_gt {
3952
4093
  std::size_t progress) noexcept
3953
4094
  : index_(index), neighbors_(neighbors), visits_(visits), current_(progress) {}
3954
4095
  candidates_iterator_t operator++(int) noexcept {
3955
- return candidates_iterator_t(index_, neighbors_, visits_, current_ + 1).skip_missing();
4096
+ candidates_iterator_t old(index_, neighbors_, visits_, current_);
4097
+ ++(*this);
4098
+ return old;
3956
4099
  }
3957
4100
  candidates_iterator_t& operator++() noexcept {
3958
4101
  ++current_;
@@ -3991,12 +4134,13 @@ class index_gt {
3991
4134
  if (!is_dummy<prefetch_at>())
3992
4135
  prefetch(citerator_at(closest_slot), citerator_at(closest_slot) + 1);
3993
4136
 
4137
+ bool const need_lock = !is_immutable();
3994
4138
  distance_t closest_dist = context.measure(query, citerator_at(closest_slot), metric);
3995
4139
  for (level_t level = begin_level; level > end_level; --level) {
3996
4140
  bool changed;
3997
4141
  do {
3998
4142
  changed = false;
3999
- node_lock_t closest_lock = node_lock_(closest_slot);
4143
+ optional_node_lock_t closest_lock = optional_node_lock_(closest_slot, need_lock);
4000
4144
  neighbors_ref_t closest_neighbors = neighbors_non_base_(node_at_(closest_slot), level);
4001
4145
 
4002
4146
  // Optional prefetching
@@ -4042,6 +4186,10 @@ class index_gt {
4042
4186
  // At the very least we are going to explore the starting node and its neighbors
4043
4187
  if (!visits.reserve(config_.connectivity_base + 1u))
4044
4188
  return false;
4189
+ if (!top.reserve(top_limit))
4190
+ return false;
4191
+ if (!next.reserve(top_limit))
4192
+ return false;
4045
4193
 
4046
4194
  // Optional prefetching
4047
4195
  if (!is_dummy<prefetch_at>())
@@ -4119,6 +4267,10 @@ class index_gt {
4119
4267
  // At the very least we are going to explore the starting node and its neighbors
4120
4268
  if (!visits.reserve(config_.connectivity_base + 1u))
4121
4269
  return false;
4270
+ if (!top.reserve(top_limit))
4271
+ return false;
4272
+ if (!next.reserve(top_limit))
4273
+ return false;
4122
4274
 
4123
4275
  // Optional prefetching
4124
4276
  if (!is_dummy<prefetch_at>())
@@ -4152,8 +4304,7 @@ class index_gt {
4152
4304
  node_try_conditional_lock_(candidate_slot, updated_slot != candidate_slot, failed_to_acquire);
4153
4305
  if (failed_to_acquire)
4154
4306
  continue;
4155
- auto optional_node_lock =
4156
- optional_node_lock_(candidate_slot, updated_slot == candidate_slot);
4307
+ auto optional_node_lock = optional_node_lock_(candidate_slot, updated_slot == candidate_slot);
4157
4308
  neighbors_ref_t candidate_neighbors = neighbors_(candidate_ref, level);
4158
4309
 
4159
4310
  // Optional prefetching
@@ -4288,16 +4439,50 @@ class index_gt {
4288
4439
  }
4289
4440
  }
4290
4441
 
4442
+ /// @brief Helper for `refine_()`: computes inter-neighbor distance, substituting
4443
+ /// @p override_value when either slot matches @p override_slot.
4444
+ /// The `std::nullptr_t` overload below avoids instantiating the override
4445
+ /// branch when no override is provided, keeping the code C++11 compatible.
4446
+ template <typename metric_at, typename override_value_at>
4447
+ distance_t inter_neighbor_distance_( //
4448
+ candidate_t const& candidate, candidate_t const& submitted, //
4449
+ compressed_slot_t override_slot, override_value_at override_value, //
4450
+ metric_at&& metric, context_t& context) const noexcept {
4451
+ if (candidate.slot == override_slot)
4452
+ return context.measure(override_value, citerator_at(submitted.slot), metric);
4453
+ else if (submitted.slot == override_slot)
4454
+ return context.measure(override_value, citerator_at(candidate.slot), metric);
4455
+ else
4456
+ return context.measure(citerator_at(candidate.slot), citerator_at(submitted.slot), metric);
4457
+ }
4458
+
4459
+ template <typename metric_at>
4460
+ distance_t inter_neighbor_distance_( //
4461
+ candidate_t const& candidate, candidate_t const& submitted, //
4462
+ compressed_slot_t, std::nullptr_t, //
4463
+ metric_at&& metric, context_t& context) const noexcept {
4464
+ return context.measure(citerator_at(candidate.slot), citerator_at(submitted.slot), metric);
4465
+ }
4466
+
4291
4467
  /**
4292
4468
  * @brief This algorithm from the original paper implements a heuristic,
4293
4469
  * that massively reduces the number of connections a point has,
4294
4470
  * to keep only the neighbors, that are from each other.
4471
+ *
4472
+ * @param[in] override_slot Optional slot whose stored vector is stale (e.g. during update,
4473
+ * where the callback has not yet committed the new vector).
4474
+ * When set, inter-result distances involving this slot will use
4475
+ * @p override_value instead of reading from `citerator_at()`.
4476
+ * @param[in] override_value The up-to-date vector for @p override_slot. Only used when
4477
+ * @p override_value_at is not `std::nullptr_t`.
4295
4478
  */
4296
- template <typename metric_at>
4479
+ template <typename metric_at, typename override_value_at = std::nullptr_t>
4297
4480
  candidates_view_t refine_( //
4298
4481
  metric_at&& metric, //
4299
4482
  std::size_t needed, top_candidates_t& top, context_t& context, //
4300
- std::size_t& refines_counter) const noexcept {
4483
+ std::size_t& refines_counter, //
4484
+ compressed_slot_t override_slot = ((std::numeric_limits<compressed_slot_t>::max))(),
4485
+ override_value_at override_value = {}) const noexcept {
4301
4486
 
4302
4487
  // Avoid expensive computation, if the set is already small
4303
4488
  candidate_t* top_data = top.data();
@@ -4316,10 +4501,8 @@ class index_gt {
4316
4501
  std::size_t idx = 0;
4317
4502
  for (; idx < submitted_count; idx++) {
4318
4503
  candidate_t submitted = top_data[idx];
4319
- distance_t inter_result_dist = context.measure( //
4320
- citerator_at(candidate.slot), //
4321
- citerator_at(submitted.slot), //
4322
- metric);
4504
+ distance_t inter_result_dist = inter_neighbor_distance_( //
4505
+ candidate, submitted, override_slot, override_value, metric, context);
4323
4506
  if (inter_result_dist < candidate.distance) {
4324
4507
  good = false;
4325
4508
  break;
@@ -4410,7 +4593,7 @@ static join_result_t join( //
4410
4593
  return result.failed("Can't join with itself, consider copying");
4411
4594
 
4412
4595
  if (config.max_proposals == 0)
4413
- config.max_proposals = std::log(men.size()) + executor.size();
4596
+ config.max_proposals = static_cast<std::size_t>(std::log(men.size())) + executor.size();
4414
4597
 
4415
4598
  using proposals_count_t = std::uint16_t;
4416
4599
  config.max_proposals = (std::min)(men.size(), config.max_proposals);