numkong 7.0.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 (294) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +495 -0
  3. package/binding.gyp +540 -0
  4. package/c/dispatch.h +512 -0
  5. package/c/dispatch_bf16.c +389 -0
  6. package/c/dispatch_bf16c.c +52 -0
  7. package/c/dispatch_e2m3.c +263 -0
  8. package/c/dispatch_e3m2.c +243 -0
  9. package/c/dispatch_e4m3.c +276 -0
  10. package/c/dispatch_e5m2.c +272 -0
  11. package/c/dispatch_f16.c +376 -0
  12. package/c/dispatch_f16c.c +58 -0
  13. package/c/dispatch_f32.c +378 -0
  14. package/c/dispatch_f32c.c +99 -0
  15. package/c/dispatch_f64.c +296 -0
  16. package/c/dispatch_f64c.c +98 -0
  17. package/c/dispatch_i16.c +96 -0
  18. package/c/dispatch_i32.c +89 -0
  19. package/c/dispatch_i4.c +150 -0
  20. package/c/dispatch_i64.c +86 -0
  21. package/c/dispatch_i8.c +289 -0
  22. package/c/dispatch_other.c +330 -0
  23. package/c/dispatch_u1.c +148 -0
  24. package/c/dispatch_u16.c +124 -0
  25. package/c/dispatch_u32.c +118 -0
  26. package/c/dispatch_u4.c +150 -0
  27. package/c/dispatch_u64.c +102 -0
  28. package/c/dispatch_u8.c +303 -0
  29. package/c/numkong.c +950 -0
  30. package/include/README.md +573 -0
  31. package/include/module.modulemap +129 -0
  32. package/include/numkong/attention/sapphireamx.h +1361 -0
  33. package/include/numkong/attention/sme.h +2066 -0
  34. package/include/numkong/attention.h +49 -0
  35. package/include/numkong/capabilities.h +748 -0
  36. package/include/numkong/cast/README.md +262 -0
  37. package/include/numkong/cast/haswell.h +975 -0
  38. package/include/numkong/cast/icelake.h +470 -0
  39. package/include/numkong/cast/neon.h +1192 -0
  40. package/include/numkong/cast/rvv.h +1021 -0
  41. package/include/numkong/cast/sapphire.h +262 -0
  42. package/include/numkong/cast/serial.h +2262 -0
  43. package/include/numkong/cast/skylake.h +856 -0
  44. package/include/numkong/cast/v128relaxed.h +180 -0
  45. package/include/numkong/cast.h +230 -0
  46. package/include/numkong/curved/README.md +223 -0
  47. package/include/numkong/curved/genoa.h +182 -0
  48. package/include/numkong/curved/haswell.h +276 -0
  49. package/include/numkong/curved/neon.h +205 -0
  50. package/include/numkong/curved/neonbfdot.h +212 -0
  51. package/include/numkong/curved/neonhalf.h +212 -0
  52. package/include/numkong/curved/rvv.h +305 -0
  53. package/include/numkong/curved/serial.h +207 -0
  54. package/include/numkong/curved/skylake.h +457 -0
  55. package/include/numkong/curved/smef64.h +506 -0
  56. package/include/numkong/curved.h +517 -0
  57. package/include/numkong/curved.hpp +144 -0
  58. package/include/numkong/dot/README.md +425 -0
  59. package/include/numkong/dot/alder.h +563 -0
  60. package/include/numkong/dot/genoa.h +315 -0
  61. package/include/numkong/dot/haswell.h +1688 -0
  62. package/include/numkong/dot/icelake.h +883 -0
  63. package/include/numkong/dot/neon.h +818 -0
  64. package/include/numkong/dot/neonbfdot.h +244 -0
  65. package/include/numkong/dot/neonfhm.h +360 -0
  66. package/include/numkong/dot/neonhalf.h +198 -0
  67. package/include/numkong/dot/neonsdot.h +508 -0
  68. package/include/numkong/dot/rvv.h +714 -0
  69. package/include/numkong/dot/rvvbb.h +72 -0
  70. package/include/numkong/dot/rvvbf16.h +123 -0
  71. package/include/numkong/dot/rvvhalf.h +129 -0
  72. package/include/numkong/dot/sapphire.h +141 -0
  73. package/include/numkong/dot/serial.h +838 -0
  74. package/include/numkong/dot/sierra.h +405 -0
  75. package/include/numkong/dot/skylake.h +1084 -0
  76. package/include/numkong/dot/sve.h +379 -0
  77. package/include/numkong/dot/svebfdot.h +74 -0
  78. package/include/numkong/dot/svehalf.h +123 -0
  79. package/include/numkong/dot/v128relaxed.h +1258 -0
  80. package/include/numkong/dot.h +1070 -0
  81. package/include/numkong/dot.hpp +94 -0
  82. package/include/numkong/dots/README.md +496 -0
  83. package/include/numkong/dots/alder.h +114 -0
  84. package/include/numkong/dots/genoa.h +94 -0
  85. package/include/numkong/dots/haswell.h +295 -0
  86. package/include/numkong/dots/icelake.h +171 -0
  87. package/include/numkong/dots/neon.h +120 -0
  88. package/include/numkong/dots/neonbfdot.h +58 -0
  89. package/include/numkong/dots/neonfhm.h +94 -0
  90. package/include/numkong/dots/neonhalf.h +57 -0
  91. package/include/numkong/dots/neonsdot.h +108 -0
  92. package/include/numkong/dots/rvv.h +2486 -0
  93. package/include/numkong/dots/sapphireamx.h +3973 -0
  94. package/include/numkong/dots/serial.h +2844 -0
  95. package/include/numkong/dots/sierra.h +97 -0
  96. package/include/numkong/dots/skylake.h +196 -0
  97. package/include/numkong/dots/sme.h +5372 -0
  98. package/include/numkong/dots/smebi32.h +461 -0
  99. package/include/numkong/dots/smef64.h +1318 -0
  100. package/include/numkong/dots/smehalf.h +47 -0
  101. package/include/numkong/dots/v128relaxed.h +294 -0
  102. package/include/numkong/dots.h +2804 -0
  103. package/include/numkong/dots.hpp +639 -0
  104. package/include/numkong/each/README.md +469 -0
  105. package/include/numkong/each/haswell.h +1658 -0
  106. package/include/numkong/each/icelake.h +272 -0
  107. package/include/numkong/each/neon.h +1104 -0
  108. package/include/numkong/each/neonbfdot.h +212 -0
  109. package/include/numkong/each/neonhalf.h +410 -0
  110. package/include/numkong/each/rvv.h +1121 -0
  111. package/include/numkong/each/sapphire.h +477 -0
  112. package/include/numkong/each/serial.h +260 -0
  113. package/include/numkong/each/skylake.h +1562 -0
  114. package/include/numkong/each.h +2146 -0
  115. package/include/numkong/each.hpp +434 -0
  116. package/include/numkong/geospatial/README.md +147 -0
  117. package/include/numkong/geospatial/haswell.h +593 -0
  118. package/include/numkong/geospatial/neon.h +571 -0
  119. package/include/numkong/geospatial/rvv.h +701 -0
  120. package/include/numkong/geospatial/serial.h +309 -0
  121. package/include/numkong/geospatial/skylake.h +577 -0
  122. package/include/numkong/geospatial/v128relaxed.h +613 -0
  123. package/include/numkong/geospatial.h +453 -0
  124. package/include/numkong/geospatial.hpp +235 -0
  125. package/include/numkong/matrix.hpp +336 -0
  126. package/include/numkong/maxsim/README.md +187 -0
  127. package/include/numkong/maxsim/alder.h +511 -0
  128. package/include/numkong/maxsim/genoa.h +115 -0
  129. package/include/numkong/maxsim/haswell.h +553 -0
  130. package/include/numkong/maxsim/icelake.h +480 -0
  131. package/include/numkong/maxsim/neonsdot.h +394 -0
  132. package/include/numkong/maxsim/sapphireamx.h +877 -0
  133. package/include/numkong/maxsim/serial.h +490 -0
  134. package/include/numkong/maxsim/sme.h +929 -0
  135. package/include/numkong/maxsim/v128relaxed.h +280 -0
  136. package/include/numkong/maxsim.h +571 -0
  137. package/include/numkong/maxsim.hpp +133 -0
  138. package/include/numkong/mesh/README.md +227 -0
  139. package/include/numkong/mesh/haswell.h +2235 -0
  140. package/include/numkong/mesh/neon.h +1329 -0
  141. package/include/numkong/mesh/neonbfdot.h +842 -0
  142. package/include/numkong/mesh/neonhalf.h +616 -0
  143. package/include/numkong/mesh/rvv.h +916 -0
  144. package/include/numkong/mesh/serial.h +742 -0
  145. package/include/numkong/mesh/skylake.h +1135 -0
  146. package/include/numkong/mesh/v128relaxed.h +1052 -0
  147. package/include/numkong/mesh.h +652 -0
  148. package/include/numkong/mesh.hpp +762 -0
  149. package/include/numkong/numkong.h +78 -0
  150. package/include/numkong/numkong.hpp +57 -0
  151. package/include/numkong/probability/README.md +173 -0
  152. package/include/numkong/probability/haswell.h +267 -0
  153. package/include/numkong/probability/neon.h +225 -0
  154. package/include/numkong/probability/rvv.h +409 -0
  155. package/include/numkong/probability/serial.h +169 -0
  156. package/include/numkong/probability/skylake.h +324 -0
  157. package/include/numkong/probability.h +383 -0
  158. package/include/numkong/probability.hpp +120 -0
  159. package/include/numkong/random.h +50 -0
  160. package/include/numkong/random.hpp +285 -0
  161. package/include/numkong/reduce/README.md +547 -0
  162. package/include/numkong/reduce/alder.h +632 -0
  163. package/include/numkong/reduce/genoa.h +201 -0
  164. package/include/numkong/reduce/haswell.h +3783 -0
  165. package/include/numkong/reduce/icelake.h +549 -0
  166. package/include/numkong/reduce/neon.h +3841 -0
  167. package/include/numkong/reduce/neonbfdot.h +353 -0
  168. package/include/numkong/reduce/neonfhm.h +665 -0
  169. package/include/numkong/reduce/neonhalf.h +157 -0
  170. package/include/numkong/reduce/neonsdot.h +357 -0
  171. package/include/numkong/reduce/rvv.h +3407 -0
  172. package/include/numkong/reduce/serial.h +757 -0
  173. package/include/numkong/reduce/sierra.h +338 -0
  174. package/include/numkong/reduce/skylake.h +3792 -0
  175. package/include/numkong/reduce/v128relaxed.h +2302 -0
  176. package/include/numkong/reduce.h +1597 -0
  177. package/include/numkong/reduce.hpp +633 -0
  178. package/include/numkong/scalar/README.md +89 -0
  179. package/include/numkong/scalar/haswell.h +113 -0
  180. package/include/numkong/scalar/neon.h +122 -0
  181. package/include/numkong/scalar/neonhalf.h +70 -0
  182. package/include/numkong/scalar/rvv.h +211 -0
  183. package/include/numkong/scalar/sapphire.h +63 -0
  184. package/include/numkong/scalar/serial.h +332 -0
  185. package/include/numkong/scalar/v128relaxed.h +56 -0
  186. package/include/numkong/scalar.h +683 -0
  187. package/include/numkong/set/README.md +179 -0
  188. package/include/numkong/set/haswell.h +334 -0
  189. package/include/numkong/set/icelake.h +485 -0
  190. package/include/numkong/set/neon.h +364 -0
  191. package/include/numkong/set/rvv.h +226 -0
  192. package/include/numkong/set/rvvbb.h +117 -0
  193. package/include/numkong/set/serial.h +174 -0
  194. package/include/numkong/set/sve.h +185 -0
  195. package/include/numkong/set/v128relaxed.h +240 -0
  196. package/include/numkong/set.h +457 -0
  197. package/include/numkong/set.hpp +114 -0
  198. package/include/numkong/sets/README.md +149 -0
  199. package/include/numkong/sets/haswell.h +63 -0
  200. package/include/numkong/sets/icelake.h +66 -0
  201. package/include/numkong/sets/neon.h +61 -0
  202. package/include/numkong/sets/serial.h +43 -0
  203. package/include/numkong/sets/smebi32.h +1099 -0
  204. package/include/numkong/sets/v128relaxed.h +58 -0
  205. package/include/numkong/sets.h +339 -0
  206. package/include/numkong/sparse/README.md +156 -0
  207. package/include/numkong/sparse/icelake.h +463 -0
  208. package/include/numkong/sparse/neon.h +288 -0
  209. package/include/numkong/sparse/serial.h +117 -0
  210. package/include/numkong/sparse/sve2.h +507 -0
  211. package/include/numkong/sparse/turin.h +322 -0
  212. package/include/numkong/sparse.h +363 -0
  213. package/include/numkong/sparse.hpp +113 -0
  214. package/include/numkong/spatial/README.md +435 -0
  215. package/include/numkong/spatial/alder.h +607 -0
  216. package/include/numkong/spatial/genoa.h +290 -0
  217. package/include/numkong/spatial/haswell.h +960 -0
  218. package/include/numkong/spatial/icelake.h +586 -0
  219. package/include/numkong/spatial/neon.h +773 -0
  220. package/include/numkong/spatial/neonbfdot.h +165 -0
  221. package/include/numkong/spatial/neonhalf.h +118 -0
  222. package/include/numkong/spatial/neonsdot.h +261 -0
  223. package/include/numkong/spatial/rvv.h +984 -0
  224. package/include/numkong/spatial/rvvbf16.h +123 -0
  225. package/include/numkong/spatial/rvvhalf.h +117 -0
  226. package/include/numkong/spatial/sapphire.h +343 -0
  227. package/include/numkong/spatial/serial.h +346 -0
  228. package/include/numkong/spatial/sierra.h +323 -0
  229. package/include/numkong/spatial/skylake.h +606 -0
  230. package/include/numkong/spatial/sve.h +224 -0
  231. package/include/numkong/spatial/svebfdot.h +122 -0
  232. package/include/numkong/spatial/svehalf.h +109 -0
  233. package/include/numkong/spatial/v128relaxed.h +717 -0
  234. package/include/numkong/spatial.h +1425 -0
  235. package/include/numkong/spatial.hpp +183 -0
  236. package/include/numkong/spatials/README.md +580 -0
  237. package/include/numkong/spatials/alder.h +94 -0
  238. package/include/numkong/spatials/genoa.h +94 -0
  239. package/include/numkong/spatials/haswell.h +219 -0
  240. package/include/numkong/spatials/icelake.h +113 -0
  241. package/include/numkong/spatials/neon.h +109 -0
  242. package/include/numkong/spatials/neonbfdot.h +60 -0
  243. package/include/numkong/spatials/neonfhm.h +92 -0
  244. package/include/numkong/spatials/neonhalf.h +58 -0
  245. package/include/numkong/spatials/neonsdot.h +109 -0
  246. package/include/numkong/spatials/rvv.h +1960 -0
  247. package/include/numkong/spatials/sapphireamx.h +1149 -0
  248. package/include/numkong/spatials/serial.h +226 -0
  249. package/include/numkong/spatials/sierra.h +96 -0
  250. package/include/numkong/spatials/skylake.h +184 -0
  251. package/include/numkong/spatials/sme.h +1901 -0
  252. package/include/numkong/spatials/smef64.h +465 -0
  253. package/include/numkong/spatials/v128relaxed.h +240 -0
  254. package/include/numkong/spatials.h +3021 -0
  255. package/include/numkong/spatials.hpp +508 -0
  256. package/include/numkong/tensor.hpp +1592 -0
  257. package/include/numkong/trigonometry/README.md +184 -0
  258. package/include/numkong/trigonometry/haswell.h +652 -0
  259. package/include/numkong/trigonometry/neon.h +639 -0
  260. package/include/numkong/trigonometry/rvv.h +699 -0
  261. package/include/numkong/trigonometry/serial.h +703 -0
  262. package/include/numkong/trigonometry/skylake.h +721 -0
  263. package/include/numkong/trigonometry/v128relaxed.h +666 -0
  264. package/include/numkong/trigonometry.h +467 -0
  265. package/include/numkong/trigonometry.hpp +166 -0
  266. package/include/numkong/types.h +1384 -0
  267. package/include/numkong/types.hpp +5603 -0
  268. package/include/numkong/vector.hpp +698 -0
  269. package/javascript/README.md +246 -0
  270. package/javascript/dist/cjs/numkong-wasm.d.ts +166 -0
  271. package/javascript/dist/cjs/numkong-wasm.js +617 -0
  272. package/javascript/dist/cjs/numkong.d.ts +343 -0
  273. package/javascript/dist/cjs/numkong.js +523 -0
  274. package/javascript/dist/cjs/package.json +3 -0
  275. package/javascript/dist/cjs/types.d.ts +284 -0
  276. package/javascript/dist/cjs/types.js +653 -0
  277. package/javascript/dist/esm/numkong-wasm.d.ts +166 -0
  278. package/javascript/dist/esm/numkong-wasm.js +595 -0
  279. package/javascript/dist/esm/numkong.d.ts +343 -0
  280. package/javascript/dist/esm/numkong.js +452 -0
  281. package/javascript/dist/esm/package.json +3 -0
  282. package/javascript/dist/esm/types.d.ts +284 -0
  283. package/javascript/dist/esm/types.js +630 -0
  284. package/javascript/dist-package-cjs.json +3 -0
  285. package/javascript/dist-package-esm.json +3 -0
  286. package/javascript/node-gyp-build.d.ts +1 -0
  287. package/javascript/numkong-wasm.ts +756 -0
  288. package/javascript/numkong.c +689 -0
  289. package/javascript/numkong.ts +575 -0
  290. package/javascript/tsconfig-base.json +39 -0
  291. package/javascript/tsconfig-cjs.json +8 -0
  292. package/javascript/tsconfig-esm.json +8 -0
  293. package/javascript/types.ts +674 -0
  294. package/package.json +87 -0
