@graphty/algorithms 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +490 -336
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11099 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +124 -170
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +56 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +3 -3
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/index.d.ts +2 -0
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +1 -0
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +45 -0
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +47 -54
- 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 +13 -3
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +50 -35
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -2
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +34 -39
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +303 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +17 -76
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +112 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +8 -40
- package/dist/src/algorithms/matching/bipartite.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 +1 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +368 -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/benchmark-all-algorithms.d.ts +23 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +462 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +16 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +209 -223
- 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 +16 -15
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +57 -21
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +8 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +40 -21
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.js +4 -4
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +17 -11
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +141 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -5
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +17 -8
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +17 -26
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +7 -11
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +143 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +292 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +86 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +341 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +223 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +62 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +146 -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 +28 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +6 -14
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +3 -29
- package/dist/src/research/sync.js.map +1 -1
- package/dist/src/research/terahac.d.ts +2 -0
- package/dist/src/research/terahac.d.ts.map +1 -1
- package/dist/src/research/terahac.js +7 -3
- 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 +79 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +196 -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 +52 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +123 -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 +33 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +47 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/package.json +18 -3
- package/src/algorithms/centrality/betweenness.ts +167 -199
- package/src/algorithms/centrality/closeness.ts +73 -191
- package/src/algorithms/centrality/degree.ts +3 -3
- package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
- package/src/algorithms/centrality/delta-pagerank.ts +435 -0
- package/src/algorithms/centrality/index.ts +2 -0
- package/src/algorithms/centrality/pagerank.ts +66 -0
- package/src/algorithms/community/girvan-newman.ts +52 -59
- package/src/algorithms/community/index.ts +2 -0
- package/src/algorithms/community/label-propagation.ts +64 -35
- package/src/algorithms/community/leiden.ts +40 -41
- package/src/algorithms/community/louvain-optimized.ts +445 -0
- package/src/algorithms/community/louvain.ts +24 -104
- package/src/algorithms/community/modularity-utils.ts +146 -0
- package/src/algorithms/matching/bipartite.ts +8 -44
- package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +17 -15
- package/src/algorithms/traversal/bfs-unified.ts +433 -0
- package/src/algorithms/traversal/bfs-variants.ts +496 -0
- package/src/algorithms/traversal/bfs.ts +10 -228
- package/src/benchmark-all-algorithms.ts +548 -0
- package/src/clustering/hierarchical.ts +241 -251
- package/src/clustering/index.ts +4 -2
- package/src/clustering/k-core.ts +87 -39
- package/src/clustering/spectral.ts +44 -20
- package/src/core/graph.ts +4 -4
- package/src/flow/ford-fulkerson.ts +186 -254
- package/src/flow/min-cut.ts +21 -11
- package/src/index.ts +6 -0
- package/src/link-prediction/adamic-adar.ts +17 -30
- package/src/link-prediction/common-neighbors.ts +7 -16
- package/src/optimized/bit-packed.ts +340 -0
- package/src/optimized/csr-graph.ts +455 -0
- package/src/optimized/direction-optimized-bfs.ts +291 -0
- package/src/optimized/graph-adapter.ts +200 -0
- package/src/optimized/index.ts +36 -0
- package/src/research/grsbm.ts +7 -16
- package/src/research/sync.ts +3 -32
- package/src/research/terahac.ts +10 -2
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +241 -0
- package/src/utils/graph-utilities.ts +199 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +140 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +81 -0
|
@@ -1,40 +1,30 @@
|
|
|
1
|
+
import { bfsDistancesOnly, bfsWeightedDistances } from "../traversal/bfs-variants.js";
|
|
1
2
|
/**
|
|
2
|
-
* Calculate closeness centrality
|
|
3
|
+
* Calculate closeness centrality from distances
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
6
|
-
const centrality = {};
|
|
7
|
-
for (const sourceNode of nodes) {
|
|
8
|
-
centrality[String(sourceNode)] = nodeClosenessCentrality(graph, sourceNode, options);
|
|
9
|
-
}
|
|
10
|
-
return centrality;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Calculate closeness centrality for a specific node
|
|
14
|
-
*/
|
|
15
|
-
export function nodeClosenessCentrality(graph, node, options = {}) {
|
|
16
|
-
if (!graph.hasNode(node)) {
|
|
17
|
-
throw new Error(`Node ${String(node)} not found in graph`);
|
|
18
|
-
}
|
|
19
|
-
const distances = singleSourceShortestPathLengths(graph, node, options.cutoff);
|
|
5
|
+
function calculateClosenessFromDistances(distances, sourceNode, totalNodes, options) {
|
|
20
6
|
if (distances.size <= 1) {
|
|
21
7
|
return 0; // No other nodes reachable
|
|
22
8
|
}
|
|
23
9
|
let centrality = 0;
|
|
24
10
|
if (options.harmonic) {
|
|
25
11
|
// Harmonic centrality: sum of reciprocals of distances
|
|
26
|
-
for (const [targetNode, distance] of
|
|
27
|
-
if (targetNode !==
|
|
12
|
+
for (const [targetNode, distance] of distances) {
|
|
13
|
+
if (targetNode !== sourceNode && distance > 0 && distance < Infinity) {
|
|
28
14
|
centrality += 1 / distance;
|
|
29
15
|
}
|
|
30
16
|
}
|
|
17
|
+
// Normalization for harmonic centrality
|
|
18
|
+
if (options.normalized && totalNodes > 1) {
|
|
19
|
+
centrality = centrality / (totalNodes - 1);
|
|
20
|
+
}
|
|
31
21
|
}
|
|
32
22
|
else {
|
|
33
23
|
// Standard closeness: reciprocal of sum of distances
|
|
34
24
|
let totalDistance = 0;
|
|
35
25
|
let reachableNodes = 0;
|
|
36
|
-
for (const [targetNode, distance] of
|
|
37
|
-
if (targetNode !==
|
|
26
|
+
for (const [targetNode, distance] of distances) {
|
|
27
|
+
if (targetNode !== sourceNode && distance < Infinity) {
|
|
38
28
|
totalDistance += distance;
|
|
39
29
|
reachableNodes++;
|
|
40
30
|
}
|
|
@@ -42,56 +32,56 @@ export function nodeClosenessCentrality(graph, node, options = {}) {
|
|
|
42
32
|
if (totalDistance > 0) {
|
|
43
33
|
centrality = 1 / totalDistance;
|
|
44
34
|
// Wasserman and Faust normalization for disconnected graphs
|
|
45
|
-
if (options.normalized) {
|
|
46
|
-
|
|
47
|
-
centrality = centrality * reachableNodes / (n - 1);
|
|
35
|
+
if (options.normalized && totalNodes > 1) {
|
|
36
|
+
centrality = centrality * reachableNodes / (totalNodes - 1);
|
|
48
37
|
}
|
|
49
38
|
}
|
|
50
39
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
40
|
+
return centrality;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Calculate closeness centrality for all nodes in the graph
|
|
44
|
+
*
|
|
45
|
+
* Closeness centrality measures how close a node is to all other nodes
|
|
46
|
+
* in the graph. It is the reciprocal of the sum of the shortest path
|
|
47
|
+
* distances to all other reachable nodes.
|
|
48
|
+
*
|
|
49
|
+
* @param graph - The input graph
|
|
50
|
+
* @param options - Algorithm options
|
|
51
|
+
* @returns Centrality scores for each node
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const graph = new Graph();
|
|
56
|
+
* graph.addEdge("A", "B");
|
|
57
|
+
* graph.addEdge("B", "C");
|
|
58
|
+
*
|
|
59
|
+
* const centrality = closenessCentrality(graph);
|
|
60
|
+
* // { A: 0.5, B: 1.0, C: 0.5 }
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* Time Complexity: O(V * (V + E)) for unweighted graphs
|
|
64
|
+
* Space Complexity: O(V)
|
|
65
|
+
*/
|
|
66
|
+
export function closenessCentrality(graph, options = {}) {
|
|
67
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
68
|
+
const centrality = {};
|
|
69
|
+
for (const sourceNode of nodes) {
|
|
70
|
+
centrality[String(sourceNode)] = nodeClosenessCentrality(graph, sourceNode, options);
|
|
57
71
|
}
|
|
58
72
|
return centrality;
|
|
59
73
|
}
|
|
60
74
|
/**
|
|
61
|
-
*
|
|
75
|
+
* Calculate closeness centrality for a specific node
|
|
62
76
|
*/
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const queue = [];
|
|
67
|
-
// Initialize
|
|
68
|
-
queue.push({ node: source, distance: 0 });
|
|
69
|
-
visited.add(source);
|
|
70
|
-
distances.set(source, 0);
|
|
71
|
-
while (queue.length > 0) {
|
|
72
|
-
const current = queue.shift();
|
|
73
|
-
if (!current) {
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
// Skip if beyond cutoff
|
|
77
|
-
if (cutoff !== undefined && current.distance >= cutoff) {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
// Explore neighbors
|
|
81
|
-
for (const neighbor of Array.from(graph.neighbors(current.node))) {
|
|
82
|
-
if (!visited.has(neighbor)) {
|
|
83
|
-
const newDistance = current.distance + 1;
|
|
84
|
-
// Skip if beyond cutoff
|
|
85
|
-
if (cutoff !== undefined && newDistance > cutoff) {
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
visited.add(neighbor);
|
|
89
|
-
distances.set(neighbor, newDistance);
|
|
90
|
-
queue.push({ node: neighbor, distance: newDistance });
|
|
91
|
-
}
|
|
92
|
-
}
|
|
77
|
+
export function nodeClosenessCentrality(graph, node, options = {}) {
|
|
78
|
+
if (!graph.hasNode(node)) {
|
|
79
|
+
throw new Error(`Node ${String(node)} not found in graph`);
|
|
93
80
|
}
|
|
94
|
-
|
|
81
|
+
// Use optimized BFS variant for unweighted graphs
|
|
82
|
+
const distances = bfsDistancesOnly(graph, node, options.cutoff, options.optimized !== undefined ? { optimized: options.optimized } : {});
|
|
83
|
+
const totalNodes = graph.nodeCount;
|
|
84
|
+
return calculateClosenessFromDistances(distances, node, totalNodes, options);
|
|
95
85
|
}
|
|
96
86
|
/**
|
|
97
87
|
* Calculate weighted closeness centrality using Dijkstra's algorithm
|
|
@@ -111,92 +101,9 @@ export function nodeWeightedClosenessCentrality(graph, node, options = {}) {
|
|
|
111
101
|
if (!graph.hasNode(node)) {
|
|
112
102
|
throw new Error(`Node ${String(node)} not found in graph`);
|
|
113
103
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
let centrality = 0;
|
|
119
|
-
if (options.harmonic) {
|
|
120
|
-
// Harmonic centrality: sum of reciprocals of distances
|
|
121
|
-
for (const [targetNode, distance] of Array.from(distances)) {
|
|
122
|
-
if (targetNode !== node && distance > 0 && distance < Infinity) {
|
|
123
|
-
centrality += 1 / distance;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
// Standard closeness: reciprocal of sum of distances
|
|
129
|
-
let totalDistance = 0;
|
|
130
|
-
let reachableNodes = 0;
|
|
131
|
-
for (const [targetNode, distance] of Array.from(distances)) {
|
|
132
|
-
if (targetNode !== node && distance < Infinity) {
|
|
133
|
-
totalDistance += distance;
|
|
134
|
-
reachableNodes++;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
if (totalDistance > 0) {
|
|
138
|
-
centrality = 1 / totalDistance;
|
|
139
|
-
// Wasserman and Faust normalization for disconnected graphs
|
|
140
|
-
if (options.normalized) {
|
|
141
|
-
const n = Array.from(graph.nodes()).length;
|
|
142
|
-
centrality = centrality * reachableNodes / (n - 1);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// Normalization for harmonic centrality
|
|
147
|
-
if (options.harmonic && options.normalized) {
|
|
148
|
-
const n = Array.from(graph.nodes()).length;
|
|
149
|
-
if (n > 1) {
|
|
150
|
-
centrality = centrality / (n - 1);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return centrality;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Single-source shortest path distances using Dijkstra's algorithm
|
|
157
|
-
*/
|
|
158
|
-
function dijkstraDistances(graph, source, cutoff) {
|
|
159
|
-
const distances = new Map();
|
|
160
|
-
const visited = new Set();
|
|
161
|
-
const pq = [];
|
|
162
|
-
// Initialize distances
|
|
163
|
-
for (const node of Array.from(graph.nodes())) {
|
|
164
|
-
distances.set(node.id, node.id === source ? 0 : Infinity);
|
|
165
|
-
}
|
|
166
|
-
pq.push({ node: source, distance: 0 });
|
|
167
|
-
while (pq.length > 0) {
|
|
168
|
-
// Simple priority queue (could be optimized with a proper heap)
|
|
169
|
-
pq.sort((a, b) => a.distance - b.distance);
|
|
170
|
-
const current = pq.shift();
|
|
171
|
-
if (!current || visited.has(current.node)) {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
visited.add(current.node);
|
|
175
|
-
// Skip if beyond cutoff
|
|
176
|
-
if (cutoff !== undefined && current.distance > cutoff) {
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
// Explore neighbors
|
|
180
|
-
for (const neighbor of Array.from(graph.neighbors(current.node))) {
|
|
181
|
-
if (visited.has(neighbor)) {
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
const edge = graph.getEdge(current.node, neighbor);
|
|
185
|
-
if (!edge) {
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
const edgeWeight = edge.weight ?? 1;
|
|
189
|
-
const tentativeDistance = current.distance + edgeWeight;
|
|
190
|
-
const currentDistance = distances.get(neighbor) ?? Infinity;
|
|
191
|
-
if (tentativeDistance < currentDistance) {
|
|
192
|
-
distances.set(neighbor, tentativeDistance);
|
|
193
|
-
// Skip if beyond cutoff
|
|
194
|
-
if (cutoff === undefined || tentativeDistance <= cutoff) {
|
|
195
|
-
pq.push({ node: neighbor, distance: tentativeDistance });
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return distances;
|
|
104
|
+
// Use optimized weighted BFS variant (simplified Dijkstra)
|
|
105
|
+
const distances = bfsWeightedDistances(graph, node, options.cutoff, options.optimized !== undefined ? { optimized: options.optimized } : {});
|
|
106
|
+
const totalNodes = graph.nodeCount;
|
|
107
|
+
return calculateClosenessFromDistances(distances, node, totalNodes, options);
|
|
201
108
|
}
|
|
202
109
|
//# sourceMappingURL=closeness.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"closeness.js","sourceRoot":"","sources":["../../../../src/algorithms/centrality/closeness.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"closeness.js","sourceRoot":"","sources":["../../../../src/algorithms/centrality/closeness.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
export function degreeCentrality(graph, options = {}) {
|
|
11
11
|
const centrality = {};
|
|
12
12
|
const { nodeCount } = graph;
|
|
13
|
-
// Calculate normalization factor
|
|
14
|
-
const maxPossibleDegree =
|
|
15
|
-
for (const node of
|
|
13
|
+
// Calculate normalization factor (same for both directed and undirected graphs)
|
|
14
|
+
const maxPossibleDegree = nodeCount - 1;
|
|
15
|
+
for (const node of graph.nodes()) {
|
|
16
16
|
let degree;
|
|
17
17
|
if (graph.isDirected && options.mode) {
|
|
18
18
|
// For directed graphs, calculate specific degree type
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degree.js","sourceRoot":"","sources":["../../../../src/algorithms/centrality/degree.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC5B,KAAY,EACZ,UAA6B,EAAE;IAE/B,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,MAAM,EAAC,SAAS,EAAC,GAAG,KAAK,CAAC;IAE1B,
|
|
1
|
+
{"version":3,"file":"degree.js","sourceRoot":"","sources":["../../../../src/algorithms/centrality/degree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Simplified Delta-based PageRank that matches the standard algorithm
|
|
5
|
+
* but only processes active nodes for efficiency.
|
|
6
|
+
*
|
|
7
|
+
* Key optimization: Supports incremental updates when graph structure changes,
|
|
8
|
+
* avoiding full recomputation from scratch.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SimpleDeltaPageRank {
|
|
11
|
+
private graph;
|
|
12
|
+
private nodeCount;
|
|
13
|
+
private previousScores;
|
|
14
|
+
constructor(graph: Graph);
|
|
15
|
+
compute(options?: {
|
|
16
|
+
dampingFactor?: number;
|
|
17
|
+
tolerance?: number;
|
|
18
|
+
maxIterations?: number;
|
|
19
|
+
personalization?: Map<NodeId, number>;
|
|
20
|
+
weight?: string;
|
|
21
|
+
}): Map<NodeId, number>;
|
|
22
|
+
/**
|
|
23
|
+
* Perform incremental update after graph modification.
|
|
24
|
+
* This is where delta-based approach provides significant speedup.
|
|
25
|
+
*
|
|
26
|
+
* @param modifiedNodes Set of nodes that were modified (edges added/removed)
|
|
27
|
+
* @param options Computation options
|
|
28
|
+
* @returns Updated PageRank scores
|
|
29
|
+
*/
|
|
30
|
+
update(modifiedNodes: Set<NodeId>, options?: {
|
|
31
|
+
dampingFactor?: number;
|
|
32
|
+
tolerance?: number;
|
|
33
|
+
maxIterations?: number;
|
|
34
|
+
personalization?: Map<NodeId, number>;
|
|
35
|
+
weight?: string;
|
|
36
|
+
}): Map<NodeId, number>;
|
|
37
|
+
private normalizeMap;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=delta-pagerank-simple.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta-pagerank-simple.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/centrality/delta-pagerank-simple.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAEjD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAoC;gBAE9C,KAAK,EAAE,KAAK;IASjB,OAAO,CAAC,OAAO,GAAE;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAgJ5B;;;;;;;OAOG;IACI,MAAM,CACT,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,EAC1B,OAAO,GAAE;QACL,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,MAAM,CAAC;KACd,GACP,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAkKtB,OAAO,CAAC,YAAY;CAYvB"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simplified Delta-based PageRank that matches the standard algorithm
|
|
3
|
+
* but only processes active nodes for efficiency.
|
|
4
|
+
*
|
|
5
|
+
* Key optimization: Supports incremental updates when graph structure changes,
|
|
6
|
+
* avoiding full recomputation from scratch.
|
|
7
|
+
*/
|
|
8
|
+
export class SimpleDeltaPageRank {
|
|
9
|
+
constructor(graph) {
|
|
10
|
+
this.previousScores = null;
|
|
11
|
+
if (!graph.isDirected) {
|
|
12
|
+
throw new Error("PageRank requires a directed graph");
|
|
13
|
+
}
|
|
14
|
+
this.graph = graph;
|
|
15
|
+
this.nodeCount = graph.nodeCount;
|
|
16
|
+
}
|
|
17
|
+
compute(options = {}) {
|
|
18
|
+
const { dampingFactor = 0.85, tolerance = 1e-6, maxIterations = 100, personalization, weight, } = options;
|
|
19
|
+
if (this.nodeCount === 0) {
|
|
20
|
+
return new Map();
|
|
21
|
+
}
|
|
22
|
+
// Initialize scores
|
|
23
|
+
const scores = new Map();
|
|
24
|
+
const newScores = new Map();
|
|
25
|
+
for (const node of this.graph.nodes()) {
|
|
26
|
+
scores.set(node.id, 1.0 / this.nodeCount);
|
|
27
|
+
}
|
|
28
|
+
// Precompute out-degrees and weights
|
|
29
|
+
const outWeights = new Map();
|
|
30
|
+
const danglingNodes = new Set();
|
|
31
|
+
for (const node of this.graph.nodes()) {
|
|
32
|
+
let totalWeight = 0;
|
|
33
|
+
let outDegree = 0;
|
|
34
|
+
for (const neighbor of Array.from(this.graph.neighbors(node.id))) {
|
|
35
|
+
outDegree++;
|
|
36
|
+
const edge = this.graph.getEdge(node.id, neighbor);
|
|
37
|
+
totalWeight += edge?.weight ?? 1;
|
|
38
|
+
}
|
|
39
|
+
outWeights.set(node.id, totalWeight);
|
|
40
|
+
if (outDegree === 0) {
|
|
41
|
+
danglingNodes.add(node.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Normalize personalization vector if provided
|
|
45
|
+
let personalVector = null;
|
|
46
|
+
if (personalization) {
|
|
47
|
+
personalVector = new Map(personalization);
|
|
48
|
+
this.normalizeMap(personalVector);
|
|
49
|
+
}
|
|
50
|
+
// Power iteration with active node tracking
|
|
51
|
+
let activeNodes = new Set(scores.keys());
|
|
52
|
+
let iteration = 0;
|
|
53
|
+
for (iteration = 0; iteration < maxIterations; iteration++) {
|
|
54
|
+
// Initialize new scores
|
|
55
|
+
for (const nodeId of scores.keys()) {
|
|
56
|
+
if (personalVector) {
|
|
57
|
+
newScores.set(nodeId, (1 - dampingFactor) * (personalVector.get(nodeId) ?? 0));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
newScores.set(nodeId, (1 - dampingFactor) / this.nodeCount);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Handle dangling nodes
|
|
64
|
+
let danglingSum = 0;
|
|
65
|
+
for (const danglingNode of danglingNodes) {
|
|
66
|
+
danglingSum += scores.get(danglingNode) ?? 0;
|
|
67
|
+
}
|
|
68
|
+
if (danglingSum > 0) {
|
|
69
|
+
const danglingContribution = dampingFactor * danglingSum / this.nodeCount;
|
|
70
|
+
for (const nodeId of scores.keys()) {
|
|
71
|
+
const current = newScores.get(nodeId) ?? 0;
|
|
72
|
+
if (personalVector) {
|
|
73
|
+
const personalContrib = danglingContribution * (personalVector.get(nodeId) ?? 0);
|
|
74
|
+
newScores.set(nodeId, current + personalContrib);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
newScores.set(nodeId, current + danglingContribution);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Propagate rank from active nodes only
|
|
82
|
+
for (const nodeId of activeNodes) {
|
|
83
|
+
const currentRank = scores.get(nodeId) ?? 0;
|
|
84
|
+
const nodeOutWeight = outWeights.get(nodeId) ?? 0;
|
|
85
|
+
if (nodeOutWeight > 0) {
|
|
86
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
87
|
+
let edgeWeight = 1;
|
|
88
|
+
if (weight) {
|
|
89
|
+
const edge = this.graph.getEdge(nodeId, neighbor);
|
|
90
|
+
edgeWeight = edge?.weight ?? 1;
|
|
91
|
+
}
|
|
92
|
+
const contribution = dampingFactor * currentRank * (edgeWeight / nodeOutWeight);
|
|
93
|
+
const neighborRank = newScores.get(neighbor) ?? 0;
|
|
94
|
+
newScores.set(neighbor, neighborRank + contribution);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Check convergence and identify active nodes
|
|
99
|
+
const nextActive = new Set();
|
|
100
|
+
let maxDiff = 0;
|
|
101
|
+
for (const nodeId of scores.keys()) {
|
|
102
|
+
const oldRank = scores.get(nodeId) ?? 0;
|
|
103
|
+
const newRank = newScores.get(nodeId) ?? 0;
|
|
104
|
+
const diff = Math.abs(newRank - oldRank);
|
|
105
|
+
maxDiff = Math.max(maxDiff, diff);
|
|
106
|
+
// Mark as active if change is significant
|
|
107
|
+
if (diff > tolerance / 10) {
|
|
108
|
+
nextActive.add(nodeId);
|
|
109
|
+
// Also mark neighbors as potentially active
|
|
110
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
111
|
+
nextActive.add(neighbor);
|
|
112
|
+
}
|
|
113
|
+
for (const neighbor of Array.from(this.graph.inNeighbors(nodeId))) {
|
|
114
|
+
nextActive.add(neighbor);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Swap score maps
|
|
119
|
+
scores.clear();
|
|
120
|
+
for (const [k, v] of newScores) {
|
|
121
|
+
scores.set(k, v);
|
|
122
|
+
}
|
|
123
|
+
newScores.clear();
|
|
124
|
+
activeNodes = nextActive;
|
|
125
|
+
if (maxDiff < tolerance) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Store scores for potential incremental updates
|
|
130
|
+
this.previousScores = new Map(scores);
|
|
131
|
+
return scores;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Perform incremental update after graph modification.
|
|
135
|
+
* This is where delta-based approach provides significant speedup.
|
|
136
|
+
*
|
|
137
|
+
* @param modifiedNodes Set of nodes that were modified (edges added/removed)
|
|
138
|
+
* @param options Computation options
|
|
139
|
+
* @returns Updated PageRank scores
|
|
140
|
+
*/
|
|
141
|
+
update(modifiedNodes, options = {}) {
|
|
142
|
+
if (!this.previousScores) {
|
|
143
|
+
// No previous computation, do full compute
|
|
144
|
+
return this.compute(options);
|
|
145
|
+
}
|
|
146
|
+
const { dampingFactor = 0.85, tolerance = 1e-6, maxIterations = 100, personalization, weight, } = options;
|
|
147
|
+
// Initialize scores from previous computation
|
|
148
|
+
const scores = new Map(this.previousScores);
|
|
149
|
+
const newScores = new Map();
|
|
150
|
+
// Ensure all current nodes are included
|
|
151
|
+
for (const node of this.graph.nodes()) {
|
|
152
|
+
if (!scores.has(node.id)) {
|
|
153
|
+
scores.set(node.id, 1.0 / this.nodeCount);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Start with only modified nodes and their neighbors as active
|
|
157
|
+
let activeNodes = new Set();
|
|
158
|
+
for (const nodeId of modifiedNodes) {
|
|
159
|
+
activeNodes.add(nodeId);
|
|
160
|
+
// Add incoming neighbors
|
|
161
|
+
for (const neighbor of Array.from(this.graph.inNeighbors(nodeId))) {
|
|
162
|
+
activeNodes.add(neighbor);
|
|
163
|
+
}
|
|
164
|
+
// Add outgoing neighbors
|
|
165
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
166
|
+
activeNodes.add(neighbor);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Recompute out-weights for modified nodes
|
|
170
|
+
const outWeights = new Map();
|
|
171
|
+
const danglingNodes = new Set();
|
|
172
|
+
for (const node of this.graph.nodes()) {
|
|
173
|
+
let totalWeight = 0;
|
|
174
|
+
let outDegree = 0;
|
|
175
|
+
for (const neighbor of Array.from(this.graph.neighbors(node.id))) {
|
|
176
|
+
outDegree++;
|
|
177
|
+
const edge = this.graph.getEdge(node.id, neighbor);
|
|
178
|
+
totalWeight += edge?.weight ?? 1;
|
|
179
|
+
}
|
|
180
|
+
outWeights.set(node.id, totalWeight);
|
|
181
|
+
if (outDegree === 0) {
|
|
182
|
+
danglingNodes.add(node.id);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Normalize personalization vector if provided
|
|
186
|
+
let personalVector = null;
|
|
187
|
+
if (personalization) {
|
|
188
|
+
personalVector = new Map(personalization);
|
|
189
|
+
this.normalizeMap(personalVector);
|
|
190
|
+
}
|
|
191
|
+
// Run limited iterations focusing on active nodes
|
|
192
|
+
let iteration = 0;
|
|
193
|
+
for (iteration = 0; iteration < maxIterations && activeNodes.size > 0; iteration++) {
|
|
194
|
+
// Initialize new scores
|
|
195
|
+
for (const nodeId of scores.keys()) {
|
|
196
|
+
if (personalVector) {
|
|
197
|
+
newScores.set(nodeId, (1 - dampingFactor) * (personalVector.get(nodeId) ?? 0));
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
newScores.set(nodeId, (1 - dampingFactor) / this.nodeCount);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Handle dangling nodes
|
|
204
|
+
let danglingSum = 0;
|
|
205
|
+
for (const danglingNode of danglingNodes) {
|
|
206
|
+
danglingSum += scores.get(danglingNode) ?? 0;
|
|
207
|
+
}
|
|
208
|
+
if (danglingSum > 0) {
|
|
209
|
+
const danglingContribution = dampingFactor * danglingSum / this.nodeCount;
|
|
210
|
+
for (const nodeId of scores.keys()) {
|
|
211
|
+
const current = newScores.get(nodeId) ?? 0;
|
|
212
|
+
if (personalVector) {
|
|
213
|
+
const personalContrib = danglingContribution * (personalVector.get(nodeId) ?? 0);
|
|
214
|
+
newScores.set(nodeId, current + personalContrib);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
newScores.set(nodeId, current + danglingContribution);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Propagate rank from ALL nodes (not just active)
|
|
222
|
+
// This ensures correctness
|
|
223
|
+
for (const nodeId of scores.keys()) {
|
|
224
|
+
const currentRank = scores.get(nodeId) ?? 0;
|
|
225
|
+
const nodeOutWeight = outWeights.get(nodeId) ?? 0;
|
|
226
|
+
if (nodeOutWeight > 0) {
|
|
227
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
228
|
+
let edgeWeight = 1;
|
|
229
|
+
if (weight) {
|
|
230
|
+
const edge = this.graph.getEdge(nodeId, neighbor);
|
|
231
|
+
edgeWeight = edge?.weight ?? 1;
|
|
232
|
+
}
|
|
233
|
+
const contribution = dampingFactor * currentRank * (edgeWeight / nodeOutWeight);
|
|
234
|
+
const neighborRank = newScores.get(neighbor) ?? 0;
|
|
235
|
+
newScores.set(neighbor, neighborRank + contribution);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Check convergence only for active nodes
|
|
240
|
+
const nextActive = new Set();
|
|
241
|
+
let maxDiff = 0;
|
|
242
|
+
for (const nodeId of activeNodes) {
|
|
243
|
+
const oldRank = scores.get(nodeId) ?? 0;
|
|
244
|
+
const newRank = newScores.get(nodeId) ?? 0;
|
|
245
|
+
const diff = Math.abs(newRank - oldRank);
|
|
246
|
+
maxDiff = Math.max(maxDiff, diff);
|
|
247
|
+
// Mark as active if change is significant
|
|
248
|
+
if (diff > tolerance / 10) {
|
|
249
|
+
nextActive.add(nodeId);
|
|
250
|
+
// Also mark neighbors as potentially active
|
|
251
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
252
|
+
nextActive.add(neighbor);
|
|
253
|
+
}
|
|
254
|
+
for (const neighbor of Array.from(this.graph.inNeighbors(nodeId))) {
|
|
255
|
+
nextActive.add(neighbor);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Swap score maps
|
|
260
|
+
scores.clear();
|
|
261
|
+
for (const [k, v] of newScores) {
|
|
262
|
+
scores.set(k, v);
|
|
263
|
+
}
|
|
264
|
+
newScores.clear();
|
|
265
|
+
activeNodes = nextActive;
|
|
266
|
+
if (maxDiff < tolerance) {
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Store scores for future incremental updates
|
|
271
|
+
this.previousScores = new Map(scores);
|
|
272
|
+
return scores;
|
|
273
|
+
}
|
|
274
|
+
normalizeMap(map) {
|
|
275
|
+
let sum = 0;
|
|
276
|
+
for (const value of map.values()) {
|
|
277
|
+
sum += value;
|
|
278
|
+
}
|
|
279
|
+
if (sum > 0) {
|
|
280
|
+
for (const [key, value] of Array.from(map)) {
|
|
281
|
+
map.set(key, value / sum);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=delta-pagerank-simple.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta-pagerank-simple.js","sourceRoot":"","sources":["../../../../src/algorithms/centrality/delta-pagerank-simple.ts"],"names":[],"mappings":"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"}
|