@graphty/algorithms 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -50
- package/dist/algorithms.js +15260 -10390
- package/dist/algorithms.js.map +1 -1
- package/dist/algorithms.standalone.js +26675 -21542
- package/dist/algorithms.standalone.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +18 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +40 -1
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +20 -0
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +93 -8
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.d.ts +9 -0
- package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +18 -0
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -0
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.js +29 -0
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
- package/dist/src/algorithms/centrality/hits.d.ts +9 -0
- package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/hits.js +23 -0
- package/dist/src/algorithms/centrality/hits.js.map +1 -1
- package/dist/src/algorithms/centrality/katz.d.ts +9 -0
- package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/katz.js +31 -0
- package/dist/src/algorithms/centrality/katz.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +13 -13
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +47 -10
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman-legacy.d.ts +27 -0
- package/dist/src/algorithms/community/girvan-newman-legacy.d.ts.map +1 -0
- package/dist/src/algorithms/community/girvan-newman-legacy.js +335 -0
- package/dist/src/algorithms/community/girvan-newman-legacy.js.map +1 -0
- package/dist/src/algorithms/community/girvan-newman.d.ts +5 -3
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +34 -308
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +9 -6
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +24 -110
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/components/connected.d.ts.map +1 -1
- package/dist/src/algorithms/components/connected.js +28 -77
- package/dist/src/algorithms/components/connected.js.map +1 -1
- package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
- package/dist/src/algorithms/mst/kruskal.js +59 -3
- package/dist/src/algorithms/mst/kruskal.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +46 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +27 -0
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +15 -5
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.js +97 -107
- package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +2 -12
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.js +47 -308
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs-variants.js +5 -25
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs.d.ts +0 -3
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +0 -4
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +33 -154
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/clustering/hierarchical-legacy.d.ts +56 -0
- package/dist/src/clustering/hierarchical-legacy.d.ts.map +1 -0
- package/dist/src/clustering/hierarchical-legacy.js +441 -0
- package/dist/src/clustering/hierarchical-legacy.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +7 -39
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +56 -417
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/k-core-legacy.d.ts +30 -0
- package/dist/src/clustering/k-core-legacy.d.ts.map +1 -0
- package/dist/src/clustering/k-core-legacy.js +191 -0
- package/dist/src/clustering/k-core-legacy.js.map +1 -0
- package/dist/src/clustering/k-core.d.ts +8 -7
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +33 -174
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/mcl-legacy.d.ts +42 -0
- package/dist/src/clustering/mcl-legacy.d.ts.map +1 -0
- package/dist/src/clustering/mcl-legacy.js +386 -0
- package/dist/src/clustering/mcl-legacy.js.map +1 -0
- package/dist/src/clustering/mcl.d.ts +9 -32
- package/dist/src/clustering/mcl.d.ts.map +1 -1
- package/dist/src/clustering/mcl.js +48 -374
- package/dist/src/clustering/mcl.js.map +1 -1
- package/dist/src/index.d.ts +29 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexed/accelerator.d.ts +141 -11
- package/dist/src/indexed/accelerator.d.ts.map +1 -1
- package/dist/src/indexed/accelerator.js +319 -5
- package/dist/src/indexed/accelerator.js.map +1 -1
- package/dist/src/indexed/all-pairs.d.ts +59 -0
- package/dist/src/indexed/all-pairs.d.ts.map +1 -0
- package/dist/src/indexed/all-pairs.js +274 -0
- package/dist/src/indexed/all-pairs.js.map +1 -0
- package/dist/src/indexed/bellman-ford.d.ts +25 -0
- package/dist/src/indexed/bellman-ford.d.ts.map +1 -0
- package/dist/src/indexed/bellman-ford.js +59 -0
- package/dist/src/indexed/bellman-ford.js.map +1 -0
- package/dist/src/indexed/betweenness.d.ts +85 -0
- package/dist/src/indexed/betweenness.d.ts.map +1 -0
- package/dist/src/indexed/betweenness.js +188 -0
- package/dist/src/indexed/betweenness.js.map +1 -0
- package/dist/src/indexed/bfs.d.ts +69 -2
- package/dist/src/indexed/bfs.d.ts.map +1 -1
- package/dist/src/indexed/bfs.js +148 -1
- package/dist/src/indexed/bfs.js.map +1 -1
- package/dist/src/indexed/bipartite.d.ts +37 -0
- package/dist/src/indexed/bipartite.d.ts.map +1 -0
- package/dist/src/indexed/bipartite.js +54 -0
- package/dist/src/indexed/bipartite.js.map +1 -0
- package/dist/src/indexed/closeness.d.ts +49 -0
- package/dist/src/indexed/closeness.d.ts.map +1 -0
- package/dist/src/indexed/closeness.js +127 -0
- package/dist/src/indexed/closeness.js.map +1 -0
- package/dist/src/indexed/common-neighbors.d.ts +14 -1
- package/dist/src/indexed/common-neighbors.d.ts.map +1 -1
- package/dist/src/indexed/common-neighbors.js +24 -14
- package/dist/src/indexed/common-neighbors.js.map +1 -1
- package/dist/src/indexed/degree.d.ts +19 -0
- package/dist/src/indexed/degree.d.ts.map +1 -0
- package/dist/src/indexed/degree.js +45 -0
- package/dist/src/indexed/degree.js.map +1 -0
- package/dist/src/indexed/delta-pagerank.d.ts +145 -0
- package/dist/src/indexed/delta-pagerank.d.ts.map +1 -0
- package/dist/src/indexed/delta-pagerank.js +428 -0
- package/dist/src/indexed/delta-pagerank.js.map +1 -0
- package/dist/src/indexed/dfs.d.ts +55 -0
- package/dist/src/indexed/dfs.d.ts.map +1 -0
- package/dist/src/indexed/dfs.js +146 -0
- package/dist/src/indexed/dfs.js.map +1 -0
- package/dist/src/indexed/eigenvector.d.ts +48 -0
- package/dist/src/indexed/eigenvector.d.ts.map +1 -0
- package/dist/src/indexed/eigenvector.js +162 -0
- package/dist/src/indexed/eigenvector.js.map +1 -0
- package/dist/src/indexed/facade.d.ts +109 -0
- package/dist/src/indexed/facade.d.ts.map +1 -0
- package/dist/src/indexed/facade.js +204 -0
- package/dist/src/indexed/facade.js.map +1 -0
- package/dist/src/indexed/flow.d.ts +120 -0
- package/dist/src/indexed/flow.d.ts.map +1 -0
- package/dist/src/indexed/flow.js +377 -0
- package/dist/src/indexed/flow.js.map +1 -0
- package/dist/src/indexed/girvan-newman.d.ts +42 -0
- package/dist/src/indexed/girvan-newman.d.ts.map +1 -0
- package/dist/src/indexed/girvan-newman.js +90 -0
- package/dist/src/indexed/girvan-newman.js.map +1 -0
- package/dist/src/indexed/grsbm.d.ts +85 -0
- package/dist/src/indexed/grsbm.d.ts.map +1 -0
- package/dist/src/indexed/grsbm.js +287 -0
- package/dist/src/indexed/grsbm.js.map +1 -0
- package/dist/src/indexed/hierarchical.d.ts +69 -0
- package/dist/src/indexed/hierarchical.d.ts.map +1 -0
- package/dist/src/indexed/hierarchical.js +245 -0
- package/dist/src/indexed/hierarchical.js.map +1 -0
- package/dist/src/indexed/index.d.ts +29 -3
- package/dist/src/indexed/index.d.ts.map +1 -1
- package/dist/src/indexed/index.js +29 -3
- package/dist/src/indexed/index.js.map +1 -1
- package/dist/src/indexed/isomorphism.d.ts +42 -0
- package/dist/src/indexed/isomorphism.d.ts.map +1 -0
- package/dist/src/indexed/isomorphism.js +269 -0
- package/dist/src/indexed/isomorphism.js.map +1 -0
- package/dist/src/indexed/label-propagation.d.ts +134 -0
- package/dist/src/indexed/label-propagation.d.ts.map +1 -0
- package/dist/src/indexed/label-propagation.js +486 -0
- package/dist/src/indexed/label-propagation.js.map +1 -0
- package/dist/src/indexed/leiden.d.ts +52 -0
- package/dist/src/indexed/leiden.d.ts.map +1 -0
- package/dist/src/indexed/leiden.js +384 -0
- package/dist/src/indexed/leiden.js.map +1 -0
- package/dist/src/indexed/link-prediction.d.ts +147 -0
- package/dist/src/indexed/link-prediction.d.ts.map +1 -0
- package/dist/src/indexed/link-prediction.js +317 -0
- package/dist/src/indexed/link-prediction.js.map +1 -0
- package/dist/src/indexed/markov.d.ts +54 -0
- package/dist/src/indexed/markov.d.ts.map +1 -0
- package/dist/src/indexed/markov.js +284 -0
- package/dist/src/indexed/markov.js.map +1 -0
- package/dist/src/indexed/matching.d.ts +53 -0
- package/dist/src/indexed/matching.d.ts.map +1 -0
- package/dist/src/indexed/matching.js +139 -0
- package/dist/src/indexed/matching.js.map +1 -0
- package/dist/src/indexed/min-cut.d.ts +48 -0
- package/dist/src/indexed/min-cut.d.ts.map +1 -0
- package/dist/src/indexed/min-cut.js +175 -0
- package/dist/src/indexed/min-cut.js.map +1 -0
- package/dist/src/indexed/modularity.d.ts +34 -0
- package/dist/src/indexed/modularity.d.ts.map +1 -0
- package/dist/src/indexed/modularity.js +74 -0
- package/dist/src/indexed/modularity.js.map +1 -0
- package/dist/src/indexed/mst.d.ts +29 -1
- package/dist/src/indexed/mst.d.ts.map +1 -1
- package/dist/src/indexed/mst.js +62 -0
- package/dist/src/indexed/mst.js.map +1 -1
- package/dist/src/indexed/pagerank.d.ts +29 -6
- package/dist/src/indexed/pagerank.d.ts.map +1 -1
- package/dist/src/indexed/pagerank.js +107 -11
- package/dist/src/indexed/pagerank.js.map +1 -1
- package/dist/src/indexed/point-to-point.d.ts +53 -0
- package/dist/src/indexed/point-to-point.d.ts.map +1 -0
- package/dist/src/indexed/point-to-point.js +173 -0
- package/dist/src/indexed/point-to-point.js.map +1 -0
- package/dist/src/indexed/scc.d.ts +53 -0
- package/dist/src/indexed/scc.d.ts.map +1 -0
- package/dist/src/indexed/scc.js +110 -0
- package/dist/src/indexed/scc.js.map +1 -0
- package/dist/src/indexed/spectral.d.ts +61 -0
- package/dist/src/indexed/spectral.d.ts.map +1 -0
- package/dist/src/indexed/spectral.js +476 -0
- package/dist/src/indexed/spectral.js.map +1 -0
- package/dist/src/indexed/structures/bit-set.d.ts +45 -0
- package/dist/src/indexed/structures/bit-set.d.ts.map +1 -0
- package/dist/src/indexed/structures/bit-set.js +57 -0
- package/dist/src/indexed/structures/bit-set.js.map +1 -0
- package/dist/src/indexed/structures/max-heap.d.ts +52 -0
- package/dist/src/indexed/structures/max-heap.d.ts.map +1 -0
- package/dist/src/indexed/structures/max-heap.js +66 -0
- package/dist/src/indexed/structures/max-heap.js.map +1 -0
- package/dist/src/indexed/structures/min-heap.d.ts +30 -1
- package/dist/src/indexed/structures/min-heap.d.ts.map +1 -1
- package/dist/src/indexed/structures/min-heap.js +46 -6
- package/dist/src/indexed/structures/min-heap.js.map +1 -1
- package/dist/src/indexed/structures/ring-queue.d.ts +41 -0
- package/dist/src/indexed/structures/ring-queue.d.ts.map +1 -0
- package/dist/src/indexed/structures/ring-queue.js +64 -0
- package/dist/src/indexed/structures/ring-queue.js.map +1 -0
- package/dist/src/indexed/sync.d.ts +50 -0
- package/dist/src/indexed/sync.d.ts.map +1 -0
- package/dist/src/indexed/sync.js +175 -0
- package/dist/src/indexed/sync.js.map +1 -0
- package/dist/src/indexed/terahac.d.ts +58 -0
- package/dist/src/indexed/terahac.d.ts.map +1 -0
- package/dist/src/indexed/terahac.js +244 -0
- package/dist/src/indexed/terahac.js.map +1 -0
- package/dist/src/indexed/to-snapshot.d.ts +45 -2
- package/dist/src/indexed/to-snapshot.d.ts.map +1 -1
- package/dist/src/indexed/to-snapshot.js +140 -6
- package/dist/src/indexed/to-snapshot.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors-legacy.d.ts +71 -0
- package/dist/src/link-prediction/common-neighbors-legacy.d.ts.map +1 -0
- package/dist/src/link-prediction/common-neighbors-legacy.js +172 -0
- package/dist/src/link-prediction/common-neighbors-legacy.js.map +1 -0
- package/dist/src/link-prediction/common-neighbors.d.ts +11 -19
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +56 -123
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/optimized/direction-optimized-bfs.d.ts +6 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -1
- package/dist/src/optimized/direction-optimized-bfs.js +6 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -1
- package/dist/src/research/grsbm-legacy.d.ts +82 -0
- package/dist/src/research/grsbm-legacy.d.ts.map +1 -0
- package/dist/src/research/grsbm-legacy.js +416 -0
- package/dist/src/research/grsbm-legacy.js.map +1 -0
- package/dist/src/research/grsbm.d.ts +9 -66
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +67 -391
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/sync-legacy.d.ts +48 -0
- package/dist/src/research/sync-legacy.d.ts.map +1 -0
- package/dist/src/research/sync-legacy.js +337 -0
- package/dist/src/research/sync-legacy.js.map +1 -0
- package/dist/src/research/sync.d.ts +10 -32
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +28 -316
- package/dist/src/research/sync.js.map +1 -1
- package/package.json +4 -3
- package/src/algorithms/centrality/betweenness.ts +51 -1
- package/src/algorithms/centrality/closeness.ts +112 -12
- package/src/algorithms/centrality/degree.ts +19 -0
- package/src/algorithms/centrality/eigenvector.ts +34 -0
- package/src/algorithms/centrality/hits.ts +24 -0
- package/src/algorithms/centrality/katz.ts +32 -0
- package/src/algorithms/centrality/pagerank.ts +53 -13
- package/src/algorithms/community/girvan-newman-legacy.ts +414 -0
- package/src/algorithms/community/girvan-newman.ts +36 -386
- package/src/algorithms/community/label-propagation.ts +24 -133
- package/src/algorithms/components/connected.ts +28 -95
- package/src/algorithms/mst/kruskal.ts +65 -4
- package/src/algorithms/shortest-path/bellman-ford.ts +49 -0
- package/src/algorithms/shortest-path/dijkstra.ts +29 -0
- package/src/algorithms/shortest-path/floyd-warshall.ts +106 -136
- package/src/algorithms/traversal/bfs-unified.ts +52 -366
- package/src/algorithms/traversal/bfs-variants.ts +5 -28
- package/src/algorithms/traversal/bfs.ts +0 -4
- package/src/algorithms/traversal/dfs.ts +39 -182
- package/src/clustering/hierarchical-legacy.ts +551 -0
- package/src/clustering/hierarchical.ts +64 -520
- package/src/clustering/k-core-legacy.ts +229 -0
- package/src/clustering/k-core.ts +38 -209
- package/src/clustering/mcl-legacy.ts +498 -0
- package/src/clustering/mcl.ts +46 -479
- package/src/index.ts +90 -3
- package/src/indexed/accelerator.ts +502 -16
- package/src/indexed/all-pairs.ts +342 -0
- package/src/indexed/bellman-ford.ts +72 -0
- package/src/indexed/betweenness.ts +258 -0
- package/src/indexed/bfs.ts +189 -3
- package/src/indexed/bipartite.ts +77 -0
- package/src/indexed/closeness.ts +160 -0
- package/src/indexed/common-neighbors.ts +31 -14
- package/src/indexed/degree.ts +55 -0
- package/src/indexed/delta-pagerank.ts +513 -0
- package/src/indexed/dfs.ts +189 -0
- package/src/indexed/eigenvector.ts +202 -0
- package/src/indexed/facade.ts +229 -0
- package/src/indexed/flow.ts +500 -0
- package/src/indexed/girvan-newman.ts +120 -0
- package/src/indexed/grsbm.ts +390 -0
- package/src/indexed/hierarchical.ts +295 -0
- package/src/indexed/index.ts +94 -3
- package/src/indexed/isomorphism.ts +305 -0
- package/src/indexed/label-propagation.ts +582 -0
- package/src/indexed/leiden.ts +436 -0
- package/src/indexed/link-prediction.ts +399 -0
- package/src/indexed/markov.ts +324 -0
- package/src/indexed/matching.ts +192 -0
- package/src/indexed/min-cut.ts +201 -0
- package/src/indexed/modularity.ts +81 -0
- package/src/indexed/mst.ts +79 -1
- package/src/indexed/pagerank.ts +128 -15
- package/src/indexed/point-to-point.ts +220 -0
- package/src/indexed/scc.ts +132 -0
- package/src/indexed/spectral.ts +550 -0
- package/src/indexed/structures/bit-set.ts +65 -0
- package/src/indexed/structures/max-heap.ts +74 -0
- package/src/indexed/structures/min-heap.ts +51 -6
- package/src/indexed/structures/ring-queue.ts +70 -0
- package/src/indexed/sync.ts +229 -0
- package/src/indexed/terahac.ts +290 -0
- package/src/indexed/to-snapshot.ts +156 -6
- package/src/link-prediction/common-neighbors-legacy.ts +252 -0
- package/src/link-prediction/common-neighbors.ts +65 -168
- package/src/optimized/direction-optimized-bfs.ts +6 -1
- package/src/research/grsbm-legacy.ts +586 -0
- package/src/research/grsbm.ts +76 -555
- package/src/research/sync-legacy.ts +456 -0
- package/src/research/sync.ts +30 -431
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { INVALID_INDEX } from "@graphty/graph-format";
|
|
2
|
+
/**
|
|
3
|
+
* Count the distinct neighbours of `u` other than itself in one adjacency.
|
|
4
|
+
* @param view - The adjacency to read the row of
|
|
5
|
+
* @param u - The node
|
|
6
|
+
* @returns The simple degree, and whether `u` has a self-loop
|
|
7
|
+
*/
|
|
8
|
+
function simpleDegree(view, u) {
|
|
9
|
+
let degree = 0;
|
|
10
|
+
let loop = false;
|
|
11
|
+
let prev = INVALID_INDEX;
|
|
12
|
+
for (let a = view.rowPtr[u]; a < view.rowPtr[u + 1]; a++) {
|
|
13
|
+
const v = view.colIdx[a];
|
|
14
|
+
if (v === prev) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
prev = v;
|
|
18
|
+
if (v === u) {
|
|
19
|
+
loop = true;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
degree++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { degree, loop };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A per-node signature a node and its image must share: simple out-degree, simple in-degree
|
|
29
|
+
* (directed only) and the self-loop bit, packed in one number.
|
|
30
|
+
* @param s - The snapshot
|
|
31
|
+
* @returns One signature per node
|
|
32
|
+
*/
|
|
33
|
+
function signatures(s) {
|
|
34
|
+
const out = new Float64Array(s.nodeCount);
|
|
35
|
+
const rev = s.directed ? s.reverse() : null;
|
|
36
|
+
for (let u = 0; u < s.nodeCount; u++) {
|
|
37
|
+
const f = simpleDegree(s, u);
|
|
38
|
+
const inDegree = rev === null ? 0 : simpleDegree(rev, u).degree;
|
|
39
|
+
out[u] = (f.degree * 2 ** 26 + inDegree) * 2 + (f.loop ? 1 : 0);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The order the nodes of `s1` are mapped in: BFS over out- and in-arcs, one component after another
|
|
45
|
+
* from the lowest unvisited index. Every node after a component's first is adjacent to an earlier
|
|
46
|
+
* one (its parent), so its candidates are the neighbours of the parent's image.
|
|
47
|
+
* @param views - The forward adjacency, and on a directed snapshot the reverse one
|
|
48
|
+
* @param n - The node count
|
|
49
|
+
* @returns The order, each node's BFS parent (INVALID_INDEX for a component's first node) and
|
|
50
|
+
* which view the parent reached it through
|
|
51
|
+
*/
|
|
52
|
+
function matchOrder(views, n) {
|
|
53
|
+
const order = new Uint32Array(n);
|
|
54
|
+
const parent = new Uint32Array(n).fill(INVALID_INDEX);
|
|
55
|
+
const parentView = new Uint8Array(n);
|
|
56
|
+
const seen = new Uint8Array(n);
|
|
57
|
+
let tail = 0;
|
|
58
|
+
for (let r = 0; r < n; r++) {
|
|
59
|
+
if (seen[r] === 1) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
seen[r] = 1;
|
|
63
|
+
let head = tail;
|
|
64
|
+
order[tail++] = r;
|
|
65
|
+
while (head < tail) {
|
|
66
|
+
const u = order[head++];
|
|
67
|
+
for (let k = 0; k < views.length; k++) {
|
|
68
|
+
const { rowPtr, colIdx } = views[k];
|
|
69
|
+
for (let a = rowPtr[u]; a < rowPtr[u + 1]; a++) {
|
|
70
|
+
const v = colIdx[a];
|
|
71
|
+
if (seen[v] === 0) {
|
|
72
|
+
seen[v] = 1;
|
|
73
|
+
parent[v] = u;
|
|
74
|
+
parentView[v] = k;
|
|
75
|
+
order[tail++] = v;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { order, parent, parentView };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* VF2-style depth-first search for isomorphisms from `s1` to `s2`.
|
|
85
|
+
* @param s1 - The first graph
|
|
86
|
+
* @param s2 - The second graph
|
|
87
|
+
* @param options - Node and edge match predicates
|
|
88
|
+
* @param found - Called with every isomorphism (a live array: copy it to keep it); returning true
|
|
89
|
+
* stops the search
|
|
90
|
+
*/
|
|
91
|
+
function search(s1, s2, options, found) {
|
|
92
|
+
const n = s1.nodeCount;
|
|
93
|
+
if (s1.directed !== s2.directed || n !== s2.nodeCount) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const sig1 = signatures(s1);
|
|
97
|
+
const sig2 = signatures(s2);
|
|
98
|
+
const sorted1 = sig1.slice().sort();
|
|
99
|
+
const sorted2 = sig2.slice().sort();
|
|
100
|
+
if (sorted1.some((x, i) => x !== sorted2[i])) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const views1 = s1.directed ? [s1, s1.reverse()] : [s1];
|
|
104
|
+
const views2 = s2.directed ? [s2, s2.reverse()] : [s2];
|
|
105
|
+
const { order, parent, parentView } = matchOrder(views1, n);
|
|
106
|
+
const core1 = new Uint32Array(n).fill(INVALID_INDEX);
|
|
107
|
+
const core2 = new Uint32Array(n).fill(INVALID_INDEX);
|
|
108
|
+
// Per view, the arc of s2 from the candidate to each neighbour, stamped with the search step.
|
|
109
|
+
const stamp = views2.map(() => new Uint32Array(n));
|
|
110
|
+
const arcTo = views2.map(() => new Uint32Array(n));
|
|
111
|
+
let step = 0;
|
|
112
|
+
const { nodeMatch, edgeMatch } = options;
|
|
113
|
+
const feasible = (u1, u2) => {
|
|
114
|
+
if (sig1[u1] !== sig2[u2] || (nodeMatch !== undefined && !nodeMatch(u1, u2, s1, s2))) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
// The signatures agree, so u1 has a self-loop exactly when u2 has one: offer the two loops.
|
|
118
|
+
if (edgeMatch !== undefined && sig1[u1] % 2 === 1) {
|
|
119
|
+
const loop1 = s1.arcToEdge[s1.findArc(u1, u1)];
|
|
120
|
+
const loop2 = s2.arcToEdge[s2.findArc(u2, u2)];
|
|
121
|
+
if (!edgeMatch(loop1, loop2, s1, s2)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
step++;
|
|
126
|
+
for (let k = 0; k < views1.length; k++) {
|
|
127
|
+
const g1 = views1[k];
|
|
128
|
+
const g2 = views2[k];
|
|
129
|
+
let mapped2 = 0;
|
|
130
|
+
let prev = INVALID_INDEX;
|
|
131
|
+
for (let a = g2.rowPtr[u2]; a < g2.rowPtr[u2 + 1]; a++) {
|
|
132
|
+
const v = g2.colIdx[a];
|
|
133
|
+
if (v === prev || v === u2) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
prev = v;
|
|
137
|
+
stamp[k][v] = step;
|
|
138
|
+
arcTo[k][v] = a;
|
|
139
|
+
if (core2[v] !== INVALID_INDEX) {
|
|
140
|
+
mapped2++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
let mapped1 = 0;
|
|
144
|
+
prev = INVALID_INDEX;
|
|
145
|
+
for (let a = g1.rowPtr[u1]; a < g1.rowPtr[u1 + 1]; a++) {
|
|
146
|
+
const v = g1.colIdx[a];
|
|
147
|
+
if (v === prev || v === u1) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
prev = v;
|
|
151
|
+
const image = core1[v];
|
|
152
|
+
if (image === INVALID_INDEX) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (stamp[k][image] !== step) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
mapped1++;
|
|
159
|
+
// An undirected edge is offered once: through the out-rows. A directed arc is
|
|
160
|
+
// offered through the view it is an out-arc or an in-arc of the new node in.
|
|
161
|
+
if (edgeMatch !== undefined && !edgeMatch(g1.arcToEdge[a], g2.arcToEdge[arcTo[k][image]], s1, s2)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (mapped1 !== mapped2) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
};
|
|
171
|
+
// Iterative DFS over depth; cursor[d] walks the candidate list of order[d].
|
|
172
|
+
const cursor = new Uint32Array(n + 1);
|
|
173
|
+
let depth = 0;
|
|
174
|
+
let stop = false;
|
|
175
|
+
const candidatesOf = (d) => {
|
|
176
|
+
const p = parent[order[d]];
|
|
177
|
+
if (p === INVALID_INDEX) {
|
|
178
|
+
return { view: null, from: 0, to: n };
|
|
179
|
+
}
|
|
180
|
+
const view = views2[parentView[order[d]]];
|
|
181
|
+
const image = core1[p];
|
|
182
|
+
return { view, from: view.rowPtr[image], to: view.rowPtr[image + 1] };
|
|
183
|
+
};
|
|
184
|
+
if (n === 0) {
|
|
185
|
+
found(core1);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
let range = candidatesOf(0);
|
|
189
|
+
cursor[0] = range.from;
|
|
190
|
+
while (!stop) {
|
|
191
|
+
const u1 = order[depth];
|
|
192
|
+
let advanced = false;
|
|
193
|
+
while (cursor[depth] < range.to) {
|
|
194
|
+
const c = cursor[depth]++;
|
|
195
|
+
const u2 = range.view === null ? c : range.view.colIdx[c];
|
|
196
|
+
// Parallel arcs repeat a candidate; take it once.
|
|
197
|
+
if (range.view !== null && c > range.from && range.view.colIdx[c - 1] === u2) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (core2[u2] !== INVALID_INDEX || !feasible(u1, u2)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
core1[u1] = u2;
|
|
204
|
+
core2[u2] = u1;
|
|
205
|
+
if (depth === n - 1) {
|
|
206
|
+
stop = found(core1);
|
|
207
|
+
core1[u1] = INVALID_INDEX;
|
|
208
|
+
core2[u2] = INVALID_INDEX;
|
|
209
|
+
if (stop) {
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
depth++;
|
|
215
|
+
range = candidatesOf(depth);
|
|
216
|
+
cursor[depth] = range.from;
|
|
217
|
+
advanced = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
if (stop || advanced) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// Exhausted: undo the mapping of the node below and resume its candidates.
|
|
224
|
+
if (depth === 0) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
depth--;
|
|
228
|
+
const back = order[depth];
|
|
229
|
+
core2[core1[back]] = INVALID_INDEX;
|
|
230
|
+
core1[back] = INVALID_INDEX;
|
|
231
|
+
range = candidatesOf(depth);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Whether two snapshots are isomorphic, by a VF2-style search. Neighbourhoods are simple-graph:
|
|
236
|
+
* parallel arcs count once and a self-loop maps only to a self-loop. On a directed snapshot both
|
|
237
|
+
* arc directions are preserved.
|
|
238
|
+
* @param s1 - The first graph
|
|
239
|
+
* @param s2 - The second graph
|
|
240
|
+
* @param options - Node and edge match predicates
|
|
241
|
+
* @returns Whether an isomorphism exists and, when it does, the first one found
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
export function isGraphIsomorphic(s1, s2, options = {}) {
|
|
245
|
+
let mapping = null;
|
|
246
|
+
search(s1, s2, options, (m) => {
|
|
247
|
+
mapping = m.slice();
|
|
248
|
+
return true;
|
|
249
|
+
});
|
|
250
|
+
return { isomorphic: mapping !== null, mapping };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Every isomorphism from `s1` to `s2`, with the neighbourhood rules of {@link isGraphIsomorphic}.
|
|
254
|
+
* Two empty graphs have one, the empty mapping.
|
|
255
|
+
* @param s1 - The first graph
|
|
256
|
+
* @param s2 - The second graph
|
|
257
|
+
* @param options - Node and edge match predicates
|
|
258
|
+
* @returns One array per isomorphism: the image in `s2` of every node of `s1`
|
|
259
|
+
* @public
|
|
260
|
+
*/
|
|
261
|
+
export function findAllIsomorphisms(s1, s2, options = {}) {
|
|
262
|
+
const all = [];
|
|
263
|
+
search(s1, s2, options, (m) => {
|
|
264
|
+
all.push(m.slice());
|
|
265
|
+
return false;
|
|
266
|
+
});
|
|
267
|
+
return all;
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=isomorphism.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isomorphism.js","sourceRoot":"","sources":["../../../src/indexed/isomorphism.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type AdjacencyView, type GraphSnapshot, type NumericVector, type U32 } from "@graphty/graph-format";
|
|
2
|
+
import { type LabelResult } from "./components.js";
|
|
3
|
+
/** Options of the index-based label propagation. @public */
|
|
4
|
+
export interface LabelPropagationOptions {
|
|
5
|
+
/** Work cap, in node visits per node (full-sweep equivalents); default 100. */
|
|
6
|
+
readonly maxIterations?: number | undefined;
|
|
7
|
+
/** Seed of the visit order and of the tie draws; default 42. */
|
|
8
|
+
readonly randomSeed?: number | undefined;
|
|
9
|
+
/** Sum arc weights (true, the default) or count each distinct neighbour once (false). */
|
|
10
|
+
readonly weighted?: boolean | undefined;
|
|
11
|
+
}
|
|
12
|
+
/** Result of the index-based label propagation. @public */
|
|
13
|
+
export interface LabelPropagationResult extends LabelResult {
|
|
14
|
+
/** Node visits divided by the node count, rounded up. */
|
|
15
|
+
readonly iterations: number;
|
|
16
|
+
/**
|
|
17
|
+
* True when the work queue emptied before the visit cap, which leaves every node's label
|
|
18
|
+
* dominant among its neighbours. False only says the cap was reached with nodes still queued:
|
|
19
|
+
* the labels may already be dominant.
|
|
20
|
+
*/
|
|
21
|
+
readonly converged: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* mulberry32: 32-bit state, output in [0, 1). The exact sequence is part of the result contract
|
|
25
|
+
* (design section 2.4): changing it changes every partition.
|
|
26
|
+
* @param seed - Generator seed; only its low 32 bits are used
|
|
27
|
+
* @returns The generator
|
|
28
|
+
*/
|
|
29
|
+
export declare function mulberry32(seed: number): () => number;
|
|
30
|
+
/**
|
|
31
|
+
* The per-arc weights of `view` that the votes use: the snapshot's exact f64 weights when it keeps
|
|
32
|
+
* them (graph-format keeps a role-"weight" f64 edge column whenever some weight is not f32-exact),
|
|
33
|
+
* gathered through arcToEdge; otherwise the view's own f32 arc array. Voting on the f32 values would
|
|
34
|
+
* turn 1 and 1 + 1e-9 into a tie, 1e39 into Infinity and 1e-50 into 0.
|
|
35
|
+
* @param view - The forward snapshot or its reverse view
|
|
36
|
+
* @param exact - The exact per-edge weights, or null when the f32 arc array is exact
|
|
37
|
+
* @returns The arc weights, or null when every arc weighs 1
|
|
38
|
+
*/
|
|
39
|
+
export declare function arcWeightsOf(view: AdjacencyView, exact: Float64Array | null): NumericVector | null;
|
|
40
|
+
/**
|
|
41
|
+
* The exact per-edge weights of `s`: its role-"weight" f64 edge column when it keeps one, else null
|
|
42
|
+
* (the f32 arc array is then exact).
|
|
43
|
+
* @param s - The snapshot
|
|
44
|
+
* @returns The exact weights per logical edge, or null
|
|
45
|
+
*/
|
|
46
|
+
export declare function exactEdgeWeights(s: GraphSnapshot): Float64Array | null;
|
|
47
|
+
/**
|
|
48
|
+
* Community detection by fast label propagation (FLPA; Traag and Subelj, Sci. Rep. 13:2701, 2023,
|
|
49
|
+
* Algorithm 3), the queue-driven form of Raghavan, Albert and Kumara's asynchronous label
|
|
50
|
+
* propagation.
|
|
51
|
+
*
|
|
52
|
+
* Every node starts in its own community. Nodes are visited from a queue that starts as a seeded
|
|
53
|
+
* shuffle of all of them; a visited node adopts the label with the largest summed arc weight among
|
|
54
|
+
* its neighbours, drawing uniformly at random among tied labels (its current label included, with
|
|
55
|
+
* no priority). When its label changes, every neighbour holding a different label is queued again.
|
|
56
|
+
* The run ends when the queue empties -- then every node's label is dominant among its neighbours
|
|
57
|
+
* and `converged` is true -- or after `maxIterations * nodeCount` node visits.
|
|
58
|
+
*
|
|
59
|
+
* Conventions: self-loops are skipped; parallel arcs are summed; on a directed snapshot a node's
|
|
60
|
+
* neighbours are its out-arcs AND its in-arcs, so a reciprocal pair counts twice. With
|
|
61
|
+
* `weighted: false` each distinct neighbour votes once. A negative, NaN or infinite weight throws.
|
|
62
|
+
* Votes use the exact f64 weights when the snapshot keeps them (as `toSnapshot` does for a legacy
|
|
63
|
+
* graph whose weights are not all f32-exact), so a weight rounded in the f32 arc array never
|
|
64
|
+
* decides a vote.
|
|
65
|
+
*
|
|
66
|
+
* One `randomSeed` gives one result, bit for bit. The partitions differ from the legacy
|
|
67
|
+
* `labelPropagation` for the same seed: the random stream and the stop rule are different
|
|
68
|
+
* (design `design/algorithms/label-propagation-indexed-port-design.md`, section 3).
|
|
69
|
+
* @param s - Any snapshot
|
|
70
|
+
* @param options - Work cap, seed and weighting
|
|
71
|
+
* @returns The partition, the full-sweep equivalents run, and whether the work queue emptied
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
export declare function labelPropagation(s: GraphSnapshot, options?: LabelPropagationOptions): LabelPropagationResult;
|
|
75
|
+
/**
|
|
76
|
+
* Semi-supervised label propagation: the FLPA kernel of {@link labelPropagation} with some nodes
|
|
77
|
+
* held at a given label (the `initial` / `fixed` inputs of igraph's `community_label_propagation`).
|
|
78
|
+
*
|
|
79
|
+
* A seeded node keeps its label for the whole run and is never visited; every other node starts in
|
|
80
|
+
* its own community and moves as in `labelPropagation`. Seeds that share a label share one community
|
|
81
|
+
* from the start, and seeds with different labels are never merged, so in the result two seeds
|
|
82
|
+
* carry the same label exactly when their seed labels are equal. The result is renumbered to
|
|
83
|
+
* `0..count-1` in first-seen node order like every other partition here, so a seed label's VALUE is
|
|
84
|
+
* not kept: read a seed's community through `labels[seedNode]`. With no seed at all this is
|
|
85
|
+
* `labelPropagation` with the same seed and options, bit for bit.
|
|
86
|
+
*
|
|
87
|
+
* `converged` is true when the work queue emptied, or when `maxIterations` is 0 and the starting
|
|
88
|
+
* labels already are dominant: every unseeded node's label is dominant among its neighbours.
|
|
89
|
+
* Seeded nodes are not held to that.
|
|
90
|
+
* @param s - Any snapshot
|
|
91
|
+
* @param seeds - One entry per node: its fixed label, any value but `INVALID_INDEX`, or
|
|
92
|
+
* `INVALID_INDEX` for a node free to move
|
|
93
|
+
* @param options - Work cap, seed of the visit order and weighting
|
|
94
|
+
* @returns The partition, the full-sweep equivalents run, and whether the work queue emptied
|
|
95
|
+
* @throws RangeError when `seeds` is not one entry per node, or for a bad option or weight
|
|
96
|
+
* @public
|
|
97
|
+
*/
|
|
98
|
+
export declare function labelPropagationSemiSupervised(s: GraphSnapshot, seeds: U32, options?: LabelPropagationOptions): LabelPropagationResult;
|
|
99
|
+
/** Options of the synchronous label propagation. @public */
|
|
100
|
+
export interface SynchronousLabelPropagationOptions {
|
|
101
|
+
/** Cap on synchronous passes over every node; default 100. */
|
|
102
|
+
readonly maxIterations?: number | undefined;
|
|
103
|
+
/** Sum arc weights (true, the default) or count each distinct neighbour once (false). */
|
|
104
|
+
readonly weighted?: boolean | undefined;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Label propagation in synchronous passes: every node reads its neighbours' labels from the
|
|
108
|
+
* previous pass, and all nodes move at once. Deterministic, with no random stream.
|
|
109
|
+
*
|
|
110
|
+
* A node keeps its label when that label is dominant among its neighbours; otherwise it takes the
|
|
111
|
+
* LOWEST label with the largest summed vote. Synchronous updates alone make two neighbours trade
|
|
112
|
+
* labels for ever (on a single edge a-b, a takes b's label while b takes a's), so passes alternate
|
|
113
|
+
* a swap guard: an even pass (the first is pass 0) lets a node move only to a higher label, an odd
|
|
114
|
+
* pass only to a lower one (the up/down rule of cuGraph's Louvain move phase). The run stops after
|
|
115
|
+
* two passes in a row with no move, one up and one down -- then every node's label is dominant and
|
|
116
|
+
* `converged` is true -- or after `maxIterations` passes.
|
|
117
|
+
*
|
|
118
|
+
* The guard stops the single-edge swap but not every cycle: on some weighted graphs a node climbs to
|
|
119
|
+
* a higher label on each up pass and falls back on each down pass. When a pass returns the labels
|
|
120
|
+
* of two passes before, the run can only repeat itself, so it stops there with `converged` false;
|
|
121
|
+
* the result is then the same for any larger `maxIterations`. Longer cycles run to the cap.
|
|
122
|
+
*
|
|
123
|
+
* This is what the legacy `labelPropagationAsync` does, despite its name, with the swap guard it
|
|
124
|
+
* lacks and the tie rule applied to the finished tally rather than to a running one. Conventions
|
|
125
|
+
* match {@link labelPropagation}: self-loops are skipped, parallel arcs summed, a directed snapshot
|
|
126
|
+
* reads out- and in-neighbours, weights are the exact f64 ones when the snapshot keeps them, and a
|
|
127
|
+
* negative, NaN or infinite weight throws.
|
|
128
|
+
* @param s - Any snapshot
|
|
129
|
+
* @param options - Pass cap and weighting
|
|
130
|
+
* @returns The partition, the passes run, and whether every label ended dominant
|
|
131
|
+
* @public
|
|
132
|
+
*/
|
|
133
|
+
export declare function labelPropagationSynchronous(s: GraphSnapshot, options?: SynchronousLabelPropagationOptions): LabelPropagationResult;
|
|
134
|
+
//# sourceMappingURL=label-propagation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label-propagation.d.ts","sourceRoot":"","sources":["../../../src/indexed/label-propagation.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,aAAa,EAClB,KAAK,aAAa,EAElB,KAAK,aAAa,EAElB,KAAK,GAAG,EACX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,iBAAiB,CAAC;AAE/D,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3C;AAED,2DAA2D;AAC3D,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACvD,yDAAyD;IACzD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC/B;AAKD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAQrD;AA0CD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,GAAG,aAAa,GAAG,IAAI,CASlG;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,GAAG,YAAY,GAAG,IAAI,CAGtE;AAwPD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CAkBhH;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,8BAA8B,CAC1C,CAAC,EAAE,aAAa,EAChB,KAAK,EAAE,GAAG,EACV,OAAO,GAAE,uBAA4B,GACtC,sBAAsB,CAmCxB;AAED,4DAA4D;AAC5D,MAAM,WAAW,kCAAkC;IAC/C,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,2BAA2B,CACvC,CAAC,EAAE,aAAa,EAChB,OAAO,GAAE,kCAAuC,GACjD,sBAAsB,CAgDxB"}
|