@@ -0,0 +1,285 @@
1
+ /**
2
+ * @brief Random number generation utilities for NumKong types.
3
+ * @file include/numkong/random.hpp
4
+ * @author Ash Vardanian
5
+ * @date February 5, 2026
6
+ *
7
+ * Lightweight header with random fill functions for testing and benchmarking.
8
+ * Only depends on types.hpp to minimize compilation overhead.
9
+ */
10
+ #ifndef NK_RANDOM_HPP
11
+ #define NK_RANDOM_HPP
12
+
13
+ #include <algorithm> // `std::sort`
14
+ #include <random> // `std::uniform_int_distribution`
15
+
16
+ #include "numkong/types.hpp"
17
+
18
+ namespace ashvardanian::numkong {
19
+
20
+ /** @brief Lightweight clamp to avoid pulling in `<algorithm>` for `std::clamp`. */
21
+ template <typename scalar_type_>
22
+ scalar_type_ clamp(scalar_type_ val, scalar_type_ low, scalar_type_ high) noexcept {
23
+ return val < low ? low : val > high ? high : val;
24
+ }
25
+
26
+ /**
27
+ * @brief Fill array with uniform random values.
28
+ *
29
+ * @tparam value_type_ A NumKong wrapper type (e.g., f32_t, f64_t, i32_t).
30
+ * @tparam generator_type_ A random number generator type (e.g., std::mt19937_64).
31
+ * @param generator The random number generator.
32
+ * @param values_ptr Pointer to the array to fill.
33
+ * @param values_count Number of storage values to fill (not dimensions for sub-byte types).
34
+ */
35
+ template <typename value_type_, typename generator_type_, typename component_type_ = typename value_type_::component_t>
36
+ void fill_uniform(generator_type_ &generator, value_type_ *values_ptr, std::size_t values_count,
37
+ component_type_ min_val, component_type_ max_val) noexcept {
38
+
39
+ // Packed types (u1x8, u4x2, i4x2) need special handling - just fill with random bytes
40
+ if constexpr (dimensions_per_value<value_type_>() > 1) {
41
+ std::uniform_int_distribution<std::int32_t> distribution(min_val, max_val);
42
+ for (std::size_t i = 0; i < values_count; ++i)
43
+ for (std::size_t j = 0; j < dimensions_per_value<value_type_>(); ++j)
44
+ values_ptr[i][j] = static_cast<component_type_>(distribution(generator));
45
+ }
46
+ // Integer distribution types aren't always defined
47
+ else if constexpr (is_integral_dtype<value_type_>()) {
48
+ using small_integer_t = std::conditional_t<is_signed_dtype<value_type_>(), std::int32_t, std::uint32_t>;
49
+ using large_integer_t = std::conditional_t<is_signed_dtype<value_type_>(), std::int64_t, std::uint64_t>;
50
+ using distribution_integer_t = std::conditional_t<sizeof(value_type_) <= 4, small_integer_t, large_integer_t>;
51
+ std::uniform_int_distribution<distribution_integer_t> distribution(min_val, max_val);
52
+ for (std::size_t i = 0; i < values_count; ++i)
53
+ values_ptr[i] = static_cast<value_type_>(distribution(generator));
54
+ }
55
+ // Complex types need both real and imaginary parts filled
56
+ else if constexpr (is_complex_dtype<value_type_>()) {
57
+ using component_t = typename value_type_::component_t;
58
+ using distribution_float_t = std::conditional_t<sizeof(component_t) <= 4, float, double>;
59
+ std::uniform_real_distribution<distribution_float_t> distribution(min_val, max_val);
60
+ for (std::size_t i = 0; i < values_count; ++i) {
61
+ auto real = distribution(generator), imag = distribution(generator);
62
+ values_ptr[i] = value_type_(component_t(static_cast<distribution_float_t>(real)),
63
+ component_t(static_cast<distribution_float_t>(imag)));
64
+ }
65
+ }
66
+ // Floats and other types use a fixed range for better numerical stability
67
+ else {
68
+ using distribution_float_t = std::conditional_t<sizeof(value_type_) <= 4, float, double>;
69
+ std::uniform_real_distribution<distribution_float_t> distribution(min_val, max_val);
70
+ for (std::size_t i = 0; i < values_count; ++i)
71
+ values_ptr[i] = static_cast<value_type_>(distribution(generator));
72
+ }
73
+ }
74
+
75
+ /**
76
+ * @brief Fill array with uniform random values within specified range.
77
+ */
78
+ template <typename value_type_, typename generator_type_>
79
+ void fill_uniform(generator_type_ &generator, value_type_ *values_ptr, std::size_t values_count) noexcept {
80
+
81
+ // Packed types (u1x8, u4x2, i4x2) need special handling - just fill with random bytes
82
+ if constexpr (dimensions_per_value<value_type_>() > 1) {
83
+ std::uniform_int_distribution<std::uint32_t> distribution(0, 255);
84
+ for (std::size_t i = 0; i < values_count; ++i)
85
+ values_ptr[i] = value_type_::from_raw(static_cast<typename value_type_::raw_t>(distribution(generator)));
86
+ }
87
+ else if constexpr (is_integral_dtype<value_type_>())
88
+ return fill_uniform(generator, values_ptr, values_count, finite_min<value_type_>(), finite_max<value_type_>());
89
+ else return fill_uniform(generator, values_ptr, values_count, -10, +10);
90
+ }
91
+
92
+ /**
93
+ * @brief Fill array with lognormal distribution (good for detecting numerical edge cases).
94
+ *
95
+ * Probability Density Function (PDF):
96
+ *
97
+ * f(x; μ, σ) = 1 / (x · σ · √(2π)) · exp(−(ln x − μ)² / (2σ²)), x > 0
98
+ *
99
+ * Equivalently, if X ~ 𝒩(μ, σ²), then eˣ ~ LogNormal(μ, σ).
100
+ * Values span many orders of magnitude, which is useful for exercising overflow/underflow
101
+ * paths in low-precision arithmetic. Common in modeling latencies, file sizes, and token
102
+ * frequencies in NLP.
103
+ */
104
+ template <typename value_type_, typename generator_type_>
105
+ void fill_lognormal(generator_type_ &generator, value_type_ *values_ptr, std::size_t values_count, //
106
+ double mean = 0.0, double stddev = 0.5) noexcept {
107
+
108
+ // Packed types (u1x8, u4x2, i4x2) need special handling
109
+ if constexpr (dimensions_per_value<value_type_>() > 1) {
110
+ std::lognormal_distribution<float> distribution(static_cast<float>(mean), static_cast<float>(stddev));
111
+ for (std::size_t i = 0; i < values_count; ++i)
112
+ for (std::size_t j = 0; j < dimensions_per_value<value_type_>(); ++j)
113
+ values_ptr[i][j] = static_cast<std::uint8_t>(clamp(distribution(generator), 0.0f, 255.0f));
114
+ }
115
+ // Complex types need both real and imaginary parts filled
116
+ else if constexpr (is_complex_dtype<value_type_>()) {
117
+ using component_t = typename value_type_::component_t;
118
+ using distribution_float_t = std::conditional_t<sizeof(component_t) <= 4, float, double>;
119
+ std::lognormal_distribution<distribution_float_t> distribution(static_cast<distribution_float_t>(mean),
120
+ static_cast<distribution_float_t>(stddev));
121
+ std::bernoulli_distribution sign_distribution(0.5);
122
+ distribution_float_t const clamp_max = finite_max<component_t>();
123
+ distribution_float_t const clamp_min = finite_min<component_t>();
124
+ constexpr distribution_float_t signs[] = {1, -1};
125
+ for (std::size_t i = 0; i < values_count; ++i) {
126
+ auto real = clamp(distribution(generator) * signs[sign_distribution(generator)], clamp_min, clamp_max);
127
+ auto imag = clamp(distribution(generator) * signs[sign_distribution(generator)], clamp_min, clamp_max);
128
+ values_ptr[i] = value_type_(component_t(real), component_t(imag));
129
+ }
130
+ }
131
+ // Floats and integers: unified path with trait-based clamping
132
+ else {
133
+ using distribution_float_t = std::conditional_t<sizeof(value_type_) <= 4, float, double>;
134
+ std::lognormal_distribution<distribution_float_t> distribution(static_cast<distribution_float_t>(mean),
135
+ static_cast<distribution_float_t>(stddev));
136
+ std::bernoulli_distribution sign_distribution(0.5);
137
+ distribution_float_t const clamp_max = static_cast<distribution_float_t>(finite_max<value_type_>());
138
+ distribution_float_t const clamp_min = static_cast<distribution_float_t>(finite_min<value_type_>());
139
+ constexpr distribution_float_t signs[] = {1, -1};
140
+ for (std::size_t i = 0; i < values_count; ++i) {
141
+ distribution_float_t val = distribution(generator);
142
+ if constexpr (is_signed_dtype<value_type_>()) val *= signs[sign_distribution(generator)];
143
+ values_ptr[i] = static_cast<value_type_>(clamp(val, clamp_min, clamp_max));
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * @brief Fill array with Cauchy distribution (heavy tails for stress testing).
150
+ *
151
+ * Probability Density Function (PDF):
152
+ *
153
+ * f(x; x₀, γ) = 1 / (π · γ · (1 + ((x − x₀) / γ)²))
154
+ *
155
+ * The Cauchy distribution has no defined mean or variance — all moments diverge.
156
+ * This makes it ideal for stress-testing numerical stability with extreme outliers.
157
+ * Common in robust Bayesian priors (half-Cauchy), Levy flights in metaheuristic
158
+ * optimization, and adversarial robustness evaluation.
159
+ */
160
+ template <typename value_type_, typename generator_type_>
161
+ void fill_cauchy(generator_type_ &generator, value_type_ *values_ptr, std::size_t values_count, //
162
+ double location = 0.0, double scale = 1.0) noexcept {
163
+
164
+ // Packed types (u1x8, u4x2, i4x2) need special handling
165
+ if constexpr (dimensions_per_value<value_type_>() > 1) {
166
+ std::cauchy_distribution<float> distribution(static_cast<float>(location), static_cast<float>(scale));
167
+ for (std::size_t i = 0; i < values_count; ++i)
168
+ for (std::size_t j = 0; j < dimensions_per_value<value_type_>(); ++j)
169
+ values_ptr[i][j] = static_cast<std::uint8_t>(clamp(distribution(generator), 0.0f, 255.0f));
170
+ }
171
+ // Complex types need both real and imaginary parts filled
172
+ else if constexpr (is_complex_dtype<value_type_>()) {
173
+ using component_t = typename value_type_::component_t;
174
+ using distribution_float_t = std::conditional_t<sizeof(component_t) <= 4, float, double>;
175
+ std::cauchy_distribution<distribution_float_t> distribution(static_cast<distribution_float_t>(location),
176
+ static_cast<distribution_float_t>(scale));
177
+ distribution_float_t const clamp_max = finite_max<component_t>();
178
+ distribution_float_t const clamp_min = finite_min<component_t>();
179
+ for (std::size_t i = 0; i < values_count; ++i) {
180
+ auto real = clamp(distribution(generator), clamp_min, clamp_max);
181
+ auto imag = clamp(distribution(generator), clamp_min, clamp_max);
182
+ values_ptr[i] = value_type_(component_t(real), component_t(imag));
183
+ }
184
+ }
185
+ // Floats and integers: unified two-sided clamp
186
+ else {
187
+ using distribution_float_t = std::conditional_t<sizeof(value_type_) <= 4, float, double>;
188
+ std::cauchy_distribution<distribution_float_t> distribution(static_cast<distribution_float_t>(location),
189
+ static_cast<distribution_float_t>(scale));
190
+ distribution_float_t const clamp_max = static_cast<distribution_float_t>(finite_max<value_type_>());
191
+ distribution_float_t const clamp_min = static_cast<distribution_float_t>(finite_min<value_type_>());
192
+ for (std::size_t i = 0; i < values_count; ++i)
193
+ values_ptr[i] = static_cast<value_type_>(clamp(distribution(generator), clamp_min, clamp_max));
194
+ }
195
+ }
196
+
197
+ /**
198
+ * @brief Fill arrays with latitude and longitude coordinate values in radians.
199
+ */
200
+ template <typename value_type_, typename generator_type_>
201
+ void fill_coordinates(generator_type_ &generator, value_type_ *lats_ptr, value_type_ *lons_ptr,
202
+ std::size_t values_count) noexcept {
203
+
204
+ using distribution_float_t = std::conditional_t<sizeof(value_type_) <= 4, float, double>;
205
+ constexpr distribution_float_t pi = distribution_float_t(3.14159265358979323846);
206
+ std::uniform_real_distribution<distribution_float_t> lat_distribution(-pi / 2, pi / 2);
207
+ std::uniform_real_distribution<distribution_float_t> lon_distribution(-pi, pi);
208
+ for (std::size_t i = 0; i < values_count; ++i) {
209
+ lats_ptr[i] = static_cast<value_type_>(lat_distribution(generator));
210
+ lons_ptr[i] = static_cast<value_type_>(lon_distribution(generator));
211
+ }
212
+ }
213
+
214
+ /**
215
+ * @brief Fill destination coordinate arrays within a max angular separation of origin coordinates.
216
+ *
217
+ * Uses the great-circle destination formula to place each destination point at a random
218
+ * angular distance (uniform in [0, max_separation_rad]) and random bearing from the
219
+ * corresponding origin point. Coordinates are in radians.
220
+ */
221
+ template <typename value_type_, typename generator_type_>
222
+ void fill_nearby_coordinates(generator_type_ &generator, value_type_ const *origin_lats_ptr,
223
+ value_type_ const *origin_lons_ptr, value_type_ *dest_lats_ptr, value_type_ *dest_lons_ptr,
224
+ std::size_t values_count, double max_separation_rad) noexcept {
225
+
226
+ using float_t = std::conditional_t<sizeof(value_type_) <= 4, float, double>;
227
+ constexpr float_t pi = float_t(3.14159265358979323846);
228
+ std::uniform_real_distribution<float_t> separation_distribution(0, float_t(max_separation_rad));
229
+ std::uniform_real_distribution<float_t> bearing_distribution(0, float_t(2) * pi);
230
+ for (std::size_t i = 0; i < values_count; ++i) {
231
+ float_t origin_lat = float_t(origin_lats_ptr[i]);
232
+ float_t origin_lon = float_t(origin_lons_ptr[i]);
233
+ float_t separation = separation_distribution(generator);
234
+ float_t bearing = bearing_distribution(generator);
235
+ float_t sin_origin_lat = std::sin(origin_lat), cos_origin_lat = std::cos(origin_lat);
236
+ float_t sin_sep = std::sin(separation), cos_sep = std::cos(separation);
237
+ float_t dest_lat = std::asin(sin_origin_lat * cos_sep + cos_origin_lat * sin_sep * std::cos(bearing));
238
+ float_t dest_lon = origin_lon + std::atan2(std::sin(bearing) * sin_sep * cos_origin_lat,
239
+ cos_sep - sin_origin_lat * std::sin(dest_lat));
240
+ dest_lats_ptr[i] = value_type_(dest_lat);
241
+ dest_lons_ptr[i] = value_type_(dest_lon);
242
+ }
243
+ }
244
+
245
+ /**
246
+ * @brief Fill array as a probability distribution (sums to 1.0).
247
+ */
248
+ template <typename value_type_, typename generator_type_>
249
+ void fill_probability(generator_type_ &generator, value_type_ *values_ptr, std::size_t values_count) noexcept {
250
+
251
+ using distribution_float_t = std::conditional_t<sizeof(value_type_) <= 4, float, double>;
252
+ std::uniform_real_distribution<distribution_float_t> distribution(distribution_float_t(0.01),
253
+ distribution_float_t(1));
254
+
255
+ distribution_float_t sum = 0;
256
+ for (std::size_t i = 0; i < values_count; ++i) {
257
+ distribution_float_t val = distribution(generator);
258
+ values_ptr[i] = static_cast<value_type_>(val);
259
+ sum += val;
260
+ }
261
+ for (std::size_t i = 0; i < values_count; ++i)
262
+ values_ptr[i] = static_cast<value_type_>(static_cast<distribution_float_t>(values_ptr[i]) / sum);
263
+ }
264
+
265
+ /**
266
+ * @brief Fill array with sorted unique random integer values (in-place).
267
+ *
268
+ * Draws @p values_count values from [0, max_val - values_count], sorts once, then adds
269
+ * the index to each element. This guarantees uniqueness (duplicates become distinct)
270
+ * and preserves sorted order — all in O(n log n) with exactly one sort, no retry loop.
271
+ * Requires @p max_val >= @p values_count.
272
+ */
273
+ template <typename value_type_, typename generator_type_>
274
+ void fill_sorted_unique(generator_type_ &generator, value_type_ *values_ptr, std::size_t values_count,
275
+ value_type_ max_val) noexcept {
276
+ using raw_t = typename value_type_::raw_t;
277
+ raw_t range = raw_t(max_val) - raw_t(values_count);
278
+ fill_uniform(generator, values_ptr, values_count, raw_t(0), range);
279
+ std::sort(values_ptr, values_ptr + values_count);
280
+ for (std::size_t i = 0; i < values_count; ++i) values_ptr[i] = value_type_(raw_t(values_ptr[i]) + raw_t(i));
281
+ }
282
+
283
+ } // namespace ashvardanian::numkong
284
+
285
+ #endif // NK_RANDOM_HPP