usearch 2.21.4 → 2.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/README.md +65 -69
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +8 -8
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +124 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/README.md +1 -1
  16. package/javascript/dist/cjs/usearch.d.ts +8 -3
  17. package/javascript/dist/cjs/usearch.js +12 -4
  18. package/javascript/dist/esm/usearch.d.ts +8 -3
  19. package/javascript/dist/esm/usearch.js +12 -4
  20. package/javascript/lib.cpp +17 -0
  21. package/javascript/usearch.test.js +117 -94
  22. package/javascript/usearch.ts +14 -6
  23. package/numkong/.clang-tidy +30 -0
  24. package/{simsimd → numkong}/.cmake-format.py +18 -0
  25. package/numkong/.editorconfig +12 -0
  26. package/numkong/.git-blame-ignore-revs +123 -0
  27. package/numkong/.mailmap +15 -0
  28. package/numkong/.spi.yml +11 -0
  29. package/numkong/.swift-format +14 -0
  30. package/numkong/CITATION.cff +81 -0
  31. package/numkong/CONTRIBUTING.md +500 -0
  32. package/numkong/Cargo.toml +54 -0
  33. package/numkong/MANIFEST.in +8 -0
  34. package/numkong/Package.swift +84 -0
  35. package/numkong/README.md +569 -0
  36. package/numkong/bench/README.md +217 -0
  37. package/numkong/bench/bench-browser.html +323 -0
  38. package/numkong/bench/bench.cpp +344 -0
  39. package/numkong/bench/bench.hpp +816 -0
  40. package/numkong/bench/bench.js +148 -0
  41. package/numkong/bench/bench.mjs +616 -0
  42. package/numkong/bench/bench_attention.cpp +113 -0
  43. package/numkong/bench/bench_cast.cpp +264 -0
  44. package/numkong/bench/bench_cross_amx.cpp +62 -0
  45. package/numkong/bench/bench_cross_arm.cpp +245 -0
  46. package/numkong/bench/bench_cross_blas.cpp +309 -0
  47. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  48. package/numkong/bench/bench_cross_power.cpp +84 -0
  49. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  50. package/numkong/bench/bench_cross_serial.cpp +151 -0
  51. package/numkong/bench/bench_cross_sme.cpp +163 -0
  52. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  53. package/numkong/bench/bench_cross_x86.cpp +455 -0
  54. package/numkong/bench/bench_curved.cpp +210 -0
  55. package/numkong/bench/bench_dot.cpp +315 -0
  56. package/numkong/bench/bench_each.cpp +503 -0
  57. package/numkong/bench/bench_geospatial.cpp +112 -0
  58. package/numkong/bench/bench_maxsim.cpp +154 -0
  59. package/numkong/bench/bench_mesh.cpp +148 -0
  60. package/numkong/bench/bench_probability.cpp +60 -0
  61. package/numkong/bench/bench_reduce.cpp +371 -0
  62. package/numkong/bench/bench_set.cpp +73 -0
  63. package/numkong/bench/bench_sparse.cpp +198 -0
  64. package/numkong/bench/bench_spatial.cpp +347 -0
  65. package/numkong/bench/bench_trigonometry.cpp +137 -0
  66. package/numkong/bench/swift/Bench.swift +506 -0
  67. package/numkong/binding.gyp +169 -0
  68. package/numkong/build.rs +484 -0
  69. package/numkong/c/dispatch.h +512 -0
  70. package/numkong/c/dispatch_bf16.c +447 -0
  71. package/numkong/c/dispatch_bf16c.c +52 -0
  72. package/numkong/c/dispatch_e2m3.c +296 -0
  73. package/numkong/c/dispatch_e3m2.c +284 -0
  74. package/numkong/c/dispatch_e4m3.c +318 -0
  75. package/numkong/c/dispatch_e5m2.c +316 -0
  76. package/numkong/c/dispatch_f16.c +452 -0
  77. package/numkong/c/dispatch_f16c.c +58 -0
  78. package/numkong/c/dispatch_f32.c +434 -0
  79. package/numkong/c/dispatch_f32c.c +99 -0
  80. package/numkong/c/dispatch_f64.c +348 -0
  81. package/numkong/c/dispatch_f64c.c +98 -0
  82. package/numkong/c/dispatch_i16.c +96 -0
  83. package/numkong/c/dispatch_i32.c +89 -0
  84. package/numkong/c/dispatch_i4.c +153 -0
  85. package/numkong/c/dispatch_i64.c +86 -0
  86. package/numkong/c/dispatch_i8.c +348 -0
  87. package/numkong/c/dispatch_other.c +348 -0
  88. package/numkong/c/dispatch_u1.c +193 -0
  89. package/numkong/c/dispatch_u16.c +124 -0
  90. package/numkong/c/dispatch_u32.c +118 -0
  91. package/numkong/c/dispatch_u4.c +153 -0
  92. package/numkong/c/dispatch_u64.c +102 -0
  93. package/numkong/c/dispatch_u8.c +364 -0
  94. package/numkong/c/numkong.c +940 -0
  95. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  96. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  97. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_math_lib.cmake +46 -0
  99. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  100. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  101. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  102. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  103. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  104. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  105. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  106. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  107. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  108. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  109. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  110. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  111. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  112. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  113. package/numkong/include/README.md +643 -0
  114. package/numkong/include/module.modulemap +129 -0
  115. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  116. package/numkong/include/numkong/attention/sme.h +2075 -0
  117. package/numkong/include/numkong/attention.h +49 -0
  118. package/numkong/include/numkong/capabilities.h +930 -0
  119. package/numkong/include/numkong/cast/README.md +262 -0
  120. package/numkong/include/numkong/cast/diamond.h +64 -0
  121. package/numkong/include/numkong/cast/haswell.h +823 -0
  122. package/numkong/include/numkong/cast/icelake.h +475 -0
  123. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  124. package/numkong/include/numkong/cast/neon.h +1174 -0
  125. package/numkong/include/numkong/cast/powervsx.h +449 -0
  126. package/numkong/include/numkong/cast/rvv.h +970 -0
  127. package/numkong/include/numkong/cast/sapphire.h +262 -0
  128. package/numkong/include/numkong/cast/serial.h +2336 -0
  129. package/numkong/include/numkong/cast/skylake.h +915 -0
  130. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  131. package/numkong/include/numkong/cast.h +254 -0
  132. package/numkong/include/numkong/cast.hpp +44 -0
  133. package/numkong/include/numkong/curved/README.md +223 -0
  134. package/numkong/include/numkong/curved/genoa.h +182 -0
  135. package/numkong/include/numkong/curved/haswell.h +276 -0
  136. package/numkong/include/numkong/curved/neon.h +329 -0
  137. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  138. package/numkong/include/numkong/curved/rvv.h +305 -0
  139. package/numkong/include/numkong/curved/serial.h +207 -0
  140. package/numkong/include/numkong/curved/skylake.h +457 -0
  141. package/numkong/include/numkong/curved/smef64.h +530 -0
  142. package/numkong/include/numkong/curved.h +513 -0
  143. package/numkong/include/numkong/curved.hpp +144 -0
  144. package/numkong/include/numkong/dot/README.md +442 -0
  145. package/numkong/include/numkong/dot/alder.h +563 -0
  146. package/numkong/include/numkong/dot/diamond.h +158 -0
  147. package/numkong/include/numkong/dot/genoa.h +289 -0
  148. package/numkong/include/numkong/dot/haswell.h +1723 -0
  149. package/numkong/include/numkong/dot/icelake.h +997 -0
  150. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  151. package/numkong/include/numkong/dot/neon.h +869 -0
  152. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  153. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  154. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  155. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  156. package/numkong/include/numkong/dot/powervsx.h +752 -0
  157. package/numkong/include/numkong/dot/rvv.h +722 -0
  158. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  159. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  160. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  161. package/numkong/include/numkong/dot/sapphire.h +141 -0
  162. package/numkong/include/numkong/dot/serial.h +874 -0
  163. package/numkong/include/numkong/dot/sierra.h +405 -0
  164. package/numkong/include/numkong/dot/skylake.h +1116 -0
  165. package/numkong/include/numkong/dot/sve.h +420 -0
  166. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  167. package/numkong/include/numkong/dot/svehalf.h +168 -0
  168. package/numkong/include/numkong/dot/svesdot.h +90 -0
  169. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  170. package/numkong/include/numkong/dot.h +1136 -0
  171. package/numkong/include/numkong/dot.hpp +94 -0
  172. package/numkong/include/numkong/dots/README.md +496 -0
  173. package/numkong/include/numkong/dots/alder.h +117 -0
  174. package/numkong/include/numkong/dots/diamond.h +86 -0
  175. package/numkong/include/numkong/dots/genoa.h +100 -0
  176. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  177. package/numkong/include/numkong/dots/haswell.h +310 -0
  178. package/numkong/include/numkong/dots/icelake.h +180 -0
  179. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  180. package/numkong/include/numkong/dots/neon.h +123 -0
  181. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  182. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  183. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  184. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  185. package/numkong/include/numkong/dots/powervsx.h +194 -0
  186. package/numkong/include/numkong/dots/rvv.h +2593 -0
  187. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  188. package/numkong/include/numkong/dots/serial.h +2867 -0
  189. package/numkong/include/numkong/dots/sierra.h +100 -0
  190. package/numkong/include/numkong/dots/skylake.h +207 -0
  191. package/numkong/include/numkong/dots/sme.h +5041 -0
  192. package/numkong/include/numkong/dots/smebi32.h +477 -0
  193. package/numkong/include/numkong/dots/smef64.h +1328 -0
  194. package/numkong/include/numkong/dots/smehalf.h +47 -0
  195. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  196. package/numkong/include/numkong/dots.h +3110 -0
  197. package/numkong/include/numkong/dots.hpp +641 -0
  198. package/numkong/include/numkong/each/README.md +465 -0
  199. package/numkong/include/numkong/each/haswell.h +1658 -0
  200. package/numkong/include/numkong/each/icelake.h +272 -0
  201. package/numkong/include/numkong/each/neon.h +1138 -0
  202. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  203. package/numkong/include/numkong/each/neonhalf.h +318 -0
  204. package/numkong/include/numkong/each/rvv.h +1121 -0
  205. package/numkong/include/numkong/each/sapphire.h +343 -0
  206. package/numkong/include/numkong/each/serial.h +282 -0
  207. package/numkong/include/numkong/each/skylake.h +1562 -0
  208. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  209. package/numkong/include/numkong/each.h +2232 -0
  210. package/numkong/include/numkong/each.hpp +434 -0
  211. package/numkong/include/numkong/geospatial/README.md +147 -0
  212. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  213. package/numkong/include/numkong/geospatial/neon.h +615 -0
  214. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  215. package/numkong/include/numkong/geospatial/serial.h +309 -0
  216. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  217. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  218. package/numkong/include/numkong/geospatial.h +453 -0
  219. package/numkong/include/numkong/geospatial.hpp +235 -0
  220. package/numkong/include/numkong/matrix.hpp +336 -0
  221. package/numkong/include/numkong/maxsim/README.md +187 -0
  222. package/numkong/include/numkong/maxsim/alder.h +511 -0
  223. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  224. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  225. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  226. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  227. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  228. package/numkong/include/numkong/maxsim/serial.h +490 -0
  229. package/numkong/include/numkong/maxsim/sme.h +993 -0
  230. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  231. package/numkong/include/numkong/maxsim.h +571 -0
  232. package/numkong/include/numkong/maxsim.hpp +133 -0
  233. package/numkong/include/numkong/mesh/README.md +219 -0
  234. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  235. package/numkong/include/numkong/mesh/neon.h +1821 -0
  236. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  237. package/numkong/include/numkong/mesh/rvv.h +936 -0
  238. package/numkong/include/numkong/mesh/serial.h +721 -0
  239. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  240. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  241. package/numkong/include/numkong/mesh.h +666 -0
  242. package/numkong/include/numkong/mesh.hpp +701 -0
  243. package/numkong/include/numkong/numkong.h +78 -0
  244. package/numkong/include/numkong/numkong.hpp +58 -0
  245. package/numkong/include/numkong/probability/README.md +177 -0
  246. package/numkong/include/numkong/probability/haswell.h +267 -0
  247. package/numkong/include/numkong/probability/neon.h +255 -0
  248. package/numkong/include/numkong/probability/rvv.h +414 -0
  249. package/numkong/include/numkong/probability/serial.h +181 -0
  250. package/numkong/include/numkong/probability/skylake.h +324 -0
  251. package/numkong/include/numkong/probability.h +380 -0
  252. package/numkong/include/numkong/probability.hpp +120 -0
  253. package/numkong/include/numkong/random.h +50 -0
  254. package/numkong/include/numkong/random.hpp +285 -0
  255. package/numkong/include/numkong/reduce/README.md +552 -0
  256. package/numkong/include/numkong/reduce/alder.h +636 -0
  257. package/numkong/include/numkong/reduce/genoa.h +201 -0
  258. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  259. package/numkong/include/numkong/reduce/icelake.h +549 -0
  260. package/numkong/include/numkong/reduce/neon.h +3980 -0
  261. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  262. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  263. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  264. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  265. package/numkong/include/numkong/reduce/serial.h +753 -0
  266. package/numkong/include/numkong/reduce/sierra.h +338 -0
  267. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  268. package/numkong/include/numkong/reduce/sve.h +52 -0
  269. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  270. package/numkong/include/numkong/reduce.h +1582 -0
  271. package/numkong/include/numkong/reduce.hpp +778 -0
  272. package/numkong/include/numkong/scalar/README.md +89 -0
  273. package/numkong/include/numkong/scalar/haswell.h +122 -0
  274. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  275. package/numkong/include/numkong/scalar/neon.h +122 -0
  276. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  277. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  278. package/numkong/include/numkong/scalar/rvv.h +211 -0
  279. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  280. package/numkong/include/numkong/scalar/serial.h +332 -0
  281. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  282. package/numkong/include/numkong/scalar.h +696 -0
  283. package/numkong/include/numkong/set/README.md +179 -0
  284. package/numkong/include/numkong/set/haswell.h +334 -0
  285. package/numkong/include/numkong/set/icelake.h +485 -0
  286. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  287. package/numkong/include/numkong/set/neon.h +363 -0
  288. package/numkong/include/numkong/set/powervsx.h +326 -0
  289. package/numkong/include/numkong/set/rvv.h +226 -0
  290. package/numkong/include/numkong/set/rvvbb.h +117 -0
  291. package/numkong/include/numkong/set/serial.h +174 -0
  292. package/numkong/include/numkong/set/sve.h +187 -0
  293. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  294. package/numkong/include/numkong/set.h +471 -0
  295. package/numkong/include/numkong/set.hpp +114 -0
  296. package/numkong/include/numkong/sets/README.md +149 -0
  297. package/numkong/include/numkong/sets/haswell.h +63 -0
  298. package/numkong/include/numkong/sets/icelake.h +66 -0
  299. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  300. package/numkong/include/numkong/sets/neon.h +61 -0
  301. package/numkong/include/numkong/sets/powervsx.h +65 -0
  302. package/numkong/include/numkong/sets/serial.h +43 -0
  303. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  304. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  305. package/numkong/include/numkong/sets.h +382 -0
  306. package/numkong/include/numkong/sparse/README.md +156 -0
  307. package/numkong/include/numkong/sparse/icelake.h +463 -0
  308. package/numkong/include/numkong/sparse/neon.h +288 -0
  309. package/numkong/include/numkong/sparse/serial.h +117 -0
  310. package/numkong/include/numkong/sparse/sve2.h +504 -0
  311. package/numkong/include/numkong/sparse/turin.h +322 -0
  312. package/numkong/include/numkong/sparse.h +363 -0
  313. package/numkong/include/numkong/sparse.hpp +113 -0
  314. package/numkong/include/numkong/spatial/README.md +439 -0
  315. package/numkong/include/numkong/spatial/alder.h +604 -0
  316. package/numkong/include/numkong/spatial/diamond.h +240 -0
  317. package/numkong/include/numkong/spatial/genoa.h +222 -0
  318. package/numkong/include/numkong/spatial/haswell.h +979 -0
  319. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  320. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  321. package/numkong/include/numkong/spatial/neon.h +846 -0
  322. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  323. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  324. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  325. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  326. package/numkong/include/numkong/spatial/rvv.h +991 -0
  327. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  328. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  329. package/numkong/include/numkong/spatial/serial.h +347 -0
  330. package/numkong/include/numkong/spatial/sierra.h +516 -0
  331. package/numkong/include/numkong/spatial/skylake.h +605 -0
  332. package/numkong/include/numkong/spatial/sve.h +246 -0
  333. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  334. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  335. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  336. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  337. package/numkong/include/numkong/spatial.h +1681 -0
  338. package/numkong/include/numkong/spatial.hpp +183 -0
  339. package/numkong/include/numkong/spatials/README.md +580 -0
  340. package/numkong/include/numkong/spatials/alder.h +94 -0
  341. package/numkong/include/numkong/spatials/diamond.h +82 -0
  342. package/numkong/include/numkong/spatials/genoa.h +94 -0
  343. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  344. package/numkong/include/numkong/spatials/haswell.h +219 -0
  345. package/numkong/include/numkong/spatials/icelake.h +113 -0
  346. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  347. package/numkong/include/numkong/spatials/neon.h +109 -0
  348. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  349. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  350. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  351. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  352. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  353. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  354. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  355. package/numkong/include/numkong/spatials/serial.h +248 -0
  356. package/numkong/include/numkong/spatials/sierra.h +96 -0
  357. package/numkong/include/numkong/spatials/skylake.h +184 -0
  358. package/numkong/include/numkong/spatials/sme.h +1927 -0
  359. package/numkong/include/numkong/spatials/smef64.h +483 -0
  360. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  361. package/numkong/include/numkong/spatials.h +3374 -0
  362. package/numkong/include/numkong/spatials.hpp +509 -0
  363. package/numkong/include/numkong/tensor.hpp +1981 -0
  364. package/numkong/include/numkong/trigonometry/README.md +184 -0
  365. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  366. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  367. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  368. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  369. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  370. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  371. package/numkong/include/numkong/trigonometry.h +467 -0
  372. package/numkong/include/numkong/trigonometry.hpp +166 -0
  373. package/numkong/include/numkong/types.h +1695 -0
  374. package/numkong/include/numkong/types.hpp +6027 -0
  375. package/numkong/include/numkong/vector.hpp +766 -0
  376. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  377. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  378. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  380. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  381. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  382. package/numkong/javascript/README.md +254 -0
  383. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  384. package/numkong/javascript/numkong-browser.ts +40 -0
  385. package/numkong/javascript/numkong-wasm.ts +750 -0
  386. package/numkong/javascript/numkong.c +712 -0
  387. package/numkong/javascript/numkong.ts +613 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  389. package/numkong/javascript/tsconfig-cjs.json +13 -0
  390. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  391. package/numkong/javascript/types.ts +784 -0
  392. package/numkong/numkong.gypi +104 -0
  393. package/numkong/package.json +108 -0
  394. package/numkong/probes/arm_neon.c +8 -0
  395. package/numkong/probes/arm_neon_bfdot.c +9 -0
  396. package/numkong/probes/arm_neon_fhm.c +9 -0
  397. package/numkong/probes/arm_neon_half.c +8 -0
  398. package/numkong/probes/arm_neon_sdot.c +9 -0
  399. package/numkong/probes/arm_neonfp8.c +9 -0
  400. package/numkong/probes/arm_sme.c +16 -0
  401. package/numkong/probes/arm_sme2.c +16 -0
  402. package/numkong/probes/arm_sme2p1.c +16 -0
  403. package/numkong/probes/arm_sme_bf16.c +16 -0
  404. package/numkong/probes/arm_sme_bi32.c +16 -0
  405. package/numkong/probes/arm_sme_f64.c +16 -0
  406. package/numkong/probes/arm_sme_fa64.c +14 -0
  407. package/numkong/probes/arm_sme_half.c +16 -0
  408. package/numkong/probes/arm_sme_lut2.c +15 -0
  409. package/numkong/probes/arm_sve.c +18 -0
  410. package/numkong/probes/arm_sve2.c +20 -0
  411. package/numkong/probes/arm_sve2p1.c +18 -0
  412. package/numkong/probes/arm_sve_bfdot.c +20 -0
  413. package/numkong/probes/arm_sve_half.c +18 -0
  414. package/numkong/probes/arm_sve_sdot.c +21 -0
  415. package/numkong/probes/loongarch_lasx.c +12 -0
  416. package/numkong/probes/power_vsx.c +12 -0
  417. package/numkong/probes/probe.js +127 -0
  418. package/numkong/probes/riscv_rvv.c +14 -0
  419. package/numkong/probes/riscv_rvv_bb.c +15 -0
  420. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  421. package/numkong/probes/riscv_rvv_half.c +14 -0
  422. package/numkong/probes/wasm_v128relaxed.c +11 -0
  423. package/numkong/probes/x86_alder.c +17 -0
  424. package/numkong/probes/x86_diamond.c +17 -0
  425. package/numkong/probes/x86_genoa.c +17 -0
  426. package/numkong/probes/x86_graniteamx.c +19 -0
  427. package/numkong/probes/x86_haswell.c +11 -0
  428. package/numkong/probes/x86_icelake.c +17 -0
  429. package/numkong/probes/x86_sapphire.c +16 -0
  430. package/numkong/probes/x86_sapphireamx.c +18 -0
  431. package/numkong/probes/x86_sierra.c +17 -0
  432. package/numkong/probes/x86_skylake.c +15 -0
  433. package/numkong/probes/x86_turin.c +17 -0
  434. package/numkong/rust/README.md +698 -0
  435. package/numkong/rust/capabilities.rs +96 -0
  436. package/numkong/rust/cast.rs +314 -0
  437. package/numkong/rust/curved.rs +391 -0
  438. package/numkong/rust/each.rs +2721 -0
  439. package/numkong/rust/geospatial.rs +343 -0
  440. package/numkong/rust/matrix.rs +5424 -0
  441. package/numkong/rust/maxsim.rs +540 -0
  442. package/numkong/rust/mesh.rs +837 -0
  443. package/numkong/rust/numkong.rs +409 -0
  444. package/numkong/rust/probability.rs +272 -0
  445. package/numkong/rust/reduce.rs +1249 -0
  446. package/numkong/rust/set.rs +194 -0
  447. package/numkong/rust/sparse.rs +513 -0
  448. package/numkong/rust/spatial.rs +1815 -0
  449. package/numkong/rust/tensor.rs +7565 -0
  450. package/numkong/rust/types.rs +3666 -0
  451. package/numkong/rust/vector.rs +1899 -0
  452. package/numkong/rustfmt.toml +2 -0
  453. package/numkong/swift/Matrix.swift +1388 -0
  454. package/numkong/swift/MaxSim.swift +151 -0
  455. package/numkong/swift/NumKong.swift +283 -0
  456. package/numkong/swift/Numerics.swift +329 -0
  457. package/numkong/swift/README.md +433 -0
  458. package/numkong/swift/Scalar.swift +741 -0
  459. package/numkong/swift/Tensor.swift +209 -0
  460. package/numkong/test/README.md +315 -0
  461. package/numkong/test/playwright.config.ts +16 -0
  462. package/numkong/test/swift/Test.swift +534 -0
  463. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  464. package/numkong/test/test-browser-bundle.html +188 -0
  465. package/numkong/test/test-browser-runner.mjs +43 -0
  466. package/numkong/test/test-browser.html +305 -0
  467. package/numkong/test/test-dtypes.mjs +453 -0
  468. package/numkong/test/test-wasm.mjs +267 -0
  469. package/numkong/test/test.cpp +442 -0
  470. package/numkong/test/test.hpp +580 -0
  471. package/numkong/test/test.mjs +363 -0
  472. package/numkong/test/test_base.py +1041 -0
  473. package/numkong/test/test_cast.cpp +242 -0
  474. package/numkong/test/test_cross.hpp +551 -0
  475. package/numkong/test/test_cross.py +467 -0
  476. package/numkong/test/test_cross_amx.cpp +50 -0
  477. package/numkong/test/test_cross_arm.cpp +225 -0
  478. package/numkong/test/test_cross_blas.cpp +354 -0
  479. package/numkong/test/test_cross_loongarch.cpp +90 -0
  480. package/numkong/test/test_cross_power.cpp +73 -0
  481. package/numkong/test/test_cross_rvv.cpp +109 -0
  482. package/numkong/test/test_cross_serial.cpp +181 -0
  483. package/numkong/test/test_cross_sme.cpp +148 -0
  484. package/numkong/test/test_cross_wasm.cpp +141 -0
  485. package/numkong/test/test_cross_x86.cpp +442 -0
  486. package/numkong/test/test_curved.cpp +182 -0
  487. package/numkong/test/test_curved.py +207 -0
  488. package/numkong/test/test_dot.cpp +353 -0
  489. package/numkong/test/test_dot.py +296 -0
  490. package/numkong/test/test_each.cpp +437 -0
  491. package/numkong/test/test_each.py +756 -0
  492. package/numkong/test/test_geospatial.cpp +155 -0
  493. package/numkong/test/test_geospatial.py +241 -0
  494. package/numkong/test/test_maxsim.cpp +138 -0
  495. package/numkong/test/test_maxsim.py +209 -0
  496. package/numkong/test/test_mesh.cpp +203 -0
  497. package/numkong/test/test_mesh.py +394 -0
  498. package/numkong/test/test_probability.cpp +136 -0
  499. package/numkong/test/test_probability.py +166 -0
  500. package/numkong/test/test_reduce.cpp +563 -0
  501. package/numkong/test/test_reduce.py +781 -0
  502. package/numkong/test/test_set.cpp +151 -0
  503. package/numkong/test/test_set.py +120 -0
  504. package/numkong/test/test_similarities.py +579 -0
  505. package/numkong/test/test_sparse.cpp +121 -0
  506. package/numkong/test/test_sparse.py +118 -0
  507. package/numkong/test/test_spatial.cpp +518 -0
  508. package/numkong/test/test_spatial.py +269 -0
  509. package/numkong/test/test_tensor.cpp +884 -0
  510. package/numkong/test/test_tensor.py +1417 -0
  511. package/numkong/test/test_trigonometry.cpp +156 -0
  512. package/numkong/test/test_trigonometry.py +180 -0
  513. package/package.json +7 -8
  514. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  515. package/prebuilds/linux-arm64/usearch.node +0 -0
  516. package/prebuilds/linux-x64/usearch.node +0 -0
  517. package/fp16/CMakeLists.txt +0 -176
  518. package/fp16/LICENSE +0 -11
  519. package/fp16/README.md +0 -20
  520. package/fp16/bench/alt-element.cc +0 -89
  521. package/fp16/bench/from-alt-array.cc +0 -175
  522. package/fp16/bench/from-ieee-array.cc +0 -399
  523. package/fp16/bench/ieee-element.cc +0 -272
  524. package/fp16/bench/to-alt-array.cc +0 -91
  525. package/fp16/bench/to-ieee-array.cc +0 -303
  526. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  527. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  528. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  529. package/fp16/configure.py +0 -65
  530. package/fp16/confu.yaml +0 -8
  531. package/fp16/include/fp16/__init__.py +0 -0
  532. package/fp16/include/fp16/avx.py +0 -50
  533. package/fp16/include/fp16/avx2.py +0 -53
  534. package/fp16/include/fp16/bitcasts.h +0 -92
  535. package/fp16/include/fp16/fp16.h +0 -451
  536. package/fp16/include/fp16/psimd.h +0 -131
  537. package/fp16/include/fp16.h +0 -11
  538. package/fp16/jni/Android.mk +0 -6
  539. package/fp16/jni/Application.mk +0 -4
  540. package/fp16/test/alt-from-fp32-value.cc +0 -498
  541. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  542. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  543. package/fp16/test/alt-to-fp32-value.cc +0 -348
  544. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  545. package/fp16/test/bitcasts.cc +0 -56
  546. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  547. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  548. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  549. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  550. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  551. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  552. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  553. package/fp16/test/peachpy/stubs.py +0 -38
  554. package/fp16/test/tables.cc +0 -530
  555. package/fp16/test/tables.h +0 -13
  556. package/fp16/third-party/THHalf.h +0 -92
  557. package/fp16/third-party/eigen-half.h +0 -170
  558. package/fp16/third-party/float16-compressor.h +0 -80
  559. package/fp16/third-party/half.hpp +0 -2916
  560. package/fp16/third-party/npy-halffloat.h +0 -328
  561. package/simsimd/.git-blame-ignore-revs +0 -2
  562. package/simsimd/CONTRIBUTING.md +0 -321
  563. package/simsimd/Cargo.toml +0 -49
  564. package/simsimd/MANIFEST.in +0 -4
  565. package/simsimd/Package.swift +0 -28
  566. package/simsimd/README.md +0 -1493
  567. package/simsimd/binding.gyp +0 -35
  568. package/simsimd/build.rs +0 -70
  569. package/simsimd/c/lib.c +0 -374
  570. package/simsimd/include/module.modulemap +0 -4
  571. package/simsimd/include/simsimd/binary.h +0 -486
  572. package/simsimd/include/simsimd/curved.h +0 -1541
  573. package/simsimd/include/simsimd/dot.h +0 -1853
  574. package/simsimd/include/simsimd/elementwise.h +0 -2465
  575. package/simsimd/include/simsimd/geospatial.h +0 -43
  576. package/simsimd/include/simsimd/mesh.h +0 -69
  577. package/simsimd/include/simsimd/probability.h +0 -606
  578. package/simsimd/include/simsimd/simsimd.h +0 -2567
  579. package/simsimd/include/simsimd/sparse.h +0 -1384
  580. package/simsimd/include/simsimd/spatial.h +0 -2335
  581. package/simsimd/include/simsimd/types.h +0 -666
  582. package/simsimd/javascript/fallback.ts +0 -233
  583. package/simsimd/javascript/lib.c +0 -125
  584. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  585. package/simsimd/javascript/simsimd.ts +0 -179
  586. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  587. package/simsimd/package-lock.json +0 -1761
  588. package/simsimd/package.json +0 -61
  589. package/simsimd/rust/lib.rs +0 -1821
  590. package/simsimd/scripts/bench.cxx +0 -1170
  591. package/simsimd/scripts/bench.ipynb +0 -187
  592. package/simsimd/scripts/bench.js +0 -127
  593. package/simsimd/scripts/bench.rs +0 -876
  594. package/simsimd/scripts/bench_vectors.py +0 -734
  595. package/simsimd/scripts/bench_vectors_live.py +0 -213
  596. package/simsimd/scripts/test.c +0 -187
  597. package/simsimd/scripts/test.mjs +0 -220
  598. package/simsimd/scripts/test.py +0 -1505
  599. package/simsimd/swift/SimSIMD.swift +0 -149
  600. package/simsimd/swift/Test.swift +0 -128
  601. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  602. /package/{simsimd → numkong}/LICENSE +0 -0
  603. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  604. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -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 4
