@graphty/algorithms 1.1.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 +820 -235
- 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 +158 -35
- 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 +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -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 +83 -0
- package/dist/src/research/grsbm.d.ts.map +1 -0
- package/dist/src/research/grsbm.js +403 -0
- package/dist/src/research/grsbm.js.map +1 -0
- package/dist/src/research/index.d.ts +12 -0
- package/dist/src/research/index.d.ts.map +1 -0
- package/dist/src/research/index.js +14 -0
- package/dist/src/research/index.js.map +1 -0
- package/dist/src/research/sync.d.ts +49 -0
- package/dist/src/research/sync.d.ts.map +1 -0
- package/dist/src/research/sync.js +316 -0
- package/dist/src/research/sync.js.map +1 -0
- package/dist/src/research/terahac.d.ts +65 -0
- package/dist/src/research/terahac.d.ts.map +1 -0
- package/dist/src/research/terahac.js +379 -0
- package/dist/src/research/terahac.js.map +1 -0
- 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 +28 -4
- 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 +185 -34
- 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 +9 -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 +580 -0
- package/src/research/index.ts +17 -0
- package/src/research/sync.ts +440 -0
- package/src/research/terahac.ts +514 -0
- 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
|
@@ -3,187 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Explores graph level by level from a starting node. Guarantees shortest path
|
|
5
5
|
* in unweighted graphs and can be used for various graph analysis tasks.
|
|
6
|
+
*
|
|
7
|
+
* Automatically uses optimized implementations for large graphs (>10k nodes)
|
|
8
|
+
* to provide the best performance without requiring manual configuration.
|
|
6
9
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
10
|
-
export function breadthFirstSearch(graph, startNode, options = {}) {
|
|
11
|
-
if (!graph.hasNode(startNode)) {
|
|
12
|
-
throw new Error(`Start node ${String(startNode)} not found in graph`);
|
|
13
|
-
}
|
|
14
|
-
const visited = new Set();
|
|
15
|
-
const queue = [];
|
|
16
|
-
const order = [];
|
|
17
|
-
const tree = new Map();
|
|
18
|
-
// Initialize with start node
|
|
19
|
-
queue.push({ node: startNode, level: 0 });
|
|
20
|
-
visited.add(startNode);
|
|
21
|
-
tree.set(startNode, null);
|
|
22
|
-
while (queue.length > 0) {
|
|
23
|
-
const current = queue.shift();
|
|
24
|
-
if (!current) {
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
order.push(current.node);
|
|
28
|
-
// Call visitor callback if provided
|
|
29
|
-
if (options.visitCallback) {
|
|
30
|
-
options.visitCallback(current.node, current.level);
|
|
31
|
-
}
|
|
32
|
-
// Early termination if target found
|
|
33
|
-
if (options.targetNode && current.node === options.targetNode) {
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
// Explore neighbors
|
|
37
|
-
for (const neighbor of graph.neighbors(current.node)) {
|
|
38
|
-
if (!visited.has(neighbor)) {
|
|
39
|
-
visited.add(neighbor);
|
|
40
|
-
tree.set(neighbor, current.node);
|
|
41
|
-
queue.push({ node: neighbor, level: current.level + 1 });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return { visited, order, tree };
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Find shortest path between two nodes in an unweighted graph using BFS
|
|
49
|
-
*/
|
|
50
|
-
export function shortestPathBFS(graph, source, target) {
|
|
51
|
-
if (!graph.hasNode(source)) {
|
|
52
|
-
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
53
|
-
}
|
|
54
|
-
if (!graph.hasNode(target)) {
|
|
55
|
-
throw new Error(`Target node ${String(target)} not found in graph`);
|
|
56
|
-
}
|
|
57
|
-
// Special case: source equals target
|
|
58
|
-
if (source === target) {
|
|
59
|
-
return {
|
|
60
|
-
distance: 0,
|
|
61
|
-
path: [source],
|
|
62
|
-
predecessor: new Map([[source, null]]),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const visited = new Set();
|
|
66
|
-
const queue = [];
|
|
67
|
-
const predecessor = new Map();
|
|
68
|
-
// Initialize BFS
|
|
69
|
-
queue.push({ node: source, distance: 0 });
|
|
70
|
-
visited.add(source);
|
|
71
|
-
predecessor.set(source, null);
|
|
72
|
-
while (queue.length > 0) {
|
|
73
|
-
const current = queue.shift();
|
|
74
|
-
if (!current) {
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
|
-
// Target found
|
|
78
|
-
if (current.node === target) {
|
|
79
|
-
const path = reconstructPath(target, predecessor);
|
|
80
|
-
return {
|
|
81
|
-
distance: current.distance,
|
|
82
|
-
path,
|
|
83
|
-
predecessor,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
// Explore neighbors
|
|
87
|
-
for (const neighbor of graph.neighbors(current.node)) {
|
|
88
|
-
if (!visited.has(neighbor)) {
|
|
89
|
-
visited.add(neighbor);
|
|
90
|
-
predecessor.set(neighbor, current.node);
|
|
91
|
-
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// No path found
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Find shortest paths from source to all reachable nodes using BFS
|
|
100
|
-
*/
|
|
101
|
-
export function singleSourceShortestPathBFS(graph, source) {
|
|
102
|
-
if (!graph.hasNode(source)) {
|
|
103
|
-
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
104
|
-
}
|
|
105
|
-
const results = new Map();
|
|
106
|
-
const visited = new Set();
|
|
107
|
-
const queue = [];
|
|
108
|
-
const predecessor = new Map();
|
|
109
|
-
// Initialize BFS
|
|
110
|
-
queue.push({ node: source, distance: 0 });
|
|
111
|
-
visited.add(source);
|
|
112
|
-
predecessor.set(source, null);
|
|
113
|
-
while (queue.length > 0) {
|
|
114
|
-
const current = queue.shift();
|
|
115
|
-
if (!current) {
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
// Store result for current node
|
|
119
|
-
const path = reconstructPath(current.node, predecessor);
|
|
120
|
-
results.set(current.node, {
|
|
121
|
-
distance: current.distance,
|
|
122
|
-
path,
|
|
123
|
-
predecessor: new Map(predecessor),
|
|
124
|
-
});
|
|
125
|
-
// Explore neighbors
|
|
126
|
-
for (const neighbor of graph.neighbors(current.node)) {
|
|
127
|
-
if (!visited.has(neighbor)) {
|
|
128
|
-
visited.add(neighbor);
|
|
129
|
-
predecessor.set(neighbor, current.node);
|
|
130
|
-
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return results;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Check if the graph is bipartite using BFS coloring
|
|
138
|
-
*/
|
|
139
|
-
export function isBipartite(graph) {
|
|
140
|
-
if (graph.isDirected) {
|
|
141
|
-
throw new Error("Bipartite test requires an undirected graph");
|
|
142
|
-
}
|
|
143
|
-
const color = new Map();
|
|
144
|
-
const visited = new Set();
|
|
145
|
-
// Check each connected component
|
|
146
|
-
for (const node of Array.from(graph.nodes())) {
|
|
147
|
-
if (!visited.has(node.id)) {
|
|
148
|
-
const queue = [node.id];
|
|
149
|
-
color.set(node.id, 0);
|
|
150
|
-
visited.add(node.id);
|
|
151
|
-
while (queue.length > 0) {
|
|
152
|
-
const current = queue.shift();
|
|
153
|
-
if (!current) {
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
const currentColor = color.get(current);
|
|
157
|
-
if (currentColor === undefined) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
for (const neighbor of Array.from(graph.neighbors(current))) {
|
|
161
|
-
if (!visited.has(neighbor)) {
|
|
162
|
-
// Color with opposite color
|
|
163
|
-
color.set(neighbor, currentColor === 0 ? 1 : 0);
|
|
164
|
-
visited.add(neighbor);
|
|
165
|
-
queue.push(neighbor);
|
|
166
|
-
}
|
|
167
|
-
else if (color.get(neighbor) === currentColor) {
|
|
168
|
-
// Same color as current node - not bipartite
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Reconstruct path from predecessor map
|
|
179
|
-
*/
|
|
180
|
-
function reconstructPath(target, predecessor) {
|
|
181
|
-
const path = [];
|
|
182
|
-
let current = target;
|
|
183
|
-
while (current !== null) {
|
|
184
|
-
path.unshift(current);
|
|
185
|
-
current = predecessor.get(current) ?? null;
|
|
186
|
-
}
|
|
187
|
-
return path;
|
|
188
|
-
}
|
|
10
|
+
// Re-export unified implementations that automatically optimize for large graphs
|
|
11
|
+
export { breadthFirstSearch, isBipartite, shortestPathBFS, singleSourceShortestPathBFS, } from "./bfs-unified.js";
|
|
189
12
|
//# sourceMappingURL=bfs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bfs.js","sourceRoot":"","sources":["../../../../src/algorithms/traversal/bfs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bfs.js","sourceRoot":"","sources":["../../../../src/algorithms/traversal/bfs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iFAAiF;AACjF,OAAO,EACH,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,2BAA2B,GAC9B,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive benchmark suite for ALL 98 algorithms in @graphty/algorithms
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* - Full benchmark: Completes in under 1 hour
|
|
6
|
+
* - Quick benchmark: Completes in under 2 minutes
|
|
7
|
+
*/
|
|
8
|
+
interface BenchmarkResult {
|
|
9
|
+
algorithm: string;
|
|
10
|
+
category: string;
|
|
11
|
+
executionTime: number;
|
|
12
|
+
success: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
nodeCount: number;
|
|
15
|
+
edgeCount: number;
|
|
16
|
+
mode: "quick" | "full";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Main benchmark runner
|
|
20
|
+
*/
|
|
21
|
+
export declare function runAllAlgorithmsBenchmark(mode?: "quick" | "full"): BenchmarkResult[];
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=benchmark-all-algorithms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"benchmark-all-algorithms.d.ts","sourceRoot":"","sources":["../../src/benchmark-all-algorithms.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAKH,UAAU,eAAe;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B;AAqGD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,GAAE,OAAO,GAAG,MAAe,GAAG,eAAe,EAAE,CA2D5F"}
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/**
|
|
3
|
+
* Comprehensive benchmark suite for ALL 98 algorithms in @graphty/algorithms
|
|
4
|
+
*
|
|
5
|
+
* Two modes:
|
|
6
|
+
* - Full benchmark: Completes in under 1 hour
|
|
7
|
+
* - Quick benchmark: Completes in under 2 minutes
|
|
8
|
+
*/
|
|
9
|
+
import * as algorithms from "./algorithms/index.js";
|
|
10
|
+
import { Graph } from "./core/graph.js";
|
|
11
|
+
const ALGORITHM_CATEGORIES = {
|
|
12
|
+
traversal: {
|
|
13
|
+
algorithms: [
|
|
14
|
+
"breadthFirstSearch",
|
|
15
|
+
"isBipartite",
|
|
16
|
+
"shortestPathBFS",
|
|
17
|
+
"singleSourceShortestPathBFS",
|
|
18
|
+
"depthFirstSearch",
|
|
19
|
+
"findStronglyConnectedComponents",
|
|
20
|
+
"hasCycleDFS",
|
|
21
|
+
"topologicalSort",
|
|
22
|
+
],
|
|
23
|
+
config: {
|
|
24
|
+
name: "Traversal",
|
|
25
|
+
quick: { nodes: 1000, edges: 5000, runs: 3 },
|
|
26
|
+
full: { nodes: 10000, edges: 50000, runs: 10 },
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
shortestPath: {
|
|
30
|
+
algorithms: [
|
|
31
|
+
"bellmanFord",
|
|
32
|
+
"bellmanFordPath",
|
|
33
|
+
"hasNegativeCycle",
|
|
34
|
+
"allPairsShortestPath",
|
|
35
|
+
"dijkstra",
|
|
36
|
+
"dijkstraPath",
|
|
37
|
+
"singleSourceShortestPath",
|
|
38
|
+
"floydWarshall",
|
|
39
|
+
"floydWarshallPath",
|
|
40
|
+
"transitiveClosure",
|
|
41
|
+
],
|
|
42
|
+
config: {
|
|
43
|
+
name: "Shortest Path",
|
|
44
|
+
quick: { nodes: 100, edges: 500, runs: 1 }, // Smaller for O(V³) algorithms
|
|
45
|
+
full: { nodes: 500, edges: 2500, runs: 3 },
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
centrality: {
|
|
49
|
+
algorithms: [
|
|
50
|
+
"betweennessCentrality",
|
|
51
|
+
"closenessCentrality",
|
|
52
|
+
"degreeCentrality",
|
|
53
|
+
"eigenvectorCentrality",
|
|
54
|
+
"hits",
|
|
55
|
+
"katzCentrality",
|
|
56
|
+
"pageRank",
|
|
57
|
+
"personalizedPageRank",
|
|
58
|
+
],
|
|
59
|
+
config: {
|
|
60
|
+
name: "Centrality",
|
|
61
|
+
quick: { nodes: 500, edges: 2500, runs: 1 },
|
|
62
|
+
full: { nodes: 2000, edges: 10000, runs: 3 },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
components: {
|
|
66
|
+
algorithms: [
|
|
67
|
+
"connectedComponents",
|
|
68
|
+
"connectedComponentsDFS",
|
|
69
|
+
"stronglyConnectedComponents",
|
|
70
|
+
"weaklyConnectedComponents",
|
|
71
|
+
"isConnected",
|
|
72
|
+
"isStronglyConnected",
|
|
73
|
+
"isWeaklyConnected",
|
|
74
|
+
"numberOfConnectedComponents",
|
|
75
|
+
"largestConnectedComponent",
|
|
76
|
+
"getConnectedComponent",
|
|
77
|
+
],
|
|
78
|
+
config: {
|
|
79
|
+
name: "Components",
|
|
80
|
+
quick: { nodes: 2000, edges: 10000, runs: 3 },
|
|
81
|
+
full: { nodes: 10000, edges: 50000, runs: 10 },
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
mst: {
|
|
85
|
+
algorithms: ["kruskalMST", "primMST", "minimumSpanningTree"],
|
|
86
|
+
config: {
|
|
87
|
+
name: "Minimum Spanning Tree",
|
|
88
|
+
quick: { nodes: 1000, edges: 5000, runs: 5 },
|
|
89
|
+
full: { nodes: 5000, edges: 25000, runs: 10 },
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
community: {
|
|
93
|
+
algorithms: ["girvanNewman", "labelPropagation", "leiden", "louvain"],
|
|
94
|
+
config: {
|
|
95
|
+
name: "Community Detection",
|
|
96
|
+
quick: { nodes: 200, edges: 1000, runs: 1 }, // Very expensive algorithms
|
|
97
|
+
full: { nodes: 1000, edges: 5000, runs: 2 },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
matching: {
|
|
101
|
+
algorithms: ["bipartitePartition", "greedyBipartiteMatching", "maximumBipartiteMatching"],
|
|
102
|
+
config: {
|
|
103
|
+
name: "Matching",
|
|
104
|
+
quick: { nodes: 500, edges: 1000, runs: 3 },
|
|
105
|
+
full: { nodes: 2000, edges: 4000, runs: 5 },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Main benchmark runner
|
|
111
|
+
*/
|
|
112
|
+
export function runAllAlgorithmsBenchmark(mode = "full") {
|
|
113
|
+
const startTime = Date.now();
|
|
114
|
+
const timeLimit = mode === "quick" ? 2 * 60 * 1000 : 60 * 60 * 1000; // 2 min or 1 hour
|
|
115
|
+
console.log(`š ${mode === "quick" ? "Quick" : "Comprehensive"} Benchmark - All ${String(getTotalAlgorithmCount())} Algorithms`);
|
|
116
|
+
console.log(`=${"=".repeat(60)}`);
|
|
117
|
+
console.log(`Time limit: ${mode === "quick" ? "2 minutes" : "1 hour"}`);
|
|
118
|
+
console.log(`Start time: ${new Date().toLocaleTimeString()}\n`);
|
|
119
|
+
const results = [];
|
|
120
|
+
let totalTested = 0;
|
|
121
|
+
let totalPassed = 0;
|
|
122
|
+
for (const [categoryKey, categoryData] of Object.entries(ALGORITHM_CATEGORIES)) {
|
|
123
|
+
const elapsed = Date.now() - startTime;
|
|
124
|
+
if (elapsed > timeLimit) {
|
|
125
|
+
console.log("ā° Time limit reached, stopping benchmark");
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
console.log(`\nš ${categoryData.config.name} Algorithms`);
|
|
129
|
+
console.log("-".repeat(categoryData.config.name.length + 12));
|
|
130
|
+
const config = categoryData.config[mode];
|
|
131
|
+
const graph = createTestGraph(config.nodes, config.edges, categoryKey);
|
|
132
|
+
for (const algoName of categoryData.algorithms) {
|
|
133
|
+
const elapsed = Date.now() - startTime;
|
|
134
|
+
if (elapsed > timeLimit) {
|
|
135
|
+
console.log(`ā° Time limit reached in category ${categoryData.config.name}`);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
const result = benchmarkAlgorithm(algoName, categoryData.config.name, graph, config.runs, mode);
|
|
139
|
+
results.push(result);
|
|
140
|
+
totalTested++;
|
|
141
|
+
if (result.success) {
|
|
142
|
+
totalPassed++;
|
|
143
|
+
console.log(` ā
${algoName}: ${result.executionTime.toFixed(2)}ms`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.log(` ā ${algoName}: ${result.error?.substring(0, 50) ?? "Failed"}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const totalTime = (Date.now() - startTime) / 1000;
|
|
151
|
+
console.log("\nš Benchmark Complete");
|
|
152
|
+
console.log("===================");
|
|
153
|
+
console.log(`Total time: ${totalTime.toFixed(1)}s`);
|
|
154
|
+
console.log(`Algorithms tested: ${String(totalTested)}`);
|
|
155
|
+
console.log(`Success rate: ${String(totalPassed)}/${String(totalTested)} (${(totalPassed / totalTested * 100).toFixed(1)}%)`);
|
|
156
|
+
if (mode === "full") {
|
|
157
|
+
displayDetailedResults(results);
|
|
158
|
+
}
|
|
159
|
+
return results;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Benchmark a single algorithm
|
|
163
|
+
*/
|
|
164
|
+
function benchmarkAlgorithm(algoName, category, graph, runs, mode) {
|
|
165
|
+
const algo = algorithms[algoName];
|
|
166
|
+
if (!algo || typeof algo !== "function") {
|
|
167
|
+
return {
|
|
168
|
+
algorithm: algoName,
|
|
169
|
+
category,
|
|
170
|
+
executionTime: 0,
|
|
171
|
+
success: false,
|
|
172
|
+
error: "Algorithm not found or not a function",
|
|
173
|
+
nodeCount: graph.nodeCount,
|
|
174
|
+
edgeCount: graph.uniqueEdgeCount,
|
|
175
|
+
mode,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const times = [];
|
|
180
|
+
for (let i = 0; i < runs; i++) {
|
|
181
|
+
const args = getAlgorithmArgs(algoName, graph);
|
|
182
|
+
const start = performance.now();
|
|
183
|
+
algo(...args);
|
|
184
|
+
const time = performance.now() - start;
|
|
185
|
+
times.push(time);
|
|
186
|
+
}
|
|
187
|
+
// Use median time to avoid outliers
|
|
188
|
+
times.sort((a, b) => a - b);
|
|
189
|
+
const medianTime = times[Math.floor(times.length / 2)] ?? 0;
|
|
190
|
+
return {
|
|
191
|
+
algorithm: algoName,
|
|
192
|
+
category,
|
|
193
|
+
executionTime: medianTime,
|
|
194
|
+
success: true,
|
|
195
|
+
nodeCount: graph.nodeCount,
|
|
196
|
+
edgeCount: graph.uniqueEdgeCount,
|
|
197
|
+
mode,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
return {
|
|
202
|
+
algorithm: algoName,
|
|
203
|
+
category,
|
|
204
|
+
executionTime: 0,
|
|
205
|
+
success: false,
|
|
206
|
+
error: error instanceof Error ? error.message : String(error),
|
|
207
|
+
nodeCount: graph.nodeCount,
|
|
208
|
+
edgeCount: graph.uniqueEdgeCount,
|
|
209
|
+
mode,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get appropriate arguments for each algorithm
|
|
215
|
+
*/
|
|
216
|
+
function getAlgorithmArgs(algoName, graph) {
|
|
217
|
+
// Get random nodes for algorithms that need them
|
|
218
|
+
const nodes = Array.from(graph.nodes()).map((n) => n.id);
|
|
219
|
+
const randomNode = nodes[Math.floor(Math.random() * nodes.length)];
|
|
220
|
+
const randomNode2 = nodes[Math.floor(Math.random() * nodes.length)];
|
|
221
|
+
// Algorithm-specific argument mapping
|
|
222
|
+
switch (algoName) {
|
|
223
|
+
// Single source algorithms
|
|
224
|
+
case "breadthFirstSearch":
|
|
225
|
+
case "depthFirstSearch":
|
|
226
|
+
case "singleSourceShortestPathBFS":
|
|
227
|
+
case "singleSourceShortestPath":
|
|
228
|
+
case "dijkstra":
|
|
229
|
+
case "bellmanFord":
|
|
230
|
+
return [graph, randomNode];
|
|
231
|
+
// PageRank algorithms need directed graph
|
|
232
|
+
case "pageRank": {
|
|
233
|
+
const directedForPR = createDirectedGraph(graph);
|
|
234
|
+
return [directedForPR];
|
|
235
|
+
}
|
|
236
|
+
case "personalizedPageRank": {
|
|
237
|
+
const directedForPPR = createDirectedGraph(graph);
|
|
238
|
+
const personalNodes = [randomNode]; // Array of nodes for personalization
|
|
239
|
+
return [directedForPPR, personalNodes];
|
|
240
|
+
}
|
|
241
|
+
// Two node algorithms
|
|
242
|
+
case "shortestPathBFS":
|
|
243
|
+
case "dijkstraPath":
|
|
244
|
+
case "bellmanFordPath":
|
|
245
|
+
return [graph, randomNode, randomNode2];
|
|
246
|
+
// Component-specific algorithms
|
|
247
|
+
case "getConnectedComponent":
|
|
248
|
+
return [graph, randomNode];
|
|
249
|
+
// Algorithms that need specific graph types
|
|
250
|
+
case "topologicalSort":
|
|
251
|
+
case "findStronglyConnectedComponents":
|
|
252
|
+
case "stronglyConnectedComponents":
|
|
253
|
+
case "weaklyConnectedComponents":
|
|
254
|
+
case "isStronglyConnected":
|
|
255
|
+
case "isWeaklyConnected": {
|
|
256
|
+
// Create a directed version of the graph for these algorithms
|
|
257
|
+
const directedGraph = createDirectedGraph(graph);
|
|
258
|
+
return [directedGraph];
|
|
259
|
+
}
|
|
260
|
+
// Bipartite algorithms need bipartite graphs
|
|
261
|
+
case "bipartitePartition":
|
|
262
|
+
case "greedyBipartiteMatching":
|
|
263
|
+
case "maximumBipartiteMatching": {
|
|
264
|
+
const bipartiteGraph = createBipartiteGraph(Math.floor(graph.nodeCount / 2));
|
|
265
|
+
return [bipartiteGraph];
|
|
266
|
+
}
|
|
267
|
+
// Community detection algorithms
|
|
268
|
+
case "labelPropagation":
|
|
269
|
+
case "leiden":
|
|
270
|
+
case "louvain":
|
|
271
|
+
case "girvanNewman":
|
|
272
|
+
return [graph, {}]; // Pass empty options
|
|
273
|
+
// Default: just the graph
|
|
274
|
+
default:
|
|
275
|
+
return [graph];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Create test graph appropriate for each algorithm category
|
|
280
|
+
*/
|
|
281
|
+
function createTestGraph(nodes, edges, category) {
|
|
282
|
+
const graph = new Graph();
|
|
283
|
+
// Add nodes
|
|
284
|
+
for (let i = 0; i < nodes; i++) {
|
|
285
|
+
graph.addNode(i);
|
|
286
|
+
}
|
|
287
|
+
// Create different graph structures for different algorithm categories
|
|
288
|
+
switch (category) {
|
|
289
|
+
case "shortestPath":
|
|
290
|
+
// Sparse connected graph for shortest path algorithms
|
|
291
|
+
createConnectedGraph(graph, Math.min(edges, nodes * 3));
|
|
292
|
+
break;
|
|
293
|
+
case "centrality":
|
|
294
|
+
// Small-world graph good for centrality analysis
|
|
295
|
+
createSmallWorldGraph(graph, Math.floor(edges / nodes));
|
|
296
|
+
break;
|
|
297
|
+
case "community":
|
|
298
|
+
// Graph with community structure
|
|
299
|
+
createCommunityGraph(graph, edges);
|
|
300
|
+
break;
|
|
301
|
+
default:
|
|
302
|
+
// Random connected graph
|
|
303
|
+
createConnectedGraph(graph, edges);
|
|
304
|
+
}
|
|
305
|
+
return graph;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create a connected random graph
|
|
309
|
+
*/
|
|
310
|
+
function createConnectedGraph(graph, targetEdges) {
|
|
311
|
+
const nodes = graph.nodeCount;
|
|
312
|
+
// First create a spanning tree to ensure connectivity
|
|
313
|
+
for (let i = 1; i < nodes; i++) {
|
|
314
|
+
const parent = Math.floor(Math.random() * i);
|
|
315
|
+
graph.addEdge(parent, i);
|
|
316
|
+
}
|
|
317
|
+
// Add remaining edges randomly
|
|
318
|
+
let edgesAdded = nodes - 1;
|
|
319
|
+
while (edgesAdded < targetEdges) {
|
|
320
|
+
const source = Math.floor(Math.random() * nodes);
|
|
321
|
+
const target = Math.floor(Math.random() * nodes);
|
|
322
|
+
if (source !== target && !graph.hasEdge(source, target)) {
|
|
323
|
+
graph.addEdge(source, target);
|
|
324
|
+
edgesAdded++;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Create small-world graph (Watts-Strogatz model)
|
|
330
|
+
*/
|
|
331
|
+
function createSmallWorldGraph(graph, avgDegree) {
|
|
332
|
+
const nodes = graph.nodeCount;
|
|
333
|
+
const k = Math.floor(avgDegree / 2);
|
|
334
|
+
// Ring lattice
|
|
335
|
+
for (let i = 0; i < nodes; i++) {
|
|
336
|
+
for (let j = 1; j <= k; j++) {
|
|
337
|
+
const target = (i + j) % nodes;
|
|
338
|
+
graph.addEdge(i, target);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Rewire some edges
|
|
342
|
+
const rewireProb = 0.1;
|
|
343
|
+
for (let i = 0; i < nodes; i++) {
|
|
344
|
+
for (let j = 1; j <= k; j++) {
|
|
345
|
+
if (Math.random() < rewireProb) {
|
|
346
|
+
const oldTarget = (i + j) % nodes;
|
|
347
|
+
const newTarget = Math.floor(Math.random() * nodes);
|
|
348
|
+
if (newTarget !== i && !graph.hasEdge(i, newTarget)) {
|
|
349
|
+
graph.removeEdge(i, oldTarget);
|
|
350
|
+
graph.addEdge(i, newTarget);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Create graph with community structure
|
|
358
|
+
*/
|
|
359
|
+
function createCommunityGraph(graph, targetEdges) {
|
|
360
|
+
const nodes = graph.nodeCount;
|
|
361
|
+
const communities = Math.min(5, Math.floor(nodes / 20)); // 5 communities max
|
|
362
|
+
const communitySize = Math.floor(nodes / communities);
|
|
363
|
+
let edgesAdded = 0;
|
|
364
|
+
// Create dense connections within communities
|
|
365
|
+
for (let c = 0; c < communities; c++) {
|
|
366
|
+
const start = c * communitySize;
|
|
367
|
+
const end = Math.min((c + 1) * communitySize, nodes);
|
|
368
|
+
for (let i = start; i < end && edgesAdded < targetEdges; i++) {
|
|
369
|
+
for (let j = i + 1; j < end && edgesAdded < targetEdges; j++) {
|
|
370
|
+
if (Math.random() < 0.8) { // High probability within community
|
|
371
|
+
graph.addEdge(i, j);
|
|
372
|
+
edgesAdded++;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// Add sparse connections between communities
|
|
378
|
+
while (edgesAdded < targetEdges) {
|
|
379
|
+
const source = Math.floor(Math.random() * nodes);
|
|
380
|
+
const target = Math.floor(Math.random() * nodes);
|
|
381
|
+
if (source !== target && !graph.hasEdge(source, target)) {
|
|
382
|
+
graph.addEdge(source, target);
|
|
383
|
+
edgesAdded++;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Create directed version of graph
|
|
389
|
+
*/
|
|
390
|
+
function createDirectedGraph(undirectedGraph) {
|
|
391
|
+
const directedGraph = new Graph({ directed: true });
|
|
392
|
+
// Copy nodes
|
|
393
|
+
for (const node of undirectedGraph.nodes()) {
|
|
394
|
+
directedGraph.addNode(node.id);
|
|
395
|
+
}
|
|
396
|
+
// Copy edges as directed
|
|
397
|
+
for (const edge of undirectedGraph.edges()) {
|
|
398
|
+
directedGraph.addEdge(edge.source, edge.target);
|
|
399
|
+
}
|
|
400
|
+
return directedGraph;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Create bipartite graph
|
|
404
|
+
*/
|
|
405
|
+
function createBipartiteGraph(nodesPerPartition) {
|
|
406
|
+
const graph = new Graph();
|
|
407
|
+
// Add nodes (0 to n-1 in first partition, n to 2n-1 in second)
|
|
408
|
+
for (let i = 0; i < nodesPerPartition * 2; i++) {
|
|
409
|
+
graph.addNode(i);
|
|
410
|
+
}
|
|
411
|
+
// Add edges only between partitions
|
|
412
|
+
for (let i = 0; i < nodesPerPartition; i++) {
|
|
413
|
+
for (let j = nodesPerPartition; j < nodesPerPartition * 2; j++) {
|
|
414
|
+
if (Math.random() < 0.3) { // Sparse bipartite graph
|
|
415
|
+
graph.addEdge(i, j);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return graph;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Get total algorithm count
|
|
423
|
+
*/
|
|
424
|
+
function getTotalAlgorithmCount() {
|
|
425
|
+
return Object.values(ALGORITHM_CATEGORIES).reduce((total, category) => total + category.algorithms.length, 0);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Display detailed results for full benchmark
|
|
429
|
+
*/
|
|
430
|
+
function displayDetailedResults(results) {
|
|
431
|
+
console.log("\nš Detailed Results");
|
|
432
|
+
console.log("==================");
|
|
433
|
+
const categories = new Map();
|
|
434
|
+
for (const result of results) {
|
|
435
|
+
if (!categories.has(result.category)) {
|
|
436
|
+
categories.set(result.category, []);
|
|
437
|
+
}
|
|
438
|
+
categories.get(result.category)?.push(result);
|
|
439
|
+
}
|
|
440
|
+
for (const [category, categoryResults] of categories) {
|
|
441
|
+
console.log(`\n${category}:`);
|
|
442
|
+
console.log("-".repeat(category.length + 1));
|
|
443
|
+
const successful = categoryResults.filter((r) => r.success);
|
|
444
|
+
const failed = categoryResults.filter((r) => !r.success);
|
|
445
|
+
if (successful.length > 0) {
|
|
446
|
+
const avgTime = successful.reduce((sum, r) => sum + r.executionTime, 0) / successful.length;
|
|
447
|
+
console.log(` Average time: ${avgTime.toFixed(2)}ms`);
|
|
448
|
+
const minTime = Math.min(...successful.map((r) => r.executionTime));
|
|
449
|
+
const maxTime = Math.max(...successful.map((r) => r.executionTime));
|
|
450
|
+
console.log(` Range: ${minTime.toFixed(2)}ms - ${maxTime.toFixed(2)}ms`);
|
|
451
|
+
}
|
|
452
|
+
if (failed.length > 0) {
|
|
453
|
+
console.log(` Failed algorithms: ${failed.map((r) => r.algorithm).join(", ")}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Run benchmark if called directly
|
|
458
|
+
if (typeof process !== "undefined" && import.meta.url === `file://${process.argv[1] ?? ""}`) {
|
|
459
|
+
const mode = process.argv.includes("--quick") ? "quick" : "full";
|
|
460
|
+
runAllAlgorithmsBenchmark(mode);
|
|
461
|
+
}
|
|
462
|
+
//# sourceMappingURL=benchmark-all-algorithms.js.map
|