@graphty/algorithms 1.2.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +375 -276
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11402 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +14 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +144 -169
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +35 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +70 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.d.ts +7 -0
- package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +12 -9
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +57 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +304 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +106 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +320 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -3
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.js +11 -4
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
- package/dist/src/algorithms/centrality/hits.d.ts +10 -3
- package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/hits.js +11 -4
- package/dist/src/algorithms/centrality/hits.js.map +1 -1
- package/dist/src/algorithms/centrality/index.d.ts +3 -1
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +2 -1
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/katz.d.ts +10 -3
- package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/katz.js +13 -8
- package/dist/src/algorithms/centrality/katz.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +31 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +61 -1
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts +2 -3
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +67 -57
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/index.d.ts +2 -0
- package/dist/src/algorithms/community/index.d.ts.map +1 -1
- package/dist/src/algorithms/community/index.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +11 -4
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +60 -38
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -3
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +70 -44
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +149 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +338 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts +2 -3
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +35 -81
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +55 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +108 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/components/connected.d.ts +23 -0
- package/dist/src/algorithms/components/connected.d.ts.map +1 -1
- package/dist/src/algorithms/components/connected.js +29 -3
- package/dist/src/algorithms/components/connected.js.map +1 -1
- package/dist/src/algorithms/matching/bipartite.d.ts +10 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +18 -40
- package/dist/src/algorithms/matching/bipartite.js.map +1 -1
- package/dist/src/algorithms/matching/index.d.ts.map +1 -1
- package/dist/src/algorithms/matching/index.js.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.d.ts +8 -0
- package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.js +36 -2
- package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
- package/dist/src/algorithms/mst/index.d.ts.map +1 -1
- package/dist/src/algorithms/mst/index.js.map +1 -1
- package/dist/src/algorithms/mst/kruskal.d.ts +14 -0
- package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
- package/dist/src/algorithms/mst/kruskal.js +17 -3
- package/dist/src/algorithms/mst/kruskal.js.map +1 -1
- package/dist/src/algorithms/mst/prim.d.ts +9 -0
- package/dist/src/algorithms/mst/prim.d.ts.map +1 -1
- package/dist/src/algorithms/mst/prim.js +9 -0
- package/dist/src/algorithms/mst/prim.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +10 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +11 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +44 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +195 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +20 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +30 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +17 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.js +17 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
- package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/index.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +42 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +370 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +77 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +402 -0
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +5 -182
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.d.ts +10 -0
- package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +48 -0
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/algorithms/traversal/index.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/index.js.map +1 -1
- package/dist/src/benchmark-all-algorithms.d.ts +25 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +491 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +23 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +226 -224
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/index.d.ts +4 -2
- package/dist/src/clustering/index.d.ts.map +1 -1
- package/dist/src/clustering/index.js +2 -2
- package/dist/src/clustering/index.js.map +1 -1
- package/dist/src/clustering/k-core.d.ts +17 -19
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +68 -30
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/mcl.d.ts +6 -0
- package/dist/src/clustering/mcl.d.ts.map +1 -1
- package/dist/src/clustering/mcl.js +34 -3
- package/dist/src/clustering/mcl.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +11 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +99 -47
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.d.ts +45 -0
- package/dist/src/core/graph.d.ts.map +1 -1
- package/dist/src/core/graph.js +49 -5
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/data-structures/index.d.ts.map +1 -1
- package/dist/src/data-structures/index.js.map +1 -1
- package/dist/src/data-structures/priority-queue.d.ts +18 -1
- package/dist/src/data-structures/priority-queue.d.ts.map +1 -1
- package/dist/src/data-structures/priority-queue.js +26 -5
- package/dist/src/data-structures/priority-queue.js.map +1 -1
- package/dist/src/data-structures/union-find.d.ts +21 -0
- package/dist/src/data-structures/union-find.d.ts.map +1 -1
- package/dist/src/data-structures/union-find.js +21 -0
- package/dist/src/data-structures/union-find.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +20 -12
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +170 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -8
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +34 -12
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts +26 -0
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +47 -30
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts +21 -0
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +31 -14
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/link-prediction/index.d.ts.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +193 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +342 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +149 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +404 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +95 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +242 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +111 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +194 -0
- package/dist/src/optimized/graph-adapter.js.map +1 -0
- package/dist/src/optimized/index.d.ts +14 -0
- package/dist/src/optimized/index.d.ts.map +1 -0
- package/dist/src/optimized/index.js +30 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/pathfinding/astar.d.ts +25 -9
- package/dist/src/pathfinding/astar.d.ts.map +1 -1
- package/dist/src/pathfinding/astar.js +25 -10
- package/dist/src/pathfinding/astar.js.map +1 -1
- package/dist/src/pathfinding/utils.d.ts +15 -6
- package/dist/src/pathfinding/utils.d.ts.map +1 -1
- package/dist/src/pathfinding/utils.js +19 -7
- package/dist/src/pathfinding/utils.js.map +1 -1
- package/dist/src/research/grsbm.d.ts +0 -1
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +28 -23
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/index.d.ts.map +1 -1
- package/dist/src/research/index.js.map +1 -1
- package/dist/src/research/sync.d.ts +0 -1
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +31 -36
- package/dist/src/research/sync.js.map +1 -1
- package/dist/src/research/terahac.d.ts +2 -1
- package/dist/src/research/terahac.d.ts.map +1 -1
- package/dist/src/research/terahac.js +39 -7
- package/dist/src/research/terahac.js.map +1 -1
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/algorithm-utilities.d.ts +2 -0
- package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
- package/dist/src/utils/algorithm-utilities.js +2 -0
- package/dist/src/utils/algorithm-utilities.js.map +1 -0
- package/dist/src/utils/graph-converters.d.ts +110 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +227 -0
- package/dist/src/utils/graph-converters.js.map +1 -0
- package/dist/src/utils/graph-utilities.d.ts +62 -0
- package/dist/src/utils/graph-utilities.d.ts.map +1 -0
- package/dist/src/utils/graph-utilities.js +148 -0
- package/dist/src/utils/graph-utilities.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +5 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/math-utilities.d.ts +63 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +132 -0
- package/dist/src/utils/math-utilities.js.map +1 -0
- package/dist/src/utils/matrix-utilities.d.ts +2 -0
- package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
- package/dist/src/utils/matrix-utilities.js +2 -0
- package/dist/src/utils/matrix-utilities.js.map +1 -0
- package/dist/src/utils/optimization-helpers.d.ts +42 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +59 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/dist/src/utils/priorityQueue.d.ts +24 -0
- package/dist/src/utils/priorityQueue.d.ts.map +1 -1
- package/dist/src/utils/priorityQueue.js +34 -4
- package/dist/src/utils/priorityQueue.js.map +1 -1
- package/package.json +58 -39
- package/src/algorithms/centrality/betweenness.ts +185 -200
- package/src/algorithms/centrality/closeness.ts +93 -194
- package/src/algorithms/centrality/degree.ts +18 -22
- package/src/algorithms/centrality/delta-pagerank-simple.ts +374 -0
- package/src/algorithms/centrality/delta-pagerank.ts +458 -0
- package/src/algorithms/centrality/eigenvector.ts +14 -15
- package/src/algorithms/centrality/hits.ts +17 -17
- package/src/algorithms/centrality/index.ts +20 -13
- package/src/algorithms/centrality/katz.ts +17 -25
- package/src/algorithms/centrality/pagerank.ts +91 -16
- package/src/algorithms/community/girvan-newman.ts +90 -86
- package/src/algorithms/community/index.ts +6 -5
- package/src/algorithms/community/label-propagation.ts +69 -48
- package/src/algorithms/community/leiden.ts +88 -65
- package/src/algorithms/community/louvain-optimized.ts +474 -0
- package/src/algorithms/community/louvain.ts +52 -122
- package/src/algorithms/community/modularity-utils.ts +134 -0
- package/src/algorithms/components/connected.ts +40 -17
- package/src/algorithms/matching/bipartite.ts +24 -53
- package/src/algorithms/matching/index.ts +4 -4
- package/src/algorithms/matching/isomorphism.ts +53 -23
- package/src/algorithms/mst/index.ts +3 -4
- package/src/algorithms/mst/kruskal.ts +21 -6
- package/src/algorithms/mst/prim.ts +13 -4
- package/src/algorithms/shortest-path/bellman-ford.ts +16 -28
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +38 -30
- package/src/algorithms/shortest-path/floyd-warshall.ts +21 -4
- package/src/algorithms/shortest-path/index.ts +5 -5
- package/src/algorithms/traversal/bfs-unified.ts +437 -0
- package/src/algorithms/traversal/bfs-variants.ts +520 -0
- package/src/algorithms/traversal/bfs.ts +5 -229
- package/src/algorithms/traversal/dfs.ts +61 -42
- package/src/algorithms/traversal/index.ts +3 -3
- package/src/benchmark-all-algorithms.ts +580 -0
- package/src/clustering/hierarchical.ts +268 -272
- package/src/clustering/index.ts +8 -6
- package/src/clustering/k-core.ts +93 -61
- package/src/clustering/mcl.ts +53 -23
- package/src/clustering/spectral.ts +130 -72
- package/src/core/graph.ts +58 -18
- package/src/data-structures/index.ts +2 -2
- package/src/data-structures/priority-queue.ts +36 -11
- package/src/data-structures/union-find.ts +22 -1
- package/src/flow/ford-fulkerson.ts +221 -262
- package/src/flow/min-cut.ts +59 -51
- package/src/index.ts +9 -2
- package/src/link-prediction/adamic-adar.ts +75 -74
- package/src/link-prediction/common-neighbors.ts +49 -49
- package/src/link-prediction/index.ts +1 -1
- package/src/optimized/bit-packed.ts +390 -0
- package/src/optimized/csr-graph.ts +518 -0
- package/src/optimized/direction-optimized-bfs.ts +310 -0
- package/src/optimized/graph-adapter.ts +248 -0
- package/src/optimized/index.ts +34 -0
- package/src/pathfinding/astar.ts +40 -25
- package/src/pathfinding/utils.ts +20 -13
- package/src/research/grsbm.ts +36 -39
- package/src/research/index.ts +4 -4
- package/src/research/sync.ts +41 -54
- package/src/research/terahac.ts +63 -21
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +269 -0
- package/src/utils/graph-utilities.ts +173 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +149 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +87 -0
- package/src/utils/priorityQueue.ts +40 -6
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import type { NodeId } from "../types/index.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface for read-only graph operations
|
|
5
|
+
*/
|
|
6
|
+
export interface ReadonlyGraph<TNodeId = NodeId> {
|
|
7
|
+
nodeCount(): number;
|
|
8
|
+
edgeCount(): number;
|
|
9
|
+
hasNode(nodeId: TNodeId): boolean;
|
|
10
|
+
hasEdge(source: TNodeId, target: TNodeId): boolean;
|
|
11
|
+
neighbors(nodeId: TNodeId): IterableIterator<TNodeId>;
|
|
12
|
+
outDegree(nodeId: TNodeId): number;
|
|
13
|
+
nodes(): IterableIterator<TNodeId>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Internal data structure for CSR representation
|
|
18
|
+
*/
|
|
19
|
+
interface CSRGraphData<TNodeId> {
|
|
20
|
+
// Row pointers: indices where each node's edges start
|
|
21
|
+
rowPointers: Uint32Array;
|
|
22
|
+
|
|
23
|
+
// Column indices: destination nodes for each edge
|
|
24
|
+
columnIndices: Uint32Array;
|
|
25
|
+
|
|
26
|
+
// Edge weights (optional)
|
|
27
|
+
edgeWeights?: Float32Array;
|
|
28
|
+
|
|
29
|
+
// Reverse edges for bottom-up BFS (optional)
|
|
30
|
+
reverseRowPointers?: Uint32Array;
|
|
31
|
+
reverseColumnIndices?: Uint32Array;
|
|
32
|
+
|
|
33
|
+
// Node ID mapping
|
|
34
|
+
nodeIdToIndex: Map<TNodeId, number>;
|
|
35
|
+
indexToNodeId: TNodeId[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Compressed Sparse Row (CSR) graph representation
|
|
40
|
+
*
|
|
41
|
+
* Provides cache-efficient graph storage with sequential memory access patterns.
|
|
42
|
+
* Optimized for traversal operations and sparse graphs.
|
|
43
|
+
*/
|
|
44
|
+
export class CSRGraph<TNodeId = NodeId> implements ReadonlyGraph<TNodeId> {
|
|
45
|
+
private data: CSRGraphData<TNodeId>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates a new CSRGraph from an adjacency list representation.
|
|
49
|
+
* @param adjacencyList - Map of node IDs to arrays of neighbor node IDs
|
|
50
|
+
* @param weights - Optional map of edge weights keyed by "source-target" strings
|
|
51
|
+
* @param buildReverse - Whether to build reverse edges for bottom-up BFS (default true)
|
|
52
|
+
*/
|
|
53
|
+
constructor(adjacencyList: Map<TNodeId, TNodeId[]>, weights?: Map<string, number>, buildReverse = true) {
|
|
54
|
+
this.data = this.buildCSR(adjacencyList, weights, buildReverse);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build CSR structure from adjacency list.
|
|
59
|
+
* @param adjacencyList - Map of node IDs to arrays of neighbor node IDs
|
|
60
|
+
* @param weights - Optional map of edge weights keyed by "source-target" strings
|
|
61
|
+
* @param buildReverse - Whether to build reverse edges for bottom-up BFS
|
|
62
|
+
* @returns The constructed CSR graph data structure
|
|
63
|
+
*/
|
|
64
|
+
private buildCSR(
|
|
65
|
+
adjacencyList: Map<TNodeId, TNodeId[]>,
|
|
66
|
+
weights?: Map<string, number>,
|
|
67
|
+
buildReverse = true,
|
|
68
|
+
): CSRGraphData<TNodeId> {
|
|
69
|
+
// Collect all unique nodes (both sources and targets)
|
|
70
|
+
const allNodes = new Set<TNodeId>();
|
|
71
|
+
for (const [source, neighbors] of adjacencyList) {
|
|
72
|
+
allNodes.add(source);
|
|
73
|
+
for (const neighbor of neighbors) {
|
|
74
|
+
allNodes.add(neighbor);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Sort nodes for consistent ordering. Numeric IDs sort numerically,
|
|
79
|
+
// string IDs sort lexicographically for predictable iteration order.
|
|
80
|
+
const nodes = Array.from(allNodes).sort((a, b) => {
|
|
81
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
82
|
+
return a - b;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return String(a).localeCompare(String(b));
|
|
86
|
+
});
|
|
87
|
+
const nodeCount = nodes.length;
|
|
88
|
+
|
|
89
|
+
// Build node mappings
|
|
90
|
+
const nodeIdToIndex = new Map<TNodeId, number>();
|
|
91
|
+
const indexToNodeId: TNodeId[] = [];
|
|
92
|
+
|
|
93
|
+
nodes.forEach((nodeId, index) => {
|
|
94
|
+
nodeIdToIndex.set(nodeId, index);
|
|
95
|
+
indexToNodeId[index] = nodeId;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Count total edges
|
|
99
|
+
let edgeCount = 0;
|
|
100
|
+
for (const neighbors of adjacencyList.values()) {
|
|
101
|
+
edgeCount += neighbors.length;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Allocate arrays
|
|
105
|
+
const rowPointers = new Uint32Array(nodeCount + 1);
|
|
106
|
+
const columnIndices = new Uint32Array(edgeCount);
|
|
107
|
+
const edgeWeights = weights ? new Float32Array(edgeCount) : undefined;
|
|
108
|
+
|
|
109
|
+
// Build CSR structure
|
|
110
|
+
let currentEdge = 0;
|
|
111
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
112
|
+
rowPointers[i] = currentEdge;
|
|
113
|
+
const nodeId = indexToNodeId[i];
|
|
114
|
+
if (nodeId === undefined) {
|
|
115
|
+
throw new Error(`Invalid node index ${String(i)}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const neighbors = adjacencyList.get(nodeId) ?? [];
|
|
119
|
+
|
|
120
|
+
// Sort neighbors for better cache locality and binary search
|
|
121
|
+
const sortedNeighbors = neighbors
|
|
122
|
+
.map((n) => {
|
|
123
|
+
const index = nodeIdToIndex.get(n);
|
|
124
|
+
if (index === undefined) {
|
|
125
|
+
throw new Error(`Node ${String(n)} not found in nodeIdToIndex map`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { id: n, index };
|
|
129
|
+
})
|
|
130
|
+
.sort((a, b) => a.index - b.index);
|
|
131
|
+
|
|
132
|
+
for (const neighbor of sortedNeighbors) {
|
|
133
|
+
columnIndices[currentEdge] = neighbor.index;
|
|
134
|
+
|
|
135
|
+
if (edgeWeights && weights) {
|
|
136
|
+
const edgeKey = `${String(nodeId)}-${String(neighbor.id)}`;
|
|
137
|
+
const weight = weights.get(edgeKey);
|
|
138
|
+
if (weight !== undefined) {
|
|
139
|
+
edgeWeights[currentEdge] = weight;
|
|
140
|
+
} else {
|
|
141
|
+
edgeWeights[currentEdge] = 1;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
currentEdge++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
rowPointers[nodeCount] = currentEdge;
|
|
149
|
+
|
|
150
|
+
const result: CSRGraphData<TNodeId> = {
|
|
151
|
+
rowPointers,
|
|
152
|
+
columnIndices,
|
|
153
|
+
nodeIdToIndex,
|
|
154
|
+
indexToNodeId,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (edgeWeights) {
|
|
158
|
+
result.edgeWeights = edgeWeights;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Build reverse edges for bottom-up BFS
|
|
162
|
+
if (buildReverse) {
|
|
163
|
+
const reverseAdjacency = new Map<number, number[]>();
|
|
164
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
165
|
+
reverseAdjacency.set(i, []);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Build reverse adjacency from forward edges
|
|
169
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
170
|
+
const start = rowPointers[i];
|
|
171
|
+
const end = rowPointers[i + 1];
|
|
172
|
+
if (start !== undefined && end !== undefined) {
|
|
173
|
+
for (let j = start; j < end; j++) {
|
|
174
|
+
const target = columnIndices[j];
|
|
175
|
+
if (target !== undefined) {
|
|
176
|
+
reverseAdjacency.get(target)?.push(i);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Build reverse CSR
|
|
183
|
+
const reverseRowPointers = new Uint32Array(nodeCount + 1);
|
|
184
|
+
const reverseColumnIndices = new Uint32Array(edgeCount);
|
|
185
|
+
|
|
186
|
+
let reverseEdge = 0;
|
|
187
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
188
|
+
reverseRowPointers[i] = reverseEdge;
|
|
189
|
+
const incoming = reverseAdjacency.get(i) ?? [];
|
|
190
|
+
incoming.sort((a, b) => a - b);
|
|
191
|
+
|
|
192
|
+
for (const source of incoming) {
|
|
193
|
+
reverseColumnIndices[reverseEdge++] = source;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
reverseRowPointers[nodeCount] = reverseEdge;
|
|
197
|
+
|
|
198
|
+
result.reverseRowPointers = reverseRowPointers;
|
|
199
|
+
result.reverseColumnIndices = reverseColumnIndices;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Core API methods
|
|
206
|
+
/**
|
|
207
|
+
* Get the total number of nodes in the graph.
|
|
208
|
+
* @returns The number of nodes
|
|
209
|
+
*/
|
|
210
|
+
nodeCount(): number {
|
|
211
|
+
return this.data.indexToNodeId.length;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get the total number of edges in the graph.
|
|
216
|
+
* @returns The number of edges
|
|
217
|
+
*/
|
|
218
|
+
edgeCount(): number {
|
|
219
|
+
return this.data.columnIndices.length;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check if a node exists in the graph.
|
|
224
|
+
* @param nodeId - The node ID to check
|
|
225
|
+
* @returns True if the node exists, false otherwise
|
|
226
|
+
*/
|
|
227
|
+
hasNode(nodeId: TNodeId): boolean {
|
|
228
|
+
return this.data.nodeIdToIndex.has(nodeId);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check if an edge exists between two nodes.
|
|
233
|
+
* @param source - The source node ID
|
|
234
|
+
* @param target - The target node ID
|
|
235
|
+
* @returns True if the edge exists, false otherwise
|
|
236
|
+
*/
|
|
237
|
+
hasEdge(source: TNodeId, target: TNodeId): boolean {
|
|
238
|
+
const sourceIndex = this.data.nodeIdToIndex.get(source);
|
|
239
|
+
const targetIndex = this.data.nodeIdToIndex.get(target);
|
|
240
|
+
|
|
241
|
+
if (sourceIndex === undefined || targetIndex === undefined) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const start = this.data.rowPointers[sourceIndex];
|
|
246
|
+
const end = this.data.rowPointers[sourceIndex + 1];
|
|
247
|
+
|
|
248
|
+
// Binary search for target in sorted neighbors
|
|
249
|
+
if (start === undefined || end === undefined) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return this.binarySearch(this.data.columnIndices, targetIndex, start, end) !== -1;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get neighbors of a node as node IDs.
|
|
258
|
+
* @param nodeId - The node ID to get neighbors for
|
|
259
|
+
* @returns An iterator over neighbor node IDs
|
|
260
|
+
*/
|
|
261
|
+
neighbors(nodeId: TNodeId): IterableIterator<TNodeId> {
|
|
262
|
+
const nodeIndex = this.data.nodeIdToIndex.get(nodeId);
|
|
263
|
+
if (nodeIndex === undefined) {
|
|
264
|
+
return new Set<TNodeId>().values();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const start = this.data.rowPointers[nodeIndex];
|
|
268
|
+
const end = this.data.rowPointers[nodeIndex + 1];
|
|
269
|
+
|
|
270
|
+
const { columnIndices, indexToNodeId } = this.data;
|
|
271
|
+
function* generateNeighbors(): Generator<TNodeId> {
|
|
272
|
+
if (start !== undefined && end !== undefined) {
|
|
273
|
+
for (let i = start; i < end; i++) {
|
|
274
|
+
const idx = columnIndices[i];
|
|
275
|
+
if (idx !== undefined) {
|
|
276
|
+
const nodeId = indexToNodeId[idx];
|
|
277
|
+
if (nodeId !== undefined) {
|
|
278
|
+
yield nodeId;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return generateNeighbors();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get all nodes in the graph.
|
|
290
|
+
* @returns An iterator over all node IDs
|
|
291
|
+
*/
|
|
292
|
+
nodes(): IterableIterator<TNodeId> {
|
|
293
|
+
return this.data.indexToNodeId.values();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Get neighbors as indices (internal use).
|
|
298
|
+
* @param nodeIndex - The internal index of the node
|
|
299
|
+
* @returns Array of neighbor indices
|
|
300
|
+
*/
|
|
301
|
+
getNeighborIndices(nodeIndex: number): number[] {
|
|
302
|
+
if (nodeIndex < 0 || nodeIndex >= this.data.indexToNodeId.length) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const start = this.data.rowPointers[nodeIndex];
|
|
307
|
+
const end = this.data.rowPointers[nodeIndex + 1];
|
|
308
|
+
if (start === undefined || end === undefined) {
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return Array.from(this.data.columnIndices.subarray(start, end));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get the out-degree (number of outgoing edges) of a node.
|
|
317
|
+
* @param nodeId - The node ID to get the out-degree for
|
|
318
|
+
* @returns The number of outgoing edges from the node
|
|
319
|
+
*/
|
|
320
|
+
outDegree(nodeId: TNodeId): number {
|
|
321
|
+
const nodeIndex = this.data.nodeIdToIndex.get(nodeId);
|
|
322
|
+
if (nodeIndex === undefined) {
|
|
323
|
+
return 0;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return this.outDegreeByIndex(nodeIndex);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Get out-degree by index (internal use).
|
|
331
|
+
* @param nodeIndex - The internal index of the node
|
|
332
|
+
* @returns The number of outgoing edges from the node
|
|
333
|
+
*/
|
|
334
|
+
outDegreeByIndex(nodeIndex: number): number {
|
|
335
|
+
const start = this.data.rowPointers[nodeIndex];
|
|
336
|
+
const end = this.data.rowPointers[nodeIndex + 1];
|
|
337
|
+
if (start !== undefined && end !== undefined) {
|
|
338
|
+
return end - start;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return 0;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Iterator support for neighbor indices.
|
|
346
|
+
* @param nodeIndex - The internal index of the node
|
|
347
|
+
* @yields The indices of neighboring nodes
|
|
348
|
+
*/
|
|
349
|
+
*iterateNeighborIndices(nodeIndex: number): Generator<number> {
|
|
350
|
+
const start = this.data.rowPointers[nodeIndex];
|
|
351
|
+
const end = this.data.rowPointers[nodeIndex + 1];
|
|
352
|
+
|
|
353
|
+
if (start !== undefined && end !== undefined) {
|
|
354
|
+
for (let i = start; i < end; i++) {
|
|
355
|
+
const value = this.data.columnIndices[i];
|
|
356
|
+
if (value !== undefined) {
|
|
357
|
+
yield value;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Iterator support for incoming neighbor indices (for bottom-up BFS).
|
|
365
|
+
* @param nodeIndex - The internal index of the node
|
|
366
|
+
* @yields The indices of nodes with edges pointing to this node
|
|
367
|
+
*/
|
|
368
|
+
*iterateIncomingNeighborIndices(nodeIndex: number): Generator<number> {
|
|
369
|
+
if (!this.data.reverseRowPointers || !this.data.reverseColumnIndices) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const start = this.data.reverseRowPointers[nodeIndex];
|
|
374
|
+
const end = this.data.reverseRowPointers[nodeIndex + 1];
|
|
375
|
+
|
|
376
|
+
if (start !== undefined && end !== undefined) {
|
|
377
|
+
for (let i = start; i < end; i++) {
|
|
378
|
+
const value = this.data.reverseColumnIndices[i];
|
|
379
|
+
if (value !== undefined) {
|
|
380
|
+
yield value;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Convert node ID to internal index.
|
|
388
|
+
* @param nodeId - The node ID to convert
|
|
389
|
+
* @returns The internal index for the node
|
|
390
|
+
*/
|
|
391
|
+
nodeToIndex(nodeId: TNodeId): number {
|
|
392
|
+
const index = this.data.nodeIdToIndex.get(nodeId);
|
|
393
|
+
if (index === undefined) {
|
|
394
|
+
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return index;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Convert internal index to node ID.
|
|
402
|
+
* @param index - The internal index to convert
|
|
403
|
+
* @returns The node ID for the given index
|
|
404
|
+
*/
|
|
405
|
+
indexToNodeId(index: number): TNodeId {
|
|
406
|
+
const nodeId = this.data.indexToNodeId[index];
|
|
407
|
+
if (nodeId === undefined) {
|
|
408
|
+
throw new Error(`Index ${String(index)} out of bounds`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return nodeId;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Get edge weight between two nodes.
|
|
416
|
+
* @param source - The source node ID
|
|
417
|
+
* @param target - The target node ID
|
|
418
|
+
* @returns The edge weight, or undefined if the edge doesn't exist or has no weight
|
|
419
|
+
*/
|
|
420
|
+
getEdgeWeight(source: TNodeId, target: TNodeId): number | undefined {
|
|
421
|
+
if (!this.data.edgeWeights) {
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const sourceIndex = this.data.nodeIdToIndex.get(source);
|
|
426
|
+
const targetIndex = this.data.nodeIdToIndex.get(target);
|
|
427
|
+
|
|
428
|
+
if (sourceIndex === undefined || targetIndex === undefined) {
|
|
429
|
+
return undefined;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const start = this.data.rowPointers[sourceIndex];
|
|
433
|
+
const end = this.data.rowPointers[sourceIndex + 1];
|
|
434
|
+
|
|
435
|
+
if (start === undefined || end === undefined) {
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const edgeIndex = this.binarySearch(this.data.columnIndices, targetIndex, start, end);
|
|
440
|
+
if (edgeIndex === -1) {
|
|
441
|
+
return undefined;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return this.data.edgeWeights[edgeIndex];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Binary search for target in sorted array.
|
|
449
|
+
* @param arr - The typed array to search in
|
|
450
|
+
* @param target - The value to search for
|
|
451
|
+
* @param start - The starting index (inclusive)
|
|
452
|
+
* @param end - The ending index (exclusive)
|
|
453
|
+
* @returns The index of the target, or -1 if not found
|
|
454
|
+
*/
|
|
455
|
+
private binarySearch(arr: Uint32Array, target: number, start: number, end: number): number {
|
|
456
|
+
let left = start;
|
|
457
|
+
let right = end - 1;
|
|
458
|
+
|
|
459
|
+
while (left <= right) {
|
|
460
|
+
const mid = (left + right) >>> 1;
|
|
461
|
+
const value = arr[mid];
|
|
462
|
+
|
|
463
|
+
if (value === undefined) {
|
|
464
|
+
return -1;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (value === target) {
|
|
468
|
+
return mid;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (value < target) {
|
|
472
|
+
left = mid + 1;
|
|
473
|
+
} else {
|
|
474
|
+
right = mid - 1;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return -1;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Create CSR graph from standard Graph interface.
|
|
483
|
+
* @param graph - The graph object to convert, must implement nodes, neighbors, hasNode, and optionally getEdge
|
|
484
|
+
* @param graph.nodes - Function that returns an iterator over node objects with id property
|
|
485
|
+
* @param graph.neighbors - Function that returns an iterator over neighbor node IDs
|
|
486
|
+
* @param graph.hasNode - Function that checks if a node exists in the graph
|
|
487
|
+
* @param graph.getEdge - Optional function that returns edge data including weight
|
|
488
|
+
* @returns A new CSRGraph instance
|
|
489
|
+
*/
|
|
490
|
+
static fromGraph<TNodeId = NodeId>(graph: {
|
|
491
|
+
nodes(): IterableIterator<{ id: TNodeId }>;
|
|
492
|
+
neighbors(nodeId: TNodeId): IterableIterator<TNodeId>;
|
|
493
|
+
hasNode(nodeId: TNodeId): boolean;
|
|
494
|
+
getEdge?(source: TNodeId, target: TNodeId): { weight?: number } | undefined;
|
|
495
|
+
}): CSRGraph<TNodeId> {
|
|
496
|
+
const adjacencyList = new Map<TNodeId, TNodeId[]>();
|
|
497
|
+
const weights = new Map<string, number>();
|
|
498
|
+
|
|
499
|
+
// Build adjacency list
|
|
500
|
+
for (const node of graph.nodes()) {
|
|
501
|
+
const neighbors: TNodeId[] = [];
|
|
502
|
+
for (const neighbor of graph.neighbors(node.id)) {
|
|
503
|
+
neighbors.push(neighbor);
|
|
504
|
+
|
|
505
|
+
// Get edge weight if available
|
|
506
|
+
if (graph.getEdge) {
|
|
507
|
+
const edge = graph.getEdge(node.id, neighbor);
|
|
508
|
+
if (edge?.weight !== undefined) {
|
|
509
|
+
weights.set(`${String(node.id)}-${String(neighbor)}`, edge.weight);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
adjacencyList.set(node.id, neighbors);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return new CSRGraph(adjacencyList, weights.size > 0 ? weights : undefined);
|
|
517
|
+
}
|
|
518
|
+
}
|