@graphty/graph-samples 0.0.1 → 0.1.2

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 (407) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +123 -0
  3. package/README.md +190 -1
  4. package/dist/chunks/build-DdCe60t3.js +47 -0
  5. package/dist/chunks/build-DdCe60t3.js.map +1 -0
  6. package/dist/chunks/meta-B6toBzaa.js +19 -0
  7. package/dist/chunks/meta-B6toBzaa.js.map +1 -0
  8. package/dist/chunks/meta-BM_YIhlA.js +28 -0
  9. package/dist/chunks/meta-BM_YIhlA.js.map +1 -0
  10. package/dist/chunks/meta-BMmtUpPx.js +30 -0
  11. package/dist/chunks/meta-BMmtUpPx.js.map +1 -0
  12. package/dist/chunks/meta-BXC7oi86.js +22 -0
  13. package/dist/chunks/meta-BXC7oi86.js.map +1 -0
  14. package/dist/chunks/meta-BaFPvhc1.js +19 -0
  15. package/dist/chunks/meta-BaFPvhc1.js.map +1 -0
  16. package/dist/chunks/meta-C58v1Oy0.js +28 -0
  17. package/dist/chunks/meta-C58v1Oy0.js.map +1 -0
  18. package/dist/chunks/meta-CQRXyexG.js +23 -0
  19. package/dist/chunks/meta-CQRXyexG.js.map +1 -0
  20. package/dist/chunks/meta-DrgM1eS0.js +23 -0
  21. package/dist/chunks/meta-DrgM1eS0.js.map +1 -0
  22. package/dist/chunks/meta-IhoaDXAV.js +19 -0
  23. package/dist/chunks/meta-IhoaDXAV.js.map +1 -0
  24. package/dist/chunks/meta-MQPbBUUB.js +29 -0
  25. package/dist/chunks/meta-MQPbBUUB.js.map +1 -0
  26. package/dist/chunks/meta-Qp4HNYAZ.js +24 -0
  27. package/dist/chunks/meta-Qp4HNYAZ.js.map +1 -0
  28. package/dist/chunks/meta-mns0uFIW.js +19 -0
  29. package/dist/chunks/meta-mns0uFIW.js.map +1 -0
  30. package/dist/datasets/celegans-neural.d.ts +1 -0
  31. package/dist/datasets/celegans-neural.js +7359 -0
  32. package/dist/datasets/celegans-neural.js.map +1 -0
  33. package/dist/datasets/contiguous-usa.d.ts +1 -0
  34. package/dist/datasets/contiguous-usa.js +501 -0
  35. package/dist/datasets/contiguous-usa.js.map +1 -0
  36. package/dist/datasets/davis-southern-women.d.ts +1 -0
  37. package/dist/datasets/davis-southern-women.js +235 -0
  38. package/dist/datasets/davis-southern-women.js.map +1 -0
  39. package/dist/datasets/dolphins.d.ts +1 -0
  40. package/dist/datasets/dolphins.js +406 -0
  41. package/dist/datasets/dolphins.js.map +1 -0
  42. package/dist/datasets/florentine-families.d.ts +1 -0
  43. package/dist/datasets/florentine-families.js +75 -0
  44. package/dist/datasets/florentine-families.js.map +1 -0
  45. package/dist/datasets/football.d.ts +1 -0
  46. package/dist/datasets/football.js +1508 -0
  47. package/dist/datasets/football.js.map +1 -0
  48. package/dist/datasets/karate.d.ts +1 -0
  49. package/dist/datasets/karate.js +295 -0
  50. package/dist/datasets/karate.js.map +1 -0
  51. package/dist/datasets/knuth-miles.d.ts +1 -0
  52. package/dist/datasets/knuth-miles.js +24933 -0
  53. package/dist/datasets/knuth-miles.js.map +1 -0
  54. package/dist/datasets/les-miserables.d.ts +1 -0
  55. package/dist/datasets/les-miserables.js +860 -0
  56. package/dist/datasets/les-miserables.js.map +1 -0
  57. package/dist/datasets/openflights.d.ts +1 -0
  58. package/dist/datasets/openflights.js +130277 -0
  59. package/dist/datasets/openflights.js.map +1 -0
  60. package/dist/datasets/political-blogs.d.ts +1 -0
  61. package/dist/datasets/political-blogs.js +42551 -0
  62. package/dist/datasets/political-blogs.js.map +1 -0
  63. package/dist/datasets/political-books.d.ts +1 -0
  64. package/dist/datasets/political-books.js +1124 -0
  65. package/dist/datasets/political-books.js.map +1 -0
  66. package/dist/generators.d.ts +1 -0
  67. package/dist/generators.js +4496 -0
  68. package/dist/generators.js.map +1 -0
  69. package/dist/graph-samples.d.ts +1 -0
  70. package/dist/graph-samples.js +142 -0
  71. package/dist/graph-samples.js.map +1 -0
  72. package/dist/src/datasets/build.d.ts +89 -0
  73. package/dist/src/datasets/build.d.ts.map +1 -0
  74. package/dist/src/datasets/build.js +53 -0
  75. package/dist/src/datasets/build.js.map +1 -0
  76. package/dist/src/datasets/catalog.d.ts +8 -0
  77. package/dist/src/datasets/catalog.d.ts.map +1 -0
  78. package/dist/src/datasets/catalog.js +34 -0
  79. package/dist/src/datasets/catalog.js.map +1 -0
  80. package/dist/src/datasets/celegans-neural/data.d.ts +3 -0
  81. package/dist/src/datasets/celegans-neural/data.d.ts.map +1 -0
  82. package/dist/src/datasets/celegans-neural/data.js +573 -0
  83. package/dist/src/datasets/celegans-neural/data.js.map +1 -0
  84. package/dist/src/datasets/celegans-neural/index.d.ts +11 -0
  85. package/dist/src/datasets/celegans-neural/index.d.ts.map +1 -0
  86. package/dist/src/datasets/celegans-neural/index.js +14 -0
  87. package/dist/src/datasets/celegans-neural/index.js.map +1 -0
  88. package/dist/src/datasets/celegans-neural/meta.d.ts +4 -0
  89. package/dist/src/datasets/celegans-neural/meta.d.ts.map +1 -0
  90. package/dist/src/datasets/celegans-neural/meta.js +21 -0
  91. package/dist/src/datasets/celegans-neural/meta.js.map +1 -0
  92. package/dist/src/datasets/contiguous-usa/data.d.ts +3 -0
  93. package/dist/src/datasets/contiguous-usa/data.d.ts.map +1 -0
  94. package/dist/src/datasets/contiguous-usa/data.js +162 -0
  95. package/dist/src/datasets/contiguous-usa/data.js.map +1 -0
  96. package/dist/src/datasets/contiguous-usa/index.d.ts +11 -0
  97. package/dist/src/datasets/contiguous-usa/index.d.ts.map +1 -0
  98. package/dist/src/datasets/contiguous-usa/index.js +14 -0
  99. package/dist/src/datasets/contiguous-usa/index.js.map +1 -0
  100. package/dist/src/datasets/contiguous-usa/meta.d.ts +4 -0
  101. package/dist/src/datasets/contiguous-usa/meta.d.ts.map +1 -0
  102. package/dist/src/datasets/contiguous-usa/meta.js +27 -0
  103. package/dist/src/datasets/contiguous-usa/meta.js.map +1 -0
  104. package/dist/src/datasets/davis-southern-women/data.d.ts +3 -0
  105. package/dist/src/datasets/davis-southern-women/data.d.ts.map +1 -0
  106. package/dist/src/datasets/davis-southern-women/data.js +57 -0
  107. package/dist/src/datasets/davis-southern-women/data.js.map +1 -0
  108. package/dist/src/datasets/davis-southern-women/index.d.ts +11 -0
  109. package/dist/src/datasets/davis-southern-women/index.d.ts.map +1 -0
  110. package/dist/src/datasets/davis-southern-women/index.js +14 -0
  111. package/dist/src/datasets/davis-southern-women/index.js.map +1 -0
  112. package/dist/src/datasets/davis-southern-women/meta.d.ts +4 -0
  113. package/dist/src/datasets/davis-southern-women/meta.d.ts.map +1 -0
  114. package/dist/src/datasets/davis-southern-women/meta.js +17 -0
  115. package/dist/src/datasets/davis-southern-women/meta.js.map +1 -0
  116. package/dist/src/datasets/dolphins/data.d.ts +3 -0
  117. package/dist/src/datasets/dolphins/data.d.ts.map +1 -0
  118. package/dist/src/datasets/dolphins/data.js +93 -0
  119. package/dist/src/datasets/dolphins/data.js.map +1 -0
  120. package/dist/src/datasets/dolphins/index.d.ts +11 -0
  121. package/dist/src/datasets/dolphins/index.d.ts.map +1 -0
  122. package/dist/src/datasets/dolphins/index.js +14 -0
  123. package/dist/src/datasets/dolphins/index.js.map +1 -0
  124. package/dist/src/datasets/dolphins/meta.d.ts +4 -0
  125. package/dist/src/datasets/dolphins/meta.d.ts.map +1 -0
  126. package/dist/src/datasets/dolphins/meta.js +17 -0
  127. package/dist/src/datasets/dolphins/meta.js.map +1 -0
  128. package/dist/src/datasets/florentine-families/data.d.ts +3 -0
  129. package/dist/src/datasets/florentine-families/data.d.ts.map +1 -0
  130. package/dist/src/datasets/florentine-families/data.js +31 -0
  131. package/dist/src/datasets/florentine-families/data.js.map +1 -0
  132. package/dist/src/datasets/florentine-families/index.d.ts +11 -0
  133. package/dist/src/datasets/florentine-families/index.d.ts.map +1 -0
  134. package/dist/src/datasets/florentine-families/index.js +14 -0
  135. package/dist/src/datasets/florentine-families/index.js.map +1 -0
  136. package/dist/src/datasets/florentine-families/meta.d.ts +4 -0
  137. package/dist/src/datasets/florentine-families/meta.d.ts.map +1 -0
  138. package/dist/src/datasets/florentine-families/meta.js +17 -0
  139. package/dist/src/datasets/florentine-families/meta.js.map +1 -0
  140. package/dist/src/datasets/football/data.d.ts +3 -0
  141. package/dist/src/datasets/football/data.d.ts.map +1 -0
  142. package/dist/src/datasets/football/data.js +210 -0
  143. package/dist/src/datasets/football/data.js.map +1 -0
  144. package/dist/src/datasets/football/index.d.ts +11 -0
  145. package/dist/src/datasets/football/index.d.ts.map +1 -0
  146. package/dist/src/datasets/football/index.js +14 -0
  147. package/dist/src/datasets/football/index.js.map +1 -0
  148. package/dist/src/datasets/football/meta.d.ts +4 -0
  149. package/dist/src/datasets/football/meta.d.ts.map +1 -0
  150. package/dist/src/datasets/football/meta.js +17 -0
  151. package/dist/src/datasets/football/meta.js.map +1 -0
  152. package/dist/src/datasets/hosted.d.ts +7 -0
  153. package/dist/src/datasets/hosted.d.ts.map +1 -0
  154. package/dist/src/datasets/hosted.js +80 -0
  155. package/dist/src/datasets/hosted.js.map +1 -0
  156. package/dist/src/datasets/karate/data.d.ts +3 -0
  157. package/dist/src/datasets/karate/data.d.ts.map +1 -0
  158. package/dist/src/datasets/karate/data.js +30 -0
  159. package/dist/src/datasets/karate/data.js.map +1 -0
  160. package/dist/src/datasets/karate/index.d.ts +11 -0
  161. package/dist/src/datasets/karate/index.d.ts.map +1 -0
  162. package/dist/src/datasets/karate/index.js +14 -0
  163. package/dist/src/datasets/karate/index.js.map +1 -0
  164. package/dist/src/datasets/karate/meta.d.ts +4 -0
  165. package/dist/src/datasets/karate/meta.d.ts.map +1 -0
  166. package/dist/src/datasets/karate/meta.js +22 -0
  167. package/dist/src/datasets/karate/meta.js.map +1 -0
  168. package/dist/src/datasets/knuth-miles/data.d.ts +3 -0
  169. package/dist/src/datasets/knuth-miles/data.d.ts.map +1 -0
  170. package/dist/src/datasets/knuth-miles/data.js +1203 -0
  171. package/dist/src/datasets/knuth-miles/data.js.map +1 -0
  172. package/dist/src/datasets/knuth-miles/index.d.ts +11 -0
  173. package/dist/src/datasets/knuth-miles/index.d.ts.map +1 -0
  174. package/dist/src/datasets/knuth-miles/index.js +14 -0
  175. package/dist/src/datasets/knuth-miles/index.js.map +1 -0
  176. package/dist/src/datasets/knuth-miles/meta.d.ts +4 -0
  177. package/dist/src/datasets/knuth-miles/meta.d.ts.map +1 -0
  178. package/dist/src/datasets/knuth-miles/meta.js +26 -0
  179. package/dist/src/datasets/knuth-miles/meta.js.map +1 -0
  180. package/dist/src/datasets/les-miserables/data.d.ts +3 -0
  181. package/dist/src/datasets/les-miserables/data.d.ts.map +1 -0
  182. package/dist/src/datasets/les-miserables/data.js +117 -0
  183. package/dist/src/datasets/les-miserables/data.js.map +1 -0
  184. package/dist/src/datasets/les-miserables/index.d.ts +11 -0
  185. package/dist/src/datasets/les-miserables/index.d.ts.map +1 -0
  186. package/dist/src/datasets/les-miserables/index.js +14 -0
  187. package/dist/src/datasets/les-miserables/index.js.map +1 -0
  188. package/dist/src/datasets/les-miserables/meta.d.ts +4 -0
  189. package/dist/src/datasets/les-miserables/meta.d.ts.map +1 -0
  190. package/dist/src/datasets/les-miserables/meta.js +21 -0
  191. package/dist/src/datasets/les-miserables/meta.js.map +1 -0
  192. package/dist/src/datasets/openflights/data.d.ts +3 -0
  193. package/dist/src/datasets/openflights/data.d.ts.map +1 -0
  194. package/dist/src/datasets/openflights/data.js +15457 -0
  195. package/dist/src/datasets/openflights/data.js.map +1 -0
  196. package/dist/src/datasets/openflights/index.d.ts +11 -0
  197. package/dist/src/datasets/openflights/index.d.ts.map +1 -0
  198. package/dist/src/datasets/openflights/index.js +14 -0
  199. package/dist/src/datasets/openflights/index.js.map +1 -0
  200. package/dist/src/datasets/openflights/meta.d.ts +4 -0
  201. package/dist/src/datasets/openflights/meta.d.ts.map +1 -0
  202. package/dist/src/datasets/openflights/meta.js +28 -0
  203. package/dist/src/datasets/openflights/meta.js.map +1 -0
  204. package/dist/src/datasets/political-blogs/data.d.ts +3 -0
  205. package/dist/src/datasets/political-blogs/data.d.ts.map +1 -0
  206. package/dist/src/datasets/political-blogs/data.js +4857 -0
  207. package/dist/src/datasets/political-blogs/data.js.map +1 -0
  208. package/dist/src/datasets/political-blogs/index.d.ts +11 -0
  209. package/dist/src/datasets/political-blogs/index.d.ts.map +1 -0
  210. package/dist/src/datasets/political-blogs/index.js +14 -0
  211. package/dist/src/datasets/political-blogs/index.js.map +1 -0
  212. package/dist/src/datasets/political-blogs/meta.d.ts +4 -0
  213. package/dist/src/datasets/political-blogs/meta.d.ts.map +1 -0
  214. package/dist/src/datasets/political-blogs/meta.js +26 -0
  215. package/dist/src/datasets/political-blogs/meta.js.map +1 -0
  216. package/dist/src/datasets/political-books/data.d.ts +3 -0
  217. package/dist/src/datasets/political-books/data.d.ts.map +1 -0
  218. package/dist/src/datasets/political-books/data.js +165 -0
  219. package/dist/src/datasets/political-books/data.js.map +1 -0
  220. package/dist/src/datasets/political-books/index.d.ts +11 -0
  221. package/dist/src/datasets/political-books/index.d.ts.map +1 -0
  222. package/dist/src/datasets/political-books/index.js +14 -0
  223. package/dist/src/datasets/political-books/index.js.map +1 -0
  224. package/dist/src/datasets/political-books/meta.d.ts +4 -0
  225. package/dist/src/datasets/political-books/meta.d.ts.map +1 -0
  226. package/dist/src/datasets/political-books/meta.js +20 -0
  227. package/dist/src/datasets/political-books/meta.js.map +1 -0
  228. package/dist/src/datasets/remote.d.ts +27 -0
  229. package/dist/src/datasets/remote.d.ts.map +1 -0
  230. package/dist/src/datasets/remote.js +30 -0
  231. package/dist/src/datasets/remote.js.map +1 -0
  232. package/dist/src/element.d.ts +20 -0
  233. package/dist/src/element.d.ts.map +1 -0
  234. package/dist/src/element.js +27 -0
  235. package/dist/src/element.js.map +1 -0
  236. package/dist/src/generators/bipartite.d.ts +51 -0
  237. package/dist/src/generators/bipartite.d.ts.map +1 -0
  238. package/dist/src/generators/bipartite.js +99 -0
  239. package/dist/src/generators/bipartite.js.map +1 -0
  240. package/dist/src/generators/block-model.d.ts +75 -0
  241. package/dist/src/generators/block-model.d.ts.map +1 -0
  242. package/dist/src/generators/block-model.js +116 -0
  243. package/dist/src/generators/block-model.js.map +1 -0
  244. package/dist/src/generators/classic.d.ts +208 -0
  245. package/dist/src/generators/classic.d.ts.map +1 -0
  246. package/dist/src/generators/classic.js +437 -0
  247. package/dist/src/generators/classic.js.map +1 -0
  248. package/dist/src/generators/degree-sequence.d.ts +273 -0
  249. package/dist/src/generators/degree-sequence.d.ts.map +1 -0
  250. package/dist/src/generators/degree-sequence.js +646 -0
  251. package/dist/src/generators/degree-sequence.js.map +1 -0
  252. package/dist/src/generators/directed.d.ts +141 -0
  253. package/dist/src/generators/directed.d.ts.map +1 -0
  254. package/dist/src/generators/directed.js +329 -0
  255. package/dist/src/generators/directed.js.map +1 -0
  256. package/dist/src/generators/erdos-renyi.d.ts +58 -0
  257. package/dist/src/generators/erdos-renyi.d.ts.map +1 -0
  258. package/dist/src/generators/erdos-renyi.js +154 -0
  259. package/dist/src/generators/erdos-renyi.js.map +1 -0
  260. package/dist/src/generators/flow.d.ts +153 -0
  261. package/dist/src/generators/flow.d.ts.map +1 -0
  262. package/dist/src/generators/flow.js +346 -0
  263. package/dist/src/generators/flow.js.map +1 -0
  264. package/dist/src/generators/geometric.d.ts +133 -0
  265. package/dist/src/generators/geometric.d.ts.map +1 -0
  266. package/dist/src/generators/geometric.js +495 -0
  267. package/dist/src/generators/geometric.js.map +1 -0
  268. package/dist/src/generators/growth.d.ts +187 -0
  269. package/dist/src/generators/growth.d.ts.map +1 -0
  270. package/dist/src/generators/growth.js +445 -0
  271. package/dist/src/generators/growth.js.map +1 -0
  272. package/dist/src/generators/hyperbolic.d.ts +84 -0
  273. package/dist/src/generators/hyperbolic.d.ts.map +1 -0
  274. package/dist/src/generators/hyperbolic.js +153 -0
  275. package/dist/src/generators/hyperbolic.js.map +1 -0
  276. package/dist/src/generators/index.d.ts +25 -0
  277. package/dist/src/generators/index.d.ts.map +1 -0
  278. package/dist/src/generators/index.js +24 -0
  279. package/dist/src/generators/index.js.map +1 -0
  280. package/dist/src/generators/lattices.d.ts +87 -0
  281. package/dist/src/generators/lattices.d.ts.map +1 -0
  282. package/dist/src/generators/lattices.js +237 -0
  283. package/dist/src/generators/lattices.js.map +1 -0
  284. package/dist/src/generators/lfr.d.ts +55 -0
  285. package/dist/src/generators/lfr.d.ts.map +1 -0
  286. package/dist/src/generators/lfr.js +178 -0
  287. package/dist/src/generators/lfr.js.map +1 -0
  288. package/dist/src/generators/named.d.ts +23 -0
  289. package/dist/src/generators/named.d.ts.map +1 -0
  290. package/dist/src/generators/named.js +191 -0
  291. package/dist/src/generators/named.js.map +1 -0
  292. package/dist/src/generators/preferential-attachment.d.ts +66 -0
  293. package/dist/src/generators/preferential-attachment.d.ts.map +1 -0
  294. package/dist/src/generators/preferential-attachment.js +157 -0
  295. package/dist/src/generators/preferential-attachment.js.map +1 -0
  296. package/dist/src/generators/trees-and-dags.d.ts +53 -0
  297. package/dist/src/generators/trees-and-dags.d.ts.map +1 -0
  298. package/dist/src/generators/trees-and-dags.js +108 -0
  299. package/dist/src/generators/trees-and-dags.js.map +1 -0
  300. package/dist/src/generators/util.d.ts +84 -0
  301. package/dist/src/generators/util.d.ts.map +1 -0
  302. package/dist/src/generators/util.js +138 -0
  303. package/dist/src/generators/util.js.map +1 -0
  304. package/dist/src/generators/variants.d.ts +85 -0
  305. package/dist/src/generators/variants.d.ts.map +1 -0
  306. package/dist/src/generators/variants.js +215 -0
  307. package/dist/src/generators/variants.js.map +1 -0
  308. package/dist/src/generators/weights.d.ts +65 -0
  309. package/dist/src/generators/weights.d.ts.map +1 -0
  310. package/dist/src/generators/weights.js +135 -0
  311. package/dist/src/generators/weights.js.map +1 -0
  312. package/dist/src/index.d.ts +12 -0
  313. package/dist/src/index.d.ts.map +1 -0
  314. package/dist/src/index.js +10 -0
  315. package/dist/src/index.js.map +1 -0
  316. package/dist/src/random/exp.d.ts +23 -0
  317. package/dist/src/random/exp.d.ts.map +1 -0
  318. package/dist/src/random/exp.js +101 -0
  319. package/dist/src/random/exp.js.map +1 -0
  320. package/dist/src/random/log.d.ts +19 -0
  321. package/dist/src/random/log.d.ts.map +1 -0
  322. package/dist/src/random/log.js +83 -0
  323. package/dist/src/random/log.js.map +1 -0
  324. package/dist/src/random/stream.d.ts +93 -0
  325. package/dist/src/random/stream.d.ts.map +1 -0
  326. package/dist/src/random/stream.js +154 -0
  327. package/dist/src/random/stream.js.map +1 -0
  328. package/dist/src/random/threefry.d.ts +19 -0
  329. package/dist/src/random/threefry.d.ts.map +1 -0
  330. package/dist/src/random/threefry.js +43 -0
  331. package/dist/src/random/threefry.js.map +1 -0
  332. package/dist/src/random/trig.d.ts +16 -0
  333. package/dist/src/random/trig.d.ts.map +1 -0
  334. package/dist/src/random/trig.js +78 -0
  335. package/dist/src/random/trig.js.map +1 -0
  336. package/dist/src/types.d.ts +28 -0
  337. package/dist/src/types.d.ts.map +1 -0
  338. package/dist/src/types.js +2 -0
  339. package/dist/src/types.js.map +1 -0
  340. package/package.json +102 -5
  341. package/src/datasets/build.ts +140 -0
  342. package/src/datasets/catalog.ts +35 -0
  343. package/src/datasets/celegans-neural/data.ts +575 -0
  344. package/src/datasets/celegans-neural/index.ts +17 -0
  345. package/src/datasets/celegans-neural/meta.ts +25 -0
  346. package/src/datasets/contiguous-usa/data.ts +164 -0
  347. package/src/datasets/contiguous-usa/index.ts +17 -0
  348. package/src/datasets/contiguous-usa/meta.ts +31 -0
  349. package/src/datasets/davis-southern-women/data.ts +59 -0
  350. package/src/datasets/davis-southern-women/index.ts +17 -0
  351. package/src/datasets/davis-southern-women/meta.ts +20 -0
  352. package/src/datasets/dolphins/data.ts +95 -0
  353. package/src/datasets/dolphins/index.ts +17 -0
  354. package/src/datasets/dolphins/meta.ts +21 -0
  355. package/src/datasets/florentine-families/data.ts +33 -0
  356. package/src/datasets/florentine-families/index.ts +17 -0
  357. package/src/datasets/florentine-families/meta.ts +20 -0
  358. package/src/datasets/football/data.ts +212 -0
  359. package/src/datasets/football/index.ts +17 -0
  360. package/src/datasets/football/meta.ts +20 -0
  361. package/src/datasets/hosted.ts +90 -0
  362. package/src/datasets/karate/data.ts +32 -0
  363. package/src/datasets/karate/index.ts +17 -0
  364. package/src/datasets/karate/meta.ts +25 -0
  365. package/src/datasets/knuth-miles/data.ts +1205 -0
  366. package/src/datasets/knuth-miles/index.ts +17 -0
  367. package/src/datasets/knuth-miles/meta.ts +29 -0
  368. package/src/datasets/les-miserables/data.ts +119 -0
  369. package/src/datasets/les-miserables/index.ts +17 -0
  370. package/src/datasets/les-miserables/meta.ts +24 -0
  371. package/src/datasets/openflights/data.ts +15459 -0
  372. package/src/datasets/openflights/index.ts +17 -0
  373. package/src/datasets/openflights/meta.ts +31 -0
  374. package/src/datasets/political-blogs/data.ts +4859 -0
  375. package/src/datasets/political-blogs/index.ts +17 -0
  376. package/src/datasets/political-blogs/meta.ts +30 -0
  377. package/src/datasets/political-books/data.ts +167 -0
  378. package/src/datasets/political-books/index.ts +17 -0
  379. package/src/datasets/political-books/meta.ts +23 -0
  380. package/src/datasets/remote.ts +42 -0
  381. package/src/element.ts +41 -0
  382. package/src/generators/bipartite.ts +127 -0
  383. package/src/generators/block-model.ts +160 -0
  384. package/src/generators/classic.ts +461 -0
  385. package/src/generators/degree-sequence.ts +807 -0
  386. package/src/generators/directed.ts +418 -0
  387. package/src/generators/erdos-renyi.ts +188 -0
  388. package/src/generators/flow.ts +443 -0
  389. package/src/generators/geometric.ts +591 -0
  390. package/src/generators/growth.ts +532 -0
  391. package/src/generators/hyperbolic.ts +193 -0
  392. package/src/generators/index.ts +133 -0
  393. package/src/generators/lattices.ts +290 -0
  394. package/src/generators/lfr.ts +227 -0
  395. package/src/generators/named.ts +198 -0
  396. package/src/generators/preferential-attachment.ts +188 -0
  397. package/src/generators/trees-and-dags.ts +139 -0
  398. package/src/generators/util.ts +167 -0
  399. package/src/generators/variants.ts +253 -0
  400. package/src/generators/weights.ts +177 -0
  401. package/src/index.ts +12 -0
  402. package/src/random/exp.ts +104 -0
  403. package/src/random/log.ts +86 -0
  404. package/src/random/stream.ts +169 -0
  405. package/src/random/threefry.ts +45 -0
  406. package/src/random/trig.ts +83 -0
  407. package/src/types.ts +28 -0