11
+ #define USEARCH_VERSION_MINOR 25
12
+ #define USEARCH_VERSION_PATCH 1
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
 
@@ -2719,7 +2843,7 @@ class index_gt {
2719
2843
  keys[i] = vector_key_t{};
2720
2844
  distances[i] = std::numeric_limits<distance_t>::has_signaling_NaN
2721
2845
  ? std::numeric_limits<distance_t>::signaling_NaN()
2722
- : std::numeric_limits<distance_t>::max();
2846
+ : (std::numeric_limits<distance_t>::max)();
2723
2847
  }
2724
2848
  return initialized_count;
2725
2849
  }
@@ -2786,6 +2910,10 @@ class index_gt {
2786
2910
  callback_at&& callback = callback_at{}, //
2787
2911
  prefetch_at&& prefetch = prefetch_at{}) usearch_noexcept_m {
2788
2912
 
2913
+ // Zero expansion is meaningless, fall back to default
2914
+ if (!config.expansion)
2915
+ config.expansion = default_expansion_add();
2916
+
2789
2917
  add_result_t result;
2790
2918
  if (is_immutable())
2791
2919
  return result.failed("Can't add to an immutable index");
@@ -3101,6 +3229,9 @@ class index_gt {
3101
3229
  predicate_at&& predicate = predicate_at{}, //
3102
3230
  prefetch_at&& prefetch = prefetch_at{}) const noexcept {
3103
3231
 
3232
+ if (!config.expansion)
3233
+ config.expansion = default_expansion_search();
3234
+
3104
3235
  context_t& context = contexts_[config.thread];
3105
3236
  cluster_result_t result;
3106
3237
  if (!nodes_count_)
@@ -3179,7 +3310,7 @@ class index_gt {
3179
3310
  continue;
3180
3311
 
3181
3312
  ++result.nodes;
3182
- result.edges += neighbors_(node, level).size();
3313
+ result.edges += neighbors_(node, static_cast<level_t>(level)).size();
3183
3314
  result.allocated_bytes += node_head_bytes_() + neighbors_bytes;
3184
3315
  }
3185
3316
 
@@ -3801,12 +3932,11 @@ class index_gt {
3801
3932
  struct node_lock_t {
3802
3933
  nodes_mutexes_t& mutexes;
3803
3934
  std::size_t slot;
3804
- inline ~node_lock_t() noexcept { mutexes.atomic_reset(slot); }
3935
+ inline ~node_lock_t() noexcept { mutexes.unlock(slot); }
3805
3936
  };
3806
3937
 
3807
3938
  inline node_lock_t node_lock_(std::size_t slot) const noexcept {
3808
- while (nodes_mutexes_.atomic_set(slot))
3809
- ;
3939
+ nodes_mutexes_.lock(slot);
3810
3940
  return {nodes_mutexes_, slot};
3811
3941
  }
3812
3942
 
@@ -3814,18 +3944,17 @@ class index_gt {
3814
3944
  nodes_mutexes_t& mutexes;
3815
3945
  std::size_t slot;
3816
3946
  inline ~optional_node_lock_t() noexcept {
3817
- if (slot != std::numeric_limits<std::size_t>::max())
3818
- mutexes.atomic_reset(slot);
3947
+ if (slot != (std::numeric_limits<std::size_t>::max)())
3948
+ mutexes.unlock(slot);
3819
3949
  }
3820
3950
  };
3821
3951
 
3822
3952
  inline optional_node_lock_t optional_node_lock_(std::size_t slot, bool condition) const noexcept {
3823
3953
  if (condition) {
3824
- while (nodes_mutexes_.atomic_set(slot))
3825
- ;
3954
+ nodes_mutexes_.lock(slot);
3826
3955
  return {nodes_mutexes_, slot};
3827
3956
  } else {
3828
- return {nodes_mutexes_, std::numeric_limits<std::size_t>::max()};
3957
+ return {nodes_mutexes_, (std::numeric_limits<std::size_t>::max)()};
3829
3958
  }
3830
3959
  }
3831
3960
 
@@ -3833,8 +3962,8 @@ class index_gt {
3833
3962
  nodes_mutexes_t& mutexes;
3834
3963
  std::size_t slot;
3835
3964
  inline ~node_conditional_lock_t() noexcept {
3836
- if (slot != std::numeric_limits<std::size_t>::max())
3837
- mutexes.atomic_reset(slot);
3965
+ if (slot != (std::numeric_limits<std::size_t>::max)())
3966
+ mutexes.unlock(slot);
3838
3967
  }
3839
3968
  };
3840
3969
 
@@ -3842,10 +3971,10 @@ class index_gt {
3842
3971
  bool& failed_to_acquire) const noexcept {
3843
3972
  if (!condition) {
3844
3973
  failed_to_acquire = false;
3845
- return {nodes_mutexes_, std::numeric_limits<std::size_t>::max()};
3974
+ return {nodes_mutexes_, (std::numeric_limits<std::size_t>::max)()};
3846
3975
  }
3847
3976
  failed_to_acquire = nodes_mutexes_.atomic_set(slot);
3848
- return {nodes_mutexes_, failed_to_acquire ? std::numeric_limits<std::size_t>::max() : slot};
3977
+ return {nodes_mutexes_, failed_to_acquire ? (std::numeric_limits<std::size_t>::max)() : slot};
3849
3978
  }
3850
3979
 
3851
3980
  template <typename metric_at, bool require_non_empty_ak = false>
@@ -3896,8 +4025,12 @@ class index_gt {
3896
4025
  usearch_assert_m(close_slot != new_slot, "Self-loops are impossible");
3897
4026
  usearch_assert_m(level <= close_node.level(), "Linking to missing level");
3898
4027
 
3899
- // If `new_slot` is already present in the neighboring connections of `close_slot`
3900
- // 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
+
3901
4034
  if (close_header.size() < connectivity_max) {
3902
4035
  close_header.push_back(new_slot);
3903
4036
  continue;
@@ -3912,7 +4045,7 @@ class index_gt {
3912
4045
  // Export the results:
3913
4046
  close_header.clear();
3914
4047
  candidates_view_t top_view = refine_(metric, connectivity_max, top_for_refine, context,
3915
- context.computed_distances_in_reverse_refines);
4048
+ context.computed_distances_in_reverse_refines, new_slot, value);
3916
4049
  usearch_assert_m(top_view.size(), "This would lead to isolated nodes");
3917
4050
  for (std::size_t idx = 0; idx != top_view.size(); idx++)
3918
4051
  close_header.push_back(top_view[idx].slot);
@@ -3960,7 +4093,9 @@ class index_gt {
3960
4093
  std::size_t progress) noexcept
3961
4094
  : index_(index), neighbors_(neighbors), visits_(visits), current_(progress) {}
3962
4095
  candidates_iterator_t operator++(int) noexcept {
3963
- 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;
3964
4099
  }
3965
4100
  candidates_iterator_t& operator++() noexcept {
3966
4101
  ++current_;
@@ -3999,12 +4134,13 @@ class index_gt {
3999
4134
  if (!is_dummy<prefetch_at>())
4000
4135
  prefetch(citerator_at(closest_slot), citerator_at(closest_slot) + 1);
4001
4136
 
4137
+ bool const need_lock = !is_immutable();
4002
4138
  distance_t closest_dist = context.measure(query, citerator_at(closest_slot), metric);
4003
4139
  for (level_t level = begin_level; level > end_level; --level) {
4004
4140
  bool changed;
4005
4141
  do {
4006
4142
  changed = false;
4007
- node_lock_t closest_lock = node_lock_(closest_slot);
4143
+ optional_node_lock_t closest_lock = optional_node_lock_(closest_slot, need_lock);
4008
4144
  neighbors_ref_t closest_neighbors = neighbors_non_base_(node_at_(closest_slot), level);
4009
4145
 
4010
4146
  // Optional prefetching
@@ -4050,6 +4186,10 @@ class index_gt {
4050
4186
  // At the very least we are going to explore the starting node and its neighbors
4051
4187
  if (!visits.reserve(config_.connectivity_base + 1u))
4052
4188
  return false;
4189
+ if (!top.reserve(top_limit))
4190
+ return false;
4191
+ if (!next.reserve(top_limit))
4192
+ return false;
4053
4193
 
4054
4194
  // Optional prefetching
4055
4195
  if (!is_dummy<prefetch_at>())
@@ -4127,6 +4267,10 @@ class index_gt {
4127
4267
  // At the very least we are going to explore the starting node and its neighbors
4128
4268
  if (!visits.reserve(config_.connectivity_base + 1u))
4129
4269
  return false;
4270
+ if (!top.reserve(top_limit))
4271
+ return false;
4272
+ if (!next.reserve(top_limit))
4273
+ return false;
4130
4274
 
4131
4275
  // Optional prefetching
4132
4276
  if (!is_dummy<prefetch_at>())
@@ -4295,16 +4439,50 @@ class index_gt {
4295
4439
  }
4296
4440
  }
4297
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
+
4298
4467
  /**
4299
4468
  * @brief This algorithm from the original paper implements a heuristic,
4300
4469
  * that massively reduces the number of connections a point has,
4301
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`.
4302
4478
  */
4303
- template <typename metric_at>
4479
+ template <typename metric_at, typename override_value_at = std::nullptr_t>
4304
4480
  candidates_view_t refine_( //
4305
4481
  metric_at&& metric, //
4306
4482
  std::size_t needed, top_candidates_t& top, context_t& context, //
4307
- 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 {
4308
4486
 
4309
4487
  // Avoid expensive computation, if the set is already small
4310
4488
  candidate_t* top_data = top.data();
@@ -4323,10 +4501,8 @@ class index_gt {
4323
4501
  std::size_t idx = 0;
4324
4502
  for (; idx < submitted_count; idx++) {
4325
4503
  candidate_t submitted = top_data[idx];
4326
- distance_t inter_result_dist = context.measure( //
4327
- citerator_at(candidate.slot), //
4328
- citerator_at(submitted.slot), //
4329
- metric);
4504
+ distance_t inter_result_dist = inter_neighbor_distance_( //
4505
+ candidate, submitted, override_slot, override_value, metric, context);
4330
4506
  if (inter_result_dist < candidate.distance) {
4331
4507
  good = false;
4332
4508
  break;
@@ -4417,7 +4593,7 @@ static join_result_t join( //
4417
4593
  return result.failed("Can't join with itself, consider copying");
4418
4594
 
4419
4595
  if (config.max_proposals == 0)
4420
- config.max_proposals = std::log(men.size()) + executor.size();
4596
+ config.max_proposals = static_cast<std::size_t>(std::log(men.size())) + executor.size();
4421
4597
 
4422
4598
  using proposals_count_t = std::uint16_t;
4423
4599
  config.max_proposals = (std::min)(men.size(), config.max_proposals);