@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,807 @@
1
+ /**
2
+ * Degree-sequence models: power-law degree sequences, the configuration model (undirected,
3
+ * directed and bipartite), Chung-Lu expected-degree graphs, the degree-corrected stochastic block
4
+ * model and random regular graphs.
5
+ */
6
+
7
+ import { MAX_COUNT, type U32 } from "@graphty/graph-format";
8
+
9
+ import { detPow } from "../random/exp.js";
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
+ /**
17
+ * What a generator does with self-loops or repeated pairs: keep them, or erase all but the first
18
+ * occurrence in edge order.
19
+ */
20
+ export type EdgePolicy = "keep" | "erase";
21
+
22
+ /** The largest power-law support (maxDegree - minDegree + 1): the size of the cumulative table. */
23
+ const MAX_POWER_LAW_SUPPORT = 2 ** 24;
24
+
25
+ /**
26
+ * Throw unless `exponent` is a finite number >= 0.
27
+ * @param name - the option name
28
+ * @param exponent - the value
29
+ */
30
+ function checkExponent(name: string, exponent: number): void {
31
+ if (!(Number.isFinite(exponent) && exponent >= 0)) {
32
+ throw new RangeError(`${name} must be a finite number >= 0, got ${String(exponent)}`);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * A sampler of the discrete power law P(d) ~ d^-exponent on [min, max]: a cumulative table of
38
+ * detPow(d, -exponent), and per draw one nextFloat u and a binary search for the first entry
39
+ * above u times the total. Checks its arguments.
40
+ * @param names - the option names of [exponent, min, max], for the messages
41
+ * @param exponent - the exponent, >= 0
42
+ * @param min - the smallest value, >= 1
43
+ * @param max - the largest value, >= min
44
+ * @returns the sampler
45
+ */
46
+ export function powerLawSampler(
47
+ names: readonly [string, string, string],
48
+ exponent: number,
49
+ min: number,
50
+ max: number,
51
+ ): (stream: RandomStream) => number {
52
+ checkExponent(names[0], exponent);
53
+ checkInt(names[1], min, 1);
54
+ checkInt(names[2], max, min, Math.min(MAX_COUNT, min + MAX_POWER_LAW_SUPPORT - 1));
55
+ const count = max - min + 1;
56
+ const cdf = new Float64Array(count);
57
+ let total = 0;
58
+ for (let k = 0; k < count; k++) {
59
+ total += detPow(min + k, -exponent);
60
+ cdf[k] = total;
61
+ }
62
+ return (stream) => {
63
+ const u = stream.nextFloat() * total;
64
+ let lo = 0;
65
+ let hi = count - 1;
66
+ while (lo < hi) {
67
+ const mid = (lo + hi) >>> 1;
68
+ if (cdf[mid] > u) {
69
+ hi = mid;
70
+ } else {
71
+ lo = mid + 1;
72
+ }
73
+ }
74
+ return min + lo;
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Make the sum of `seq` even by changing its LAST entry: +1 when it is below `max`, else -1 when
80
+ * it is above `min`; a RangeError when neither is possible.
81
+ * @param seq - the sequence, changed in place
82
+ * @param min - the smallest allowed value
83
+ * @param max - the largest allowed value
84
+ */
85
+ export function makeSumEven(seq: U32, min: number, max: number): void {
86
+ let total = 0;
87
+ for (const d of seq) {
88
+ total += d;
89
+ }
90
+ if (total % 2 === 0) {
91
+ return;
92
+ }
93
+ const last = seq.length - 1;
94
+ if (seq[last] < max) {
95
+ seq[last]++;
96
+ } else if (seq[last] > min) {
97
+ seq[last]--;
98
+ } else {
99
+ throw new RangeError(`cannot make the degree sum even: every degree is ${min} and n is odd`);
100
+ }
101
+ }
102
+
103
+ /** Options of {@link powerLawDegreeSequence}. */
104
+ export interface PowerLawDegreeSequenceOptions {
105
+ /** The sequence length, >= 0. */
106
+ n: number;
107
+ /** The exponent of P(d) ~ d^-exponent, a finite number >= 0 (typically 2 to 3). */
108
+ exponent: number;
109
+ /** The smallest degree, >= 1. */
110
+ minDegree: number;
111
+ /** The largest degree, >= minDegree, and at most minDegree + 2^24 - 1. */
112
+ maxDegree: number;
113
+ /** Make the sum even (so a configuration model can pair it); default true. */
114
+ evenSum?: boolean | undefined;
115
+ /** The seed, an integer in [0, 2^53); default 0. */
116
+ seed?: number | undefined;
117
+ }
118
+
119
+ /**
120
+ * A sequence of n integers drawn independently from the discrete power law
121
+ * P(d) ~ d^-exponent on [minDegree, maxDegree], by inversion of a cumulative table built with
122
+ * detPow: entry i is one nextFloat of stream (seed, "power-law", 0), in index order. With
123
+ * `evenSum` (the default) an odd sum is fixed by changing the last entry: +1 when it is below
124
+ * maxDegree, else -1. O(n log(maxDegree - minDegree) + maxDegree - minDegree).
125
+ * @param options - n, exponent, minDegree, maxDegree, evenSum and seed
126
+ * @returns the sequence
127
+ */
128
+ export function powerLawDegreeSequence(options: PowerLawDegreeSequenceOptions): Uint32Array<ArrayBuffer> {
129
+ const { n, exponent, minDegree, maxDegree } = options;
130
+ const seed = resolveSeed(options.seed);
131
+ checkInt("n", n, 0);
132
+ const sample = powerLawSampler(["exponent", "minDegree", "maxDegree"], exponent, minDegree, maxDegree);
133
+ const stream = new RandomStream(seed, "power-law", 0);
134
+ const seq = new Uint32Array(n);
135
+ for (let i = 0; i < n; i++) {
136
+ seq[i] = sample(stream);
137
+ }
138
+ if ((options.evenSum ?? true) && n > 0) {
139
+ makeSumEven(seq, minDegree, maxDegree);
140
+ }
141
+ return seq;
142
+ }
143
+
144
+ /**
145
+ * Check a degree sequence and return its sum.
146
+ * @param name - the option name
147
+ * @param degrees - the degrees
148
+ * @returns the sum
149
+ */
150
+ function degreeSum(name: string, degrees: ArrayLike<number>): number {
151
+ checkInt(`${name}.length`, degrees.length, 0);
152
+ let total = 0;
153
+ for (let i = 0; i < degrees.length; i++) {
154
+ const d = degrees[i];
155
+ if (!(Number.isInteger(d) && d >= 0 && d <= MAX_COUNT)) {
156
+ checkInt(`${name}[${i}]`, d, 0);
157
+ }
158
+ total += d;
159
+ }
160
+ checkEdgeCount(total / 2);
161
+ return total;
162
+ }
163
+
164
+ /**
165
+ * The option value of a keep / erase policy, checked.
166
+ * @param name - the option name
167
+ * @param value - the value (default "erase")
168
+ * @returns true for keep
169
+ */
170
+ function keeps(name: string, value: EdgePolicy | undefined): boolean {
171
+ if (value !== undefined && value !== "keep" && value !== "erase") {
172
+ throw new RangeError(`${name} must be "keep" or "erase", got ${String(value)}`);
173
+ }
174
+ return value === "keep";
175
+ }
176
+
177
+ /**
178
+ * The stub list: node i + offset repeated degrees[i] times, ascending.
179
+ * @param degrees - the degrees
180
+ * @param total - their sum
181
+ * @param offset - added to every node index
182
+ * @returns the stubs
183
+ */
184
+ export function stubList(degrees: ArrayLike<number>, total: number, offset = 0): Uint32Array<ArrayBuffer> {
185
+ const stubs = new Uint32Array(total);
186
+ let k = 0;
187
+ for (let i = 0; i < degrees.length; i++) {
188
+ stubs.fill(i + offset, k, k + degrees[i]);
189
+ k += degrees[i];
190
+ }
191
+ return stubs;
192
+ }
193
+
194
+ /**
195
+ * Fisher-Yates shuffle in place: for i = length - 1 down to 1, swap entries i and nextBelow(i + 1).
196
+ * @param a - the array
197
+ * @param stream - the stream
198
+ */
199
+ export function shuffle(a: U32, stream: RandomStream): void {
200
+ for (let i = a.length - 1; i > 0; i--) {
201
+ const j = stream.nextBelow(i + 1);
202
+ const t = a[i];
203
+ a[i] = a[j];
204
+ a[j] = t;
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Filter an edge list, keeping edge order: drop self-loops unless `keepLoops`, drop edges whose
210
+ * endpoints share a `group` value when `group` is given, and drop every repeat of a pair (ordered
211
+ * when directed, unordered otherwise) after its first kept occurrence unless `keepMulti`. O(n + m)
212
+ * by a counting sort on the smaller endpoint and a last-seen mark per node, no hashing.
213
+ * @param n - the node count
214
+ * @param src - the sources
215
+ * @param dst - the targets
216
+ * @param directed - whether pairs are ordered
217
+ * @param keepLoops - keep self-loops
218
+ * @param keepMulti - keep repeated pairs
219
+ * @param out - receives the kept edges
220
+ * @param group - a node column; edges inside one group are dropped
221
+ */
222
+ function eraseEdges(
223
+ n: number,
224
+ src: U32,
225
+ dst: U32,
226
+ directed: boolean,
227
+ keepLoops: boolean,
228
+ keepMulti: boolean,
229
+ out: EdgeBuffer,
230
+ group?: U32,
231
+ ): void {
232
+ const m = src.length;
233
+ const keep = new Uint8Array(m).fill(1);
234
+ for (let e = 0; e < m; e++) {
235
+ const u = src[e];
236
+ const v = dst[e];
237
+ if ((!keepLoops && u === v) || (group !== undefined && group[u] === group[v])) {
238
+ keep[e] = 0;
239
+ }
240
+ }
241
+ if (!keepMulti) {
242
+ const lo = (e: number): number => (directed ? src[e] : Math.min(src[e], dst[e]));
243
+ const start = new Uint32Array(n + 1);
244
+ for (let e = 0; e < m; e++) {
245
+ start[lo(e) + 1]++;
246
+ }
247
+ for (let i = 0; i < n; i++) {
248
+ start[i + 1] += start[i];
249
+ }
250
+ const fill = start.slice(0, n);
251
+ const order = new Uint32Array(m);
252
+ for (let e = 0; e < m; e++) {
253
+ order[fill[lo(e)]++] = e;
254
+ }
255
+ // mark[v] = u + 1 when the pair (u, v) has been seen in u's bucket
256
+ const mark = new Uint32Array(n);
257
+ for (let k = 0; k < m; k++) {
258
+ const e = order[k];
259
+ if (keep[e] === 0) {
260
+ continue;
261
+ }
262
+ const u = lo(e);
263
+ const v = directed ? dst[e] : Math.max(src[e], dst[e]);
264
+ if (mark[v] === u + 1) {
265
+ keep[e] = 0;
266
+ } else {
267
+ mark[v] = u + 1;
268
+ }
269
+ }
270
+ }
271
+ for (let e = 0; e < m; e++) {
272
+ if (keep[e] === 1) {
273
+ out.push(src[e], dst[e]);
274
+ }
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Pair consecutive stubs of a shuffled undirected stub list into edges (stubs[2k], stubs[2k + 1])
280
+ * and erase as asked.
281
+ * @param n - the node count
282
+ * @param stubs - the shuffled stubs (even length)
283
+ * @param keepLoops - keep self-loops
284
+ * @param keepMulti - keep repeated pairs
285
+ * @param out - receives the edges
286
+ * @param group - a node column; edges inside one group are dropped
287
+ */
288
+ export function pairStubs(
289
+ n: number,
290
+ stubs: U32,
291
+ keepLoops: boolean,
292
+ keepMulti: boolean,
293
+ out: EdgeBuffer,
294
+ group?: U32,
295
+ ): void {
296
+ const m = stubs.length / 2;
297
+ const src = new Uint32Array(m);
298
+ const dst = new Uint32Array(m);
299
+ for (let k = 0; k < m; k++) {
300
+ src[k] = stubs[2 * k];
301
+ dst[k] = stubs[2 * k + 1];
302
+ }
303
+ eraseEdges(n, src, dst, false, keepLoops, keepMulti, out, group);
304
+ }
305
+
306
+ /** Options of {@link configurationModelGraph}. */
307
+ export interface ConfigurationModelOptions extends WeightOptions {
308
+ /** The degree of every node; the sum must be even. */
309
+ degrees: ArrayLike<number>;
310
+ /** Keep or erase self-loops; default "erase". */
311
+ selfLoops?: EdgePolicy | undefined;
312
+ /** Keep or erase repeated pairs (the first occurrence in edge order stays); default "erase". */
313
+ multiEdges?: EdgePolicy | undefined;
314
+ /** The seed, an integer in [0, 2^53); default 0. */
315
+ seed?: number | undefined;
316
+ }
317
+
318
+ /**
319
+ * The configuration model (E. A. Bender and E. R. Canfield, "The asymptotic number of labeled
320
+ * graphs with given degree sequences", J. Combin. Theory A 24, 296-307, 1978,
321
+ * doi:10.1016/0097-3165(78)90059-6; M. Molloy and B. Reed, "A critical point for random graphs with
322
+ * a given degree sequence", Random Struct. Algorithms 6, 161-179, 1995, doi:10.1002/rsa.3240060204;
323
+ * M. E. J. Newman, S. H. Strogatz and D. J. Watts, "Random graphs with arbitrary degree
324
+ * distributions and their applications", Phys. Rev. E 64, 026118, 2001,
325
+ * doi:10.1103/PhysRevE.64.026118). The stub list (node i repeated degrees[i] times, ascending) is
326
+ * Fisher-Yates shuffled with stream (seed, "configuration", 0) and consecutive stubs are paired:
327
+ * edge k is (stubs[2k], stubs[2k + 1]), in that order. With keep / keep the degrees are exact (a
328
+ * multigraph); erasing drops self-loops and every repeat of a pair after its first occurrence, so
329
+ * degrees can only go down. An odd degree sum is a RangeError. O(n + m).
330
+ * @param options - degrees, selfLoops, multiEdges and seed
331
+ * @returns the undirected graph
332
+ */
333
+ export function configurationModelGraph(options: ConfigurationModelOptions): SampleGraph {
334
+ const { degrees } = options;
335
+ const seed = resolveSeed(options.seed);
336
+ const keepLoops = keeps("selfLoops", options.selfLoops);
337
+ const keepMulti = keeps("multiEdges", options.multiEdges);
338
+ const total = degreeSum("degrees", degrees);
339
+ if (total % 2 !== 0) {
340
+ throw new RangeError(`the degree sum must be even, got ${total}`);
341
+ }
342
+ const n = degrees.length;
343
+ const stubs = stubList(degrees, total);
344
+ shuffle(stubs, new RandomStream(seed, "configuration", 0));
345
+ const out = new EdgeBuffer(total / 2);
346
+ pairStubs(n, stubs, keepLoops, keepMulti, out);
347
+ return applyWeights(toGraph(n, out, false), options);
348
+ }
349
+
350
+ /** Options of {@link directedConfigurationModelGraph}. */
351
+ export interface DirectedConfigurationModelOptions extends WeightOptions {
352
+ /** The out-degree of every node. */
353
+ outDegrees: ArrayLike<number>;
354
+ /** The in-degree of every node; same length and same sum as outDegrees. */
355
+ inDegrees: ArrayLike<number>;
356
+ /** Keep or erase self-loops; default "erase". */
357
+ selfLoops?: EdgePolicy | undefined;
358
+ /** Keep or erase repeated ordered pairs (the first occurrence stays); default "erase". */
359
+ multiEdges?: EdgePolicy | undefined;
360
+ /** The seed, an integer in [0, 2^53); default 0. */
361
+ seed?: number | undefined;
362
+ }
363
+
364
+ /**
365
+ * The directed configuration model (Newman, Strogatz and Watts 2001, section on directed graphs):
366
+ * the in-stub list (node i repeated inDegrees[i] times, ascending) is Fisher-Yates shuffled with
367
+ * stream (seed, "configuration-directed", 0) and paired in order with the ascending out-stub list,
368
+ * so edge k runs from the k-th out-stub to the k-th shuffled in-stub (edges come grouped by
369
+ * source, ascending). Erasing works as in {@link configurationModelGraph} on ordered pairs.
370
+ * O(n + m).
371
+ * @param options - outDegrees, inDegrees, selfLoops, multiEdges and seed
372
+ * @returns the directed graph
373
+ */
374
+ export function directedConfigurationModelGraph(options: DirectedConfigurationModelOptions): SampleGraph {
375
+ const { outDegrees, inDegrees } = options;
376
+ const seed = resolveSeed(options.seed);
377
+ const keepLoops = keeps("selfLoops", options.selfLoops);
378
+ const keepMulti = keeps("multiEdges", options.multiEdges);
379
+ const outTotal = degreeSum("outDegrees", outDegrees);
380
+ const inTotal = degreeSum("inDegrees", inDegrees);
381
+ if (outDegrees.length !== inDegrees.length) {
382
+ throw new RangeError(`outDegrees and inDegrees must have the same length`);
383
+ }
384
+ if (outTotal !== inTotal) {
385
+ throw new RangeError(`the out-degree sum (${outTotal}) must equal the in-degree sum (${inTotal})`);
386
+ }
387
+ const n = outDegrees.length;
388
+ const dst = stubList(inDegrees, inTotal);
389
+ shuffle(dst, new RandomStream(seed, "configuration-directed", 0));
390
+ const out = new EdgeBuffer(outTotal);
391
+ eraseEdges(n, stubList(outDegrees, outTotal), dst, true, keepLoops, keepMulti, out);
392
+ return applyWeights(toGraph(n, out, true), options);
393
+ }
394
+
395
+ /** Options of {@link bipartiteConfigurationModelGraph}. */
396
+ export interface BipartiteConfigurationModelOptions extends WeightOptions {
397
+ /** The degree of every left node (nodes 0 .. L - 1). */
398
+ leftDegrees: ArrayLike<number>;
399
+ /** The degree of every right node (nodes L .. L + R - 1); same sum as leftDegrees. */
400
+ rightDegrees: ArrayLike<number>;
401
+ /** Keep or erase repeated pairs (the first occurrence stays); default "erase". */
402
+ multiEdges?: EdgePolicy | undefined;
403
+ /** The seed, an integer in [0, 2^53); default 0. */
404
+ seed?: number | undefined;
405
+ }
406
+
407
+ /**
408
+ * The bipartite configuration model (Newman, Strogatz and Watts 2001, section on bipartite
409
+ * graphs): left nodes are 0 .. L - 1, right nodes L .. L + R - 1. The right stub list (ascending)
410
+ * is Fisher-Yates shuffled with stream (seed, "bipartite-configuration", 0) and paired in order with
411
+ * the ascending left stub list; edge k is (k-th left stub, k-th shuffled right stub). Node column
412
+ * `side` (u8): 0 left, 1 right. O(n + m).
413
+ * @param options - leftDegrees, rightDegrees, multiEdges and seed
414
+ * @returns the undirected bipartite graph
415
+ */
416
+ export function bipartiteConfigurationModelGraph(options: BipartiteConfigurationModelOptions): SampleGraph {
417
+ const { leftDegrees, rightDegrees } = options;
418
+ const seed = resolveSeed(options.seed);
419
+ const keepMulti = keeps("multiEdges", options.multiEdges);
420
+ const leftTotal = degreeSum("leftDegrees", leftDegrees);
421
+ const rightTotal = degreeSum("rightDegrees", rightDegrees);
422
+ if (leftTotal !== rightTotal) {
423
+ throw new RangeError(`the left degree sum (${leftTotal}) must equal the right degree sum (${rightTotal})`);
424
+ }
425
+ const left = leftDegrees.length;
426
+ const n = left + rightDegrees.length;
427
+ checkInt("the node count", n, 0);
428
+ const dst = stubList(rightDegrees, rightTotal, left);
429
+ shuffle(dst, new RandomStream(seed, "bipartite-configuration", 0));
430
+ const out = new EdgeBuffer(leftTotal);
431
+ eraseEdges(n, stubList(leftDegrees, leftTotal), dst, false, true, keepMulti, out);
432
+ const side = new Uint8Array(n).fill(1, left);
433
+ return applyWeights(toGraph(n, out, false, { side }), options);
434
+ }
435
+
436
+ /** The checked and precomputed form of an expected-degree model (Chung-Lu or the DC-SBM). */
437
+ interface ExpectedDegreePlan {
438
+ readonly n: number;
439
+ readonly seed: number;
440
+ readonly domain: string;
441
+ /** order[row] = the node of that row. */
442
+ readonly order: U32;
443
+ /** The weight of every row. */
444
+ readonly weight: Float64Array;
445
+ /** The block of every row. */
446
+ readonly rowBlock: U32;
447
+ /** starts[b] = the first row of block b; starts[B] = n. */
448
+ readonly starts: readonly number[];
449
+ /** P(u, v) = min(1, factor[r][s] w_u w_v) for u in block r, v in block s. */
450
+ readonly factor: readonly (readonly number[])[];
451
+ /** The sum of the weights. */
452
+ readonly total: number;
453
+ }
454
+
455
+ /**
456
+ * Check weights (finite, >= 0) and return their sum.
457
+ * @param weights - the weights
458
+ * @returns the sum
459
+ */
460
+ function weightSum(weights: ArrayLike<number>): number {
461
+ checkInt("expectedDegrees.length", weights.length, 0);
462
+ let total = 0;
463
+ for (let i = 0; i < weights.length; i++) {
464
+ if (!(Number.isFinite(weights[i]) && weights[i] >= 0)) {
465
+ throw new RangeError(`expectedDegrees[${i}] must be a finite number >= 0, got ${String(weights[i])}`);
466
+ }
467
+ total += weights[i];
468
+ }
469
+ return total;
470
+ }
471
+
472
+ /**
473
+ * Build the rows of an expected-degree model: nodes of each block (consecutive index ranges) sorted
474
+ * by weight descending, ties by index ascending.
475
+ * @param weights - the node weights
476
+ * @param nodeStarts - block boundaries in node indices
477
+ * @param factor - the block-pair factors
478
+ * @param seed - the seed
479
+ * @param domain - the stream domain
480
+ * @param total - the weight sum
481
+ * @returns the plan
482
+ */
483
+ function planRows(
484
+ weights: ArrayLike<number>,
485
+ nodeStarts: readonly number[],
486
+ factor: readonly (readonly number[])[],
487
+ seed: number,
488
+ domain: string,
489
+ total: number,
490
+ ): ExpectedDegreePlan {
491
+ const n = weights.length;
492
+ const order = new Uint32Array(n);
493
+ const rowBlock = new Uint32Array(n);
494
+ for (let i = 0; i < n; i++) {
495
+ order[i] = i;
496
+ }
497
+ for (let b = 0; b + 1 < nodeStarts.length; b++) {
498
+ order.subarray(nodeStarts[b], nodeStarts[b + 1]).sort((x, y) => weights[y] - weights[x] || x - y);
499
+ rowBlock.fill(b, nodeStarts[b], nodeStarts[b + 1]);
500
+ }
501
+ const weight = Float64Array.from(order, (i) => weights[i]);
502
+ return { n, seed, domain, order, weight, rowBlock, starts: nodeStarts, factor, total };
503
+ }
504
+
505
+ /** Options of {@link chungLuGraph}. */
506
+ export interface ChungLuOptions extends WeightOptions {
507
+ /** The expected degree (weight) of every node, finite and >= 0. */
508
+ expectedDegrees: ArrayLike<number>;
509
+ /** The seed, an integer in [0, 2^53); default 0. */
510
+ seed?: number | undefined;
511
+ }
512
+
513
+ /**
514
+ * Check Chung-Lu options and build the plan: one block, factor 1 / S.
515
+ * @param options - the options
516
+ * @returns the plan
517
+ */
518
+ export function planChungLu(options: ChungLuOptions): ExpectedDegreePlan {
519
+ const seed = resolveSeed(options.seed);
520
+ const total = weightSum(options.expectedDegrees);
521
+ const n = options.expectedDegrees.length;
522
+ return planRows(options.expectedDegrees, [0, n], [[total > 0 ? 1 / total : 0]], seed, "chung-lu", total);
523
+ }
524
+
525
+ /**
526
+ * Rows [start, end) of an expected-degree model (Chung-Lu, or the DC-SBM with its own plan and
527
+ * domain) by the skipping of Miller and Hagberg: row `row` (in block r) draws from stream
528
+ * (seed, domain, row) and walks blocks s = r .. B - 1 in order; inside block s it visits the later
529
+ * rows v (all rows of s when s > r) in row order, whose weights never increase, skipping with the
530
+ * previous probability p (nextSkip(detLog(1 - p)) unless p = 1) and accepting the landing v with
531
+ * probability q / p (one nextFloat), q = min(1, factor[r][s] w_row w_v). Edges are
532
+ * (order[row], order[v]) in original node indices. Concatenating consecutive row ranges gives
533
+ * the whole graph.
534
+ * @param plan - the checked options
535
+ * @param start - the first row
536
+ * @param end - one past the last row
537
+ * @param out - receives the edges
538
+ */
539
+ export function chungLuRows(plan: ExpectedDegreePlan, start: number, end: number, out: EdgeBuffer): void {
540
+ const { order, weight, rowBlock, starts, factor } = plan;
541
+ const stream = new RandomStream(plan.seed, plan.domain, 0);
542
+ const count = starts.length - 1;
543
+ for (let row = start; row < end; row++) {
544
+ stream.reset(row);
545
+ const r = rowBlock[row];
546
+ // ponytail: O(B) per row like the block model; iterate non-zero blocks if B grows large
547
+ for (let s = r; s < count; s++) {
548
+ const cu = factor[r][s] * weight[row];
549
+ let v = s === r ? row + 1 : starts[s];
550
+ const hi = starts[s + 1];
551
+ if (cu === 0 || v >= hi) {
552
+ continue;
553
+ }
554
+ let p = Math.min(1, cu * weight[v]);
555
+ while (v < hi && p > 0) {
556
+ if (p !== 1) {
557
+ const logQ = detLog(1 - p);
558
+ // p below 2^-53 rounds 1 - p to 1: no further edge in this segment
559
+ if (logQ === 0) {
560
+ break;
561
+ }
562
+ v += stream.nextSkip(logQ);
563
+ if (v >= hi) {
564
+ break;
565
+ }
566
+ }
567
+ const q = Math.min(1, cu * weight[v]);
568
+ if (stream.nextFloat() < q / p) {
569
+ out.push(order[row], order[v]);
570
+ }
571
+ p = q;
572
+ v++;
573
+ }
574
+ }
575
+ }
576
+ }
577
+
578
+ /**
579
+ * Run a plan over all its rows.
580
+ * @param plan - the plan
581
+ * @param nodeColumns - ground-truth columns
582
+ * @param options - for the weights option
583
+ * @returns the graph
584
+ */
585
+ function runPlan(plan: ExpectedDegreePlan, nodeColumns: SampleGraph["nodeColumns"], options: WeightOptions): SampleGraph {
586
+ const mean = plan.total / 2;
587
+ checkEdgeCount(mean);
588
+ const out = new EdgeBuffer(Math.ceil(mean + 6 * Math.sqrt(mean) + 16));
589
+ chungLuRows(plan, 0, plan.n, out);
590
+ return applyWeights(toGraph(plan.n, out, false, nodeColumns), options);
591
+ }
592
+
593
+ /**
594
+ * The Chung-Lu expected-degree graph (F. Chung and L. Lu, "The average distances in random graphs
595
+ * with given expected degrees", PNAS 99, 15879-15882, 2002, doi:10.1073/pnas.252631999): every
596
+ * pair u != v is joined independently with probability min(1, w_u w_v / S), S the weight sum, so
597
+ * node u's expected degree is about w_u when every w_u w_v is below S. Linear time by the skipping
598
+ * of J. C. Miller and A. Hagberg, "Efficient generation of networks with given expected degrees",
599
+ * WAW 2011, LNCS 6732, 115-126, doi:10.1007/978-3-642-21286-4_10. Rows are the nodes sorted by
600
+ * weight descending (ties by index ascending); row i draws from stream (seed, "chung-lu", i) (see
601
+ * {@link chungLuRows}). Edges are listed by row, each (row node, later node) in original indices.
602
+ * Simple, undirected. O(n log n + m).
603
+ * @param options - expectedDegrees and seed
604
+ * @returns the undirected graph
605
+ */
606
+ export function chungLuGraph(options: ChungLuOptions): SampleGraph {
607
+ return runPlan(planChungLu(options), undefined, options);
608
+ }
609
+
610
+ /** Options of {@link degreeCorrectedSbmGraph}. */
611
+ export interface DegreeCorrectedSbmOptions extends WeightOptions {
612
+ /** The size of every block; block b holds the next `sizes[b]` node indices. */
613
+ sizes: readonly number[];
614
+ /** The target degree of every node, finite and >= 0; length = the sum of sizes. */
615
+ expectedDegrees: ArrayLike<number>;
616
+ /** The mixing parameter mu in [0, 1]: the share of each node's edges that leave its block. */
617
+ mixing: number;
618
+ /** The seed, an integer in [0, 2^53); default 0. */
619
+ seed?: number | undefined;
620
+ }
621
+
622
+ /**
623
+ * Check DC-SBM options and build the plan.
624
+ * @param options - the options
625
+ * @returns the plan
626
+ */
627
+ export function planDegreeCorrectedSbm(options: DegreeCorrectedSbmOptions): ExpectedDegreePlan {
628
+ const { sizes, expectedDegrees, mixing } = options;
629
+ const seed = resolveSeed(options.seed);
630
+ checkInt("sizes.length", sizes.length, 1);
631
+ checkProbability("mixing", mixing);
632
+ const total = weightSum(expectedDegrees);
633
+ const starts = [0];
634
+ for (let b = 0; b < sizes.length; b++) {
635
+ checkInt(`sizes[${b}]`, sizes[b], 0);
636
+ starts.push(starts[b] + sizes[b]);
637
+ }
638
+ if (starts[sizes.length] !== expectedDegrees.length) {
639
+ throw new RangeError(
640
+ `the sizes sum to ${starts[sizes.length]}, but expectedDegrees has ${expectedDegrees.length} entries`,
641
+ );
642
+ }
643
+ const kappa = sizes.map((_, b) => {
644
+ let k = 0;
645
+ for (let i = starts[b]; i < starts[b + 1]; i++) {
646
+ k += expectedDegrees[i];
647
+ }
648
+ return k;
649
+ });
650
+ const between = total > 0 ? mixing / total : 0;
651
+ const inside = kappa.map((kr) => (kr > 0 ? (1 - mixing) / kr : 0));
652
+ const factor = kappa.map((_, r) => kappa.map((_2, s) => (r === s ? inside[r] : between)));
653
+ return planRows(expectedDegrees, starts, factor, seed, "dcsbm", total);
654
+ }
655
+
656
+ /**
657
+ * The degree-corrected stochastic block model (B. Karrer and M. E. J. Newman, "Stochastic
658
+ * blockmodels and community structure in networks", Phys. Rev. E 83, 016107, 2011,
659
+ * doi:10.1103/PhysRevE.83.016107), sampled as a simple graph with Bernoulli edges:
660
+ * P(uv) = min(1, theta_u theta_v omega_rs) with theta_u = d_u / kappa_r (kappa_r the degree total of
661
+ * u's block r, K the grand total), omega_rr = (1 - mu) kappa_r and omega_rs = mu kappa_r kappa_s / K
662
+ * for r != s. So node u's expected degree is about d_u (1 - mu kappa_r / K): the inside share is
663
+ * 1 - mu, but the outside share misses the mu kappa_r / K that would land in u's own block.
664
+ * Rows: block by block, inside a block the nodes sorted by d descending (ties by index); row i
665
+ * draws from stream (seed, "dcsbm", i) and walks its own block's later rows, then every later
666
+ * block (see {@link chungLuRows}). Edges are listed by row in original node indices. Node column
667
+ * `community` (u32). With one block and mu = 0 it is Chung-Lu. O(n log n + n B + m).
668
+ * @param options - sizes, expectedDegrees, mixing and seed
669
+ * @returns the undirected graph
670
+ */
671
+ export function degreeCorrectedSbmGraph(options: DegreeCorrectedSbmOptions): SampleGraph {
672
+ const plan = planDegreeCorrectedSbm(options);
673
+ const community = new Uint32Array(plan.n);
674
+ for (let b = 0; b + 1 < plan.starts.length; b++) {
675
+ community.fill(b, plan.starts[b], plan.starts[b + 1]);
676
+ }
677
+ return runPlan(plan, { community }, options);
678
+ }
679
+
680
+ /** Options of {@link randomRegularGraph}. */
681
+ export interface RandomRegularOptions extends WeightOptions {
682
+ /** The node count, >= 0. */
683
+ n: number;
684
+ /** The degree of every node, in [0, n - 1]; n d must be even. */
685
+ d: number;
686
+ /** The seed, an integer in [0, 2^53); default 0. */
687
+ seed?: number | undefined;
688
+ }
689
+
690
+ /** Attempts before randomRegularGraph gives up. */
691
+ const REGULAR_ATTEMPTS = 100;
692
+ /** Re-pairing rounds inside one attempt before it counts as failed. */
693
+ const REGULAR_ROUNDS = 1000;
694
+
695
+ /**
696
+ * One attempt of the Steger-Wormald pairing; fills `adj` (d slots per node) and `deg`.
697
+ * @param n - the node count
698
+ * @param d - the degree
699
+ * @param stream - the attempt's stream
700
+ * @param adj - the adjacency slots
701
+ * @param deg - the filled slot count per node
702
+ * @returns true on success
703
+ */
704
+ function regularAttempt(n: number, d: number, stream: RandomStream, adj: U32, deg: U32): boolean {
705
+ deg.fill(0);
706
+ const has = (u: number, v: number): boolean => {
707
+ const base = u * d;
708
+ for (let k = base; k < base + deg[u]; k++) {
709
+ if (adj[k] === v) {
710
+ return true;
711
+ }
712
+ }
713
+ return false;
714
+ };
715
+ const potential = new Uint32Array(n);
716
+ let stubs: U32 = stubList(new Uint32Array(n).fill(d), n * d);
717
+ for (let round = 0; round < REGULAR_ROUNDS && stubs.length > 0; round++) {
718
+ shuffle(stubs, stream);
719
+ const touched: number[] = [];
720
+ for (let k = 0; k < stubs.length; k += 2) {
721
+ const u = Math.min(stubs[k], stubs[k + 1]);
722
+ const v = Math.max(stubs[k], stubs[k + 1]);
723
+ if (u !== v && !has(u, v)) {
724
+ adj[u * d + deg[u]++] = v;
725
+ adj[v * d + deg[v]++] = u;
726
+ } else {
727
+ for (const x of [u, v]) {
728
+ if (potential[x]++ === 0) {
729
+ touched.push(x);
730
+ }
731
+ }
732
+ }
733
+ }
734
+ touched.sort((a, b) => a - b);
735
+ // suitable: some pair of distinct leftover nodes is not yet an edge
736
+ let suitable = touched.length === 0;
737
+ for (let i = 0; i < touched.length && !suitable; i++) {
738
+ for (let j = i + 1; j < touched.length && !suitable; j++) {
739
+ suitable = !has(touched[i], touched[j]);
740
+ }
741
+ }
742
+ if (!suitable) {
743
+ return false;
744
+ }
745
+ let total = 0;
746
+ for (const x of touched) {
747
+ total += potential[x];
748
+ }
749
+ const next = new Uint32Array(total);
750
+ let k = 0;
751
+ for (const x of touched) {
752
+ next.fill(x, k, k + potential[x]);
753
+ k += potential[x];
754
+ potential[x] = 0;
755
+ }
756
+ stubs = next;
757
+ }
758
+ return stubs.length === 0;
759
+ }
760
+
761
+ /**
762
+ * A uniformly-ish random d-regular simple graph by the pairing algorithm of A. Steger and
763
+ * N. C. Wormald, "Generating random regular graphs quickly", Combin. Probab. Comput. 8, 377-396,
764
+ * 1999, doi:10.1017/S0963548399003867, structured like networkx's `random_regular_graph`: attempt
765
+ * a (a = 0, 1, ...) draws from stream (seed, "random-regular", a); it Fisher-Yates shuffles the
766
+ * stub list (node i repeated d times, ascending), keeps each consecutive pair that is not a loop
767
+ * and not yet an edge, and re-pairs the leftover stubs (ascending node order) while some leftover
768
+ * pair could still be joined; otherwise it restarts. At most 100 attempts of at most 1000 rounds,
769
+ * then a RangeError. Edges (u, v), u < v, in lexicographic order. Expected O(n d^2) for small d.
770
+ * @param options - n, d and seed
771
+ * @returns the undirected graph
772
+ */
773
+ export function randomRegularGraph(options: RandomRegularOptions): SampleGraph {
774
+ const { n, d } = options;
775
+ const seed = resolveSeed(options.seed);
776
+ checkInt("n", n, 0);
777
+ checkInt("d", d, 0, Math.max(0, n - 1));
778
+ if ((n * d) % 2 !== 0) {
779
+ throw new RangeError(`n * d must be even, got ${n} * ${d}`);
780
+ }
781
+ checkEdgeCount((n * d) / 2);
782
+ const out = new EdgeBuffer((n * d) / 2);
783
+ if (d > 0) {
784
+ const adj = new Uint32Array(n * d);
785
+ const deg = new Uint32Array(n);
786
+ const stream = new RandomStream(seed, "random-regular", 0);
787
+ let attempt = 0;
788
+ for (; attempt < REGULAR_ATTEMPTS; attempt++) {
789
+ stream.reset(attempt);
790
+ if (regularAttempt(n, d, stream, adj, deg)) {
791
+ break;
792
+ }
793
+ }
794
+ if (attempt === REGULAR_ATTEMPTS) {
795
+ throw new RangeError(`randomRegularGraph found no ${d}-regular graph on ${n} nodes in ${REGULAR_ATTEMPTS} attempts`);
796
+ }
797
+ for (let u = 0; u < n; u++) {
798
+ const row = adj.subarray(u * d, u * d + d).sort();
799
+ for (const v of row) {
800
+ if (v > u) {
801
+ out.push(u, v);
802
+ }
803
+ }
804
+ }
805
+ }
806
+ return applyWeights(toGraph(n, out, false), options);
807
+ }