@@ -0,0 +1,591 @@
1
+ /**
2
+ * Geometric random graphs: nodes are random points, edges depend on the distance between them.
3
+ * Every generator emits its points as Float64Array node columns `x`, `y` (and `z` in 3D), so the
4
+ * `weights: { kind: "euclidean" }` option and a fixed layout can use them.
5
+ *
6
+ * Node i's point always comes from its own stream block i, so the points do not depend on n or on
7
+ * how the work is split. Edge decisions compare squared distances (no square root).
8
+ */
9
+
10
+ import { detLog } from "../random/log.js";
11
+ import { RandomStream, resolveSeed } from "../random/stream.js";
12
+ import { type SampleGraph } from "../types.js";
13
+ import { checkEdgeCount, checkInt, checkProbability, EdgeBuffer, toGraph } from "./util.js";
14
+ import { applyWeights, type WeightOptions } from "./weights.js";
15
+
16
+ /** L of the Waxman model: the diagonal of the unit square, the largest possible distance. */
17
+ const WAXMAN_L = Math.SQRT2;
18
+
19
+ /** The largest expected number of Waxman candidate draws, beta n^2 / 2. */
20
+ const WAXMAN_MAX_DRAWS = 5e8;
21
+
22
+ /**
23
+ * Throw unless `dimension` is 2 or 3.
24
+ * @param dimension - the option value
25
+ * @returns the dimension
26
+ */
27
+ function checkDimension(dimension: number | undefined): 2 | 3 {
28
+ const d = dimension ?? 2;
29
+ if (d !== 2 && d !== 3) {
30
+ throw new RangeError(`dimension must be 2 or 3, got ${String(d)}`);
31
+ }
32
+ return d;
33
+ }
34
+
35
+ /**
36
+ * Throw unless `value` is a finite number >= 0 (or > 0 when `positive`).
37
+ * @param name - the option name
38
+ * @param value - the value
39
+ * @param positive - whether 0 is excluded
40
+ */
41
+ function checkNonNegative(name: string, value: number, positive = false): void {
42
+ if (!(Number.isFinite(value) && (positive ? value > 0 : value >= 0))) {
43
+ throw new RangeError(`${name} must be a finite number ${positive ? ">" : ">="} 0, got ${String(value)}`);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Uniform points in [0, 1)^dimension: point i takes `dimension` nextFloat() draws (x, then y, then
49
+ * z) from stream (seed, domain, i).
50
+ * @param seed - the seed
51
+ * @param domain - the points' stream domain
52
+ * @param n - the point count
53
+ * @param dimension - 2 or 3
54
+ * @returns one column per axis
55
+ */
56
+ function uniformPoints(seed: number, domain: string, n: number, dimension: number): Float64Array<ArrayBuffer>[] {
57
+ const axes = Array.from({ length: dimension }, () => new Float64Array(n));
58
+ const stream = new RandomStream(seed, domain, 0);
59
+ for (let i = 0; i < n; i++) {
60
+ stream.reset(i);
61
+ for (const axis of axes) {
62
+ axis[i] = stream.nextFloat();
63
+ }
64
+ }
65
+ return axes;
66
+ }
67
+
68
+ /**
69
+ * The position columns x, y (and z) of a graph.
70
+ * @param axes - the coordinate columns
71
+ * @returns the node columns
72
+ */
73
+ function positionColumns(axes: Float64Array<ArrayBuffer>[]): Record<string, Float64Array<ArrayBuffer>> {
74
+ const names = ["x", "y", "z"];
75
+ return Object.fromEntries(axes.map((axis, a) => [names[a], axis]));
76
+ }
77
+
78
+ /**
79
+ * The largest g >= 1 with g^dimension <= target.
80
+ * @param target - the cell budget
81
+ * @param dimension - 2 or 3
82
+ * @returns cells per axis
83
+ */
84
+ function cellsPerAxis(target: number, dimension: number): number {
85
+ let g = 1;
86
+ while ((g + 1) ** dimension <= target) {
87
+ g++;
88
+ }
89
+ return g;
90
+ }
91
+
92
+ /** Points bucketed into a uniform grid of g^dimension cells by a counting sort. */
93
+ interface CellGrid {
94
+ /** Cells per axis. */
95
+ readonly g: number;
96
+ /** The low corner of the grid on every axis. */
97
+ readonly lo: readonly number[];
98
+ /** The cell side on every axis. */
99
+ readonly side: readonly number[];
100
+ /** start[c] .. start[c + 1] indexes `items` for cell c. */
101
+ readonly start: Uint32Array;
102
+ /** Point indices grouped by cell, ascending inside each cell. */
103
+ readonly items: Uint32Array;
104
+ /** The cell coordinate of every point on every axis. */
105
+ readonly cell: Uint32Array[];
106
+ }
107
+
108
+ /**
109
+ * Bucket points into a g^dimension grid spanning [lo, hi] on each axis.
110
+ * @param axes - the coordinate columns
111
+ * @param g - cells per axis
112
+ * @param lo - the low corner per axis
113
+ * @param hi - the high corner per axis
114
+ * @returns the grid
115
+ */
116
+ function buildGrid(axes: Float64Array[], g: number, lo: number[], hi: number[]): CellGrid {
117
+ const n = axes[0].length;
118
+ const side = lo.map((l, a) => (hi[a] - l) / g || 1);
119
+ const cell = axes.map(() => new Uint32Array(n));
120
+ const flat = new Uint32Array(n);
121
+ const start = new Uint32Array(g ** axes.length + 1);
122
+ for (let i = 0; i < n; i++) {
123
+ let c = 0;
124
+ for (let a = 0; a < axes.length; a++) {
125
+ const k = Math.min(g - 1, Math.floor((axes[a][i] - lo[a]) / side[a]));
126
+ cell[a][i] = k;
127
+ c = c * g + k;
128
+ }
129
+ flat[i] = c;
130
+ start[c + 1]++;
131
+ }
132
+ for (let c = 0; c + 1 < start.length; c++) {
133
+ start[c + 1] += start[c];
134
+ }
135
+ const fill = start.slice(0, -1);
136
+ const items = new Uint32Array(n);
137
+ for (let i = 0; i < n; i++) {
138
+ items[fill[flat[i]]++] = i;
139
+ }
140
+ return { g, lo, side, start, items, cell };
141
+ }
142
+
143
+ /** Options of {@link randomGeometricGraph}. */
144
+ export interface RandomGeometricOptions extends WeightOptions {
145
+ /** The node count, >= 0. */
146
+ n: number;
147
+ /** The connection radius, a finite number >= 0: u and v are joined iff their distance is <= radius. */
148
+ radius: number;
149
+ /** 2 (the unit square, default) or 3 (the unit cube). */
150
+ dimension?: 2 | 3 | undefined;
151
+ /** Measure distance on the torus (each axis wraps around), removing the boundary effect; default false. */
152
+ periodic?: boolean | undefined;
153
+ /** The seed, an integer in [0, 2^53); default 0. */
154
+ seed?: number | undefined;
155
+ }
156
+
157
+ /**
158
+ * The random geometric graph (E. N. Gilbert, "Random plane networks", J. SIAM 9(4), 533-543, 1961,
159
+ * doi:10.1137/0109045; M. Penrose, Random Geometric Graphs, Oxford University Press, 2003): n
160
+ * uniform points in the unit square or cube, u and v joined iff their Euclidean distance (torus
161
+ * distance when `periodic`) is at most `radius`.
162
+ *
163
+ * Node i's point is x, y (, z) = one nextFloat() per axis from stream (seed, "rgg-points", i). The
164
+ * points are bucketed into a uniform grid of cells of side >= radius (at most about n cells) and
165
+ * each node checks the 3^dimension cells around its own. Edges are the pairs (u, v), u < v,
166
+ * ascending u then ascending v. Expected cost O(n + m). Node columns `x`, `y` (, `z`): Float64Array
167
+ * in [0, 1). The mean degree is about n pi r^2 in 2D and n 4/3 pi r^3 in 3D (less near the border
168
+ * unless periodic); connectivity needs r above about sqrt(ln n / (pi n)) in 2D.
169
+ * @param options - n, radius, dimension, periodic and seed
170
+ * @returns the undirected graph
171
+ */
172
+ export function randomGeometricGraph(options: RandomGeometricOptions): SampleGraph {
173
+ const { n, radius } = options;
174
+ checkInt("n", n, 0);
175
+ checkNonNegative("radius", radius);
176
+ const dimension = checkDimension(options.dimension);
177
+ const periodic = options.periodic ?? false;
178
+ const seed = resolveSeed(options.seed);
179
+ const axes = uniformPoints(seed, "rgg-points", n, dimension);
180
+
181
+ const r2 = radius * radius;
182
+ // cells a hair wider than the radius, so a point rounded into the next cell is still covered
183
+ const g = Math.max(1, Math.min(Math.floor((1 - 1e-9) / radius), cellsPerAxis(Math.max(1, n), dimension)));
184
+ const grid = buildGrid(axes, g, new Array<number>(dimension).fill(0), new Array<number>(dimension).fill(1));
185
+ const volume = dimension === 2 ? Math.PI * r2 : (4 / 3) * Math.PI * r2 * radius;
186
+ const pairs = (n * (n - 1)) / 2;
187
+ const out = new EdgeBuffer(Math.ceil(Math.min(pairs, pairs * volume * 1.1, 1 << 24) + 16));
188
+
189
+ // the distinct neighbouring cell coordinates of cell k on one axis
190
+ const around = Array.from({ length: g }, (_, k) => {
191
+ const list = periodic ? [(k + g - 1) % g, k, (k + 1) % g] : [k - 1, k, k + 1].filter((c) => c >= 0 && c < g);
192
+ return [...new Set(list)];
193
+ });
194
+ let found = new Uint32Array(16);
195
+ for (let u = 0; u < n; u++) {
196
+ let count = 0;
197
+ const zCells = dimension === 3 ? around[grid.cell[2][u]] : [0];
198
+ for (const cx of around[grid.cell[0][u]]) {
199
+ for (const cy of around[grid.cell[1][u]]) {
200
+ for (const cz of zCells) {
201
+ const c = dimension === 3 ? (cx * g + cy) * g + cz : cx * g + cy;
202
+ for (let t = grid.start[c]; t < grid.start[c + 1]; t++) {
203
+ const v = grid.items[t];
204
+ if (v <= u) {
205
+ continue;
206
+ }
207
+ let d2 = 0;
208
+ for (const axis of axes) {
209
+ let d = Math.abs(axis[u] - axis[v]);
210
+ if (periodic && d > 0.5) {
211
+ d = 1 - d;
212
+ }
213
+ d2 += d * d;
214
+ }
215
+ if (d2 <= r2) {
216
+ if (count === found.length) {
217
+ const grown = new Uint32Array(count * 2);
218
+ grown.set(found);
219
+ found = grown;
220
+ }
221
+ found[count++] = v;
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ const row = found.subarray(0, count).sort();
228
+ for (const v of row) {
229
+ out.push(u, v);
230
+ }
231
+ }
232
+ return applyWeights(toGraph(n, out, false, positionColumns(axes)), options);
233
+ }
234
+
235
+ /** Options of {@link waxmanGraph}. */
236
+ export interface WaxmanOptions extends WeightOptions {
237
+ /** The node count, >= 0; beta n^2 / 2 must stay below 5e8. */
238
+ n: number;
239
+ /** The distance scale, a finite number > 0: larger alpha makes long edges likelier. */
240
+ alpha: number;
241
+ /** The edge probability at distance 0, in [0, 1]. */
242
+ beta: number;
243
+ /** The seed, an integer in [0, 2^53); default 0. */
244
+ seed?: number | undefined;
245
+ }
246
+
247
+ /** The checked and precomputed form of {@link WaxmanOptions}. */
248
+ interface WaxmanPlan {
249
+ readonly n: number;
250
+ readonly seed: number;
251
+ readonly beta: number;
252
+ readonly logQ: number;
253
+ /** alpha L. */
254
+ readonly scale: number;
255
+ readonly x: Float64Array<ArrayBuffer>;
256
+ readonly y: Float64Array<ArrayBuffer>;
257
+ }
258
+
259
+ /**
260
+ * Check the Waxman options and draw the points.
261
+ * @param options - the options
262
+ * @returns the plan
263
+ */
264
+ export function planWaxman(options: WaxmanOptions): WaxmanPlan {
265
+ const { n, alpha, beta } = options;
266
+ checkInt("n", n, 0);
267
+ checkNonNegative("alpha", alpha, true);
268
+ checkProbability("beta", beta);
269
+ const seed = resolveSeed(options.seed);
270
+ if ((beta * n * n) / 2 > WAXMAN_MAX_DRAWS) {
271
+ throw new RangeError(
272
+ `waxmanGraph: beta n^2 / 2 = ${(beta * n * n) / 2} candidate pairs, above the limit of ${WAXMAN_MAX_DRAWS}`,
273
+ );
274
+ }
275
+ const [x, y] = uniformPoints(seed, "waxman-points", n, 2);
276
+ return { n, seed, beta, logQ: detLog(1 - beta), scale: alpha * WAXMAN_L, x, y };
277
+ }
278
+
279
+ /**
280
+ * Rows [start, end) of the Waxman graph: row u draws from stream (seed, "waxman", u), walks the
281
+ * candidates v > u by geometric skipping at probability beta (one draw per skip), and keeps a
282
+ * candidate with a second draw t iff d^2 < (alpha L ln t)^2, which is t < exp(-d / (alpha L)) with
283
+ * no exp. Edges ascend in v. Any split of [0, n) into consecutive ranges gives the whole graph.
284
+ * @param plan - the checked options and points
285
+ * @param start - the first row
286
+ * @param end - one past the last row
287
+ * @param out - receives the edges
288
+ */
289
+ export function waxmanRows(plan: WaxmanPlan, start: number, end: number, out: EdgeBuffer): void {
290
+ const { n, beta, logQ, scale, x, y } = plan;
291
+ if (beta === 0) {
292
+ return;
293
+ }
294
+ const stream = new RandomStream(plan.seed, "waxman", 0);
295
+ const skip = (): number => (beta === 1 ? 0 : stream.nextSkip(logQ));
296
+ for (let u = start; u < end; u++) {
297
+ stream.reset(u);
298
+ for (let v = u + 1 + skip(); v < n; v += 1 + skip()) {
299
+ const dx = x[u] - x[v];
300
+ const dy = y[u] - y[v];
301
+ const bound = scale * detLog(stream.nextFloat());
302
+ if (dx * dx + dy * dy < bound * bound) {
303
+ out.push(u, v);
304
+ }
305
+ }
306
+ }
307
+ }
308
+
309
+ /**
310
+ * The Waxman graph (B. M. Waxman, "Routing of multipoint connections", IEEE J. Selected Areas in
311
+ * Communications 6(9), 1617-1622, 1988): n uniform points in the unit square, each pair joined
312
+ * independently with probability beta exp(-d / (alpha L)).
313
+ *
314
+ * L is fixed at sqrt(2), the diagonal of the unit square (networkx uses the largest distance
315
+ * between the drawn points instead, so the two differ slightly). Node i's point is x, y = two
316
+ * nextFloat() draws from stream (seed, "waxman-points", i); the pairs are drawn by
317
+ * {@link waxmanRows}. Edges are the pairs (u, v), u < v, ascending u then v. Every pair has a
318
+ * non-zero probability, so the cost is O(n + beta n^2 / 2) draws; above 5e8 expected draws it
319
+ * throws a RangeError (n about 31,600 at beta 1). Node columns `x`, `y`: Float64Array in [0, 1).
320
+ * @param options - n, alpha, beta and seed
321
+ * @returns the undirected graph
322
+ */
323
+ export function waxmanGraph(options: WaxmanOptions): SampleGraph {
324
+ const plan = planWaxman(options);
325
+ const out = new EdgeBuffer(Math.min(Math.ceil((plan.beta * plan.n * plan.n) / 8), 1 << 24) + 16);
326
+ waxmanRows(plan, 0, plan.n, out);
327
+ return applyWeights(toGraph(plan.n, out, false, positionColumns([plan.x, plan.y])), options);
328
+ }
329
+
330
+ /** Options of {@link knnGraph}. */
331
+ export interface KnnOptions extends WeightOptions {
332
+ /** The node count, >= 0. */
333
+ n: number;
334
+ /** The neighbours per node, in [0, n - 1]. */
335
+ k: number;
336
+ /** 2 (default) or 3. */
337
+ dimension?: 2 | 3 | undefined;
338
+ /** Arcs u -> each of u's k nearest (default true), or with false the undirected union without duplicates. */
339
+ directed?: boolean | undefined;
340
+ /** Draw the points from a mixture of this many Gaussian clusters, >= 1; default uniform points. */
341
+ clusters?: number | undefined;
342
+ /** The standard deviation of every cluster on each axis, a finite number >= 0; default 0.05. Needs `clusters`. */
343
+ spread?: number | undefined;
344
+ /** The seed, an integer in [0, 2^53); default 0. */
345
+ seed?: number | undefined;
346
+ }
347
+
348
+ /**
349
+ * Gaussian mixture points: cluster c's centre is `dimension` nextFloat() draws from stream
350
+ * (seed, "knn-centres", c); point i draws its cluster with nextBelow(clusters) and then standard
351
+ * normal offsets by the Marsaglia polar method (pairs u, v = 2 nextFloat() - 1 until
352
+ * 0 < s = u^2 + v^2 < 1, then u sqrt(-2 ln s / s) and v sqrt(-2 ln s / s)), all from stream
353
+ * (seed, "knn-points", i).
354
+ * @param seed - the seed
355
+ * @param n - the point count
356
+ * @param dimension - 2 or 3
357
+ * @param clusters - the cluster count
358
+ * @param spread - the standard deviation
359
+ * @returns the coordinate columns and the cluster of every point
360
+ */
361
+ function mixturePoints(
362
+ seed: number,
363
+ n: number,
364
+ dimension: number,
365
+ clusters: number,
366
+ spread: number,
367
+ ): { axes: Float64Array<ArrayBuffer>[]; community: Uint32Array<ArrayBuffer> } {
368
+ const centres = uniformPoints(seed, "knn-centres", clusters, dimension);
369
+ const axes = Array.from({ length: dimension }, () => new Float64Array(n));
370
+ const community = new Uint32Array(n);
371
+ const stream = new RandomStream(seed, "knn-points", 0);
372
+ const normals = new Float64Array(4);
373
+ for (let i = 0; i < n; i++) {
374
+ stream.reset(i);
375
+ const c = stream.nextBelow(clusters);
376
+ community[i] = c;
377
+ for (let j = 0; j < dimension; j += 2) {
378
+ let u: number;
379
+ let v: number;
380
+ let s: number;
381
+ do {
382
+ u = 2 * stream.nextFloat() - 1;
383
+ v = 2 * stream.nextFloat() - 1;
384
+ s = u * u + v * v;
385
+ } while (s >= 1 || s === 0);
386
+ const m = Math.sqrt((-2 * detLog(s)) / s);
387
+ normals[j] = u * m;
388
+ normals[j + 1] = v * m;
389
+ }
390
+ for (let a = 0; a < dimension; a++) {
391
+ axes[a][i] = centres[a][c] + spread * normals[a];
392
+ }
393
+ }
394
+ return { axes, community };
395
+ }
396
+
397
+ /**
398
+ * The k nearest neighbours of every point, exact, by an expanding ring search over a cell grid.
399
+ * @param axes - the coordinate columns
400
+ * @param k - neighbours per point
401
+ * @returns row u's neighbours at [u k, (u + 1) k), ascending by index
402
+ */
403
+ function nearestNeighbours(axes: Float64Array[], k: number): Uint32Array<ArrayBuffer> {
404
+ const n = axes[0].length;
405
+ const dimension = axes.length;
406
+ const result = new Uint32Array(n * k);
407
+ if (k === 0) {
408
+ return result;
409
+ }
410
+ const lo = axes.map((axis) => axis.reduce((a, b) => Math.min(a, b), Infinity));
411
+ const hi = axes.map((axis) => axis.reduce((a, b) => Math.max(a, b), -Infinity));
412
+ const g = cellsPerAxis(Math.max(1, n / k), dimension);
413
+ const grid = buildGrid(axes, g, lo, hi);
414
+ const bestD = new Float64Array(k);
415
+ const bestI = new Uint32Array(k);
416
+ // the absolute rounding slack of a cell assignment
417
+ const slack = 1e-12 * Math.max(1, ...lo.map(Math.abs), ...hi.map(Math.abs));
418
+ const cell = new Array<number>(dimension).fill(0);
419
+ const offset = new Array<number>(dimension).fill(0);
420
+ for (let u = 0; u < n; u++) {
421
+ let count = 0;
422
+ const consider = (v: number): void => {
423
+ let d2 = 0;
424
+ for (const axis of axes) {
425
+ const d = Math.abs(axis[u] - axis[v]);
426
+ d2 += d * d;
427
+ }
428
+ // insert (d2, v) into the sorted best list when it beats the worst kept
429
+ if (count === k && (d2 > bestD[k - 1] || (d2 === bestD[k - 1] && v > bestI[k - 1]))) {
430
+ return;
431
+ }
432
+ let j = count < k ? count++ : k - 1;
433
+ while (j > 0 && (bestD[j - 1] > d2 || (bestD[j - 1] === d2 && bestI[j - 1] > v))) {
434
+ bestD[j] = bestD[j - 1];
435
+ bestI[j] = bestI[j - 1];
436
+ j--;
437
+ }
438
+ bestD[j] = d2;
439
+ bestI[j] = v;
440
+ };
441
+ for (let a = 0; a < dimension; a++) {
442
+ cell[a] = grid.cell[a][u];
443
+ }
444
+ // ponytail: ring r scans the whole (2r + 1)^dimension block and skips its inside, O(r^dimension)
445
+ // per ring; walk only the shell if large k or very uneven clusters make that measurable
446
+ for (let r = 0; ; r++) {
447
+ let covered = true;
448
+ for (let a = 0; a < dimension; a++) {
449
+ offset[a] = -r;
450
+ if (cell[a] - r > 0 || cell[a] + r < g - 1) {
451
+ covered = false;
452
+ }
453
+ }
454
+ for (;;) {
455
+ let chebyshev = 0;
456
+ let inside = true;
457
+ let c = 0;
458
+ for (let a = 0; a < dimension; a++) {
459
+ const k2 = cell[a] + offset[a];
460
+ if (k2 < 0 || k2 >= g) {
461
+ inside = false;
462
+ }
463
+ chebyshev = Math.max(chebyshev, Math.abs(offset[a]));
464
+ c = c * g + k2;
465
+ }
466
+ if (inside && chebyshev === r) {
467
+ for (let t = grid.start[c]; t < grid.start[c + 1]; t++) {
468
+ const v = grid.items[t];
469
+ if (v !== u) {
470
+ consider(v);
471
+ }
472
+ }
473
+ }
474
+ let a = dimension - 1;
475
+ while (a >= 0 && offset[a] === r) {
476
+ offset[a] = -r;
477
+ a--;
478
+ }
479
+ if (a < 0) {
480
+ break;
481
+ }
482
+ offset[a]++;
483
+ }
484
+ if (covered) {
485
+ break;
486
+ }
487
+ if (count === k) {
488
+ // every point outside the searched block is at least `gap` away
489
+ let gap = Infinity;
490
+ for (let a = 0; a < dimension; a++) {
491
+ const p = axes[a][u] - grid.lo[a];
492
+ gap = Math.min(gap, p - (cell[a] - r) * grid.side[a], (cell[a] + r + 1) * grid.side[a] - p);
493
+ }
494
+ // the margins cover the rounding of the cell assignment and of the squared distances, so
495
+ // a point outside the block can never tie or beat the k-th best
496
+ gap -= slack;
497
+ if (gap > 0 && bestD[k - 1] < gap * gap * (1 - 1e-9)) {
498
+ break;
499
+ }
500
+ }
501
+ }
502
+ const row = result.subarray(u * k, (u + 1) * k);
503
+ row.set(bestI);
504
+ row.sort();
505
+ }
506
+ return result;
507
+ }
508
+
509
+ /**
510
+ * The k-nearest-neighbour graph of random points, the standard input of spectral clustering
511
+ * (U. von Luxburg, "A tutorial on spectral clustering", Statistics and Computing 17, 395-416, 2007,
512
+ * doi:10.1007/s11222-007-9033-z).
513
+ *
514
+ * Points: uniform in the unit square or cube (point i = nextFloat() per axis from stream
515
+ * (seed, "knn-points", i)), or with `clusters` a Gaussian mixture: cluster centres uniform in the
516
+ * unit cube from stream (seed, "knn-centres", c), point i picks its cluster uniformly and adds
517
+ * normal offsets of standard deviation `spread` (Marsaglia polar method) from stream
518
+ * (seed, "knn-points", i); mixture points may leave [0, 1). Each node's k nearest are exact,
519
+ * ties broken by the smaller index, found by an expanding ring search over a cell grid of about
520
+ * n / k cells: expected O(n k^2) for uniform points.
521
+ *
522
+ * Directed (default): the arcs u -> each of its k nearest, ascending u then ascending target.
523
+ * Undirected: the union of those pairs without duplicates as (u, v), u < v, ascending u then v.
524
+ * Node columns `x`, `y` (, `z`): Float64Array; with `clusters`, `community` (u32): the cluster.
525
+ * @param options - n, k, dimension, directed, clusters, spread and seed
526
+ * @returns the graph
527
+ */
528
+ export function knnGraph(options: KnnOptions): SampleGraph {
529
+ const { n, k, clusters, spread } = options;
530
+ checkInt("n", n, 0);
531
+ checkInt("k", k, 0, Math.max(0, n - 1));
532
+ const dimension = checkDimension(options.dimension);
533
+ const directed = options.directed ?? true;
534
+ if (clusters === undefined && spread !== undefined) {
535
+ throw new RangeError("spread needs clusters");
536
+ }
537
+ const seed = resolveSeed(options.seed);
538
+ let axes: Float64Array<ArrayBuffer>[];
539
+ const columns: Record<string, Float64Array<ArrayBuffer> | Uint32Array<ArrayBuffer>> = {};
540
+ if (clusters === undefined) {
541
+ axes = uniformPoints(seed, "knn-points", n, dimension);
542
+ } else {
543
+ checkInt("clusters", clusters, 1);
544
+ const sd = spread ?? 0.05;
545
+ checkNonNegative("spread", sd);
546
+ let community: Uint32Array<ArrayBuffer>;
547
+ ({ axes, community } = mixturePoints(seed, n, dimension, clusters, sd));
548
+ columns.community = community;
549
+ }
550
+ Object.assign(columns, positionColumns(axes));
551
+ const neighbours = nearestNeighbours(axes, k);
552
+ checkEdgeCount(n * k);
553
+ let out: EdgeBuffer;
554
+ if (directed) {
555
+ out = new EdgeBuffer(n * k);
556
+ for (let u = 0; u < n; u++) {
557
+ for (let j = u * k; j < (u + 1) * k; j++) {
558
+ out.push(u, neighbours[j]);
559
+ }
560
+ }
561
+ } else {
562
+ // bucket the pairs (min, max) by their smaller end with a counting sort, then sort and dedupe each bucket
563
+ const start = new Uint32Array(n + 1);
564
+ for (let u = 0; u < n; u++) {
565
+ for (let j = u * k; j < (u + 1) * k; j++) {
566
+ start[Math.min(u, neighbours[j]) + 1]++;
567
+ }
568
+ }
569
+ for (let u = 0; u < n; u++) {
570
+ start[u + 1] += start[u];
571
+ }
572
+ const fill = start.slice(0, -1);
573
+ const other = new Uint32Array(n * k);
574
+ for (let u = 0; u < n; u++) {
575
+ for (let j = u * k; j < (u + 1) * k; j++) {
576
+ const v = neighbours[j];
577
+ other[fill[Math.min(u, v)]++] = Math.max(u, v);
578
+ }
579
+ }
580
+ out = new EdgeBuffer(n * k);
581
+ for (let u = 0; u < n; u++) {
582
+ const row = other.subarray(start[u], start[u + 1]).sort();
583
+ for (let j = 0; j < row.length; j++) {
584
+ if (j === 0 || row[j] !== row[j - 1]) {
585
+ out.push(u, row[j]);
586
+ }
587
+ }
588
+ }
589
+ }
590
+ return applyWeights(toGraph(n, out, directed, columns), options);
591
+ }