@graphty/graph-samples 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +123 -0
- package/README.md +190 -1
- package/dist/chunks/build-DdCe60t3.js +47 -0
- package/dist/chunks/build-DdCe60t3.js.map +1 -0
- package/dist/chunks/meta-B6toBzaa.js +19 -0
- package/dist/chunks/meta-B6toBzaa.js.map +1 -0
- package/dist/chunks/meta-BM_YIhlA.js +28 -0
- package/dist/chunks/meta-BM_YIhlA.js.map +1 -0
- package/dist/chunks/meta-BMmtUpPx.js +30 -0
- package/dist/chunks/meta-BMmtUpPx.js.map +1 -0
- package/dist/chunks/meta-BXC7oi86.js +22 -0
- package/dist/chunks/meta-BXC7oi86.js.map +1 -0
- package/dist/chunks/meta-BaFPvhc1.js +19 -0
- package/dist/chunks/meta-BaFPvhc1.js.map +1 -0
- package/dist/chunks/meta-C58v1Oy0.js +28 -0
- package/dist/chunks/meta-C58v1Oy0.js.map +1 -0
- package/dist/chunks/meta-CQRXyexG.js +23 -0
- package/dist/chunks/meta-CQRXyexG.js.map +1 -0
- package/dist/chunks/meta-DrgM1eS0.js +23 -0
- package/dist/chunks/meta-DrgM1eS0.js.map +1 -0
- package/dist/chunks/meta-IhoaDXAV.js +19 -0
- package/dist/chunks/meta-IhoaDXAV.js.map +1 -0
- package/dist/chunks/meta-MQPbBUUB.js +29 -0
- package/dist/chunks/meta-MQPbBUUB.js.map +1 -0
- package/dist/chunks/meta-Qp4HNYAZ.js +24 -0
- package/dist/chunks/meta-Qp4HNYAZ.js.map +1 -0
- package/dist/chunks/meta-mns0uFIW.js +19 -0
- package/dist/chunks/meta-mns0uFIW.js.map +1 -0
- package/dist/datasets/celegans-neural.d.ts +1 -0
- package/dist/datasets/celegans-neural.js +7359 -0
- package/dist/datasets/celegans-neural.js.map +1 -0
- package/dist/datasets/contiguous-usa.d.ts +1 -0
- package/dist/datasets/contiguous-usa.js +501 -0
- package/dist/datasets/contiguous-usa.js.map +1 -0
- package/dist/datasets/davis-southern-women.d.ts +1 -0
- package/dist/datasets/davis-southern-women.js +235 -0
- package/dist/datasets/davis-southern-women.js.map +1 -0
- package/dist/datasets/dolphins.d.ts +1 -0
- package/dist/datasets/dolphins.js +406 -0
- package/dist/datasets/dolphins.js.map +1 -0
- package/dist/datasets/florentine-families.d.ts +1 -0
- package/dist/datasets/florentine-families.js +75 -0
- package/dist/datasets/florentine-families.js.map +1 -0
- package/dist/datasets/football.d.ts +1 -0
- package/dist/datasets/football.js +1508 -0
- package/dist/datasets/football.js.map +1 -0
- package/dist/datasets/karate.d.ts +1 -0
- package/dist/datasets/karate.js +295 -0
- package/dist/datasets/karate.js.map +1 -0
- package/dist/datasets/knuth-miles.d.ts +1 -0
- package/dist/datasets/knuth-miles.js +24933 -0
- package/dist/datasets/knuth-miles.js.map +1 -0
- package/dist/datasets/les-miserables.d.ts +1 -0
- package/dist/datasets/les-miserables.js +860 -0
- package/dist/datasets/les-miserables.js.map +1 -0
- package/dist/datasets/openflights.d.ts +1 -0
- package/dist/datasets/openflights.js +130277 -0
- package/dist/datasets/openflights.js.map +1 -0
- package/dist/datasets/political-blogs.d.ts +1 -0
- package/dist/datasets/political-blogs.js +42551 -0
- package/dist/datasets/political-blogs.js.map +1 -0
- package/dist/datasets/political-books.d.ts +1 -0
- package/dist/datasets/political-books.js +1124 -0
- package/dist/datasets/political-books.js.map +1 -0
- package/dist/generators.d.ts +1 -0
- package/dist/generators.js +4496 -0
- package/dist/generators.js.map +1 -0
- package/dist/graph-samples.d.ts +1 -0
- package/dist/graph-samples.js +142 -0
- package/dist/graph-samples.js.map +1 -0
- package/dist/src/datasets/build.d.ts +89 -0
- package/dist/src/datasets/build.d.ts.map +1 -0
- package/dist/src/datasets/build.js +53 -0
- package/dist/src/datasets/build.js.map +1 -0
- package/dist/src/datasets/catalog.d.ts +8 -0
- package/dist/src/datasets/catalog.d.ts.map +1 -0
- package/dist/src/datasets/catalog.js +34 -0
- package/dist/src/datasets/catalog.js.map +1 -0
- package/dist/src/datasets/celegans-neural/data.d.ts +3 -0
- package/dist/src/datasets/celegans-neural/data.d.ts.map +1 -0
- package/dist/src/datasets/celegans-neural/data.js +573 -0
- package/dist/src/datasets/celegans-neural/data.js.map +1 -0
- package/dist/src/datasets/celegans-neural/index.d.ts +11 -0
- package/dist/src/datasets/celegans-neural/index.d.ts.map +1 -0
- package/dist/src/datasets/celegans-neural/index.js +14 -0
- package/dist/src/datasets/celegans-neural/index.js.map +1 -0
- package/dist/src/datasets/celegans-neural/meta.d.ts +4 -0
- package/dist/src/datasets/celegans-neural/meta.d.ts.map +1 -0
- package/dist/src/datasets/celegans-neural/meta.js +21 -0
- package/dist/src/datasets/celegans-neural/meta.js.map +1 -0
- package/dist/src/datasets/contiguous-usa/data.d.ts +3 -0
- package/dist/src/datasets/contiguous-usa/data.d.ts.map +1 -0
- package/dist/src/datasets/contiguous-usa/data.js +162 -0
- package/dist/src/datasets/contiguous-usa/data.js.map +1 -0
- package/dist/src/datasets/contiguous-usa/index.d.ts +11 -0
- package/dist/src/datasets/contiguous-usa/index.d.ts.map +1 -0
- package/dist/src/datasets/contiguous-usa/index.js +14 -0
- package/dist/src/datasets/contiguous-usa/index.js.map +1 -0
- package/dist/src/datasets/contiguous-usa/meta.d.ts +4 -0
- package/dist/src/datasets/contiguous-usa/meta.d.ts.map +1 -0
- package/dist/src/datasets/contiguous-usa/meta.js +27 -0
- package/dist/src/datasets/contiguous-usa/meta.js.map +1 -0
- package/dist/src/datasets/davis-southern-women/data.d.ts +3 -0
- package/dist/src/datasets/davis-southern-women/data.d.ts.map +1 -0
- package/dist/src/datasets/davis-southern-women/data.js +57 -0
- package/dist/src/datasets/davis-southern-women/data.js.map +1 -0
- package/dist/src/datasets/davis-southern-women/index.d.ts +11 -0
- package/dist/src/datasets/davis-southern-women/index.d.ts.map +1 -0
- package/dist/src/datasets/davis-southern-women/index.js +14 -0
- package/dist/src/datasets/davis-southern-women/index.js.map +1 -0
- package/dist/src/datasets/davis-southern-women/meta.d.ts +4 -0
- package/dist/src/datasets/davis-southern-women/meta.d.ts.map +1 -0
- package/dist/src/datasets/davis-southern-women/meta.js +17 -0
- package/dist/src/datasets/davis-southern-women/meta.js.map +1 -0
- package/dist/src/datasets/dolphins/data.d.ts +3 -0
- package/dist/src/datasets/dolphins/data.d.ts.map +1 -0
- package/dist/src/datasets/dolphins/data.js +93 -0
- package/dist/src/datasets/dolphins/data.js.map +1 -0
- package/dist/src/datasets/dolphins/index.d.ts +11 -0
- package/dist/src/datasets/dolphins/index.d.ts.map +1 -0
- package/dist/src/datasets/dolphins/index.js +14 -0
- package/dist/src/datasets/dolphins/index.js.map +1 -0
- package/dist/src/datasets/dolphins/meta.d.ts +4 -0
- package/dist/src/datasets/dolphins/meta.d.ts.map +1 -0
- package/dist/src/datasets/dolphins/meta.js +17 -0
- package/dist/src/datasets/dolphins/meta.js.map +1 -0
- package/dist/src/datasets/florentine-families/data.d.ts +3 -0
- package/dist/src/datasets/florentine-families/data.d.ts.map +1 -0
- package/dist/src/datasets/florentine-families/data.js +31 -0
- package/dist/src/datasets/florentine-families/data.js.map +1 -0
- package/dist/src/datasets/florentine-families/index.d.ts +11 -0
- package/dist/src/datasets/florentine-families/index.d.ts.map +1 -0
- package/dist/src/datasets/florentine-families/index.js +14 -0
- package/dist/src/datasets/florentine-families/index.js.map +1 -0
- package/dist/src/datasets/florentine-families/meta.d.ts +4 -0
- package/dist/src/datasets/florentine-families/meta.d.ts.map +1 -0
- package/dist/src/datasets/florentine-families/meta.js +17 -0
- package/dist/src/datasets/florentine-families/meta.js.map +1 -0
- package/dist/src/datasets/football/data.d.ts +3 -0
- package/dist/src/datasets/football/data.d.ts.map +1 -0
- package/dist/src/datasets/football/data.js +210 -0
- package/dist/src/datasets/football/data.js.map +1 -0
- package/dist/src/datasets/football/index.d.ts +11 -0
- package/dist/src/datasets/football/index.d.ts.map +1 -0
- package/dist/src/datasets/football/index.js +14 -0
- package/dist/src/datasets/football/index.js.map +1 -0
- package/dist/src/datasets/football/meta.d.ts +4 -0
- package/dist/src/datasets/football/meta.d.ts.map +1 -0
- package/dist/src/datasets/football/meta.js +17 -0
- package/dist/src/datasets/football/meta.js.map +1 -0
- package/dist/src/datasets/hosted.d.ts +7 -0
- package/dist/src/datasets/hosted.d.ts.map +1 -0
- package/dist/src/datasets/hosted.js +80 -0
- package/dist/src/datasets/hosted.js.map +1 -0
- package/dist/src/datasets/karate/data.d.ts +3 -0
- package/dist/src/datasets/karate/data.d.ts.map +1 -0
- package/dist/src/datasets/karate/data.js +30 -0
- package/dist/src/datasets/karate/data.js.map +1 -0
- package/dist/src/datasets/karate/index.d.ts +11 -0
- package/dist/src/datasets/karate/index.d.ts.map +1 -0
- package/dist/src/datasets/karate/index.js +14 -0
- package/dist/src/datasets/karate/index.js.map +1 -0
- package/dist/src/datasets/karate/meta.d.ts +4 -0
- package/dist/src/datasets/karate/meta.d.ts.map +1 -0
- package/dist/src/datasets/karate/meta.js +22 -0
- package/dist/src/datasets/karate/meta.js.map +1 -0
- package/dist/src/datasets/knuth-miles/data.d.ts +3 -0
- package/dist/src/datasets/knuth-miles/data.d.ts.map +1 -0
- package/dist/src/datasets/knuth-miles/data.js +1203 -0
- package/dist/src/datasets/knuth-miles/data.js.map +1 -0
- package/dist/src/datasets/knuth-miles/index.d.ts +11 -0
- package/dist/src/datasets/knuth-miles/index.d.ts.map +1 -0
- package/dist/src/datasets/knuth-miles/index.js +14 -0
- package/dist/src/datasets/knuth-miles/index.js.map +1 -0
- package/dist/src/datasets/knuth-miles/meta.d.ts +4 -0
- package/dist/src/datasets/knuth-miles/meta.d.ts.map +1 -0
- package/dist/src/datasets/knuth-miles/meta.js +26 -0
- package/dist/src/datasets/knuth-miles/meta.js.map +1 -0
- package/dist/src/datasets/les-miserables/data.d.ts +3 -0
- package/dist/src/datasets/les-miserables/data.d.ts.map +1 -0
- package/dist/src/datasets/les-miserables/data.js +117 -0
- package/dist/src/datasets/les-miserables/data.js.map +1 -0
- package/dist/src/datasets/les-miserables/index.d.ts +11 -0
- package/dist/src/datasets/les-miserables/index.d.ts.map +1 -0
- package/dist/src/datasets/les-miserables/index.js +14 -0
- package/dist/src/datasets/les-miserables/index.js.map +1 -0
- package/dist/src/datasets/les-miserables/meta.d.ts +4 -0
- package/dist/src/datasets/les-miserables/meta.d.ts.map +1 -0
- package/dist/src/datasets/les-miserables/meta.js +21 -0
- package/dist/src/datasets/les-miserables/meta.js.map +1 -0
- package/dist/src/datasets/openflights/data.d.ts +3 -0
- package/dist/src/datasets/openflights/data.d.ts.map +1 -0
- package/dist/src/datasets/openflights/data.js +15457 -0
- package/dist/src/datasets/openflights/data.js.map +1 -0
- package/dist/src/datasets/openflights/index.d.ts +11 -0
- package/dist/src/datasets/openflights/index.d.ts.map +1 -0
- package/dist/src/datasets/openflights/index.js +14 -0
- package/dist/src/datasets/openflights/index.js.map +1 -0
- package/dist/src/datasets/openflights/meta.d.ts +4 -0
- package/dist/src/datasets/openflights/meta.d.ts.map +1 -0
- package/dist/src/datasets/openflights/meta.js +28 -0
- package/dist/src/datasets/openflights/meta.js.map +1 -0
- package/dist/src/datasets/political-blogs/data.d.ts +3 -0
- package/dist/src/datasets/political-blogs/data.d.ts.map +1 -0
- package/dist/src/datasets/political-blogs/data.js +4857 -0
- package/dist/src/datasets/political-blogs/data.js.map +1 -0
- package/dist/src/datasets/political-blogs/index.d.ts +11 -0
- package/dist/src/datasets/political-blogs/index.d.ts.map +1 -0
- package/dist/src/datasets/political-blogs/index.js +14 -0
- package/dist/src/datasets/political-blogs/index.js.map +1 -0
- package/dist/src/datasets/political-blogs/meta.d.ts +4 -0
- package/dist/src/datasets/political-blogs/meta.d.ts.map +1 -0
- package/dist/src/datasets/political-blogs/meta.js +26 -0
- package/dist/src/datasets/political-blogs/meta.js.map +1 -0
- package/dist/src/datasets/political-books/data.d.ts +3 -0
- package/dist/src/datasets/political-books/data.d.ts.map +1 -0
- package/dist/src/datasets/political-books/data.js +165 -0
- package/dist/src/datasets/political-books/data.js.map +1 -0
- package/dist/src/datasets/political-books/index.d.ts +11 -0
- package/dist/src/datasets/political-books/index.d.ts.map +1 -0
- package/dist/src/datasets/political-books/index.js +14 -0
- package/dist/src/datasets/political-books/index.js.map +1 -0
- package/dist/src/datasets/political-books/meta.d.ts +4 -0
- package/dist/src/datasets/political-books/meta.d.ts.map +1 -0
- package/dist/src/datasets/political-books/meta.js +20 -0
- package/dist/src/datasets/political-books/meta.js.map +1 -0
- package/dist/src/datasets/remote.d.ts +27 -0
- package/dist/src/datasets/remote.d.ts.map +1 -0
- package/dist/src/datasets/remote.js +30 -0
- package/dist/src/datasets/remote.js.map +1 -0
- package/dist/src/element.d.ts +20 -0
- package/dist/src/element.d.ts.map +1 -0
- package/dist/src/element.js +27 -0
- package/dist/src/element.js.map +1 -0
- package/dist/src/generators/bipartite.d.ts +51 -0
- package/dist/src/generators/bipartite.d.ts.map +1 -0
- package/dist/src/generators/bipartite.js +99 -0
- package/dist/src/generators/bipartite.js.map +1 -0
- package/dist/src/generators/block-model.d.ts +75 -0
- package/dist/src/generators/block-model.d.ts.map +1 -0
- package/dist/src/generators/block-model.js +116 -0
- package/dist/src/generators/block-model.js.map +1 -0
- package/dist/src/generators/classic.d.ts +208 -0
- package/dist/src/generators/classic.d.ts.map +1 -0
- package/dist/src/generators/classic.js +437 -0
- package/dist/src/generators/classic.js.map +1 -0
- package/dist/src/generators/degree-sequence.d.ts +273 -0
- package/dist/src/generators/degree-sequence.d.ts.map +1 -0
- package/dist/src/generators/degree-sequence.js +646 -0
- package/dist/src/generators/degree-sequence.js.map +1 -0
- package/dist/src/generators/directed.d.ts +141 -0
- package/dist/src/generators/directed.d.ts.map +1 -0
- package/dist/src/generators/directed.js +329 -0
- package/dist/src/generators/directed.js.map +1 -0
- package/dist/src/generators/erdos-renyi.d.ts +58 -0
- package/dist/src/generators/erdos-renyi.d.ts.map +1 -0
- package/dist/src/generators/erdos-renyi.js +154 -0
- package/dist/src/generators/erdos-renyi.js.map +1 -0
- package/dist/src/generators/flow.d.ts +153 -0
- package/dist/src/generators/flow.d.ts.map +1 -0
- package/dist/src/generators/flow.js +346 -0
- package/dist/src/generators/flow.js.map +1 -0
- package/dist/src/generators/geometric.d.ts +133 -0
- package/dist/src/generators/geometric.d.ts.map +1 -0
- package/dist/src/generators/geometric.js +495 -0
- package/dist/src/generators/geometric.js.map +1 -0
- package/dist/src/generators/growth.d.ts +187 -0
- package/dist/src/generators/growth.d.ts.map +1 -0
- package/dist/src/generators/growth.js +445 -0
- package/dist/src/generators/growth.js.map +1 -0
- package/dist/src/generators/hyperbolic.d.ts +84 -0
- package/dist/src/generators/hyperbolic.d.ts.map +1 -0
- package/dist/src/generators/hyperbolic.js +153 -0
- package/dist/src/generators/hyperbolic.js.map +1 -0
- package/dist/src/generators/index.d.ts +25 -0
- package/dist/src/generators/index.d.ts.map +1 -0
- package/dist/src/generators/index.js +24 -0
- package/dist/src/generators/index.js.map +1 -0
- package/dist/src/generators/lattices.d.ts +87 -0
- package/dist/src/generators/lattices.d.ts.map +1 -0
- package/dist/src/generators/lattices.js +237 -0
- package/dist/src/generators/lattices.js.map +1 -0
- package/dist/src/generators/lfr.d.ts +55 -0
- package/dist/src/generators/lfr.d.ts.map +1 -0
- package/dist/src/generators/lfr.js +178 -0
- package/dist/src/generators/lfr.js.map +1 -0
- package/dist/src/generators/named.d.ts +23 -0
- package/dist/src/generators/named.d.ts.map +1 -0
- package/dist/src/generators/named.js +191 -0
- package/dist/src/generators/named.js.map +1 -0
- package/dist/src/generators/preferential-attachment.d.ts +66 -0
- package/dist/src/generators/preferential-attachment.d.ts.map +1 -0
- package/dist/src/generators/preferential-attachment.js +157 -0
- package/dist/src/generators/preferential-attachment.js.map +1 -0
- package/dist/src/generators/trees-and-dags.d.ts +53 -0
- package/dist/src/generators/trees-and-dags.d.ts.map +1 -0
- package/dist/src/generators/trees-and-dags.js +108 -0
- package/dist/src/generators/trees-and-dags.js.map +1 -0
- package/dist/src/generators/util.d.ts +84 -0
- package/dist/src/generators/util.d.ts.map +1 -0
- package/dist/src/generators/util.js +138 -0
- package/dist/src/generators/util.js.map +1 -0
- package/dist/src/generators/variants.d.ts +85 -0
- package/dist/src/generators/variants.d.ts.map +1 -0
- package/dist/src/generators/variants.js +215 -0
- package/dist/src/generators/variants.js.map +1 -0
- package/dist/src/generators/weights.d.ts +65 -0
- package/dist/src/generators/weights.d.ts.map +1 -0
- package/dist/src/generators/weights.js +135 -0
- package/dist/src/generators/weights.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/random/exp.d.ts +23 -0
- package/dist/src/random/exp.d.ts.map +1 -0
- package/dist/src/random/exp.js +101 -0
- package/dist/src/random/exp.js.map +1 -0
- package/dist/src/random/log.d.ts +19 -0
- package/dist/src/random/log.d.ts.map +1 -0
- package/dist/src/random/log.js +83 -0
- package/dist/src/random/log.js.map +1 -0
- package/dist/src/random/stream.d.ts +93 -0
- package/dist/src/random/stream.d.ts.map +1 -0
- package/dist/src/random/stream.js +154 -0
- package/dist/src/random/stream.js.map +1 -0
- package/dist/src/random/threefry.d.ts +19 -0
- package/dist/src/random/threefry.d.ts.map +1 -0
- package/dist/src/random/threefry.js +43 -0
- package/dist/src/random/threefry.js.map +1 -0
- package/dist/src/random/trig.d.ts +16 -0
- package/dist/src/random/trig.d.ts.map +1 -0
- package/dist/src/random/trig.js +78 -0
- package/dist/src/random/trig.js.map +1 -0
- package/dist/src/types.d.ts +28 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +102 -5
- package/src/datasets/build.ts +140 -0
- package/src/datasets/catalog.ts +35 -0
- package/src/datasets/celegans-neural/data.ts +575 -0
- package/src/datasets/celegans-neural/index.ts +17 -0
- package/src/datasets/celegans-neural/meta.ts +25 -0
- package/src/datasets/contiguous-usa/data.ts +164 -0
- package/src/datasets/contiguous-usa/index.ts +17 -0
- package/src/datasets/contiguous-usa/meta.ts +31 -0
- package/src/datasets/davis-southern-women/data.ts +59 -0
- package/src/datasets/davis-southern-women/index.ts +17 -0
- package/src/datasets/davis-southern-women/meta.ts +20 -0
- package/src/datasets/dolphins/data.ts +95 -0
- package/src/datasets/dolphins/index.ts +17 -0
- package/src/datasets/dolphins/meta.ts +21 -0
- package/src/datasets/florentine-families/data.ts +33 -0
- package/src/datasets/florentine-families/index.ts +17 -0
- package/src/datasets/florentine-families/meta.ts +20 -0
- package/src/datasets/football/data.ts +212 -0
- package/src/datasets/football/index.ts +17 -0
- package/src/datasets/football/meta.ts +20 -0
- package/src/datasets/hosted.ts +90 -0
- package/src/datasets/karate/data.ts +32 -0
- package/src/datasets/karate/index.ts +17 -0
- package/src/datasets/karate/meta.ts +25 -0
- package/src/datasets/knuth-miles/data.ts +1205 -0
- package/src/datasets/knuth-miles/index.ts +17 -0
- package/src/datasets/knuth-miles/meta.ts +29 -0
- package/src/datasets/les-miserables/data.ts +119 -0
- package/src/datasets/les-miserables/index.ts +17 -0
- package/src/datasets/les-miserables/meta.ts +24 -0
- package/src/datasets/openflights/data.ts +15459 -0
- package/src/datasets/openflights/index.ts +17 -0
- package/src/datasets/openflights/meta.ts +31 -0
- package/src/datasets/political-blogs/data.ts +4859 -0
- package/src/datasets/political-blogs/index.ts +17 -0
- package/src/datasets/political-blogs/meta.ts +30 -0
- package/src/datasets/political-books/data.ts +167 -0
- package/src/datasets/political-books/index.ts +17 -0
- package/src/datasets/political-books/meta.ts +23 -0
- package/src/datasets/remote.ts +42 -0
- package/src/element.ts +41 -0
- package/src/generators/bipartite.ts +127 -0
- package/src/generators/block-model.ts +160 -0
- package/src/generators/classic.ts +461 -0
- package/src/generators/degree-sequence.ts +807 -0
- package/src/generators/directed.ts +418 -0
- package/src/generators/erdos-renyi.ts +188 -0
- package/src/generators/flow.ts +443 -0
- package/src/generators/geometric.ts +591 -0
- package/src/generators/growth.ts +532 -0
- package/src/generators/hyperbolic.ts +193 -0
- package/src/generators/index.ts +133 -0
- package/src/generators/lattices.ts +290 -0
- package/src/generators/lfr.ts +227 -0
- package/src/generators/named.ts +198 -0
- package/src/generators/preferential-attachment.ts +188 -0
- package/src/generators/trees-and-dags.ts +139 -0
- package/src/generators/util.ts +167 -0
- package/src/generators/variants.ts +253 -0
- package/src/generators/weights.ts +177 -0
- package/src/index.ts +12 -0
- package/src/random/exp.ts +104 -0
- package/src/random/log.ts +86 -0
- package/src/random/stream.ts +169 -0
- package/src/random/threefry.ts +45 -0
- package/src/random/trig.ts +83 -0
- package/src/types.ts +28 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The LFR community-detection benchmark: power-law degrees, power-law community sizes and a
|
|
3
|
+
* mixing parameter, with the planted communities as ground truth.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { RandomStream, resolveSeed } from "../random/stream.js";
|
|
7
|
+
import { type SampleGraph } from "../types.js";
|
|
8
|
+
import { makeSumEven, pairStubs, powerLawSampler, shuffle, stubList } from "./degree-sequence.js";
|
|
9
|
+
import { checkInt, checkProbability, EdgeBuffer, toGraph } from "./util.js";
|
|
10
|
+
import { applyWeights, type WeightOptions } from "./weights.js";
|
|
11
|
+
|
|
12
|
+
/** The largest LFR graph. */
|
|
13
|
+
const MAX_LFR_NODES = 1_000_000;
|
|
14
|
+
|
|
15
|
+
/** Options of {@link lfrGraph}. */
|
|
16
|
+
export interface LfrOptions extends WeightOptions {
|
|
17
|
+
/** The node count, in [1, 1,000,000]. */
|
|
18
|
+
n: number;
|
|
19
|
+
/** The smallest degree, >= 1. */
|
|
20
|
+
minDegree: number;
|
|
21
|
+
/** The largest degree, in [minDegree, n - 1]. */
|
|
22
|
+
maxDegree: number;
|
|
23
|
+
/** The degree power-law exponent (tau1), a finite number >= 0, typically 2 to 3. */
|
|
24
|
+
degreeExponent: number;
|
|
25
|
+
/** The smallest community, >= 1. */
|
|
26
|
+
minCommunity: number;
|
|
27
|
+
/** The largest community, in [minCommunity, n]. */
|
|
28
|
+
maxCommunity: number;
|
|
29
|
+
/** The community-size power-law exponent (tau2), a finite number >= 0, typically 1 to 2. */
|
|
30
|
+
communityExponent: number;
|
|
31
|
+
/** The mixing parameter mu in [0, 1]: the share of each node's edges that leave its community. */
|
|
32
|
+
mixing: number;
|
|
33
|
+
/** The seed, an integer in [0, 2^53); default 0. */
|
|
34
|
+
seed?: number | undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Community sizes from the power law on [min, max] summing to exactly n: draw sizes from stream
|
|
39
|
+
* (seed, "lfr-sizes", 0) until their sum reaches n; if k sizes of at least `min` no longer fit n,
|
|
40
|
+
* drop the last draw and grow sizes from the last one backwards (each up to max) to close the gap,
|
|
41
|
+
* otherwise shrink them from the last one backwards (each down to min) to remove the excess.
|
|
42
|
+
* @param n - the node count
|
|
43
|
+
* @param min - the smallest size
|
|
44
|
+
* @param max - the largest size
|
|
45
|
+
* @param sample - the power-law sampler
|
|
46
|
+
* @param seed - the seed
|
|
47
|
+
* @returns the sizes
|
|
48
|
+
*/
|
|
49
|
+
function communitySizes(
|
|
50
|
+
n: number,
|
|
51
|
+
min: number,
|
|
52
|
+
max: number,
|
|
53
|
+
sample: (stream: RandomStream) => number,
|
|
54
|
+
seed: number,
|
|
55
|
+
): number[] {
|
|
56
|
+
if (Math.ceil(n / max) * min > n) {
|
|
57
|
+
throw new RangeError(`there is no partition of ${n} nodes into communities of ${min} to ${max} nodes`);
|
|
58
|
+
}
|
|
59
|
+
const stream = new RandomStream(seed, "lfr-sizes", 0);
|
|
60
|
+
const sizes: number[] = [];
|
|
61
|
+
let excess = -n;
|
|
62
|
+
while (excess < 0) {
|
|
63
|
+
const s = sample(stream);
|
|
64
|
+
sizes.push(s);
|
|
65
|
+
excess += s;
|
|
66
|
+
}
|
|
67
|
+
if (sizes.length * min > n) {
|
|
68
|
+
excess -= sizes[sizes.length - 1];
|
|
69
|
+
sizes.pop();
|
|
70
|
+
}
|
|
71
|
+
// the feasibility check above guarantees these loops close the gap exactly
|
|
72
|
+
for (let i = sizes.length - 1; i >= 0 && excess !== 0; i--) {
|
|
73
|
+
const change = excess > 0 ? -Math.min(excess, sizes[i] - min) : Math.min(-excess, max - sizes[i]);
|
|
74
|
+
sizes[i] += change;
|
|
75
|
+
excess += change;
|
|
76
|
+
}
|
|
77
|
+
return sizes;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Assign every node a community larger than its internal degree: nodes by internal degree
|
|
82
|
+
* descending (ties by index), each to a uniform choice (nextBelow of stream (seed, "lfr-assign", 0))
|
|
83
|
+
* among the communities with room whose size exceeds its internal degree. The communities that fit
|
|
84
|
+
* only grow as the internal degree falls, so this fails exactly when no assignment exists.
|
|
85
|
+
* @param internal - the internal degree of every node
|
|
86
|
+
* @param sizes - the community sizes (summing to the node count)
|
|
87
|
+
* @param seed - the seed
|
|
88
|
+
* @returns the community of every node
|
|
89
|
+
*/
|
|
90
|
+
function assignCommunities(internal: Uint32Array, sizes: readonly number[], seed: number): Uint32Array<ArrayBuffer> {
|
|
91
|
+
const n = internal.length;
|
|
92
|
+
const nodes = Uint32Array.from({ length: n }, (_, i) => i).sort((a, b) => internal[b] - internal[a] || a - b);
|
|
93
|
+
const bySize = Uint32Array.from(sizes, (_, i) => i).sort((a, b) => sizes[b] - sizes[a] || a - b);
|
|
94
|
+
const room = sizes.slice();
|
|
95
|
+
const open: number[] = [];
|
|
96
|
+
const community = new Uint32Array(n);
|
|
97
|
+
const stream = new RandomStream(seed, "lfr-assign", 0);
|
|
98
|
+
let next = 0;
|
|
99
|
+
for (const node of nodes) {
|
|
100
|
+
while (next < bySize.length && sizes[bySize[next]] > internal[node]) {
|
|
101
|
+
open.push(bySize[next++]);
|
|
102
|
+
}
|
|
103
|
+
if (open.length === 0) {
|
|
104
|
+
throw new RangeError(
|
|
105
|
+
`could not assign communities: node ${node} needs a community of more than ${internal[node]} nodes; ` +
|
|
106
|
+
`raise maxCommunity or mixing, or lower maxDegree`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const j = stream.nextBelow(open.length);
|
|
110
|
+
const c = open[j];
|
|
111
|
+
community[node] = c;
|
|
112
|
+
if (--room[c] === 0) {
|
|
113
|
+
open[j] = open[open.length - 1];
|
|
114
|
+
open.pop();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return community;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The LFR benchmark (A. Lancichinetti, S. Fortunato and F. Radicchi, "Benchmark graphs for testing
|
|
122
|
+
* community detection algorithms", Phys. Rev. E 78, 046110, 2008,
|
|
123
|
+
* doi:10.1103/PhysRevE.78.046110), built with configuration models:
|
|
124
|
+
*
|
|
125
|
+
* 1. Degrees: node i's degree is the i-th power-law draw on [minDegree, maxDegree] from stream
|
|
126
|
+
* (seed, "lfr-degrees", 0); an odd sum is fixed on the last node as in powerLawDegreeSequence.
|
|
127
|
+
* 2. Community sizes: power law on [minCommunity, maxCommunity] summing to exactly n (stream
|
|
128
|
+
* "lfr-sizes"); community ids are the draw order.
|
|
129
|
+
* 3. Internal degree round((1 - mu) d); assignment of nodes to communities larger than their
|
|
130
|
+
* internal degree (stream "lfr-assign"); a RangeError when none exists.
|
|
131
|
+
* 4. Inside each community c, ascending: when its internal degrees sum to an odd number the member
|
|
132
|
+
* with the largest (lowest index on ties) moves one stub to the outside; then a configuration
|
|
133
|
+
* model on the members' ascending stub list shuffled with stream (seed, "lfr-internal", c).
|
|
134
|
+
* 5. Outside: a configuration model on the remaining degrees d - internal, stream
|
|
135
|
+
* (seed, "lfr-external", 0).
|
|
136
|
+
*
|
|
137
|
+
* Self-loops and repeated pairs are erased, and so are external pairs that land inside one
|
|
138
|
+
* community, so degrees and the mixing come out approximate: the mean degree drops by up to about
|
|
139
|
+
* 10% (repeated pairs inside small communities), and the measured mixing lands within about 0.02 of
|
|
140
|
+
* mu for thousands of nodes. No edge switching repairs this. Edges: every community's internal
|
|
141
|
+
* edges (communities ascending, pair order), then the external edges. Node column `community` (u32).
|
|
142
|
+
* O(n log n + m); n at most 1,000,000.
|
|
143
|
+
* @param options - n, degree and community power laws, mixing and seed
|
|
144
|
+
* @returns the undirected graph
|
|
145
|
+
*/
|
|
146
|
+
export function lfrGraph(options: LfrOptions): SampleGraph {
|
|
147
|
+
const { n, minDegree, maxDegree, minCommunity, maxCommunity, mixing } = options;
|
|
148
|
+
const seed = resolveSeed(options.seed);
|
|
149
|
+
checkInt("n", n, 1, MAX_LFR_NODES);
|
|
150
|
+
checkInt("maxDegree", maxDegree, 1, n - 1);
|
|
151
|
+
checkProbability("mixing", mixing);
|
|
152
|
+
checkInt("maxCommunity", maxCommunity, 1, n);
|
|
153
|
+
const degreeOf = powerLawSampler(
|
|
154
|
+
["degreeExponent", "minDegree", "maxDegree"],
|
|
155
|
+
options.degreeExponent,
|
|
156
|
+
minDegree,
|
|
157
|
+
maxDegree,
|
|
158
|
+
);
|
|
159
|
+
const sizeOf = powerLawSampler(
|
|
160
|
+
["communityExponent", "minCommunity", "maxCommunity"],
|
|
161
|
+
options.communityExponent,
|
|
162
|
+
minCommunity,
|
|
163
|
+
maxCommunity,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const degree = new Uint32Array(n);
|
|
167
|
+
const degreeStream = new RandomStream(seed, "lfr-degrees", 0);
|
|
168
|
+
for (let i = 0; i < n; i++) {
|
|
169
|
+
degree[i] = degreeOf(degreeStream);
|
|
170
|
+
}
|
|
171
|
+
makeSumEven(degree, minDegree, maxDegree);
|
|
172
|
+
const sizes = communitySizes(n, minCommunity, maxCommunity, sizeOf, seed);
|
|
173
|
+
const internal = Uint32Array.from(degree, (d) => Math.round((1 - mixing) * d));
|
|
174
|
+
const community = assignCommunities(internal, sizes, seed);
|
|
175
|
+
|
|
176
|
+
// members of every community, ascending, by a counting sort
|
|
177
|
+
const start = new Uint32Array(sizes.length + 1);
|
|
178
|
+
for (let c = 0; c < sizes.length; c++) {
|
|
179
|
+
start[c + 1] = start[c] + sizes[c];
|
|
180
|
+
}
|
|
181
|
+
const fill = start.slice(0, sizes.length);
|
|
182
|
+
const members = new Uint32Array(n);
|
|
183
|
+
for (let i = 0; i < n; i++) {
|
|
184
|
+
members[fill[community[i]]++] = i;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let total = 0;
|
|
188
|
+
for (const d of degree) {
|
|
189
|
+
total += d;
|
|
190
|
+
}
|
|
191
|
+
const out = new EdgeBuffer(total / 2);
|
|
192
|
+
const stream = new RandomStream(seed, "lfr-internal", 0);
|
|
193
|
+
for (let c = 0; c < sizes.length; c++) {
|
|
194
|
+
const group = members.subarray(start[c], start[c + 1]);
|
|
195
|
+
const k = Uint32Array.from(group, (i) => internal[i]);
|
|
196
|
+
let sum = 0;
|
|
197
|
+
let largest = 0;
|
|
198
|
+
for (let j = 0; j < k.length; j++) {
|
|
199
|
+
sum += k[j];
|
|
200
|
+
if (k[j] > k[largest]) {
|
|
201
|
+
largest = j;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (sum % 2 === 1) {
|
|
205
|
+
k[largest]--;
|
|
206
|
+
internal[group[largest]]--;
|
|
207
|
+
sum--;
|
|
208
|
+
}
|
|
209
|
+
const stubs = stubList(k, sum);
|
|
210
|
+
for (let j = 0; j < stubs.length; j++) {
|
|
211
|
+
stubs[j] = group[stubs[j]];
|
|
212
|
+
}
|
|
213
|
+
stream.reset(c);
|
|
214
|
+
shuffle(stubs, stream);
|
|
215
|
+
pairStubs(n, stubs, false, false, out);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const external = Uint32Array.from(degree, (d, i) => d - internal[i]);
|
|
219
|
+
let externalTotal = 0;
|
|
220
|
+
for (const d of external) {
|
|
221
|
+
externalTotal += d;
|
|
222
|
+
}
|
|
223
|
+
const stubs = stubList(external, externalTotal);
|
|
224
|
+
shuffle(stubs, new RandomStream(seed, "lfr-external", 0));
|
|
225
|
+
pairStubs(n, stubs, false, false, out, community);
|
|
226
|
+
return applyWeights(toGraph(n, out, false, { community }), options);
|
|
227
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named small graphs with well-known invariants: the teaching graphs and the platonic solids.
|
|
3
|
+
* The edge lists (node order and edge order) are those of networkx 3.1's `small.py`
|
|
4
|
+
* (A. Hagberg, D. Schult, P. Swart, "Exploring network structure, dynamics, and function using
|
|
5
|
+
* NetworkX", SciPy 2008; BSD-3-Clause), which in turn follow the literature (Krackhardt 1990,
|
|
6
|
+
* Frucht 1939, Tutte 1946, Hoffman and Singleton 1960, Sedgewick 1990). They are mathematical facts;
|
|
7
|
+
* the ordering is frozen like any other generator's. The Petersen graph is `petersenGraph()`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { type SampleGraph } from "../types.js";
|
|
11
|
+
import { applyWeights, type WeightOptions } from "./weights.js";
|
|
12
|
+
|
|
13
|
+
/** The name of every graph {@link namedGraph} knows. */
|
|
14
|
+
export const NAMED_GRAPH_NAMES = [
|
|
15
|
+
"bull",
|
|
16
|
+
"chvatal",
|
|
17
|
+
"cubical",
|
|
18
|
+
"desargues",
|
|
19
|
+
"diamond",
|
|
20
|
+
"dodecahedral",
|
|
21
|
+
"frucht",
|
|
22
|
+
"heawood",
|
|
23
|
+
"hoffman-singleton",
|
|
24
|
+
"house",
|
|
25
|
+
"house-x",
|
|
26
|
+
"icosahedral",
|
|
27
|
+
"krackhardt-kite",
|
|
28
|
+
"moebius-kantor",
|
|
29
|
+
"octahedral",
|
|
30
|
+
"pappus",
|
|
31
|
+
"sedgewick-maze",
|
|
32
|
+
"tetrahedral",
|
|
33
|
+
"truncated-cube",
|
|
34
|
+
"truncated-tetrahedron",
|
|
35
|
+
"tutte",
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
38
|
+
/** A name {@link namedGraph} accepts. */
|
|
39
|
+
export type NamedGraphName = (typeof NAMED_GRAPH_NAMES)[number];
|
|
40
|
+
|
|
41
|
+
/** Node count and flat edge list [u0, v0, u1, v1, ...] of every named graph. */
|
|
42
|
+
const GRAPHS: Readonly<Record<NamedGraphName, readonly [number, readonly number[]]>> = {
|
|
43
|
+
// a triangle with two pendant horns; 5 nodes, 5 edges
|
|
44
|
+
bull: [5, [0, 1, 0, 2, 1, 2, 1, 3, 2, 4]],
|
|
45
|
+
// the smallest triangle-free 4-regular 4-chromatic graph; 12 nodes, 24 edges
|
|
46
|
+
chvatal: [
|
|
47
|
+
12,
|
|
48
|
+
[
|
|
49
|
+
0, 1, 0, 4, 0, 6, 0, 9, 1, 2, 1, 5, 1, 7, 2, 3, 2, 6, 2, 8, 3, 4, 3, 7, 3, 9, 4, 5, 4, 8, 5, 10, 5, 11, 6,
|
|
50
|
+
10, 6, 11, 7, 8, 7, 11, 8, 10, 9, 10, 9, 11,
|
|
51
|
+
],
|
|
52
|
+
],
|
|
53
|
+
// the cube's skeleton (Q_3); 8 nodes, 12 edges, planar
|
|
54
|
+
cubical: [8, [0, 1, 0, 3, 0, 4, 1, 2, 1, 7, 2, 3, 2, 6, 3, 5, 4, 5, 4, 7, 5, 6, 6, 7]],
|
|
55
|
+
// the Desargues graph, 3-regular, distance-transitive; 20 nodes, 30 edges
|
|
56
|
+
desargues: [
|
|
57
|
+
20,
|
|
58
|
+
[
|
|
59
|
+
0, 1, 0, 19, 0, 5, 1, 2, 1, 16, 2, 3, 2, 11, 3, 4, 3, 14, 4, 5, 4, 9, 5, 6, 6, 7, 6, 15, 7, 8, 7, 18, 8, 9,
|
|
60
|
+
8, 13, 9, 10, 10, 11, 10, 19, 11, 12, 12, 13, 12, 17, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
|
|
61
|
+
],
|
|
62
|
+
],
|
|
63
|
+
// K_4 minus one edge; 4 nodes, 5 edges
|
|
64
|
+
diamond: [4, [0, 1, 0, 2, 1, 2, 1, 3, 2, 3]],
|
|
65
|
+
// the dodecahedron's skeleton; 20 nodes, 30 edges, planar, 3-regular
|
|
66
|
+
dodecahedral: [
|
|
67
|
+
20,
|
|
68
|
+
[
|
|
69
|
+
0, 1, 0, 19, 0, 10, 1, 2, 1, 8, 2, 3, 2, 6, 3, 4, 3, 19, 4, 5, 4, 17, 5, 6, 5, 15, 6, 7, 7, 8, 7, 14, 8, 9,
|
|
70
|
+
9, 10, 9, 13, 10, 11, 11, 12, 11, 18, 12, 13, 12, 16, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
|
|
71
|
+
],
|
|
72
|
+
],
|
|
73
|
+
// 3-regular with no non-trivial automorphism; 12 nodes, 18 edges
|
|
74
|
+
frucht: [
|
|
75
|
+
12,
|
|
76
|
+
[
|
|
77
|
+
0, 1, 0, 6, 0, 7, 1, 2, 1, 7, 2, 3, 2, 8, 3, 4, 3, 9, 4, 5, 4, 9, 5, 6, 5, 10, 6, 10, 7, 11, 8, 11, 8, 9,
|
|
78
|
+
10, 11,
|
|
79
|
+
],
|
|
80
|
+
],
|
|
81
|
+
// the (3,6)-cage, the Fano plane's incidence graph; 14 nodes, 21 edges
|
|
82
|
+
heawood: [
|
|
83
|
+
14,
|
|
84
|
+
[
|
|
85
|
+
0, 1, 0, 13, 0, 5, 1, 2, 1, 10, 2, 3, 2, 7, 3, 4, 3, 12, 4, 5, 4, 9, 5, 6, 6, 7, 6, 11, 7, 8, 8, 9, 8, 13,
|
|
86
|
+
9, 10, 10, 11, 11, 12, 12, 13,
|
|
87
|
+
],
|
|
88
|
+
],
|
|
89
|
+
// the (7,5)-cage, a Moore graph; 50 nodes, 175 edges
|
|
90
|
+
"hoffman-singleton": [
|
|
91
|
+
50,
|
|
92
|
+
[
|
|
93
|
+
0, 1, 0, 2, 0, 3, 0, 6, 0, 7, 0, 8, 0, 9, 1, 17, 1, 12, 1, 26, 1, 27, 1, 28, 1, 29, 2, 10, 2, 11, 2, 13, 2,
|
|
94
|
+
14, 2, 15, 2, 16, 3, 4, 3, 5, 3, 30, 3, 35, 3, 40, 3, 45, 4, 11, 4, 17, 4, 34, 4, 39, 4, 44, 4, 49, 5, 12,
|
|
95
|
+
5, 10, 5, 33, 5, 38, 5, 43, 5, 48, 6, 22, 6, 18, 6, 31, 6, 39, 6, 43, 6, 47, 7, 34, 7, 23, 7, 19, 7, 37, 7,
|
|
96
|
+
41, 7, 48, 8, 33, 8, 36, 8, 24, 8, 20, 8, 42, 8, 49, 9, 32, 9, 38, 9, 44, 9, 25, 9, 21, 9, 46, 10, 17, 10,
|
|
97
|
+
18, 10, 19, 10, 20, 10, 21, 11, 12, 11, 32, 11, 37, 11, 42, 11, 47, 12, 31, 12, 36, 12, 41, 12, 46, 13, 30,
|
|
98
|
+
13, 26, 13, 22, 13, 36, 13, 44, 13, 48, 14, 31, 14, 27, 14, 23, 14, 38, 14, 40, 14, 49, 15, 34, 15, 35, 15,
|
|
99
|
+
28, 15, 24, 15, 43, 15, 46, 16, 33, 16, 39, 16, 41, 16, 45, 16, 29, 16, 25, 17, 22, 17, 23, 17, 24, 17, 25,
|
|
100
|
+
18, 32, 18, 26, 18, 35, 18, 41, 18, 49, 19, 30, 19, 27, 19, 39, 19, 42, 19, 46, 20, 31, 20, 37, 20, 28, 20,
|
|
101
|
+
44, 20, 45, 21, 34, 21, 36, 21, 40, 21, 47, 21, 29, 22, 33, 22, 37, 22, 40, 22, 46, 23, 32, 23, 36, 23, 43,
|
|
102
|
+
23, 45, 24, 30, 24, 38, 24, 41, 24, 47, 25, 31, 25, 35, 25, 42, 25, 48, 26, 34, 26, 38, 26, 42, 26, 45, 27,
|
|
103
|
+
33, 27, 35, 27, 44, 27, 47, 28, 32, 28, 39, 28, 40, 28, 48, 29, 30, 29, 37, 29, 43, 29, 49, 30, 31, 30, 32,
|
|
104
|
+
31, 34, 32, 33, 33, 34, 35, 36, 35, 37, 36, 39, 37, 38, 38, 39, 40, 41, 40, 42, 41, 44, 42, 43, 43, 44, 45,
|
|
105
|
+
46, 45, 47, 46, 49, 47, 48, 48, 49,
|
|
106
|
+
],
|
|
107
|
+
],
|
|
108
|
+
// a square with a triangular roof; 5 nodes, 6 edges
|
|
109
|
+
house: [5, [0, 1, 0, 2, 1, 3, 2, 3, 2, 4, 3, 4]],
|
|
110
|
+
// the house with both diagonals of the square; 5 nodes, 8 edges
|
|
111
|
+
"house-x": [5, [0, 1, 0, 2, 0, 3, 1, 3, 1, 2, 2, 3, 2, 4, 3, 4]],
|
|
112
|
+
// the icosahedron's skeleton; 12 nodes, 30 edges, planar, 5-regular
|
|
113
|
+
icosahedral: [
|
|
114
|
+
12,
|
|
115
|
+
[
|
|
116
|
+
0, 1, 0, 5, 0, 7, 0, 8, 0, 11, 1, 2, 1, 5, 1, 6, 1, 8, 2, 3, 2, 6, 2, 8, 2, 9, 3, 4, 3, 6, 3, 9, 3, 10, 4,
|
|
117
|
+
5, 4, 6, 4, 10, 4, 11, 5, 6, 5, 11, 7, 8, 7, 9, 7, 10, 7, 11, 8, 9, 9, 10, 10, 11,
|
|
118
|
+
],
|
|
119
|
+
],
|
|
120
|
+
// Krackhardt's kite: degree, betweenness and closeness each crown a different node; 10 nodes, 18 edges
|
|
121
|
+
"krackhardt-kite": [
|
|
122
|
+
10,
|
|
123
|
+
[0, 1, 0, 2, 0, 3, 0, 5, 1, 3, 1, 4, 1, 6, 2, 3, 2, 5, 3, 4, 3, 5, 3, 6, 4, 6, 5, 6, 5, 7, 6, 7, 7, 8, 8, 9],
|
|
124
|
+
],
|
|
125
|
+
// the Moebius-Kantor graph, the generalized Petersen graph GP(8, 3); 16 nodes, 24 edges
|
|
126
|
+
"moebius-kantor": [
|
|
127
|
+
16,
|
|
128
|
+
[
|
|
129
|
+
0, 1, 0, 15, 0, 5, 1, 2, 1, 12, 2, 3, 2, 7, 3, 4, 3, 14, 4, 5, 4, 9, 5, 6, 6, 7, 6, 11, 7, 8, 8, 9, 8, 13,
|
|
130
|
+
9, 10, 10, 11, 10, 15, 11, 12, 12, 13, 13, 14, 14, 15,
|
|
131
|
+
],
|
|
132
|
+
],
|
|
133
|
+
// the octahedron's skeleton, K_{2,2,2}; 6 nodes, 12 edges
|
|
134
|
+
octahedral: [6, [0, 1, 0, 2, 0, 3, 0, 4, 1, 2, 1, 3, 1, 5, 2, 4, 2, 5, 3, 4, 3, 5, 4, 5]],
|
|
135
|
+
// the Pappus graph, 3-regular, bipartite, distance-regular; 18 nodes, 27 edges
|
|
136
|
+
pappus: [
|
|
137
|
+
18,
|
|
138
|
+
[
|
|
139
|
+
0, 1, 0, 17, 0, 5, 1, 2, 1, 8, 2, 3, 2, 13, 3, 4, 3, 10, 4, 5, 4, 15, 5, 6, 6, 7, 6, 11, 7, 8, 7, 14, 8, 9,
|
|
140
|
+
9, 10, 9, 16, 10, 11, 11, 12, 12, 13, 12, 17, 13, 14, 14, 15, 15, 16, 16, 17,
|
|
141
|
+
],
|
|
142
|
+
],
|
|
143
|
+
// the small maze of Sedgewick's Algorithms in C (DFS teaching); 8 nodes, 10 edges
|
|
144
|
+
"sedgewick-maze": [8, [0, 2, 0, 7, 0, 5, 1, 7, 2, 6, 3, 4, 3, 5, 4, 5, 4, 7, 4, 6]],
|
|
145
|
+
// the tetrahedron's skeleton, K_4; 4 nodes, 6 edges
|
|
146
|
+
tetrahedral: [4, [0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3]],
|
|
147
|
+
// the truncated cube's skeleton; 24 nodes, 36 edges, planar
|
|
148
|
+
"truncated-cube": [
|
|
149
|
+
24,
|
|
150
|
+
[
|
|
151
|
+
0, 1, 0, 2, 0, 4, 1, 11, 1, 14, 2, 3, 2, 4, 3, 6, 3, 8, 4, 5, 5, 16, 5, 18, 6, 7, 6, 8, 7, 10, 7, 12, 8, 9,
|
|
152
|
+
9, 17, 9, 20, 10, 11, 10, 12, 11, 14, 12, 13, 13, 21, 13, 22, 14, 15, 15, 19, 15, 23, 16, 17, 16, 18, 17,
|
|
153
|
+
20, 18, 19, 19, 23, 20, 21, 21, 22, 22, 23,
|
|
154
|
+
],
|
|
155
|
+
],
|
|
156
|
+
// the truncated tetrahedron's skeleton; 12 nodes, 18 edges, planar
|
|
157
|
+
"truncated-tetrahedron": [
|
|
158
|
+
12,
|
|
159
|
+
[
|
|
160
|
+
0, 1, 0, 2, 0, 9, 1, 2, 1, 6, 2, 3, 3, 4, 3, 11, 4, 5, 4, 11, 5, 6, 5, 7, 6, 7, 7, 8, 8, 9, 8, 10, 9, 10,
|
|
161
|
+
10, 11,
|
|
162
|
+
],
|
|
163
|
+
],
|
|
164
|
+
// Tutte's graph: 3-regular, 3-connected, planar and not Hamiltonian; 46 nodes, 69 edges
|
|
165
|
+
tutte: [
|
|
166
|
+
46,
|
|
167
|
+
[
|
|
168
|
+
0, 1, 0, 2, 0, 3, 1, 4, 1, 26, 2, 10, 2, 11, 3, 18, 3, 19, 4, 5, 4, 33, 5, 6, 5, 29, 6, 7, 6, 27, 7, 8, 7,
|
|
169
|
+
14, 8, 9, 8, 38, 9, 10, 9, 37, 10, 39, 11, 12, 11, 39, 12, 13, 12, 35, 13, 14, 13, 15, 14, 34, 15, 16, 15,
|
|
170
|
+
22, 16, 17, 16, 44, 17, 18, 17, 43, 18, 45, 19, 20, 19, 45, 20, 21, 20, 41, 21, 22, 21, 23, 22, 40, 23, 24,
|
|
171
|
+
23, 27, 24, 25, 24, 32, 25, 26, 25, 31, 26, 33, 27, 28, 28, 29, 28, 32, 29, 30, 30, 31, 30, 33, 31, 32, 34,
|
|
172
|
+
35, 34, 38, 35, 36, 36, 37, 36, 39, 37, 38, 40, 41, 40, 44, 41, 42, 42, 43, 42, 45, 43, 44,
|
|
173
|
+
],
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* A named small graph (see {@link NAMED_GRAPH_NAMES}): an undirected simple graph with networkx's
|
|
179
|
+
* node and edge order.
|
|
180
|
+
* @param name - the graph's name
|
|
181
|
+
* @param options - the common weight options
|
|
182
|
+
* @returns the graph
|
|
183
|
+
*/
|
|
184
|
+
export function namedGraph(name: NamedGraphName, options: WeightOptions = {}): SampleGraph {
|
|
185
|
+
const entry = Object.prototype.hasOwnProperty.call(GRAPHS, name) ? GRAPHS[name] : undefined;
|
|
186
|
+
if (entry === undefined) {
|
|
187
|
+
throw new RangeError(`unknown named graph "${name}"; see NAMED_GRAPH_NAMES`);
|
|
188
|
+
}
|
|
189
|
+
const [nodeCount, flat] = entry;
|
|
190
|
+
const m = flat.length / 2;
|
|
191
|
+
const src = new Uint32Array(m);
|
|
192
|
+
const dst = new Uint32Array(m);
|
|
193
|
+
for (let e = 0; e < m; e++) {
|
|
194
|
+
src[e] = flat[2 * e];
|
|
195
|
+
dst[e] = flat[2 * e + 1];
|
|
196
|
+
}
|
|
197
|
+
return applyWeights({ directed: false, nodeCount, src, dst }, options);
|
|
198
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Growth models: Barabasi-Albert preferential attachment with the Holme-Kim triad-formation step,
|
|
3
|
+
* and the Watts-Strogatz small world.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { RandomStream, resolveSeed } from "../random/stream.js";
|
|
7
|
+
import { type SampleGraph } from "../types.js";
|
|
8
|
+
import { checkEdgeCount, checkInt, checkProbability, EdgeBuffer, toGraph } from "./util.js";
|
|
9
|
+
import { applyWeights, type WeightOptions } from "./weights.js";
|
|
10
|
+
|
|
11
|
+
/** Options of {@link barabasiAlbertGraph}. */
|
|
12
|
+
export interface BarabasiAlbertOptions extends WeightOptions {
|
|
13
|
+
/** The node count, > m. */
|
|
14
|
+
n: number;
|
|
15
|
+
/** The number of edges each new node brings, >= 1. */
|
|
16
|
+
m: number;
|
|
17
|
+
/**
|
|
18
|
+
* Holme-Kim: after each preferential edge, the probability that the next of the node's m edges
|
|
19
|
+
* closes a triangle with a neighbour of that edge's target instead. 0 (the default) is plain
|
|
20
|
+
* Barabasi-Albert.
|
|
21
|
+
*/
|
|
22
|
+
triadProbability?: number | undefined;
|
|
23
|
+
/** The seed, an integer in [0, 2^53); default 0. */
|
|
24
|
+
seed?: number | undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Barabasi-Albert preferential attachment (A.-L. Barabasi and R. Albert, "Emergence of scaling in
|
|
29
|
+
* random networks", Science 286, 509-512, 1999), optionally with triad formation (P. Holme and
|
|
30
|
+
* B. J. Kim, "Growing scale-free networks with tunable clustering", Phys. Rev. E 65, 026107, 2002),
|
|
31
|
+
* in O(n m) with the repeated-endpoint list of Batagelj and Brandes (2005).
|
|
32
|
+
*
|
|
33
|
+
* The algorithm is networkx's `powerlaw_cluster_graph`, which is `barabasi_albert_graph` when the
|
|
34
|
+
* triad probability is 0: start from m isolated nodes 0 .. m - 1 whose repeated list holds each
|
|
35
|
+
* once; each new node s = m .. n - 1 draws m distinct targets uniformly from the repeated list
|
|
36
|
+
* (in draw order), then adds m edges (s, t): the first to the first target; each further one, with
|
|
37
|
+
* probability `triadProbability`, to a uniformly chosen neighbour of the previous target that s is
|
|
38
|
+
* not yet joined to, otherwise to the next unused target. Every endpoint is appended to the
|
|
39
|
+
* repeated list, s itself m times. All draws come from the single stream (seed,
|
|
40
|
+
* "barabasi-albert", 0): the process is sequential. Edges are listed by new node, in the order
|
|
41
|
+
* added. (n - m) m edges, no self-loops, no repeats.
|
|
42
|
+
* @param options - n, m, triadProbability and seed
|
|
43
|
+
* @returns the undirected graph
|
|
44
|
+
*/
|
|
45
|
+
export function barabasiAlbertGraph(options: BarabasiAlbertOptions): SampleGraph {
|
|
46
|
+
const { n, m } = options;
|
|
47
|
+
const triad = options.triadProbability ?? 0;
|
|
48
|
+
checkInt("m", m, 1);
|
|
49
|
+
checkInt("n", n, m + 1);
|
|
50
|
+
checkProbability("triadProbability", triad);
|
|
51
|
+
const seed = resolveSeed(options.seed);
|
|
52
|
+
const edgeCount = (n - m) * m;
|
|
53
|
+
checkEdgeCount(edgeCount);
|
|
54
|
+
const stream = new RandomStream(seed, "barabasi-albert", 0);
|
|
55
|
+
const out = new EdgeBuffer(edgeCount);
|
|
56
|
+
const repeated = new Uint32Array(m + 2 * edgeCount);
|
|
57
|
+
let length = 0;
|
|
58
|
+
for (let i = 0; i < m; i++) {
|
|
59
|
+
repeated[length++] = i;
|
|
60
|
+
}
|
|
61
|
+
// neighbour lists, only for the triad step
|
|
62
|
+
// ponytail: number[][] per node; a CSR-like growable adjacency if HK at 1M+ nodes matters
|
|
63
|
+
const adjacency: number[][] | null = triad > 0 ? Array.from({ length: n }, () => []) : null;
|
|
64
|
+
const targets = new Array<number>(m);
|
|
65
|
+
const link = (s: number, t: number): void => {
|
|
66
|
+
out.push(s, t);
|
|
67
|
+
repeated[length++] = t;
|
|
68
|
+
if (adjacency !== null) {
|
|
69
|
+
adjacency[s].push(t);
|
|
70
|
+
adjacency[t].push(s);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
for (let s = m; s < n; s++) {
|
|
74
|
+
// m distinct targets from the repeated list, in draw order
|
|
75
|
+
let found = 0;
|
|
76
|
+
while (found < m) {
|
|
77
|
+
const t = repeated[stream.nextBelow(length)];
|
|
78
|
+
let fresh = true;
|
|
79
|
+
for (let i = 0; i < found; i++) {
|
|
80
|
+
fresh &&= targets[i] !== t;
|
|
81
|
+
}
|
|
82
|
+
if (fresh) {
|
|
83
|
+
targets[found++] = t;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
let next = 0;
|
|
87
|
+
let target = targets[next++];
|
|
88
|
+
link(s, target);
|
|
89
|
+
for (let count = 1; count < m; count++) {
|
|
90
|
+
if (adjacency !== null && stream.nextFloat() < triad) {
|
|
91
|
+
const mine = adjacency[s];
|
|
92
|
+
const candidates = adjacency[target].filter((x) => x !== s && !mine.includes(x));
|
|
93
|
+
if (candidates.length > 0) {
|
|
94
|
+
link(s, candidates[stream.nextBelow(candidates.length)]);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// the next unused target (a triad step may already have joined s to it)
|
|
99
|
+
do {
|
|
100
|
+
target = targets[next++];
|
|
101
|
+
} while (adjacency !== null && adjacency[s].includes(target) && next < m);
|
|
102
|
+
if (adjacency !== null && adjacency[s].includes(target)) {
|
|
103
|
+
// every planned target is taken: fall back to a fresh preferential draw
|
|
104
|
+
do {
|
|
105
|
+
target = repeated[stream.nextBelow(length)];
|
|
106
|
+
} while (target === s || adjacency[s].includes(target));
|
|
107
|
+
}
|
|
108
|
+
link(s, target);
|
|
109
|
+
}
|
|
110
|
+
for (let i = 0; i < m; i++) {
|
|
111
|
+
repeated[length++] = s;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return applyWeights(toGraph(n, out, false), options);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Options of {@link wattsStrogatzGraph}. */
|
|
118
|
+
export interface WattsStrogatzOptions extends WeightOptions {
|
|
119
|
+
/** The node count, > k. */
|
|
120
|
+
n: number;
|
|
121
|
+
/** Each node's ring neighbours before rewiring, even, >= 2. */
|
|
122
|
+
k: number;
|
|
123
|
+
/** The rewiring probability of each edge, in [0, 1]. */
|
|
124
|
+
beta: number;
|
|
125
|
+
/** The seed, an integer in [0, 2^53); default 0. */
|
|
126
|
+
seed?: number | undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The Watts-Strogatz small world (D. J. Watts and S. H. Strogatz, "Collective dynamics of
|
|
131
|
+
* 'small-world' networks", Nature 393, 440-442, 1998), as networkx's `watts_strogatz_graph`
|
|
132
|
+
* builds it, in O(n k).
|
|
133
|
+
*
|
|
134
|
+
* Start from the ring lattice: edge slot u k/2 + (j - 1) holds (u, (u + j) mod n) for j = 1 .. k/2.
|
|
135
|
+
* Then for j = 1 .. k/2 and u = 0 .. n - 1 in that order: draw a float; if it is below beta and u is
|
|
136
|
+
* not already joined to every other node, redraw w = nextBelow(n) until w is neither u nor a
|
|
137
|
+
* neighbour of u, and rewire the slot to (u, w). All draws come from the single stream (seed,
|
|
138
|
+
* "watts-strogatz", 0). Edges are listed in slot order.
|
|
139
|
+
* @param options - n, k, beta and seed
|
|
140
|
+
* @returns the undirected graph
|
|
141
|
+
*/
|
|
142
|
+
export function wattsStrogatzGraph(options: WattsStrogatzOptions): SampleGraph {
|
|
143
|
+
const { n, k, beta } = options;
|
|
144
|
+
checkInt("k", k, 2);
|
|
145
|
+
if (k % 2 !== 0) {
|
|
146
|
+
throw new RangeError(`k must be even, got ${k}`);
|
|
147
|
+
}
|
|
148
|
+
checkInt("n", n, k + 1);
|
|
149
|
+
checkProbability("beta", beta);
|
|
150
|
+
const seed = resolveSeed(options.seed);
|
|
151
|
+
const half = k / 2;
|
|
152
|
+
const m = n * half;
|
|
153
|
+
checkEdgeCount(m);
|
|
154
|
+
const src = new Uint32Array(m);
|
|
155
|
+
const dst = new Uint32Array(m);
|
|
156
|
+
const degree = new Uint32Array(n).fill(k);
|
|
157
|
+
// ponytail: a Set of u * n + v keys, fine to a few million edges; a hashed typed table beyond
|
|
158
|
+
const edges = new Set<number>();
|
|
159
|
+
const key = (a: number, b: number): number => (a < b ? a * n + b : b * n + a);
|
|
160
|
+
for (let u = 0; u < n; u++) {
|
|
161
|
+
for (let j = 1; j <= half; j++) {
|
|
162
|
+
const v = (u + j) % n;
|
|
163
|
+
src[u * half + j - 1] = u;
|
|
164
|
+
dst[u * half + j - 1] = v;
|
|
165
|
+
edges.add(key(u, v));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const stream = new RandomStream(seed, "watts-strogatz", 0);
|
|
169
|
+
for (let j = 1; j <= half; j++) {
|
|
170
|
+
for (let u = 0; u < n; u++) {
|
|
171
|
+
if (stream.nextFloat() >= beta || degree[u] >= n - 1) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
let w = stream.nextBelow(n);
|
|
175
|
+
while (w === u || edges.has(key(u, w))) {
|
|
176
|
+
w = stream.nextBelow(n);
|
|
177
|
+
}
|
|
178
|
+
const slot = u * half + j - 1;
|
|
179
|
+
const v = dst[slot];
|
|
180
|
+
edges.delete(key(u, v));
|
|
181
|
+
edges.add(key(u, w));
|
|
182
|
+
degree[v]--;
|
|
183
|
+
degree[w]++;
|
|
184
|
+
dst[slot] = w;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return applyWeights({ directed: false, nodeCount: n, src, dst }, options);
|
|
188
|
+
}
|