@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.
Files changed (237) hide show
  1. package/README.md +820 -235
  2. package/dist/algorithms.d.ts +42 -2
  3. package/dist/algorithms.js +11099 -2
  4. package/dist/algorithms.js.map +1 -1
  5. package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +124 -170
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
  10. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  11. package/dist/src/algorithms/centrality/closeness.js +56 -149
  12. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  13. package/dist/src/algorithms/centrality/degree.js +3 -3
  14. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  15. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
  16. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
  17. package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
  18. package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
  19. package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
  20. package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
  21. package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
  22. package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
  23. package/dist/src/algorithms/centrality/index.d.ts +2 -0
  24. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  25. package/dist/src/algorithms/centrality/index.js +1 -0
  26. package/dist/src/algorithms/centrality/index.js.map +1 -1
  27. package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
  28. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  29. package/dist/src/algorithms/centrality/pagerank.js +45 -0
  30. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  31. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  32. package/dist/src/algorithms/community/girvan-newman.js +47 -54
  33. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  34. package/dist/src/algorithms/community/index.d.ts +2 -0
  35. package/dist/src/algorithms/community/index.d.ts.map +1 -1
  36. package/dist/src/algorithms/community/index.js.map +1 -1
  37. package/dist/src/algorithms/community/label-propagation.d.ts +13 -3
  38. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  39. package/dist/src/algorithms/community/label-propagation.js +50 -35
  40. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  41. package/dist/src/algorithms/community/leiden.d.ts +3 -2
  42. package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
  43. package/dist/src/algorithms/community/leiden.js +34 -39
  44. package/dist/src/algorithms/community/leiden.js.map +1 -1
  45. package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
  46. package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
  47. package/dist/src/algorithms/community/louvain-optimized.js +303 -0
  48. package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
  49. package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
  50. package/dist/src/algorithms/community/louvain.js +17 -76
  51. package/dist/src/algorithms/community/louvain.js.map +1 -1
  52. package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
  53. package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
  54. package/dist/src/algorithms/community/modularity-utils.js +112 -0
  55. package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
  56. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
  57. package/dist/src/algorithms/matching/bipartite.js +8 -40
  58. package/dist/src/algorithms/matching/bipartite.js.map +1 -1
  59. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  60. package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -12
  61. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  62. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
  63. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
  64. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
  65. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
  66. package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
  67. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  68. package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
  69. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  70. package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
  71. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
  72. package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
  73. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
  74. package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
  75. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
  76. package/dist/src/algorithms/traversal/bfs-variants.js +368 -0
  77. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
  78. package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
  79. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  80. package/dist/src/algorithms/traversal/bfs.js +5 -182
  81. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  82. package/dist/src/benchmark-all-algorithms.d.ts +23 -0
  83. package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
  84. package/dist/src/benchmark-all-algorithms.js +462 -0
  85. package/dist/src/benchmark-all-algorithms.js.map +1 -0
  86. package/dist/src/clustering/hierarchical.d.ts +16 -15
  87. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  88. package/dist/src/clustering/hierarchical.js +209 -223
  89. package/dist/src/clustering/hierarchical.js.map +1 -1
  90. package/dist/src/clustering/index.d.ts +4 -2
  91. package/dist/src/clustering/index.d.ts.map +1 -1
  92. package/dist/src/clustering/index.js +2 -2
  93. package/dist/src/clustering/index.js.map +1 -1
  94. package/dist/src/clustering/k-core.d.ts +16 -15
  95. package/dist/src/clustering/k-core.d.ts.map +1 -1
  96. package/dist/src/clustering/k-core.js +57 -21
  97. package/dist/src/clustering/k-core.js.map +1 -1
  98. package/dist/src/clustering/spectral.d.ts +8 -0
  99. package/dist/src/clustering/spectral.d.ts.map +1 -1
  100. package/dist/src/clustering/spectral.js +158 -35
  101. package/dist/src/clustering/spectral.js.map +1 -1
  102. package/dist/src/core/graph.js +4 -4
  103. package/dist/src/core/graph.js.map +1 -1
  104. package/dist/src/flow/ford-fulkerson.d.ts +17 -11
  105. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
  106. package/dist/src/flow/ford-fulkerson.js +141 -217
  107. package/dist/src/flow/ford-fulkerson.js.map +1 -1
  108. package/dist/src/flow/min-cut.d.ts +6 -5
  109. package/dist/src/flow/min-cut.d.ts.map +1 -1
  110. package/dist/src/flow/min-cut.js +17 -8
  111. package/dist/src/flow/min-cut.js.map +1 -1
  112. package/dist/src/index.d.ts +2 -0
  113. package/dist/src/index.d.ts.map +1 -1
  114. package/dist/src/index.js +6 -0
  115. package/dist/src/index.js.map +1 -1
  116. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
  117. package/dist/src/link-prediction/adamic-adar.js +17 -26
  118. package/dist/src/link-prediction/adamic-adar.js.map +1 -1
  119. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  120. package/dist/src/link-prediction/common-neighbors.js +7 -11
  121. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  122. package/dist/src/optimized/bit-packed.d.ts +143 -0
  123. package/dist/src/optimized/bit-packed.d.ts.map +1 -0
  124. package/dist/src/optimized/bit-packed.js +292 -0
  125. package/dist/src/optimized/bit-packed.js.map +1 -0
  126. package/dist/src/optimized/csr-graph.d.ts +86 -0
  127. package/dist/src/optimized/csr-graph.d.ts.map +1 -0
  128. package/dist/src/optimized/csr-graph.js +341 -0
  129. package/dist/src/optimized/csr-graph.js.map +1 -0
  130. package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
  131. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
  132. package/dist/src/optimized/direction-optimized-bfs.js +223 -0
  133. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
  134. package/dist/src/optimized/graph-adapter.d.ts +62 -0
  135. package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
  136. package/dist/src/optimized/graph-adapter.js +146 -0
  137. package/dist/src/optimized/graph-adapter.js.map +1 -0
  138. package/dist/src/optimized/index.d.ts +14 -0
  139. package/dist/src/optimized/index.d.ts.map +1 -0
  140. package/dist/src/optimized/index.js +28 -0
  141. package/dist/src/optimized/index.js.map +1 -0
  142. package/dist/src/research/grsbm.d.ts +83 -0
  143. package/dist/src/research/grsbm.d.ts.map +1 -0
  144. package/dist/src/research/grsbm.js +403 -0
  145. package/dist/src/research/grsbm.js.map +1 -0
  146. package/dist/src/research/index.d.ts +12 -0
  147. package/dist/src/research/index.d.ts.map +1 -0
  148. package/dist/src/research/index.js +14 -0
  149. package/dist/src/research/index.js.map +1 -0
  150. package/dist/src/research/sync.d.ts +49 -0
  151. package/dist/src/research/sync.d.ts.map +1 -0
  152. package/dist/src/research/sync.js +316 -0
  153. package/dist/src/research/sync.js.map +1 -0
  154. package/dist/src/research/terahac.d.ts +65 -0
  155. package/dist/src/research/terahac.d.ts.map +1 -0
  156. package/dist/src/research/terahac.js +379 -0
  157. package/dist/src/research/terahac.js.map +1 -0
  158. package/dist/src/types/index.d.ts +8 -0
  159. package/dist/src/types/index.d.ts.map +1 -1
  160. package/dist/src/utils/algorithm-utilities.d.ts +2 -0
  161. package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
  162. package/dist/src/utils/algorithm-utilities.js +2 -0
  163. package/dist/src/utils/algorithm-utilities.js.map +1 -0
  164. package/dist/src/utils/graph-converters.d.ts +79 -0
  165. package/dist/src/utils/graph-converters.d.ts.map +1 -0
  166. package/dist/src/utils/graph-converters.js +196 -0
  167. package/dist/src/utils/graph-converters.js.map +1 -0
  168. package/dist/src/utils/graph-utilities.d.ts +62 -0
  169. package/dist/src/utils/graph-utilities.d.ts.map +1 -0
  170. package/dist/src/utils/graph-utilities.js +148 -0
  171. package/dist/src/utils/graph-utilities.js.map +1 -0
  172. package/dist/src/utils/index.d.ts +5 -0
  173. package/dist/src/utils/index.d.ts.map +1 -0
  174. package/dist/src/utils/index.js +5 -0
  175. package/dist/src/utils/index.js.map +1 -0
  176. package/dist/src/utils/math-utilities.d.ts +52 -0
  177. package/dist/src/utils/math-utilities.d.ts.map +1 -0
  178. package/dist/src/utils/math-utilities.js +123 -0
  179. package/dist/src/utils/math-utilities.js.map +1 -0
  180. package/dist/src/utils/matrix-utilities.d.ts +2 -0
  181. package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
  182. package/dist/src/utils/matrix-utilities.js +2 -0
  183. package/dist/src/utils/matrix-utilities.js.map +1 -0
  184. package/dist/src/utils/optimization-helpers.d.ts +33 -0
  185. package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
  186. package/dist/src/utils/optimization-helpers.js +47 -0
  187. package/dist/src/utils/optimization-helpers.js.map +1 -0
  188. package/package.json +28 -4
  189. package/src/algorithms/centrality/betweenness.ts +167 -199
  190. package/src/algorithms/centrality/closeness.ts +73 -191
  191. package/src/algorithms/centrality/degree.ts +3 -3
  192. package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
  193. package/src/algorithms/centrality/delta-pagerank.ts +435 -0
  194. package/src/algorithms/centrality/index.ts +2 -0
  195. package/src/algorithms/centrality/pagerank.ts +66 -0
  196. package/src/algorithms/community/girvan-newman.ts +52 -59
  197. package/src/algorithms/community/index.ts +2 -0
  198. package/src/algorithms/community/label-propagation.ts +64 -35
  199. package/src/algorithms/community/leiden.ts +40 -41
  200. package/src/algorithms/community/louvain-optimized.ts +445 -0
  201. package/src/algorithms/community/louvain.ts +24 -104
  202. package/src/algorithms/community/modularity-utils.ts +146 -0
  203. package/src/algorithms/matching/bipartite.ts +8 -44
  204. package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
  205. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
  206. package/src/algorithms/shortest-path/dijkstra.ts +17 -15
  207. package/src/algorithms/traversal/bfs-unified.ts +433 -0
  208. package/src/algorithms/traversal/bfs-variants.ts +496 -0
  209. package/src/algorithms/traversal/bfs.ts +10 -228
  210. package/src/benchmark-all-algorithms.ts +548 -0
  211. package/src/clustering/hierarchical.ts +241 -251
  212. package/src/clustering/index.ts +4 -2
  213. package/src/clustering/k-core.ts +87 -39
  214. package/src/clustering/spectral.ts +185 -34
  215. package/src/core/graph.ts +4 -4
  216. package/src/flow/ford-fulkerson.ts +186 -254
  217. package/src/flow/min-cut.ts +21 -11
  218. package/src/index.ts +9 -0
  219. package/src/link-prediction/adamic-adar.ts +17 -30
  220. package/src/link-prediction/common-neighbors.ts +7 -16
  221. package/src/optimized/bit-packed.ts +340 -0
  222. package/src/optimized/csr-graph.ts +455 -0
  223. package/src/optimized/direction-optimized-bfs.ts +291 -0
  224. package/src/optimized/graph-adapter.ts +200 -0
  225. package/src/optimized/index.ts +36 -0
  226. package/src/research/grsbm.ts +580 -0
  227. package/src/research/index.ts +17 -0
  228. package/src/research/sync.ts +440 -0
  229. package/src/research/terahac.ts +514 -0
  230. package/src/types/index.ts +8 -0
  231. package/src/utils/algorithm-utilities.ts +2 -0
  232. package/src/utils/graph-converters.ts +241 -0
  233. package/src/utils/graph-utilities.ts +199 -0
  234. package/src/utils/index.ts +4 -0
  235. package/src/utils/math-utilities.ts +140 -0
  236. package/src/utils/matrix-utilities.ts +2 -0
  237. package/src/utils/optimization-helpers.ts +81 -0
