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
@@ -0,0 +1,613 @@
1
+ /**
2
+ * @brief SIMD-accelerated Geospatial Distances for Skylake.
3
+ * @file include/numkong/geospatial/skylake.h
4
+ * @author Ash Vardanian
5
+ * @date February 6, 2026
6
+ *
7
+ * @sa include/numkong/geospatial.h
8
+ *
9
+ * @section geospatial_skylake_instructions Key AVX-512 Geospatial Instructions
10
+ *
11
+ * Intrinsic Instruction Icelake Genoa
12
+ * _mm512_sqrt_ps VSQRTPS (ZMM, ZMM) 19cy @ p0+p0+p05 15cy @ p01
13
+ * _mm512_sqrt_pd VSQRTPD (ZMM, ZMM) 23cy @ p0+p0+p05 21cy @ p01
14
+ * _mm256_div_ps VDIVPS (YMM, YMM, YMM) 11cy @ p0 11cy @ p01
15
+ * _mm256_div_pd VDIVPD (YMM, YMM, YMM) 13cy @ p0 13cy @ p01
16
+ * _mm256_fmadd_ps VFMADD231PS (YMM, YMM, YMM) 4cy @ p01 4cy @ p01
17
+ * _mm256_fmadd_pd VFMADD231PD (YMM, YMM, YMM) 4cy @ p01 4cy @ p01
18
+ * _mm512_cmp_ps_mask VCMPPS (K, ZMM, ZMM, I8) 4cy @ p5 5cy @ p01
19
+ */
20
+ #ifndef NK_GEOSPATIAL_SKYLAKE_H
21
+ #define NK_GEOSPATIAL_SKYLAKE_H
22
+
23
+ #if NK_TARGET_X8664_
24
+ #if NK_TARGET_SKYLAKE
25
+
26
+ #include "numkong/types.h"
27
+ #include "numkong/trigonometry/skylake.h" // `nk_sin_f64x8_skylake_`, `nk_cos_f64x8_skylake_`, `nk_atan2_f64x8_skylake_`
28
+
29
+ #if defined(__cplusplus)
30
+ extern "C" {
31
+ #endif
32
+
33
+ #if defined(__clang__)
34
+ #pragma clang attribute push(__attribute__((target("avx2,avx512f,avx512vl,avx512bw,avx512dq,f16c,fma,bmi,bmi2"))), \
35
+ apply_to = function)
36
+ #elif defined(__GNUC__)
37
+ #pragma GCC push_options
38
+ #pragma GCC target("avx2", "avx512f", "avx512vl", "avx512bw", "avx512dq", "f16c", "fma", "bmi", "bmi2")
39
+ #endif
40
+
41
+ NK_INTERNAL __m512d nk_haversine_f64x8_skylake_( //
42
+ __m512d first_latitudes_f64x8, __m512d first_longitudes_f64x8, //
43
+ __m512d second_latitudes_f64x8, __m512d second_longitudes_f64x8) {
44
+
45
+ __m512d const earth_radius_f64x8 = _mm512_set1_pd(NK_EARTH_MEDIATORIAL_RADIUS);
46
+ __m512d const half_f64x8 = _mm512_set1_pd(0.5);
47
+ __m512d const one_f64x8 = _mm512_set1_pd(1.0);
48
+ __m512d const two_f64x8 = _mm512_set1_pd(2.0);
49
+
50
+ __m512d latitude_delta_f64x8 = _mm512_sub_pd(second_latitudes_f64x8, first_latitudes_f64x8);
51
+ __m512d longitude_delta_f64x8 = _mm512_sub_pd(second_longitudes_f64x8, first_longitudes_f64x8);
52
+
53
+ // Haversine terms: sin²(Δ/2)
54
+ __m512d latitude_delta_half_f64x8 = _mm512_mul_pd(latitude_delta_f64x8, half_f64x8);
55
+ __m512d longitude_delta_half_f64x8 = _mm512_mul_pd(longitude_delta_f64x8, half_f64x8);
56
+ __m512d sin_latitude_delta_half_f64x8 = nk_sin_f64x8_skylake_(latitude_delta_half_f64x8);
57
+ __m512d sin_longitude_delta_half_f64x8 = nk_sin_f64x8_skylake_(longitude_delta_half_f64x8);
58
+ __m512d sin_squared_latitude_delta_half_f64x8 = _mm512_mul_pd(sin_latitude_delta_half_f64x8,
59
+ sin_latitude_delta_half_f64x8);
60
+ __m512d sin_squared_longitude_delta_half_f64x8 = _mm512_mul_pd(sin_longitude_delta_half_f64x8,
61
+ sin_longitude_delta_half_f64x8);
62
+
63
+ // Latitude cosine product
64
+ __m512d cos_first_latitude_f64x8 = nk_cos_f64x8_skylake_(first_latitudes_f64x8);
65
+ __m512d cos_second_latitude_f64x8 = nk_cos_f64x8_skylake_(second_latitudes_f64x8);
66
+ __m512d cos_latitude_product_f64x8 = _mm512_mul_pd(cos_first_latitude_f64x8, cos_second_latitude_f64x8);
67
+
68
+ // a = sin²(Δlat/2) + cos(lat1) × cos(lat2) × sin²(Δlon/2)
69
+ __m512d haversine_term_f64x8 = _mm512_add_pd(
70
+ sin_squared_latitude_delta_half_f64x8,
71
+ _mm512_mul_pd(cos_latitude_product_f64x8, sin_squared_longitude_delta_half_f64x8));
72
+ // Clamp haversine_term_f64x8 to [0, 1] to prevent NaN from sqrt of negative values
73
+ __m512d zero_f64x8 = _mm512_setzero_pd();
74
+ haversine_term_f64x8 = _mm512_max_pd(zero_f64x8, _mm512_min_pd(one_f64x8, haversine_term_f64x8));
75
+
76
+ // Central angle: c = 2 × atan2(√a, √(1-a))
77
+ __m512d sqrt_haversine_f64x8 = _mm512_sqrt_pd(haversine_term_f64x8);
78
+ __m512d sqrt_complement_f64x8 = _mm512_sqrt_pd(_mm512_sub_pd(one_f64x8, haversine_term_f64x8));
79
+ __m512d central_angle_f64x8 = _mm512_mul_pd(two_f64x8,
80
+ nk_atan2_f64x8_skylake_(sqrt_haversine_f64x8, sqrt_complement_f64x8));
81
+
82
+ return _mm512_mul_pd(earth_radius_f64x8, central_angle_f64x8);
83
+ }
84
+
85
+ NK_PUBLIC void nk_haversine_f64_skylake( //
86
+ nk_f64_t const *a_lats, nk_f64_t const *a_lons, //
87
+ nk_f64_t const *b_lats, nk_f64_t const *b_lons, //
88
+ nk_size_t n, nk_f64_t *results) {
89
+
90
+ while (n >= 8) {
91
+ __m512d first_latitudes_f64x8 = _mm512_loadu_pd(a_lats);
92
+ __m512d first_longitudes_f64x8 = _mm512_loadu_pd(a_lons);
93
+ __m512d second_latitudes_f64x8 = _mm512_loadu_pd(b_lats);
94
+ __m512d second_longitudes_f64x8 = _mm512_loadu_pd(b_lons);
95
+
96
+ __m512d distances_f64x8 = nk_haversine_f64x8_skylake_(first_latitudes_f64x8, first_longitudes_f64x8,
97
+ second_latitudes_f64x8, second_longitudes_f64x8);
98
+ _mm512_storeu_pd(results, distances_f64x8);
99
+
100
+ a_lats += 8, a_lons += 8, b_lats += 8, b_lons += 8, results += 8, n -= 8;
101
+ }
102
+
103
+ // Handle remaining elements with masked operations
104
+ if (n > 0) {
105
+ __mmask8 mask = (__mmask8)_bzhi_u32(0xFF, n);
106
+ __m512d first_latitudes_f64x8 = _mm512_maskz_loadu_pd(mask, a_lats);
107
+ __m512d first_longitudes_f64x8 = _mm512_maskz_loadu_pd(mask, a_lons);
108
+ __m512d second_latitudes_f64x8 = _mm512_maskz_loadu_pd(mask, b_lats);
109
+ __m512d second_longitudes_f64x8 = _mm512_maskz_loadu_pd(mask, b_lons);
110
+
111
+ __m512d distances_f64x8 = nk_haversine_f64x8_skylake_(first_latitudes_f64x8, first_longitudes_f64x8,
112
+ second_latitudes_f64x8, second_longitudes_f64x8);
113
+ _mm512_mask_storeu_pd(results, mask, distances_f64x8);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * @brief AVX-512 helper for Vincenty's geodesic distance on 8 f64 point pairs.
119
+ * @note This is a true SIMD implementation using masked convergence tracking.
120
+ */
121
+ NK_INTERNAL __m512d nk_vincenty_f64x8_skylake_( //
122
+ __m512d first_latitudes_f64x8, __m512d first_longitudes_f64x8, //
123
+ __m512d second_latitudes_f64x8, __m512d second_longitudes_f64x8) {
124
+
125
+ __m512d const equatorial_radius_f64x8 = _mm512_set1_pd(NK_EARTH_ELLIPSOID_EQUATORIAL_RADIUS);
126
+ __m512d const polar_radius_f64x8 = _mm512_set1_pd(NK_EARTH_ELLIPSOID_POLAR_RADIUS);
127
+ __m512d const flattening_f64x8 = _mm512_set1_pd(1.0 / NK_EARTH_ELLIPSOID_INVERSE_FLATTENING);
128
+ __m512d const convergence_threshold_f64x8 = _mm512_set1_pd(NK_VINCENTY_CONVERGENCE_THRESHOLD_F64);
129
+ __m512d const one_f64x8 = _mm512_set1_pd(1.0);
130
+ __m512d const two_f64x8 = _mm512_set1_pd(2.0);
131
+ __m512d const three_f64x8 = _mm512_set1_pd(3.0);
132
+ __m512d const four_f64x8 = _mm512_set1_pd(4.0);
133
+ __m512d const six_f64x8 = _mm512_set1_pd(6.0);
134
+ __m512d const sixteen_f64x8 = _mm512_set1_pd(16.0);
135
+
136
+ // Longitude difference
137
+ __m512d longitude_difference_f64x8 = _mm512_sub_pd(second_longitudes_f64x8, first_longitudes_f64x8);
138
+
139
+ // Reduced latitudes: tan(U) = (1-f) * tan(lat)
140
+ __m512d one_minus_f_f64x8 = _mm512_sub_pd(one_f64x8, flattening_f64x8);
141
+ __m512d tan_first_f64x8 = _mm512_div_pd(nk_sin_f64x8_skylake_(first_latitudes_f64x8),
142
+ nk_cos_f64x8_skylake_(first_latitudes_f64x8));
143
+ __m512d tan_second_f64x8 = _mm512_div_pd(nk_sin_f64x8_skylake_(second_latitudes_f64x8),
144
+ nk_cos_f64x8_skylake_(second_latitudes_f64x8));
145
+ __m512d tan_reduced_first_f64x8 = _mm512_mul_pd(one_minus_f_f64x8, tan_first_f64x8);
146
+ __m512d tan_reduced_second_f64x8 = _mm512_mul_pd(one_minus_f_f64x8, tan_second_f64x8);
147
+
148
+ // cos(U) = 1/√(1 + tan²(U)), sin(U) = tan(U) × cos(U)
149
+ __m512d cos_reduced_first_f64x8 = _mm512_div_pd(
150
+ one_f64x8, _mm512_sqrt_pd(_mm512_fmadd_pd(tan_reduced_first_f64x8, tan_reduced_first_f64x8, one_f64x8)));
151
+ __m512d sin_reduced_first_f64x8 = _mm512_mul_pd(tan_reduced_first_f64x8, cos_reduced_first_f64x8);
152
+ __m512d cos_reduced_second_f64x8 = _mm512_div_pd(
153
+ one_f64x8, _mm512_sqrt_pd(_mm512_fmadd_pd(tan_reduced_second_f64x8, tan_reduced_second_f64x8, one_f64x8)));
154
+ __m512d sin_reduced_second_f64x8 = _mm512_mul_pd(tan_reduced_second_f64x8, cos_reduced_second_f64x8);
155
+
156
+ // Initialize lambda_f64x8 and tracking variables
157
+ __m512d lambda_f64x8 = longitude_difference_f64x8;
158
+ __m512d sin_angular_distance_f64x8, cos_angular_distance_f64x8, angular_distance_f64x8;
159
+ __m512d sin_azimuth_f64x8, cos_squared_azimuth_f64x8, cos_double_angular_midpoint_f64x8;
160
+
161
+ // Track convergence and coincident points
162
+ __mmask8 converged_mask = 0;
163
+ __mmask8 coincident_mask = 0;
164
+
165
+ for (nk_u32_t iteration = 0; iteration < NK_VINCENTY_MAX_ITERATIONS && converged_mask != 0xFF; ++iteration) {
166
+ __m512d sin_lambda_f64x8 = nk_sin_f64x8_skylake_(lambda_f64x8);
167
+ __m512d cos_lambda_f64x8 = nk_cos_f64x8_skylake_(lambda_f64x8);
168
+
169
+ // sin²(angular_distance_f64x8) = (cos(U₂) × sin(λ))² + (cos(U₁) × sin(U₂) - sin(U₁) × cos(U₂) × cos(λ))²
170
+ __m512d cross_term_f64x8 = _mm512_mul_pd(cos_reduced_second_f64x8, sin_lambda_f64x8);
171
+ __m512d mixed_term_f64x8 = _mm512_sub_pd(
172
+ _mm512_mul_pd(cos_reduced_first_f64x8, sin_reduced_second_f64x8),
173
+ _mm512_mul_pd(_mm512_mul_pd(sin_reduced_first_f64x8, cos_reduced_second_f64x8), cos_lambda_f64x8));
174
+ __m512d sin_angular_dist_sq_f64x8 = _mm512_fmadd_pd(cross_term_f64x8, cross_term_f64x8,
175
+ _mm512_mul_pd(mixed_term_f64x8, mixed_term_f64x8));
176
+ sin_angular_distance_f64x8 = _mm512_sqrt_pd(sin_angular_dist_sq_f64x8);
177
+
178
+ // Check for coincident points (sin_angular_distance_f64x8 ≈ 0)
179
+ coincident_mask = _mm512_cmp_pd_mask(sin_angular_distance_f64x8, _mm512_set1_pd(1e-15), _CMP_LT_OS);
180
+
181
+ // cos(angular_distance_f64x8) = sin(U₁) × sin(U₂) + cos(U₁) × cos(U₂) × cos(λ)
182
+ cos_angular_distance_f64x8 = _mm512_fmadd_pd(_mm512_mul_pd(cos_reduced_first_f64x8, cos_reduced_second_f64x8),
183
+ cos_lambda_f64x8,
184
+ _mm512_mul_pd(sin_reduced_first_f64x8, sin_reduced_second_f64x8));
185
+
186
+ // angular_distance_f64x8 = atan2(sin, cos)
187
+ angular_distance_f64x8 = nk_atan2_f64x8_skylake_(sin_angular_distance_f64x8, cos_angular_distance_f64x8);
188
+
189
+ // sin(azimuth) = cos(U₁) × cos(U₂) × sin(λ) / sin(angular_distance_f64x8)
190
+ // Use masked divide: zero result for coincident lanes, avoids division by zero
191
+ sin_azimuth_f64x8 = _mm512_maskz_div_pd(
192
+ _knot_mask8(coincident_mask),
193
+ _mm512_mul_pd(_mm512_mul_pd(cos_reduced_first_f64x8, cos_reduced_second_f64x8), sin_lambda_f64x8),
194
+ sin_angular_distance_f64x8);
195
+ cos_squared_azimuth_f64x8 = _mm512_sub_pd(one_f64x8, _mm512_mul_pd(sin_azimuth_f64x8, sin_azimuth_f64x8));
196
+
197
+ // Handle equatorial case: cos²α = 0
198
+ __mmask8 equatorial_mask = _mm512_cmp_pd_mask(cos_squared_azimuth_f64x8, _mm512_set1_pd(1e-15), _CMP_LT_OS);
199
+
200
+ // cos(2σₘ) = cos(σ) - 2 × sin(U₁) × sin(U₂) / cos²(α)
201
+ // Use masked divide: for equatorial lanes, quotient_f64x8 = cos_angular_distance_f64x8 (passthrough),
202
+ // so subtraction yields zero. Avoids division by zero.
203
+ __m512d sin_product_f64x8 = _mm512_mul_pd(sin_reduced_first_f64x8, sin_reduced_second_f64x8);
204
+ __m512d quotient_f64x8 = _mm512_mask_div_pd(cos_angular_distance_f64x8, _knot_mask8(equatorial_mask),
205
+ _mm512_mul_pd(two_f64x8, sin_product_f64x8),
206
+ cos_squared_azimuth_f64x8);
207
+ cos_double_angular_midpoint_f64x8 = _mm512_sub_pd(cos_angular_distance_f64x8, quotient_f64x8);
208
+
209
+ // C = f/16 * cos²α * (4 + f*(4 - 3*cos²α))
210
+ __m512d correction_factor_f64x8 = _mm512_mul_pd(
211
+ _mm512_div_pd(flattening_f64x8, sixteen_f64x8),
212
+ _mm512_mul_pd(
213
+ cos_squared_azimuth_f64x8,
214
+ _mm512_fmadd_pd(flattening_f64x8, _mm512_fnmadd_pd(three_f64x8, cos_squared_azimuth_f64x8, four_f64x8),
215
+ four_f64x8)));
216
+
217
+ // λ' = L + (1-C) × f × sin(α) × (σ + C × sin(σ) × (cos(2σₘ) + C × cos(σ) × (-1 + 2 × cos²(2σₘ))))
218
+ __m512d cos_2sm_sq_f64x8 = _mm512_mul_pd(cos_double_angular_midpoint_f64x8, cos_double_angular_midpoint_f64x8);
219
+ // innermost_f64x8 = -1 + 2 × cos²(2σₘ)
220
+ __m512d innermost_f64x8 = _mm512_fmadd_pd(two_f64x8, cos_2sm_sq_f64x8, _mm512_set1_pd(-1.0));
221
+ // middle_f64x8 = cos(2σₘ) + C × cos(σ) × innermost_f64x8
222
+ __m512d middle_f64x8 = _mm512_fmadd_pd(_mm512_mul_pd(correction_factor_f64x8, cos_angular_distance_f64x8),
223
+ innermost_f64x8, cos_double_angular_midpoint_f64x8);
224
+ // inner_f64x8 = C × sin(σ) × middle_f64x8
225
+ __m512d inner_f64x8 = _mm512_mul_pd(_mm512_mul_pd(correction_factor_f64x8, sin_angular_distance_f64x8),
226
+ middle_f64x8);
227
+
228
+ // λ' = L + (1-C) * f * sin_α * (σ + inner_f64x8)
229
+ __m512d lambda_new_f64x8 = _mm512_fmadd_pd(
230
+ _mm512_mul_pd(_mm512_mul_pd(_mm512_sub_pd(one_f64x8, correction_factor_f64x8), flattening_f64x8),
231
+ sin_azimuth_f64x8),
232
+ _mm512_add_pd(angular_distance_f64x8, inner_f64x8), longitude_difference_f64x8);
233
+
234
+ // Check convergence: |λ - λ'| < threshold
235
+ __m512d lambda_diff_f64x8 = _mm512_abs_pd(_mm512_sub_pd(lambda_new_f64x8, lambda_f64x8));
236
+ converged_mask = _mm512_cmp_pd_mask(lambda_diff_f64x8, convergence_threshold_f64x8, _CMP_LT_OS);
237
+
238
+ lambda_f64x8 = lambda_new_f64x8;
239
+ }
240
+
241
+ // Final distance calculation
242
+ // u² = cos²α * (a² - b²) / b²
243
+ __m512d a_sq_f64x8 = _mm512_mul_pd(equatorial_radius_f64x8, equatorial_radius_f64x8);
244
+ __m512d b_sq_f64x8 = _mm512_mul_pd(polar_radius_f64x8, polar_radius_f64x8);
245
+ __m512d u_squared_f64x8 = _mm512_div_pd(
246
+ _mm512_mul_pd(cos_squared_azimuth_f64x8, _mm512_sub_pd(a_sq_f64x8, b_sq_f64x8)), b_sq_f64x8);
247
+
248
+ // A = 1 + u²/16384 * (4096 + u²*(-768 + u²*(320 - 175*u²)))
249
+ __m512d series_a_f64x8 = _mm512_fmadd_pd(u_squared_f64x8, _mm512_set1_pd(-175.0), _mm512_set1_pd(320.0));
250
+ series_a_f64x8 = _mm512_fmadd_pd(u_squared_f64x8, series_a_f64x8, _mm512_set1_pd(-768.0));
251
+ series_a_f64x8 = _mm512_fmadd_pd(u_squared_f64x8, series_a_f64x8, _mm512_set1_pd(4096.0));
252
+ series_a_f64x8 = _mm512_fmadd_pd(_mm512_div_pd(u_squared_f64x8, _mm512_set1_pd(16384.0)), series_a_f64x8,
253
+ one_f64x8);
254
+
255
+ // B = u²/1024 * (256 + u²*(-128 + u²*(74 - 47*u²)))
256
+ __m512d series_b_f64x8 = _mm512_fmadd_pd(u_squared_f64x8, _mm512_set1_pd(-47.0), _mm512_set1_pd(74.0));
257
+ series_b_f64x8 = _mm512_fmadd_pd(u_squared_f64x8, series_b_f64x8, _mm512_set1_pd(-128.0));
258
+ series_b_f64x8 = _mm512_fmadd_pd(u_squared_f64x8, series_b_f64x8, _mm512_set1_pd(256.0));
259
+ series_b_f64x8 = _mm512_mul_pd(_mm512_div_pd(u_squared_f64x8, _mm512_set1_pd(1024.0)), series_b_f64x8);
260
+
261
+ // Δσ = B × sin(σ) × (cos(2σₘ) +
262
+ // B/4 × (cos(σ) × (-1 + 2 × cos²(2σₘ)) - B/6 × cos(2σₘ) × (-3 + 4 × sin²(σ)) × (-3 + 4 × cos²(2σₘ))))
263
+ __m512d cos_2sm_sq_f64x8 = _mm512_mul_pd(cos_double_angular_midpoint_f64x8, cos_double_angular_midpoint_f64x8);
264
+ __m512d sin_sq_f64x8 = _mm512_mul_pd(sin_angular_distance_f64x8, sin_angular_distance_f64x8);
265
+ __m512d term1_f64x8 = _mm512_fmadd_pd(two_f64x8, cos_2sm_sq_f64x8, _mm512_set1_pd(-1.0));
266
+ term1_f64x8 = _mm512_mul_pd(cos_angular_distance_f64x8, term1_f64x8);
267
+ __m512d term2_f64x8 = _mm512_fmadd_pd(four_f64x8, sin_sq_f64x8, _mm512_set1_pd(-3.0));
268
+ __m512d term3_f64x8 = _mm512_fmadd_pd(four_f64x8, cos_2sm_sq_f64x8, _mm512_set1_pd(-3.0));
269
+ term2_f64x8 = _mm512_mul_pd(
270
+ _mm512_mul_pd(_mm512_div_pd(series_b_f64x8, six_f64x8), cos_double_angular_midpoint_f64x8),
271
+ _mm512_mul_pd(term2_f64x8, term3_f64x8));
272
+ __m512d delta_sigma_f64x8 = _mm512_mul_pd(
273
+ series_b_f64x8, _mm512_mul_pd(sin_angular_distance_f64x8,
274
+ _mm512_add_pd(cos_double_angular_midpoint_f64x8,
275
+ _mm512_mul_pd(_mm512_div_pd(series_b_f64x8, four_f64x8),
276
+ _mm512_sub_pd(term1_f64x8, term2_f64x8)))));
277
+
278
+ // s = b * A * (σ - Δσ)
279
+ __m512d distances_f64x8 = _mm512_mul_pd(_mm512_mul_pd(polar_radius_f64x8, series_a_f64x8),
280
+ _mm512_sub_pd(angular_distance_f64x8, delta_sigma_f64x8));
281
+
282
+ // Set coincident points to zero
283
+ distances_f64x8 = _mm512_mask_blend_pd(coincident_mask, distances_f64x8, _mm512_setzero_pd());
284
+
285
+ return distances_f64x8;
286
+ }
287
+
288
+ NK_PUBLIC void nk_vincenty_f64_skylake( //
289
+ nk_f64_t const *a_lats, nk_f64_t const *a_lons, //
290
+ nk_f64_t const *b_lats, nk_f64_t const *b_lons, //
291
+ nk_size_t n, nk_f64_t *results) {
292
+
293
+ while (n >= 8) {
294
+ __m512d first_latitudes_f64x8 = _mm512_loadu_pd(a_lats);
295
+ __m512d first_longitudes_f64x8 = _mm512_loadu_pd(a_lons);
296
+ __m512d second_latitudes_f64x8 = _mm512_loadu_pd(b_lats);
297
+ __m512d second_longitudes_f64x8 = _mm512_loadu_pd(b_lons);
298
+
299
+ __m512d distances_f64x8 = nk_vincenty_f64x8_skylake_(first_latitudes_f64x8, first_longitudes_f64x8,
300
+ second_latitudes_f64x8, second_longitudes_f64x8);
301
+ _mm512_storeu_pd(results, distances_f64x8);
302
+
303
+ a_lats += 8, a_lons += 8, b_lats += 8, b_lons += 8, results += 8, n -= 8;
304
+ }
305
+
306
+ // Handle remaining elements with masked operations
307
+ if (n > 0) {
308
+ __mmask8 mask = (__mmask8)_bzhi_u32(0xFF, n);
309
+ __m512d first_latitudes_f64x8 = _mm512_maskz_loadu_pd(mask, a_lats);
310
+ __m512d first_longitudes_f64x8 = _mm512_maskz_loadu_pd(mask, a_lons);
311
+ __m512d second_latitudes_f64x8 = _mm512_maskz_loadu_pd(mask, b_lats);
312
+ __m512d second_longitudes_f64x8 = _mm512_maskz_loadu_pd(mask, b_lons);
313
+
314
+ __m512d distances_f64x8 = nk_vincenty_f64x8_skylake_(first_latitudes_f64x8, first_longitudes_f64x8,
315
+ second_latitudes_f64x8, second_longitudes_f64x8);
316
+ _mm512_mask_storeu_pd(results, mask, distances_f64x8);
317
+ }
318
+ }
319
+
320
+ NK_INTERNAL __m512 nk_haversine_f32x16_skylake_( //
321
+ __m512 first_latitudes_f32x16, __m512 first_longitudes_f32x16, //
322
+ __m512 second_latitudes_f32x16, __m512 second_longitudes_f32x16) {
323
+
324
+ __m512 const earth_radius_f32x16 = _mm512_set1_ps((float)NK_EARTH_MEDIATORIAL_RADIUS);
325
+ __m512 const half_f32x16 = _mm512_set1_ps(0.5f);
326
+ __m512 const one_f32x16 = _mm512_set1_ps(1.0f);
327
+ __m512 const two_f32x16 = _mm512_set1_ps(2.0f);
328
+
329
+ __m512 latitude_delta_f32x16 = _mm512_sub_ps(second_latitudes_f32x16, first_latitudes_f32x16);
330
+ __m512 longitude_delta_f32x16 = _mm512_sub_ps(second_longitudes_f32x16, first_longitudes_f32x16);
331
+
332
+ // Haversine terms: sin²(Δ/2)
333
+ __m512 latitude_delta_half_f32x16 = _mm512_mul_ps(latitude_delta_f32x16, half_f32x16);
334
+ __m512 longitude_delta_half_f32x16 = _mm512_mul_ps(longitude_delta_f32x16, half_f32x16);
335
+ __m512 sin_latitude_delta_half_f32x16 = nk_sin_f32x16_skylake_(latitude_delta_half_f32x16);
336
+ __m512 sin_longitude_delta_half_f32x16 = nk_sin_f32x16_skylake_(longitude_delta_half_f32x16);
337
+ __m512 sin_squared_latitude_delta_half_f32x16 = _mm512_mul_ps(sin_latitude_delta_half_f32x16,
338
+ sin_latitude_delta_half_f32x16);
339
+ __m512 sin_squared_longitude_delta_half_f32x16 = _mm512_mul_ps(sin_longitude_delta_half_f32x16,
340
+ sin_longitude_delta_half_f32x16);
341
+
342
+ // Latitude cosine product
343
+ __m512 cos_first_latitude_f32x16 = nk_cos_f32x16_skylake_(first_latitudes_f32x16);
344
+ __m512 cos_second_latitude_f32x16 = nk_cos_f32x16_skylake_(second_latitudes_f32x16);
345
+ __m512 cos_latitude_product_f32x16 = _mm512_mul_ps(cos_first_latitude_f32x16, cos_second_latitude_f32x16);
346
+
347
+ // a = sin²(Δlat/2) + cos(lat1) × cos(lat2) × sin²(Δlon/2)
348
+ __m512 haversine_term_f32x16 = _mm512_add_ps(
349
+ sin_squared_latitude_delta_half_f32x16,
350
+ _mm512_mul_ps(cos_latitude_product_f32x16, sin_squared_longitude_delta_half_f32x16));
351
+
352
+ // Clamp to [0, 1] to avoid NaN from sqrt of negative numbers (due to floating point errors)
353
+ __m512 zero_f32x16 = _mm512_setzero_ps();
354
+ haversine_term_f32x16 = _mm512_max_ps(zero_f32x16, _mm512_min_ps(one_f32x16, haversine_term_f32x16));
355
+
356
+ // Central angle: c = 2 × atan2(√a, √(1-a))
357
+ __m512 sqrt_haversine_f32x16 = _mm512_sqrt_ps(haversine_term_f32x16);
358
+ __m512 sqrt_complement_f32x16 = _mm512_sqrt_ps(_mm512_sub_ps(one_f32x16, haversine_term_f32x16));
359
+ __m512 central_angle_f32x16 = _mm512_mul_ps(
360
+ two_f32x16, nk_atan2_f32x16_skylake_(sqrt_haversine_f32x16, sqrt_complement_f32x16));
361
+
362
+ return _mm512_mul_ps(earth_radius_f32x16, central_angle_f32x16);
363
+ }
364
+
365
+ NK_PUBLIC void nk_haversine_f32_skylake( //
366
+ nk_f32_t const *a_lats, nk_f32_t const *a_lons, //
367
+ nk_f32_t const *b_lats, nk_f32_t const *b_lons, //
368
+ nk_size_t n, nk_f32_t *results) {
369
+
370
+ while (n >= 16) {
371
+ __m512 first_latitudes_f32x16 = _mm512_loadu_ps(a_lats);
372
+ __m512 first_longitudes_f32x16 = _mm512_loadu_ps(a_lons);
373
+ __m512 second_latitudes_f32x16 = _mm512_loadu_ps(b_lats);
374
+ __m512 second_longitudes_f32x16 = _mm512_loadu_ps(b_lons);
375
+
376
+ __m512 distances_f32x16 = nk_haversine_f32x16_skylake_(first_latitudes_f32x16, first_longitudes_f32x16,
377
+ second_latitudes_f32x16, second_longitudes_f32x16);
378
+ _mm512_storeu_ps(results, distances_f32x16);
379
+
380
+ a_lats += 16, a_lons += 16, b_lats += 16, b_lons += 16, results += 16, n -= 16;
381
+ }
382
+
383
+ // Handle remaining elements with masked operations
384
+ if (n > 0) {
385
+ __mmask16 mask = (__mmask16)_bzhi_u32(0xFFFF, n);
386
+ __m512 first_latitudes_f32x16 = _mm512_maskz_loadu_ps(mask, a_lats);
387
+ __m512 first_longitudes_f32x16 = _mm512_maskz_loadu_ps(mask, a_lons);
388
+ __m512 second_latitudes_f32x16 = _mm512_maskz_loadu_ps(mask, b_lats);
389
+ __m512 second_longitudes_f32x16 = _mm512_maskz_loadu_ps(mask, b_lons);
390
+
391
+ __m512 distances_f32x16 = nk_haversine_f32x16_skylake_(first_latitudes_f32x16, first_longitudes_f32x16,
392
+ second_latitudes_f32x16, second_longitudes_f32x16);
393
+ _mm512_mask_storeu_ps(results, mask, distances_f32x16);
394
+ }
395
+ }
396
+
397
+ /**
398
+ * @brief AVX-512 helper for Vincenty's geodesic distance on 16 f32 point pairs.
399
+ * @note This is a true SIMD implementation using masked convergence tracking.
400
+ */
401
+ NK_INTERNAL __m512 nk_vincenty_f32x16_skylake_( //
402
+ __m512 first_latitudes_f32x16, __m512 first_longitudes_f32x16, //
403
+ __m512 second_latitudes_f32x16, __m512 second_longitudes_f32x16) {
404
+
405
+ __m512 const equatorial_radius_f32x16 = _mm512_set1_ps((float)NK_EARTH_ELLIPSOID_EQUATORIAL_RADIUS);
406
+ __m512 const polar_radius_f32x16 = _mm512_set1_ps((float)NK_EARTH_ELLIPSOID_POLAR_RADIUS);
407
+ __m512 const flattening_f32x16 = _mm512_set1_ps(1.0f / (float)NK_EARTH_ELLIPSOID_INVERSE_FLATTENING);
408
+ __m512 const convergence_threshold_f32x16 = _mm512_set1_ps(NK_VINCENTY_CONVERGENCE_THRESHOLD_F32);
409
+ __m512 const one_f32x16 = _mm512_set1_ps(1.0f);
410
+ __m512 const two_f32x16 = _mm512_set1_ps(2.0f);
411
+ __m512 const three_f32x16 = _mm512_set1_ps(3.0f);
412
+ __m512 const four_f32x16 = _mm512_set1_ps(4.0f);
413
+ __m512 const six_f32x16 = _mm512_set1_ps(6.0f);
414
+ __m512 const sixteen_f32x16 = _mm512_set1_ps(16.0f);
415
+
416
+ // Longitude difference
417
+ __m512 longitude_difference_f32x16 = _mm512_sub_ps(second_longitudes_f32x16, first_longitudes_f32x16);
418
+
419
+ // Reduced latitudes: tan(U) = (1-f) * tan(lat)
420
+ __m512 one_minus_f_f32x16 = _mm512_sub_ps(one_f32x16, flattening_f32x16);
421
+ __m512 tan_first_f32x16 = _mm512_div_ps(nk_sin_f32x16_skylake_(first_latitudes_f32x16),
422
+ nk_cos_f32x16_skylake_(first_latitudes_f32x16));
423
+ __m512 tan_second_f32x16 = _mm512_div_ps(nk_sin_f32x16_skylake_(second_latitudes_f32x16),
424
+ nk_cos_f32x16_skylake_(second_latitudes_f32x16));
425
+ __m512 tan_reduced_first_f32x16 = _mm512_mul_ps(one_minus_f_f32x16, tan_first_f32x16);
426
+ __m512 tan_reduced_second_f32x16 = _mm512_mul_ps(one_minus_f_f32x16, tan_second_f32x16);
427
+
428
+ // cos(U) = 1/√(1 + tan²(U)), sin(U) = tan(U) × cos(U)
429
+ __m512 cos_reduced_first_f32x16 = _mm512_div_ps(
430
+ one_f32x16, _mm512_sqrt_ps(_mm512_fmadd_ps(tan_reduced_first_f32x16, tan_reduced_first_f32x16, one_f32x16)));
431
+ __m512 sin_reduced_first_f32x16 = _mm512_mul_ps(tan_reduced_first_f32x16, cos_reduced_first_f32x16);
432
+ __m512 cos_reduced_second_f32x16 = _mm512_div_ps(
433
+ one_f32x16, _mm512_sqrt_ps(_mm512_fmadd_ps(tan_reduced_second_f32x16, tan_reduced_second_f32x16, one_f32x16)));
434
+ __m512 sin_reduced_second_f32x16 = _mm512_mul_ps(tan_reduced_second_f32x16, cos_reduced_second_f32x16);
435
+
436
+ // Initialize lambda_f32x16 and tracking variables
437
+ __m512 lambda_f32x16 = longitude_difference_f32x16;
438
+ __m512 sin_angular_distance_f32x16, cos_angular_distance_f32x16, angular_distance_f32x16;
439
+ __m512 sin_azimuth_f32x16, cos_squared_azimuth_f32x16, cos_double_angular_midpoint_f32x16;
440
+
441
+ // Track convergence and coincident points
442
+ __mmask16 converged_mask = 0;
443
+ __mmask16 coincident_mask = 0;
444
+
445
+ for (nk_u32_t iteration = 0; iteration < NK_VINCENTY_MAX_ITERATIONS && converged_mask != 0xFFFF; ++iteration) {
446
+ __m512 sin_lambda_f32x16 = nk_sin_f32x16_skylake_(lambda_f32x16);
447
+ __m512 cos_lambda_f32x16 = nk_cos_f32x16_skylake_(lambda_f32x16);
448
+
449
+ // sin²(angular_distance_f32x16) = (cos(U₂) × sin(λ))² + (cos(U₁) × sin(U₂) - sin(U₁) × cos(U₂) × cos(λ))²
450
+ __m512 cross_term_f32x16 = _mm512_mul_ps(cos_reduced_second_f32x16, sin_lambda_f32x16);
451
+ __m512 mixed_term_f32x16 = _mm512_sub_ps(
452
+ _mm512_mul_ps(cos_reduced_first_f32x16, sin_reduced_second_f32x16),
453
+ _mm512_mul_ps(_mm512_mul_ps(sin_reduced_first_f32x16, cos_reduced_second_f32x16), cos_lambda_f32x16));
454
+ __m512 sin_angular_dist_sq_f32x16 = _mm512_fmadd_ps(cross_term_f32x16, cross_term_f32x16,
455
+ _mm512_mul_ps(mixed_term_f32x16, mixed_term_f32x16));
456
+ sin_angular_distance_f32x16 = _mm512_sqrt_ps(sin_angular_dist_sq_f32x16);
457
+
458
+ // Check for coincident points (sin_angular_distance_f32x16 ≈ 0)
459
+ coincident_mask = _mm512_cmp_ps_mask(sin_angular_distance_f32x16, _mm512_set1_ps(1e-7f), _CMP_LT_OS);
460
+
461
+ // cos(angular_distance_f32x16) = sin(U₁) × sin(U₂) + cos(U₁) × cos(U₂) × cos(λ)
462
+ cos_angular_distance_f32x16 = _mm512_fmadd_ps(
463
+ _mm512_mul_ps(cos_reduced_first_f32x16, cos_reduced_second_f32x16), cos_lambda_f32x16,
464
+ _mm512_mul_ps(sin_reduced_first_f32x16, sin_reduced_second_f32x16));
465
+
466
+ // angular_distance_f32x16 = atan2(sin, cos)
467
+ angular_distance_f32x16 = nk_atan2_f32x16_skylake_(sin_angular_distance_f32x16, cos_angular_distance_f32x16);
468
+
469
+ // sin(azimuth) = cos(U₁) × cos(U₂) × sin(λ) / sin(angular_distance_f32x16)
470
+ // Use masked divide: zero result for coincident lanes, avoids division by zero
471
+ sin_azimuth_f32x16 = _mm512_maskz_div_ps(
472
+ _knot_mask16(coincident_mask),
473
+ _mm512_mul_ps(_mm512_mul_ps(cos_reduced_first_f32x16, cos_reduced_second_f32x16), sin_lambda_f32x16),
474
+ sin_angular_distance_f32x16);
475
+ cos_squared_azimuth_f32x16 = _mm512_sub_ps(one_f32x16, _mm512_mul_ps(sin_azimuth_f32x16, sin_azimuth_f32x16));
476
+
477
+ // Handle equatorial case: cos²α = 0
478
+ __mmask16 equatorial_mask = _mm512_cmp_ps_mask(cos_squared_azimuth_f32x16, _mm512_set1_ps(1e-7f), _CMP_LT_OS);
479
+
480
+ // cos(2σₘ) = cos(σ) - 2 × sin(U₁) × sin(U₂) / cos²(α)
481
+ // Use masked divide: for equatorial lanes, quotient_f32x16 = cos_angular_distance_f32x16 (passthrough),
482
+ // so subtraction yields zero. Avoids division by zero.
483
+ __m512 sin_product_f32x16 = _mm512_mul_ps(sin_reduced_first_f32x16, sin_reduced_second_f32x16);
484
+ __m512 quotient_f32x16 = _mm512_mask_div_ps(cos_angular_distance_f32x16, _knot_mask16(equatorial_mask),
485
+ _mm512_mul_ps(two_f32x16, sin_product_f32x16),
486
+ cos_squared_azimuth_f32x16);
487
+ cos_double_angular_midpoint_f32x16 = _mm512_sub_ps(cos_angular_distance_f32x16, quotient_f32x16);
488
+
489
+ // C = f/16 * cos²α * (4 + f*(4 - 3*cos²α))
490
+ __m512 correction_factor_f32x16 = _mm512_mul_ps(
491
+ _mm512_div_ps(flattening_f32x16, sixteen_f32x16),
492
+ _mm512_mul_ps(
493
+ cos_squared_azimuth_f32x16,
494
+ _mm512_fmadd_ps(flattening_f32x16,
495
+ _mm512_fnmadd_ps(three_f32x16, cos_squared_azimuth_f32x16, four_f32x16), four_f32x16)));
496
+
497
+ // λ' = L + (1-C) × f × sin(α) × (σ + C × sin(σ) × (cos(2σₘ) + C × cos(σ) × (-1 + 2 × cos²(2σₘ))))
498
+ __m512 cos_2sm_sq_f32x16 = _mm512_mul_ps(cos_double_angular_midpoint_f32x16,
499
+ cos_double_angular_midpoint_f32x16);
500
+ // innermost_f32x16 = -1 + 2 × cos²(2σₘ)
501
+ __m512 innermost_f32x16 = _mm512_fmadd_ps(two_f32x16, cos_2sm_sq_f32x16, _mm512_set1_ps(-1.0f));
502
+ // middle_f32x16 = cos(2σₘ) + C × cos(σ) × innermost_f32x16
503
+ __m512 middle_f32x16 = _mm512_fmadd_ps(_mm512_mul_ps(correction_factor_f32x16, cos_angular_distance_f32x16),
504
+ innermost_f32x16, cos_double_angular_midpoint_f32x16);
505
+ // inner_f32x16 = C × sin(σ) × middle_f32x16
506
+ __m512 inner_f32x16 = _mm512_mul_ps(_mm512_mul_ps(correction_factor_f32x16, sin_angular_distance_f32x16),
507
+ middle_f32x16);
508
+
509
+ // λ' = L + (1-C) * f * sin_α * (σ + inner_f32x16)
510
+ __m512 lambda_new_f32x16 = _mm512_fmadd_ps(
511
+ _mm512_mul_ps(_mm512_mul_ps(_mm512_sub_ps(one_f32x16, correction_factor_f32x16), flattening_f32x16),
512
+ sin_azimuth_f32x16),
513
+ _mm512_add_ps(angular_distance_f32x16, inner_f32x16), longitude_difference_f32x16);
514
+
515
+ // Check convergence: |λ - λ'| < threshold
516
+ __m512 lambda_diff_f32x16 = _mm512_abs_ps(_mm512_sub_ps(lambda_new_f32x16, lambda_f32x16));
517
+ converged_mask = _mm512_cmp_ps_mask(lambda_diff_f32x16, convergence_threshold_f32x16, _CMP_LT_OS);
518
+
519
+ lambda_f32x16 = lambda_new_f32x16;
520
+ }
521
+
522
+ // Final distance calculation
523
+ // u² = cos²α * (a² - b²) / b²
524
+ __m512 a_sq_f32x16 = _mm512_mul_ps(equatorial_radius_f32x16, equatorial_radius_f32x16);
525
+ __m512 b_sq_f32x16 = _mm512_mul_ps(polar_radius_f32x16, polar_radius_f32x16);
526
+ __m512 u_squared_f32x16 = _mm512_div_ps(
527
+ _mm512_mul_ps(cos_squared_azimuth_f32x16, _mm512_sub_ps(a_sq_f32x16, b_sq_f32x16)), b_sq_f32x16);
528
+
529
+ // A = 1 + u²/16384 * (4096 + u²*(-768 + u²*(320 - 175*u²)))
530
+ __m512 series_a_f32x16 = _mm512_fmadd_ps(u_squared_f32x16, _mm512_set1_ps(-175.0f), _mm512_set1_ps(320.0f));
531
+ series_a_f32x16 = _mm512_fmadd_ps(u_squared_f32x16, series_a_f32x16, _mm512_set1_ps(-768.0f));
532
+ series_a_f32x16 = _mm512_fmadd_ps(u_squared_f32x16, series_a_f32x16, _mm512_set1_ps(4096.0f));
533
+ series_a_f32x16 = _mm512_fmadd_ps(_mm512_div_ps(u_squared_f32x16, _mm512_set1_ps(16384.0f)), series_a_f32x16,
534
+ one_f32x16);
535
+
536
+ // B = u²/1024 * (256 + u²*(-128 + u²*(74 - 47*u²)))
537
+ __m512 series_b_f32x16 = _mm512_fmadd_ps(u_squared_f32x16, _mm512_set1_ps(-47.0f), _mm512_set1_ps(74.0f));
538
+ series_b_f32x16 = _mm512_fmadd_ps(u_squared_f32x16, series_b_f32x16, _mm512_set1_ps(-128.0f));
539
+ series_b_f32x16 = _mm512_fmadd_ps(u_squared_f32x16, series_b_f32x16, _mm512_set1_ps(256.0f));
540
+ series_b_f32x16 = _mm512_mul_ps(_mm512_div_ps(u_squared_f32x16, _mm512_set1_ps(1024.0f)), series_b_f32x16);
541
+
542
+ // Δσ = B × sin(σ) × (cos(2σₘ) +
543
+ // B/4 × (cos(σ) × (-1 + 2 × cos²(2σₘ)) - B/6 × cos(2σₘ) × (-3 + 4 × sin²(σ)) × (-3 + 4 × cos²(2σₘ))))
544
+ __m512 cos_2sm_sq_f32x16 = _mm512_mul_ps(cos_double_angular_midpoint_f32x16, cos_double_angular_midpoint_f32x16);
545
+ __m512 sin_sq_f32x16 = _mm512_mul_ps(sin_angular_distance_f32x16, sin_angular_distance_f32x16);
546
+ __m512 term1_f32x16 = _mm512_fmadd_ps(two_f32x16, cos_2sm_sq_f32x16, _mm512_set1_ps(-1.0f));
547
+ term1_f32x16 = _mm512_mul_ps(cos_angular_distance_f32x16, term1_f32x16);
548
+ __m512 term2_f32x16 = _mm512_fmadd_ps(four_f32x16, sin_sq_f32x16, _mm512_set1_ps(-3.0f));
549
+ __m512 term3_f32x16 = _mm512_fmadd_ps(four_f32x16, cos_2sm_sq_f32x16, _mm512_set1_ps(-3.0f));
550
+ term2_f32x16 = _mm512_mul_ps(
551
+ _mm512_mul_ps(_mm512_div_ps(series_b_f32x16, six_f32x16), cos_double_angular_midpoint_f32x16),
552
+ _mm512_mul_ps(term2_f32x16, term3_f32x16));
553
+ __m512 delta_sigma_f32x16 = _mm512_mul_ps(
554
+ series_b_f32x16, _mm512_mul_ps(sin_angular_distance_f32x16,
555
+ _mm512_add_ps(cos_double_angular_midpoint_f32x16,
556
+ _mm512_mul_ps(_mm512_div_ps(series_b_f32x16, four_f32x16),
557
+ _mm512_sub_ps(term1_f32x16, term2_f32x16)))));
558
+
559
+ // s = b * A * (σ - Δσ)
560
+ __m512 distances_f32x16 = _mm512_mul_ps(_mm512_mul_ps(polar_radius_f32x16, series_a_f32x16),
561
+ _mm512_sub_ps(angular_distance_f32x16, delta_sigma_f32x16));
562
+
563
+ // Set coincident points to zero
564
+ distances_f32x16 = _mm512_mask_blend_ps(coincident_mask, distances_f32x16, _mm512_setzero_ps());
565
+
566
+ return distances_f32x16;
567
+ }
568
+
569
+ NK_PUBLIC void nk_vincenty_f32_skylake( //
570
+ nk_f32_t const *a_lats, nk_f32_t const *a_lons, //
571
+ nk_f32_t const *b_lats, nk_f32_t const *b_lons, //
572
+ nk_size_t n, nk_f32_t *results) {
573
+
574
+ while (n >= 16) {
575
+ __m512 first_latitudes_f32x16 = _mm512_loadu_ps(a_lats);
576
+ __m512 first_longitudes_f32x16 = _mm512_loadu_ps(a_lons);
577
+ __m512 second_latitudes_f32x16 = _mm512_loadu_ps(b_lats);
578
+ __m512 second_longitudes_f32x16 = _mm512_loadu_ps(b_lons);
579
+
580
+ __m512 distances_f32x16 = nk_vincenty_f32x16_skylake_(first_latitudes_f32x16, first_longitudes_f32x16,
581
+ second_latitudes_f32x16, second_longitudes_f32x16);
582
+ _mm512_storeu_ps(results, distances_f32x16);
583
+
584
+ a_lats += 16, a_lons += 16, b_lats += 16, b_lons += 16, results += 16, n -= 16;
585
+ }
586
+
587
+ // Handle remaining elements with masked operations
588
+ if (n > 0) {
589
+ __mmask16 mask = (__mmask16)_bzhi_u32(0xFFFF, n);
590
+ __m512 first_latitudes_f32x16 = _mm512_maskz_loadu_ps(mask, a_lats);
591
+ __m512 first_longitudes_f32x16 = _mm512_maskz_loadu_ps(mask, a_lons);
592
+ __m512 second_latitudes_f32x16 = _mm512_maskz_loadu_ps(mask, b_lats);
593
+ __m512 second_longitudes_f32x16 = _mm512_maskz_loadu_ps(mask, b_lons);
594
+
595
+ __m512 distances_f32x16 = nk_vincenty_f32x16_skylake_(first_latitudes_f32x16, first_longitudes_f32x16,
596
+ second_latitudes_f32x16, second_longitudes_f32x16);
597
+ _mm512_mask_storeu_ps(results, mask, distances_f32x16);
598
+ }
599
+ }
600
+
601
+ #if defined(__clang__)
602
+ #pragma clang attribute pop
603
+ #elif defined(__GNUC__)
604
+ #pragma GCC pop_options
605
+ #endif
606
+
607
+ #if defined(__cplusplus)
608
+ } // extern "C"
609
+ #endif
610
+
611
+ #endif // NK_TARGET_SKYLAKE
612
+ #endif // NK_TARGET_X8664_
613
+ #endif // NK_GEOSPATIAL_SKYLAKE_H