@graphty/algorithms 2.0.2 → 2.0.4
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 +42 -43
- package/dist/algorithms.js +85 -47
- package/dist/algorithms.js.map +1 -1
- package/dist/algorithms.standalone.js +86 -48
- package/dist/algorithms.standalone.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +9 -3
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +29 -31
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.d.ts +6 -3
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.js +14 -5
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +7 -3
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/core/graph.d.ts.map +1 -1
- package/dist/src/core/graph.js +7 -3
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/errors.d.ts +22 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +24 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexed/dijkstra.d.ts +2 -0
- package/dist/src/indexed/dijkstra.d.ts.map +1 -1
- package/dist/src/indexed/dijkstra.js +32 -13
- package/dist/src/indexed/dijkstra.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +1 -1
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +1 -1
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/types/index.d.ts +4 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/algorithms/centrality/delta-pagerank-simple.ts +44 -33
- package/src/algorithms/centrality/eigenvector.ts +14 -5
- package/src/algorithms/centrality/pagerank.ts +9 -3
- package/src/core/graph.ts +8 -3
- package/src/errors.ts +29 -0
- package/src/index.ts +1 -1
- package/src/indexed/dijkstra.ts +33 -13
- package/src/link-prediction/adamic-adar.ts +1 -1
- package/src/link-prediction/common-neighbors.ts +1 -1
- package/src/types/index.ts +4 -0
package/README.md
CHANGED
|
@@ -54,9 +54,8 @@ _Note: Optimizations activate automatically for graphs ≥10K nodes to avoid con
|
|
|
54
54
|
|
|
55
55
|
### Learn More
|
|
56
56
|
|
|
57
|
-
- 📖 [Performance Guide](docs/
|
|
58
|
-
-
|
|
59
|
-
- 💾 [Memory vs Speed Tradeoffs](docs/PERFORMANCE_GUIDE.md#memory-vs-speed-tradeoffs) - Making the right choices
|
|
57
|
+
- 📖 [Performance Guide](docs/guide/performance.md) - Detailed optimization explanations
|
|
58
|
+
- 💾 [Memory Optimization](docs/guide/performance.md#memory-optimization) - Making the right choices
|
|
60
59
|
|
|
61
60
|
## Installation
|
|
62
61
|
|
|
@@ -111,8 +110,8 @@ class Graph {
|
|
|
111
110
|
```typescript
|
|
112
111
|
interface GraphConfig {
|
|
113
112
|
directed: boolean; // Default: false
|
|
114
|
-
allowSelfLoops: boolean; // Default:
|
|
115
|
-
allowParallelEdges: boolean; // Default: false
|
|
113
|
+
allowSelfLoops: boolean; // Default: true
|
|
114
|
+
allowParallelEdges: boolean; // Default: false. When true, re-adding a pair replaces its edge (one edge per pair)
|
|
116
115
|
}
|
|
117
116
|
```
|
|
118
117
|
|
|
@@ -1050,68 +1049,68 @@ The library includes comprehensive examples demonstrating each algorithm. You ca
|
|
|
1050
1049
|
|
|
1051
1050
|
- **[Browse Interactive HTML Examples](https://graphty.app/algorithms/examples/)** - Visual demonstrations with step-by-step execution
|
|
1052
1051
|
- **[View Performance Benchmarks](https://graphty.app/algorithms/benchmarks/)** - Comparative analysis of algorithm performance
|
|
1053
|
-
- **[Explore Code Examples](https://github.com/graphty-org/
|
|
1052
|
+
- **[Explore Code Examples](https://github.com/graphty-org/graphty-monorepo/tree/master/algorithms/examples)** - Implementation examples for each algorithm
|
|
1054
1053
|
|
|
1055
1054
|
### Basic Algorithms
|
|
1056
1055
|
|
|
1057
|
-
- [BFS Traversal](https://github.com/graphty-org/
|
|
1058
|
-
- [DFS Traversal](https://github.com/graphty-org/
|
|
1059
|
-
- [Dijkstra's Algorithm](https://github.com/graphty-org/
|
|
1060
|
-
- [Bellman-Ford](https://github.com/graphty-org/
|
|
1061
|
-
- [Floyd-Warshall](https://github.com/graphty-org/
|
|
1056
|
+
- [BFS Traversal](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/bfs-example.js) - Breadth-first search and shortest paths
|
|
1057
|
+
- [DFS Traversal](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/dfs-example.js) - Depth-first search and applications
|
|
1058
|
+
- [Dijkstra's Algorithm](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/dijkstra-example.js) - Weighted shortest paths
|
|
1059
|
+
- [Bellman-Ford](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/bellman-ford-example.js) - Shortest paths with negative weights
|
|
1060
|
+
- [Floyd-Warshall](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/floyd-warshall-example.js) - All pairs shortest paths
|
|
1062
1061
|
|
|
1063
1062
|
### Centrality Measures
|
|
1064
1063
|
|
|
1065
|
-
- [Degree Centrality](https://github.com/graphty-org/
|
|
1066
|
-
- [Betweenness Centrality](https://github.com/graphty-org/
|
|
1067
|
-
- [Closeness Centrality](https://github.com/graphty-org/
|
|
1068
|
-
- [PageRank](https://github.com/graphty-org/
|
|
1069
|
-
- [Eigenvector Centrality](https://github.com/graphty-org/
|
|
1070
|
-
- [Katz Centrality](https://github.com/graphty-org/
|
|
1071
|
-
- [HITS Algorithm](https://github.com/graphty-org/
|
|
1064
|
+
- [Degree Centrality](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/degree-centrality-example.js) - Node importance by connections
|
|
1065
|
+
- [Betweenness Centrality](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/betweenness-centrality-example.js) - Bridge nodes
|
|
1066
|
+
- [Closeness Centrality](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/closeness-centrality-example.js) - Central nodes
|
|
1067
|
+
- [PageRank](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/pagerank-example.js) - Node ranking algorithm
|
|
1068
|
+
- [Eigenvector Centrality](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/eigenvector-centrality-example.js) - Influence from important nodes
|
|
1069
|
+
- [Katz Centrality](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/katz-centrality-example.js) - Weighted path counting
|
|
1070
|
+
- [HITS Algorithm](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/hits-algorithm-example.js) - Hub and authority scores
|
|
1072
1071
|
|
|
1073
1072
|
### Graph Structure
|
|
1074
1073
|
|
|
1075
|
-
- [Connected Components](https://github.com/graphty-org/
|
|
1076
|
-
- [Kruskal's MST](https://github.com/graphty-org/
|
|
1077
|
-
- [Prim's MST](https://github.com/graphty-org/
|
|
1074
|
+
- [Connected Components](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/connected-components-example.js) - Find graph components
|
|
1075
|
+
- [Kruskal's MST](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/kruskal-example.js) - Minimum spanning tree
|
|
1076
|
+
- [Prim's MST](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/prim-example.js) - Alternative MST algorithm
|
|
1078
1077
|
|
|
1079
1078
|
### Community Detection
|
|
1080
1079
|
|
|
1081
|
-
- [Louvain Method](https://github.com/graphty-org/
|
|
1082
|
-
- [Leiden Algorithm](https://github.com/graphty-org/
|
|
1083
|
-
- [Label Propagation](https://github.com/graphty-org/
|
|
1084
|
-
- [Girvan-Newman](https://github.com/graphty-org/
|
|
1080
|
+
- [Louvain Method](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/louvain-example.js) - Modularity-based communities
|
|
1081
|
+
- [Leiden Algorithm](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/leiden-community.ts) - Improved Louvain
|
|
1082
|
+
- [Label Propagation](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/label-propagation.ts) - Fast community detection
|
|
1083
|
+
- [Girvan-Newman](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/girvan-newman-example.js) - Hierarchical communities
|
|
1085
1084
|
|
|
1086
1085
|
### Clustering
|
|
1087
1086
|
|
|
1088
|
-
- [Hierarchical Clustering](https://github.com/graphty-org/
|
|
1089
|
-
- [K-Core Decomposition](https://github.com/graphty-org/
|
|
1090
|
-
- [Spectral Clustering](https://github.com/graphty-org/
|
|
1091
|
-
- [MCL Clustering](https://github.com/graphty-org/
|
|
1087
|
+
- [Hierarchical Clustering](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/hierarchical-clustering.ts) - Graph clustering
|
|
1088
|
+
- [K-Core Decomposition](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/k-core-decomposition.ts) - Core analysis
|
|
1089
|
+
- [Spectral Clustering](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/spectral-clustering-example.js) - Eigenvalue-based clustering
|
|
1090
|
+
- [MCL Clustering](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/mcl-clustering-example.js) - Markov clustering
|
|
1092
1091
|
|
|
1093
1092
|
### Matching
|
|
1094
1093
|
|
|
1095
|
-
- [Bipartite Matching](https://github.com/graphty-org/
|
|
1096
|
-
- [Graph Isomorphism](https://github.com/graphty-org/
|
|
1094
|
+
- [Bipartite Matching](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/bipartite-matching-example.js) - Job assignment, dating apps
|
|
1095
|
+
- [Graph Isomorphism](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/graph-isomorphism-example.js) - Structural equivalence
|
|
1097
1096
|
|
|
1098
1097
|
### Link Prediction
|
|
1099
1098
|
|
|
1100
|
-
- [Common Neighbors](https://github.com/graphty-org/
|
|
1101
|
-
- [Adamic-Adar](https://github.com/graphty-org/
|
|
1099
|
+
- [Common Neighbors](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/common-neighbors-example.js) - Friend suggestions
|
|
1100
|
+
- [Adamic-Adar](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/adamic-adar-example.js) - Weighted predictions
|
|
1102
1101
|
|
|
1103
1102
|
### Advanced Algorithms
|
|
1104
1103
|
|
|
1105
|
-
- [A\* Pathfinding](https://github.com/graphty-org/
|
|
1106
|
-
- [Flow Algorithms](https://github.com/graphty-org/
|
|
1107
|
-
- [Ford-Fulkerson Flow](https://github.com/graphty-org/
|
|
1108
|
-
- [Minimum Cut](https://github.com/graphty-org/
|
|
1104
|
+
- [A\* Pathfinding](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/astar-pathfinding.ts) - Heuristic pathfinding
|
|
1105
|
+
- [Flow Algorithms](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/flow-algorithms.ts) - Maximum flow and applications
|
|
1106
|
+
- [Ford-Fulkerson Flow](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/ford-fulkerson-flow.ts) - Maximum flow implementation
|
|
1107
|
+
- [Minimum Cut](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/min-cut.ts) - Graph partitioning
|
|
1109
1108
|
|
|
1110
1109
|
### Research Algorithms
|
|
1111
1110
|
|
|
1112
|
-
- [SynC Clustering](https://github.com/graphty-org/
|
|
1113
|
-
- [TeraHAC](https://github.com/graphty-org/
|
|
1114
|
-
- [GRSBM](https://github.com/graphty-org/
|
|
1111
|
+
- [SynC Clustering](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/sync-example.js) - Deep learning based clustering
|
|
1112
|
+
- [TeraHAC](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/terahac-example.js) - Scalable hierarchical clustering
|
|
1113
|
+
- [GRSBM](https://github.com/graphty-org/graphty-monorepo/blob/master/algorithms/examples/grsbm-example.js) - Explainable community detection
|
|
1115
1114
|
|
|
1116
1115
|
## Advanced Usage Examples
|
|
1117
1116
|
|
|
@@ -1482,7 +1481,7 @@ test/
|
|
|
1482
1481
|
|
|
1483
1482
|
## Contributing
|
|
1484
1483
|
|
|
1485
|
-
We welcome contributions! Please
|
|
1484
|
+
We welcome contributions! Please open an issue or a pull request on [GitHub](https://github.com/graphty-org/graphty-monorepo).
|
|
1486
1485
|
|
|
1487
1486
|
### Commit Convention
|
|
1488
1487
|
|
|
@@ -1501,5 +1500,5 @@ MIT © Adam Powers
|
|
|
1501
1500
|
|
|
1502
1501
|
## Related Projects
|
|
1503
1502
|
|
|
1504
|
-
- [@graphty/layout](https://github.com/graphty-org/layout) - Graph layout algorithms
|
|
1505
|
-
- [@graphty/graphty-element](https://github.com/graphty-org/graphty-element) - 3D graph visualization web component
|
|
1503
|
+
- [@graphty/layout](https://github.com/graphty-org/graphty-monorepo/tree/master/layout) - Graph layout algorithms
|
|
1504
|
+
- [@graphty/graphty-element](https://github.com/graphty-org/graphty-monorepo/tree/master/graphty-element) - 3D graph visualization web component
|
package/dist/algorithms.js
CHANGED
|
@@ -85,7 +85,8 @@ class Graph {
|
|
|
85
85
|
if (!this.config.allowSelfLoops && source === target) {
|
|
86
86
|
throw new Error("Self-loops are not allowed in this graph");
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
const replacing = this.hasEdge(source, target);
|
|
89
|
+
if (!this.config.allowParallelEdges && replacing) {
|
|
89
90
|
throw new Error("Parallel edges are not allowed in this graph");
|
|
90
91
|
}
|
|
91
92
|
const edge = { source, target, weight, data };
|
|
@@ -107,7 +108,9 @@ class Graph {
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
+
if (!replacing) {
|
|
112
|
+
this.edgeCount++;
|
|
113
|
+
}
|
|
111
114
|
this.mutations++;
|
|
112
115
|
}
|
|
113
116
|
/**
|
|
@@ -352,6 +355,23 @@ class ConvergenceError extends Error {
|
|
|
352
355
|
this.name = "ConvergenceError";
|
|
353
356
|
}
|
|
354
357
|
}
|
|
358
|
+
class PathWalkError extends Error {
|
|
359
|
+
/**
|
|
360
|
+
* Builds the error and its message.
|
|
361
|
+
* @param source - The search's source node index
|
|
362
|
+
* @param target - The node index the walk started from
|
|
363
|
+
* @param reason - `"gap"` or `"cycle"`, as above
|
|
364
|
+
*/
|
|
365
|
+
constructor(source, target, reason) {
|
|
366
|
+
super(
|
|
367
|
+
`cannot walk the shortest path from node ${String(source)} to node ${String(target)}: the predecessor array has a ${reason}`
|
|
368
|
+
);
|
|
369
|
+
this.source = source;
|
|
370
|
+
this.target = target;
|
|
371
|
+
this.reason = reason;
|
|
372
|
+
this.name = "PathWalkError";
|
|
373
|
+
}
|
|
374
|
+
}
|
|
355
375
|
var lib = {};
|
|
356
376
|
var SparseTypedFastBitSet = {};
|
|
357
377
|
var utils = {};
|
|
@@ -5253,7 +5273,7 @@ class PriorityDeltaPageRank {
|
|
|
5253
5273
|
}
|
|
5254
5274
|
}
|
|
5255
5275
|
function eigenvectorCentrality(graph, options = {}) {
|
|
5256
|
-
const { maxIterations = 100, tolerance = 1e-6, normalized = true, startVector } = options;
|
|
5276
|
+
const { maxIterations = 100, tolerance = 1e-6, normalized = true, startVector, mode = "in" } = options;
|
|
5257
5277
|
const nodeIds = Array.from(graph.nodes(), (node) => node.id);
|
|
5258
5278
|
const keys = nodeIds.map((id) => id.toString());
|
|
5259
5279
|
const n = keys.length;
|
|
@@ -5262,7 +5282,13 @@ function eigenvectorCentrality(graph, options = {}) {
|
|
|
5262
5282
|
return centrality;
|
|
5263
5283
|
}
|
|
5264
5284
|
const index2 = new Map(keys.map((key, i) => [key, i]));
|
|
5265
|
-
const
|
|
5285
|
+
const feeders = (id) => {
|
|
5286
|
+
if (!graph.isDirected || mode === "out") {
|
|
5287
|
+
return graph.neighbors(id);
|
|
5288
|
+
}
|
|
5289
|
+
return mode === "in" ? graph.inNeighbors(id) : /* @__PURE__ */ new Set([...graph.inNeighbors(id), ...graph.neighbors(id)]);
|
|
5290
|
+
};
|
|
5291
|
+
const adjacency = nodeIds.map((id) => Array.from(feeders(id), (m) => index2.get(m.toString()) ?? 0));
|
|
5266
5292
|
if (isNilpotent(adjacency)) {
|
|
5267
5293
|
for (const key of keys) {
|
|
5268
5294
|
centrality[key] = 0;
|
|
@@ -5550,6 +5576,8 @@ class SimpleDeltaPageRank {
|
|
|
5550
5576
|
*/
|
|
5551
5577
|
constructor(graph) {
|
|
5552
5578
|
this.previousScores = null;
|
|
5579
|
+
this.iterations = 0;
|
|
5580
|
+
this.converged = false;
|
|
5553
5581
|
if (!graph.isDirected) {
|
|
5554
5582
|
throw new Error("PageRank requires a directed graph");
|
|
5555
5583
|
}
|
|
@@ -5562,20 +5590,32 @@ class SimpleDeltaPageRank {
|
|
|
5562
5590
|
* @param options.dampingFactor - Probability of following a link (default: 0.85)
|
|
5563
5591
|
* @param options.tolerance - Convergence tolerance threshold (default: 1e-6)
|
|
5564
5592
|
* @param options.maxIterations - Maximum number of iterations (default: 100)
|
|
5593
|
+
* @param options.initialRanks - Starting scores (missing nodes start at 1/n; normalized to sum 1)
|
|
5565
5594
|
* @param options.personalization - Personalization vector for Personalized PageRank
|
|
5566
5595
|
* @param options.weight - Edge attribute name for weighted PageRank
|
|
5567
|
-
* @returns Map of node IDs to their PageRank scores
|
|
5596
|
+
* @returns Map of node IDs to their PageRank scores; `iterations` and `converged` describe the run
|
|
5568
5597
|
*/
|
|
5569
5598
|
compute(options = {}) {
|
|
5570
|
-
const {
|
|
5599
|
+
const {
|
|
5600
|
+
dampingFactor = 0.85,
|
|
5601
|
+
tolerance = 1e-6,
|
|
5602
|
+
maxIterations = 100,
|
|
5603
|
+
initialRanks,
|
|
5604
|
+
personalization,
|
|
5605
|
+
weight
|
|
5606
|
+
} = options;
|
|
5607
|
+
this.iterations = 0;
|
|
5608
|
+
this.converged = false;
|
|
5571
5609
|
if (this.nodeCount === 0) {
|
|
5610
|
+
this.converged = true;
|
|
5572
5611
|
return /* @__PURE__ */ new Map();
|
|
5573
5612
|
}
|
|
5574
5613
|
const scores = /* @__PURE__ */ new Map();
|
|
5575
5614
|
const newScores = /* @__PURE__ */ new Map();
|
|
5576
5615
|
for (const node of this.graph.nodes()) {
|
|
5577
|
-
scores.set(node.id, 1 / this.nodeCount);
|
|
5616
|
+
scores.set(node.id, initialRanks?.get(node.id) ?? 1 / this.nodeCount);
|
|
5578
5617
|
}
|
|
5618
|
+
this.normalizeMap(scores);
|
|
5579
5619
|
const outWeights = /* @__PURE__ */ new Map();
|
|
5580
5620
|
const danglingNodes = /* @__PURE__ */ new Set();
|
|
5581
5621
|
for (const node of this.graph.nodes()) {
|
|
@@ -5583,8 +5623,7 @@ class SimpleDeltaPageRank {
|
|
|
5583
5623
|
let outDegree = 0;
|
|
5584
5624
|
for (const neighbor of Array.from(this.graph.neighbors(node.id))) {
|
|
5585
5625
|
outDegree++;
|
|
5586
|
-
|
|
5587
|
-
totalWeight += edge?.weight ?? 1;
|
|
5626
|
+
totalWeight += weight ? this.graph.getEdge(node.id, neighbor)?.weight ?? 1 : 1;
|
|
5588
5627
|
}
|
|
5589
5628
|
outWeights.set(node.id, totalWeight);
|
|
5590
5629
|
if (outDegree === 0) {
|
|
@@ -5596,7 +5635,6 @@ class SimpleDeltaPageRank {
|
|
|
5596
5635
|
personalVector = new Map(personalization);
|
|
5597
5636
|
this.normalizeMap(personalVector);
|
|
5598
5637
|
}
|
|
5599
|
-
let activeNodes = new Set(scores.keys());
|
|
5600
5638
|
let iteration = 0;
|
|
5601
5639
|
for (iteration = 0; iteration < maxIterations; iteration++) {
|
|
5602
5640
|
for (const nodeId of scores.keys()) {
|
|
@@ -5622,7 +5660,7 @@ class SimpleDeltaPageRank {
|
|
|
5622
5660
|
}
|
|
5623
5661
|
}
|
|
5624
5662
|
}
|
|
5625
|
-
for (const nodeId of
|
|
5663
|
+
for (const nodeId of scores.keys()) {
|
|
5626
5664
|
const currentRank = scores.get(nodeId) ?? 0;
|
|
5627
5665
|
const nodeOutWeight = outWeights.get(nodeId) ?? 0;
|
|
5628
5666
|
if (nodeOutWeight > 0) {
|
|
@@ -5638,33 +5676,21 @@ class SimpleDeltaPageRank {
|
|
|
5638
5676
|
}
|
|
5639
5677
|
}
|
|
5640
5678
|
}
|
|
5641
|
-
const nextActive = /* @__PURE__ */ new Set();
|
|
5642
5679
|
let maxDiff = 0;
|
|
5643
5680
|
for (const nodeId of scores.keys()) {
|
|
5644
|
-
|
|
5645
|
-
const newRank = newScores.get(nodeId) ?? 0;
|
|
5646
|
-
const diff = Math.abs(newRank - oldRank);
|
|
5647
|
-
maxDiff = Math.max(maxDiff, diff);
|
|
5648
|
-
if (diff > tolerance / 10) {
|
|
5649
|
-
nextActive.add(nodeId);
|
|
5650
|
-
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
5651
|
-
nextActive.add(neighbor);
|
|
5652
|
-
}
|
|
5653
|
-
for (const neighbor of Array.from(this.graph.inNeighbors(nodeId))) {
|
|
5654
|
-
nextActive.add(neighbor);
|
|
5655
|
-
}
|
|
5656
|
-
}
|
|
5681
|
+
maxDiff = Math.max(maxDiff, Math.abs((newScores.get(nodeId) ?? 0) - (scores.get(nodeId) ?? 0)));
|
|
5657
5682
|
}
|
|
5658
5683
|
scores.clear();
|
|
5659
5684
|
for (const [k, v] of newScores) {
|
|
5660
5685
|
scores.set(k, v);
|
|
5661
5686
|
}
|
|
5662
5687
|
newScores.clear();
|
|
5663
|
-
activeNodes = nextActive;
|
|
5664
5688
|
if (maxDiff < tolerance) {
|
|
5689
|
+
this.converged = true;
|
|
5665
5690
|
break;
|
|
5666
5691
|
}
|
|
5667
5692
|
}
|
|
5693
|
+
this.iterations = this.converged ? iteration + 1 : iteration;
|
|
5668
5694
|
this.previousScores = new Map(scores);
|
|
5669
5695
|
return scores;
|
|
5670
5696
|
}
|
|
@@ -5685,6 +5711,8 @@ class SimpleDeltaPageRank {
|
|
|
5685
5711
|
return this.compute(options);
|
|
5686
5712
|
}
|
|
5687
5713
|
const { dampingFactor = 0.85, tolerance = 1e-6, maxIterations = 100, personalization, weight } = options;
|
|
5714
|
+
this.iterations = 0;
|
|
5715
|
+
this.converged = false;
|
|
5688
5716
|
const scores = new Map(this.previousScores);
|
|
5689
5717
|
const newScores = /* @__PURE__ */ new Map();
|
|
5690
5718
|
for (const node of this.graph.nodes()) {
|
|
@@ -5709,8 +5737,7 @@ class SimpleDeltaPageRank {
|
|
|
5709
5737
|
let outDegree = 0;
|
|
5710
5738
|
for (const neighbor of Array.from(this.graph.neighbors(node.id))) {
|
|
5711
5739
|
outDegree++;
|
|
5712
|
-
|
|
5713
|
-
totalWeight += edge?.weight ?? 1;
|
|
5740
|
+
totalWeight += weight ? this.graph.getEdge(node.id, neighbor)?.weight ?? 1 : 1;
|
|
5714
5741
|
}
|
|
5715
5742
|
outWeights.set(node.id, totalWeight);
|
|
5716
5743
|
if (outDegree === 0) {
|
|
@@ -5787,9 +5814,11 @@ class SimpleDeltaPageRank {
|
|
|
5787
5814
|
newScores.clear();
|
|
5788
5815
|
activeNodes = nextActive;
|
|
5789
5816
|
if (maxDiff < tolerance) {
|
|
5817
|
+
this.converged = true;
|
|
5790
5818
|
break;
|
|
5791
5819
|
}
|
|
5792
5820
|
}
|
|
5821
|
+
this.iterations = this.converged ? iteration + 1 : iteration;
|
|
5793
5822
|
this.previousScores = new Map(scores);
|
|
5794
5823
|
return scores;
|
|
5795
5824
|
}
|
|
@@ -5832,6 +5861,9 @@ function pageRank$1(graph, options = {}) {
|
|
|
5832
5861
|
tolerance,
|
|
5833
5862
|
maxIterations
|
|
5834
5863
|
};
|
|
5864
|
+
if (initialRanks) {
|
|
5865
|
+
deltaOptions.initialRanks = initialRanks;
|
|
5866
|
+
}
|
|
5835
5867
|
if (personalization) {
|
|
5836
5868
|
deltaOptions.personalization = personalization;
|
|
5837
5869
|
}
|
|
@@ -5846,9 +5878,8 @@ function pageRank$1(graph, options = {}) {
|
|
|
5846
5878
|
}
|
|
5847
5879
|
return {
|
|
5848
5880
|
ranks: result2,
|
|
5849
|
-
iterations:
|
|
5850
|
-
|
|
5851
|
-
converged: true
|
|
5881
|
+
iterations: deltaPageRank.iterations,
|
|
5882
|
+
converged: deltaPageRank.converged
|
|
5852
5883
|
};
|
|
5853
5884
|
}
|
|
5854
5885
|
let ranks = /* @__PURE__ */ new Map();
|
|
@@ -5950,7 +5981,8 @@ function pageRank$1(graph, options = {}) {
|
|
|
5950
5981
|
}
|
|
5951
5982
|
return {
|
|
5952
5983
|
ranks: result,
|
|
5953
|
-
|
|
5984
|
+
// The loop breaks before incrementing on convergence, and leaves at maxIterations otherwise.
|
|
5985
|
+
iterations: converged ? iteration + 1 : iteration,
|
|
5954
5986
|
converged
|
|
5955
5987
|
};
|
|
5956
5988
|
}
|
|
@@ -10122,7 +10154,7 @@ function adamicAdarPrediction(graph, options = {}) {
|
|
|
10122
10154
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
10123
10155
|
const source = nodes[i];
|
|
10124
10156
|
const target = nodes[j];
|
|
10125
|
-
if (
|
|
10157
|
+
if (source === void 0 || target === void 0) {
|
|
10126
10158
|
continue;
|
|
10127
10159
|
}
|
|
10128
10160
|
if (!includeExisting && graph.hasEdge(source, target)) {
|
|
@@ -10300,7 +10332,7 @@ function commonNeighborsPrediction(graph, options = {}) {
|
|
|
10300
10332
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
10301
10333
|
const source = nodes[i];
|
|
10302
10334
|
const target = nodes[j];
|
|
10303
|
-
if (
|
|
10335
|
+
if (source === void 0 || target === void 0) {
|
|
10304
10336
|
continue;
|
|
10305
10337
|
}
|
|
10306
10338
|
if (!includeExisting && graph.hasEdge(source, target)) {
|
|
@@ -11604,6 +11636,22 @@ class IndexedMinHeap {
|
|
|
11604
11636
|
this.slot[node] = at;
|
|
11605
11637
|
}
|
|
11606
11638
|
}
|
|
11639
|
+
function walkBack(g, predArc, source, target) {
|
|
11640
|
+
const arcs = [];
|
|
11641
|
+
let node = target;
|
|
11642
|
+
while (node !== source) {
|
|
11643
|
+
if (arcs.length >= g.nodeCount - 1) {
|
|
11644
|
+
throw new PathWalkError(source, target, "cycle");
|
|
11645
|
+
}
|
|
11646
|
+
const arc = predArc[node];
|
|
11647
|
+
if (!(arc < g.arcCount)) {
|
|
11648
|
+
throw new PathWalkError(source, target, "gap");
|
|
11649
|
+
}
|
|
11650
|
+
arcs.push(arc);
|
|
11651
|
+
node = arcSourceIn(g.rowPtr, arc);
|
|
11652
|
+
}
|
|
11653
|
+
return arcs;
|
|
11654
|
+
}
|
|
11607
11655
|
function walkPredArcs(g, predArc, source, target) {
|
|
11608
11656
|
if (target === source) {
|
|
11609
11657
|
return Uint32Array.of(source);
|
|
@@ -11611,12 +11659,7 @@ function walkPredArcs(g, predArc, source, target) {
|
|
|
11611
11659
|
if (predArc[target] === INVALID_INDEX) {
|
|
11612
11660
|
return new Uint32Array(0);
|
|
11613
11661
|
}
|
|
11614
|
-
const reversed = [target];
|
|
11615
|
-
let node = target;
|
|
11616
|
-
while (node !== source) {
|
|
11617
|
-
node = arcSourceIn(g.rowPtr, predArc[node]);
|
|
11618
|
-
reversed.push(node);
|
|
11619
|
-
}
|
|
11662
|
+
const reversed = [target, ...walkBack(g, predArc, source, target).map((arc) => arcSourceIn(g.rowPtr, arc))];
|
|
11620
11663
|
const out = new Uint32Array(reversed.length);
|
|
11621
11664
|
for (let i = 0; i < reversed.length; i++) {
|
|
11622
11665
|
out[i] = reversed[reversed.length - 1 - i];
|
|
@@ -11627,13 +11670,7 @@ function walkPredEdges(g, predArc, source, target) {
|
|
|
11627
11670
|
if (target === source || predArc[target] === INVALID_INDEX) {
|
|
11628
11671
|
return new Uint32Array(0);
|
|
11629
11672
|
}
|
|
11630
|
-
const reversed = [];
|
|
11631
|
-
let node = target;
|
|
11632
|
-
while (node !== source) {
|
|
11633
|
-
const arc = predArc[node];
|
|
11634
|
-
reversed.push(g.arcToEdge[arc]);
|
|
11635
|
-
node = arcSourceIn(g.rowPtr, arc);
|
|
11636
|
-
}
|
|
11673
|
+
const reversed = walkBack(g, predArc, source, target).map((arc) => g.arcToEdge[arc]);
|
|
11637
11674
|
const out = new Uint32Array(reversed.length);
|
|
11638
11675
|
for (let i = 0; i < reversed.length; i++) {
|
|
11639
11676
|
out[i] = reversed[reversed.length - 1 - i];
|
|
@@ -11811,6 +11848,7 @@ export {
|
|
|
11811
11848
|
DirectionOptimizedBFS,
|
|
11812
11849
|
Graph,
|
|
11813
11850
|
GraphBitSet,
|
|
11851
|
+
PathWalkError,
|
|
11814
11852
|
PriorityDeltaPageRank,
|
|
11815
11853
|
PriorityQueue,
|
|
11816
11854
|
UnionFind,
|