@@ -0,0 +1,548 @@
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
+
10
+ import * as algorithms from "./algorithms/index.js";
11
+ import {Graph} from "./core/graph.js";
12
+
13
+ interface BenchmarkResult {
14
+ algorithm: string;
15
+ category: string;
16
+ executionTime: number;
17
+ success: boolean;
18
+ error?: string;
19
+ nodeCount: number;
20
+ edgeCount: number;
21
+ mode: "quick" | "full";
22
+ }
23
+
24
+ const ALGORITHM_CATEGORIES = {
25
+ traversal: {
26
+ algorithms: [
27
+ "breadthFirstSearch",
28
+ "isBipartite",
29
+ "shortestPathBFS",
30
+ "singleSourceShortestPathBFS",
31
+ "depthFirstSearch",
32
+ "findStronglyConnectedComponents",
33
+ "hasCycleDFS",
34
+ "topologicalSort",
35
+ ],
36
+ config: {
37
+ name: "Traversal",
38
+ quick: {nodes: 1000, edges: 5000, runs: 3},
39
+ full: {nodes: 10000, edges: 50000, runs: 10},
40
+ },
41
+ },
42
+ shortestPath: {
43
+ algorithms: [
44
+ "bellmanFord",
45
+ "bellmanFordPath",
46
+ "hasNegativeCycle",
47
+ "allPairsShortestPath",
48
+ "dijkstra",
49
+ "dijkstraPath",
50
+ "singleSourceShortestPath",
51
+ "floydWarshall",
52
+ "floydWarshallPath",
53
+ "transitiveClosure",
54
+ ],
55
+ config: {
56
+ name: "Shortest Path",
57
+ quick: {nodes: 100, edges: 500, runs: 1}, // Smaller for O(V³) algorithms
58
+ full: {nodes: 500, edges: 2500, runs: 3},
59
+ },
60
+ },
61
+ centrality: {
62
+ algorithms: [
63
+ "betweennessCentrality",
64
+ "closenessCentrality",
65
+ "degreeCentrality",
66
+ "eigenvectorCentrality",
67
+ "hits",
68
+ "katzCentrality",
69
+ "pageRank",
70
+ "personalizedPageRank",
71
+ ],
72
+ config: {
73
+ name: "Centrality",
74
+ quick: {nodes: 500, edges: 2500, runs: 1},
75
+ full: {nodes: 2000, edges: 10000, runs: 3},
76
+ },
77
+ },
78
+ components: {
79
+ algorithms: [
80
+ "connectedComponents",
81
+ "connectedComponentsDFS",
82
+ "stronglyConnectedComponents",
83
+ "weaklyConnectedComponents",
84
+ "isConnected",
85
+ "isStronglyConnected",
86
+ "isWeaklyConnected",
87
+ "numberOfConnectedComponents",
88
+ "largestConnectedComponent",
89
+ "getConnectedComponent",
90
+ ],
91
+ config: {
92
+ name: "Components",
93
+ quick: {nodes: 2000, edges: 10000, runs: 3},
94
+ full: {nodes: 10000, edges: 50000, runs: 10},
95
+ },
96
+ },
97
+ mst: {
98
+ algorithms: ["kruskalMST", "primMST", "minimumSpanningTree"],
99
+ config: {
100
+ name: "Minimum Spanning Tree",
101
+ quick: {nodes: 1000, edges: 5000, runs: 5},
102
+ full: {nodes: 5000, edges: 25000, runs: 10},
103
+ },
104
+ },
105
+ community: {
106
+ algorithms: ["girvanNewman", "labelPropagation", "leiden", "louvain"],
107
+ config: {
108
+ name: "Community Detection",
109
+ quick: {nodes: 200, edges: 1000, runs: 1}, // Very expensive algorithms
110
+ full: {nodes: 1000, edges: 5000, runs: 2},
111
+ },
112
+ },
113
+ matching: {
114
+ algorithms: ["bipartitePartition", "greedyBipartiteMatching", "maximumBipartiteMatching"],
115
+ config: {
116
+ name: "Matching",
117
+ quick: {nodes: 500, edges: 1000, runs: 3},
118
+ full: {nodes: 2000, edges: 4000, runs: 5},
119
+ },
120
+ },
121
+ } as const;
122
+
123
+ /**
124
+ * Main benchmark runner
125
+ */
126
+ export function runAllAlgorithmsBenchmark(mode: "quick" | "full" = "full"): BenchmarkResult[] {
127
+ const startTime = Date.now();
128
+ const timeLimit = mode === "quick" ? 2 * 60 * 1000 : 60 * 60 * 1000; // 2 min or 1 hour
129
+
130
+ console.log(`šŸš€ ${mode === "quick" ? "Quick" : "Comprehensive"} Benchmark - All ${String(getTotalAlgorithmCount())} Algorithms`);
131
+ console.log(`=${"=".repeat(60)}`);
132
+ console.log(`Time limit: ${mode === "quick" ? "2 minutes" : "1 hour"}`);
133
+ console.log(`Start time: ${new Date().toLocaleTimeString()}\n`);
134
+
135
+ const results: BenchmarkResult[] = [];
136
+ let totalTested = 0;
137
+ let totalPassed = 0;
138
+
139
+ for (const [categoryKey, categoryData] of Object.entries(ALGORITHM_CATEGORIES)) {
140
+ const elapsed = Date.now() - startTime;
141
+ if (elapsed > timeLimit) {
142
+ console.log("ā° Time limit reached, stopping benchmark");
143
+ break;
144
+ }
145
+
146
+ console.log(`\nšŸ“Š ${categoryData.config.name} Algorithms`);
147
+ console.log("-".repeat(categoryData.config.name.length + 12));
148
+
149
+ const config = categoryData.config[mode];
150
+ const graph = createTestGraph(config.nodes, config.edges, categoryKey);
151
+
152
+ for (const algoName of categoryData.algorithms) {
153
+ const elapsed = Date.now() - startTime;
154
+ if (elapsed > timeLimit) {
155
+ console.log(`ā° Time limit reached in category ${categoryData.config.name}`);
156
+ break;
157
+ }
158
+
159
+ const result = benchmarkAlgorithm(algoName, categoryData.config.name, graph, config.runs, mode);
160
+ results.push(result);
161
+ totalTested++;
162
+
163
+ if (result.success) {
164
+ totalPassed++;
165
+ console.log(` āœ… ${algoName}: ${result.executionTime.toFixed(2)}ms`);
166
+ } else {
167
+ console.log(` āŒ ${algoName}: ${result.error?.substring(0, 50) ?? "Failed"}`);
168
+ }
169
+ }
170
+ }
171
+
172
+ const totalTime = (Date.now() - startTime) / 1000;
173
+
174
+ console.log("\nšŸ“ˆ Benchmark Complete");
175
+ console.log("===================");
176
+ console.log(`Total time: ${totalTime.toFixed(1)}s`);
177
+ console.log(`Algorithms tested: ${String(totalTested)}`);
178
+ console.log(`Success rate: ${String(totalPassed)}/${String(totalTested)} (${(totalPassed / totalTested * 100).toFixed(1)}%)`);
179
+
180
+ if (mode === "full") {
181
+ displayDetailedResults(results);
182
+ }
183
+
184
+ return results;
185
+ }
186
+
187
+ /**
188
+ * Benchmark a single algorithm
189
+ */
190
+ function benchmarkAlgorithm(
191
+ algoName: string,
192
+ category: string,
193
+ graph: Graph,
194
+ runs: number,
195
+ mode: "quick" | "full",
196
+ ): BenchmarkResult {
197
+ const algo = (algorithms as Record<string, unknown>)[algoName];
198
+
199
+ if (!algo || typeof algo !== "function") {
200
+ return {
201
+ algorithm: algoName,
202
+ category,
203
+ executionTime: 0,
204
+ success: false,
205
+ error: "Algorithm not found or not a function",
206
+ nodeCount: graph.nodeCount,
207
+ edgeCount: graph.uniqueEdgeCount,
208
+ mode,
209
+ };
210
+ }
211
+
212
+ try {
213
+ const times: number[] = [];
214
+
215
+ for (let i = 0; i < runs; i++) {
216
+ const args = getAlgorithmArgs(algoName, graph);
217
+ const start = performance.now();
218
+
219
+ (algo as (... args: unknown[]) => unknown)(... args);
220
+
221
+ const time = performance.now() - start;
222
+ times.push(time);
223
+ }
224
+
225
+ // Use median time to avoid outliers
226
+ times.sort((a, b) => a - b);
227
+ const medianTime = times[Math.floor(times.length / 2)] ?? 0;
228
+
229
+ return {
230
+ algorithm: algoName,
231
+ category,
232
+ executionTime: medianTime,
233
+ success: true,
234
+ nodeCount: graph.nodeCount,
235
+ edgeCount: graph.uniqueEdgeCount,
236
+ mode,
237
+ };
238
+ } catch (error) {
239
+ return {
240
+ algorithm: algoName,
241
+ category,
242
+ executionTime: 0,
243
+ success: false,
244
+ error: error instanceof Error ? error.message : String(error),
245
+ nodeCount: graph.nodeCount,
246
+ edgeCount: graph.uniqueEdgeCount,
247
+ mode,
248
+ };
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Get appropriate arguments for each algorithm
254
+ */
255
+ function getAlgorithmArgs(algoName: string, graph: Graph): unknown[] {
256
+ // Get random nodes for algorithms that need them
257
+ const nodes = Array.from(graph.nodes()).map((n) => n.id);
258
+ const randomNode = nodes[Math.floor(Math.random() * nodes.length)];
259
+ const randomNode2 = nodes[Math.floor(Math.random() * nodes.length)];
260
+
261
+ // Algorithm-specific argument mapping
262
+ switch (algoName) {
263
+ // Single source algorithms
264
+ case "breadthFirstSearch":
265
+ case "depthFirstSearch":
266
+ case "singleSourceShortestPathBFS":
267
+ case "singleSourceShortestPath":
268
+ case "dijkstra":
269
+ case "bellmanFord":
270
+ return [graph, randomNode];
271
+
272
+ // PageRank algorithms need directed graph
273
+ case "pageRank": {
274
+ const directedForPR = createDirectedGraph(graph);
275
+ return [directedForPR];
276
+ }
277
+
278
+ case "personalizedPageRank": {
279
+ const directedForPPR = createDirectedGraph(graph);
280
+ const personalNodes = [randomNode]; // Array of nodes for personalization
281
+ return [directedForPPR, personalNodes];
282
+ }
283
+
284
+ // Two node algorithms
285
+ case "shortestPathBFS":
286
+ case "dijkstraPath":
287
+ case "bellmanFordPath":
288
+ return [graph, randomNode, randomNode2];
289
+
290
+ // Component-specific algorithms
291
+ case "getConnectedComponent":
292
+ return [graph, randomNode];
293
+
294
+ // Algorithms that need specific graph types
295
+ case "topologicalSort":
296
+ case "findStronglyConnectedComponents":
297
+ case "stronglyConnectedComponents":
298
+ case "weaklyConnectedComponents":
299
+ case "isStronglyConnected":
300
+ case "isWeaklyConnected": {
301
+ // Create a directed version of the graph for these algorithms
302
+ const directedGraph = createDirectedGraph(graph);
303
+ return [directedGraph];
304
+ }
305
+
306
+ // Bipartite algorithms need bipartite graphs
307
+ case "bipartitePartition":
308
+ case "greedyBipartiteMatching":
309
+ case "maximumBipartiteMatching": {
310
+ const bipartiteGraph = createBipartiteGraph(Math.floor(graph.nodeCount / 2));
311
+ return [bipartiteGraph];
312
+ }
313
+
314
+ // Community detection algorithms
315
+ case "labelPropagation":
316
+ case "leiden":
317
+ case "louvain":
318
+ case "girvanNewman":
319
+ return [graph, {}]; // Pass empty options
320
+
321
+ // Default: just the graph
322
+ default:
323
+ return [graph];
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Create test graph appropriate for each algorithm category
329
+ */
330
+ function createTestGraph(nodes: number, edges: number, category: string): Graph {
331
+ const graph = new Graph();
332
+
333
+ // Add nodes
334
+ for (let i = 0; i < nodes; i++) {
335
+ graph.addNode(i);
336
+ }
337
+
338
+ // Create different graph structures for different algorithm categories
339
+ switch (category) {
340
+ case "shortestPath":
341
+ // Sparse connected graph for shortest path algorithms
342
+ createConnectedGraph(graph, Math.min(edges, nodes * 3));
343
+ break;
344
+
345
+ case "centrality":
346
+ // Small-world graph good for centrality analysis
347
+ createSmallWorldGraph(graph, Math.floor(edges / nodes));
348
+ break;
349
+
350
+ case "community":
351
+ // Graph with community structure
352
+ createCommunityGraph(graph, edges);
353
+ break;
354
+
355
+ default:
356
+ // Random connected graph
357
+ createConnectedGraph(graph, edges);
358
+ }
359
+
360
+ return graph;
361
+ }
362
+
363
+ /**
364
+ * Create a connected random graph
365
+ */
366
+ function createConnectedGraph(graph: Graph, targetEdges: number): void {
367
+ const nodes = graph.nodeCount;
368
+
369
+ // First create a spanning tree to ensure connectivity
370
+ for (let i = 1; i < nodes; i++) {
371
+ const parent = Math.floor(Math.random() * i);
372
+ graph.addEdge(parent, i);
373
+ }
374
+
375
+ // Add remaining edges randomly
376
+ let edgesAdded = nodes - 1;
377
+ while (edgesAdded < targetEdges) {
378
+ const source = Math.floor(Math.random() * nodes);
379
+ const target = Math.floor(Math.random() * nodes);
380
+
381
+ if (source !== target && !graph.hasEdge(source, target)) {
382
+ graph.addEdge(source, target);
383
+ edgesAdded++;
384
+ }
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Create small-world graph (Watts-Strogatz model)
390
+ */
391
+ function createSmallWorldGraph(graph: Graph, avgDegree: number): void {
392
+ const nodes = graph.nodeCount;
393
+ const k = Math.floor(avgDegree / 2);
394
+
395
+ // Ring lattice
396
+ for (let i = 0; i < nodes; i++) {
397
+ for (let j = 1; j <= k; j++) {
398
+ const target = (i + j) % nodes;
399
+ graph.addEdge(i, target);
400
+ }
401
+ }
402
+
403
+ // Rewire some edges
404
+ const rewireProb = 0.1;
405
+ for (let i = 0; i < nodes; i++) {
406
+ for (let j = 1; j <= k; j++) {
407
+ if (Math.random() < rewireProb) {
408
+ const oldTarget = (i + j) % nodes;
409
+ const newTarget = Math.floor(Math.random() * nodes);
410
+ if (newTarget !== i && !graph.hasEdge(i, newTarget)) {
411
+ graph.removeEdge(i, oldTarget);
412
+ graph.addEdge(i, newTarget);
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Create graph with community structure
421
+ */
422
+ function createCommunityGraph(graph: Graph, targetEdges: number): void {
423
+ const nodes = graph.nodeCount;
424
+ const communities = Math.min(5, Math.floor(nodes / 20)); // 5 communities max
425
+ const communitySize = Math.floor(nodes / communities);
426
+
427
+ let edgesAdded = 0;
428
+
429
+ // Create dense connections within communities
430
+ for (let c = 0; c < communities; c++) {
431
+ const start = c * communitySize;
432
+ const end = Math.min((c + 1) * communitySize, nodes);
433
+
434
+ for (let i = start; i < end && edgesAdded < targetEdges; i++) {
435
+ for (let j = i + 1; j < end && edgesAdded < targetEdges; j++) {
436
+ if (Math.random() < 0.8) { // High probability within community
437
+ graph.addEdge(i, j);
438
+ edgesAdded++;
439
+ }
440
+ }
441
+ }
442
+ }
443
+
444
+ // Add sparse connections between communities
445
+ while (edgesAdded < targetEdges) {
446
+ const source = Math.floor(Math.random() * nodes);
447
+ const target = Math.floor(Math.random() * nodes);
448
+
449
+ if (source !== target && !graph.hasEdge(source, target)) {
450
+ graph.addEdge(source, target);
451
+ edgesAdded++;
452
+ }
453
+ }
454
+ }
455
+
456
+ /**
457
+ * Create directed version of graph
458
+ */
459
+ function createDirectedGraph(undirectedGraph: Graph): Graph {
460
+ const directedGraph = new Graph({directed: true});
461
+
462
+ // Copy nodes
463
+ for (const node of undirectedGraph.nodes()) {
464
+ directedGraph.addNode(node.id);
465
+ }
466
+
467
+ // Copy edges as directed
468
+ for (const edge of undirectedGraph.edges()) {
469
+ directedGraph.addEdge(edge.source, edge.target);
470
+ }
471
+
472
+ return directedGraph;
473
+ }
474
+
475
+ /**
476
+ * Create bipartite graph
477
+ */
478
+ function createBipartiteGraph(nodesPerPartition: number): Graph {
479
+ const graph = new Graph();
480
+
481
+ // Add nodes (0 to n-1 in first partition, n to 2n-1 in second)
482
+ for (let i = 0; i < nodesPerPartition * 2; i++) {
483
+ graph.addNode(i);
484
+ }
485
+
486
+ // Add edges only between partitions
487
+ for (let i = 0; i < nodesPerPartition; i++) {
488
+ for (let j = nodesPerPartition; j < nodesPerPartition * 2; j++) {
489
+ if (Math.random() < 0.3) { // Sparse bipartite graph
490
+ graph.addEdge(i, j);
491
+ }
492
+ }
493
+ }
494
+
495
+ return graph;
496
+ }
497
+
498
+ /**
499
+ * Get total algorithm count
500
+ */
501
+ function getTotalAlgorithmCount(): number {
502
+ return Object.values(ALGORITHM_CATEGORIES).reduce((total, category) =>
503
+ total + category.algorithms.length, 0);
504
+ }
505
+
506
+ /**
507
+ * Display detailed results for full benchmark
508
+ */
509
+ function displayDetailedResults(results: BenchmarkResult[]): void {
510
+ console.log("\nšŸ“Š Detailed Results");
511
+ console.log("==================");
512
+
513
+ const categories = new Map<string, BenchmarkResult[]>();
514
+
515
+ for (const result of results) {
516
+ if (!categories.has(result.category)) {
517
+ categories.set(result.category, []);
518
+ }
519
+
520
+ categories.get(result.category)?.push(result);
521
+ }
522
+
523
+ for (const [category, categoryResults] of categories) {
524
+ console.log(`\n${category}:`);
525
+ console.log("-".repeat(category.length + 1));
526
+
527
+ const successful = categoryResults.filter((r) => r.success);
528
+ const failed = categoryResults.filter((r) => !r.success);
529
+
530
+ if (successful.length > 0) {
531
+ const avgTime = successful.reduce((sum, r) => sum + r.executionTime, 0) / successful.length;
532
+ console.log(` Average time: ${avgTime.toFixed(2)}ms`);
533
+ const minTime = Math.min(... successful.map((r) => r.executionTime));
534
+ const maxTime = Math.max(... successful.map((r) => r.executionTime));
535
+ console.log(` Range: ${minTime.toFixed(2)}ms - ${maxTime.toFixed(2)}ms`);
536
+ }
537
+
538
+ if (failed.length > 0) {
539
+ console.log(` Failed algorithms: ${failed.map((r) => r.algorithm).join(", ")}`);
540
+ }
541
+ }
542
+ }
543
+
544
+ // Run benchmark if called directly
545
+ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv[1] ?? ""}`) {
546
+ const mode = process.argv.includes("--quick") ? "quick" : "full";
547
+ runAllAlgorithmsBenchmark(mode);
548
+ }