@graphty/algorithms 1.3.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/README.md +358 -413
  2. package/dist/algorithms.js +564 -261
  3. package/dist/algorithms.js.map +1 -1
  4. package/dist/src/algorithms/centrality/betweenness.d.ts +10 -0
  5. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  6. package/dist/src/algorithms/centrality/betweenness.js +27 -6
  7. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  8. package/dist/src/algorithms/centrality/closeness.d.ts +11 -2
  9. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  10. package/dist/src/algorithms/centrality/closeness.js +17 -3
  11. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  12. package/dist/src/algorithms/centrality/degree.d.ts +7 -0
  13. package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
  14. package/dist/src/algorithms/centrality/degree.js +9 -6
  15. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  16. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +21 -3
  17. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -1
  18. package/dist/src/algorithms/centrality/delta-pagerank-simple.js +25 -7
  19. package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -1
  20. package/dist/src/algorithms/centrality/delta-pagerank.d.ts +28 -2
  21. package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -1
  22. package/dist/src/algorithms/centrality/delta-pagerank.js +30 -4
  23. package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -1
  24. package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -3
  25. package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
  26. package/dist/src/algorithms/centrality/eigenvector.js +11 -4
  27. package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
  28. package/dist/src/algorithms/centrality/hits.d.ts +10 -3
  29. package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
  30. package/dist/src/algorithms/centrality/hits.js +11 -4
  31. package/dist/src/algorithms/centrality/hits.js.map +1 -1
  32. package/dist/src/algorithms/centrality/index.d.ts +1 -1
  33. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  34. package/dist/src/algorithms/centrality/index.js +1 -1
  35. package/dist/src/algorithms/centrality/index.js.map +1 -1
  36. package/dist/src/algorithms/centrality/katz.d.ts +10 -3
  37. package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
  38. package/dist/src/algorithms/centrality/katz.js +13 -8
  39. package/dist/src/algorithms/centrality/katz.js.map +1 -1
  40. package/dist/src/algorithms/centrality/pagerank.d.ts +14 -0
  41. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  42. package/dist/src/algorithms/centrality/pagerank.js +16 -1
  43. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  44. package/dist/src/algorithms/community/girvan-newman.d.ts +2 -3
  45. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  46. package/dist/src/algorithms/community/girvan-newman.js +21 -4
  47. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  48. package/dist/src/algorithms/community/index.d.ts.map +1 -1
  49. package/dist/src/algorithms/community/index.js.map +1 -1
  50. package/dist/src/algorithms/community/label-propagation.d.ts +0 -3
  51. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  52. package/dist/src/algorithms/community/label-propagation.js +13 -6
  53. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  54. package/dist/src/algorithms/community/leiden.d.ts +0 -1
  55. package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
  56. package/dist/src/algorithms/community/leiden.js +37 -6
  57. package/dist/src/algorithms/community/leiden.js.map +1 -1
  58. package/dist/src/algorithms/community/louvain-optimized.d.ts +37 -0
  59. package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -1
  60. package/dist/src/algorithms/community/louvain-optimized.js +42 -7
  61. package/dist/src/algorithms/community/louvain-optimized.js.map +1 -1
  62. package/dist/src/algorithms/community/louvain.d.ts +2 -3
  63. package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
  64. package/dist/src/algorithms/community/louvain.js +19 -6
  65. package/dist/src/algorithms/community/louvain.js.map +1 -1
  66. package/dist/src/algorithms/community/modularity-utils.d.ts +0 -4
  67. package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -1
  68. package/dist/src/algorithms/community/modularity-utils.js +1 -5
  69. package/dist/src/algorithms/community/modularity-utils.js.map +1 -1
  70. package/dist/src/algorithms/components/connected.d.ts +23 -0
  71. package/dist/src/algorithms/components/connected.d.ts.map +1 -1
  72. package/dist/src/algorithms/components/connected.js +29 -3
  73. package/dist/src/algorithms/components/connected.js.map +1 -1
  74. package/dist/src/algorithms/matching/bipartite.d.ts +10 -0
  75. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
  76. package/dist/src/algorithms/matching/bipartite.js +10 -0
  77. package/dist/src/algorithms/matching/bipartite.js.map +1 -1
  78. package/dist/src/algorithms/matching/index.d.ts.map +1 -1
  79. package/dist/src/algorithms/matching/index.js.map +1 -1
  80. package/dist/src/algorithms/matching/isomorphism.d.ts +8 -0
  81. package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -1
  82. package/dist/src/algorithms/matching/isomorphism.js +36 -2
  83. package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
  84. package/dist/src/algorithms/mst/index.d.ts.map +1 -1
  85. package/dist/src/algorithms/mst/index.js.map +1 -1
  86. package/dist/src/algorithms/mst/kruskal.d.ts +14 -0
  87. package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
  88. package/dist/src/algorithms/mst/kruskal.js +17 -3
  89. package/dist/src/algorithms/mst/kruskal.js.map +1 -1
  90. package/dist/src/algorithms/mst/prim.d.ts +9 -0
  91. package/dist/src/algorithms/mst/prim.d.ts.map +1 -1
  92. package/dist/src/algorithms/mst/prim.js +9 -0
  93. package/dist/src/algorithms/mst/prim.js.map +1 -1
  94. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +10 -0
  95. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  96. package/dist/src/algorithms/shortest-path/bellman-ford.js +10 -0
  97. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  98. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +11 -4
  99. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -1
  100. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +18 -16
  101. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -1
  102. package/dist/src/algorithms/shortest-path/dijkstra.d.ts +15 -0
  103. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  104. package/dist/src/algorithms/shortest-path/dijkstra.js +15 -0
  105. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  106. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +17 -0
  107. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
  108. package/dist/src/algorithms/shortest-path/floyd-warshall.js +17 -0
  109. package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
  110. package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
  111. package/dist/src/algorithms/shortest-path/index.js.map +1 -1
  112. package/dist/src/algorithms/traversal/bfs-unified.d.ts +13 -0
  113. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -1
  114. package/dist/src/algorithms/traversal/bfs-unified.js +37 -0
  115. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -1
  116. package/dist/src/algorithms/traversal/bfs-variants.d.ts +23 -0
  117. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -1
  118. package/dist/src/algorithms/traversal/bfs-variants.js +34 -0
  119. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -1
  120. package/dist/src/algorithms/traversal/bfs.d.ts +1 -1
  121. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  122. package/dist/src/algorithms/traversal/bfs.js +1 -1
  123. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  124. package/dist/src/algorithms/traversal/dfs.d.ts +10 -0
  125. package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
  126. package/dist/src/algorithms/traversal/dfs.js +48 -0
  127. package/dist/src/algorithms/traversal/dfs.js.map +1 -1
  128. package/dist/src/algorithms/traversal/index.d.ts.map +1 -1
  129. package/dist/src/algorithms/traversal/index.js.map +1 -1
  130. package/dist/src/benchmark-all-algorithms.d.ts +2 -0
  131. package/dist/src/benchmark-all-algorithms.d.ts.map +1 -1
  132. package/dist/src/benchmark-all-algorithms.js +32 -3
  133. package/dist/src/benchmark-all-algorithms.js.map +1 -1
  134. package/dist/src/clustering/hierarchical.d.ts +8 -1
  135. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  136. package/dist/src/clustering/hierarchical.js +22 -6
  137. package/dist/src/clustering/hierarchical.js.map +1 -1
  138. package/dist/src/clustering/index.d.ts.map +1 -1
  139. package/dist/src/clustering/index.js.map +1 -1
  140. package/dist/src/clustering/k-core.d.ts +2 -5
  141. package/dist/src/clustering/k-core.d.ts.map +1 -1
  142. package/dist/src/clustering/k-core.js +14 -12
  143. package/dist/src/clustering/k-core.js.map +1 -1
  144. package/dist/src/clustering/mcl.d.ts +6 -0
  145. package/dist/src/clustering/mcl.d.ts.map +1 -1
  146. package/dist/src/clustering/mcl.js +34 -3
  147. package/dist/src/clustering/mcl.js.map +1 -1
  148. package/dist/src/clustering/spectral.d.ts +4 -1
  149. package/dist/src/clustering/spectral.d.ts.map +1 -1
  150. package/dist/src/clustering/spectral.js +61 -28
  151. package/dist/src/clustering/spectral.js.map +1 -1
  152. package/dist/src/core/graph.d.ts +45 -0
  153. package/dist/src/core/graph.d.ts.map +1 -1
  154. package/dist/src/core/graph.js +45 -1
  155. package/dist/src/core/graph.js.map +1 -1
  156. package/dist/src/data-structures/index.d.ts.map +1 -1
  157. package/dist/src/data-structures/index.js.map +1 -1
  158. package/dist/src/data-structures/priority-queue.d.ts +18 -1
  159. package/dist/src/data-structures/priority-queue.d.ts.map +1 -1
  160. package/dist/src/data-structures/priority-queue.js +26 -5
  161. package/dist/src/data-structures/priority-queue.js.map +1 -1
  162. package/dist/src/data-structures/union-find.d.ts +21 -0
  163. package/dist/src/data-structures/union-find.d.ts.map +1 -1
  164. package/dist/src/data-structures/union-find.js +21 -0
  165. package/dist/src/data-structures/union-find.js.map +1 -1
  166. package/dist/src/flow/ford-fulkerson.d.ts +4 -2
  167. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
  168. package/dist/src/flow/ford-fulkerson.js +31 -2
  169. package/dist/src/flow/ford-fulkerson.js.map +1 -1
  170. package/dist/src/flow/min-cut.d.ts +0 -3
  171. package/dist/src/flow/min-cut.d.ts.map +1 -1
  172. package/dist/src/flow/min-cut.js +17 -4
  173. package/dist/src/flow/min-cut.js.map +1 -1
  174. package/dist/src/index.d.ts +2 -1
  175. package/dist/src/index.d.ts.map +1 -1
  176. package/dist/src/index.js +2 -1
  177. package/dist/src/index.js.map +1 -1
  178. package/dist/src/link-prediction/adamic-adar.d.ts +26 -0
  179. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
  180. package/dist/src/link-prediction/adamic-adar.js +36 -10
  181. package/dist/src/link-prediction/adamic-adar.js.map +1 -1
  182. package/dist/src/link-prediction/common-neighbors.d.ts +21 -0
  183. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  184. package/dist/src/link-prediction/common-neighbors.js +27 -6
  185. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  186. package/dist/src/link-prediction/index.d.ts.map +1 -1
  187. package/dist/src/optimized/bit-packed.d.ts +103 -53
  188. package/dist/src/optimized/bit-packed.d.ts.map +1 -1
  189. package/dist/src/optimized/bit-packed.js +104 -54
  190. package/dist/src/optimized/bit-packed.js.map +1 -1
  191. package/dist/src/optimized/csr-graph.d.ts +87 -24
  192. package/dist/src/optimized/csr-graph.d.ts.map +1 -1
  193. package/dist/src/optimized/csr-graph.js +87 -24
  194. package/dist/src/optimized/csr-graph.js.map +1 -1
  195. package/dist/src/optimized/direction-optimized-bfs.d.ts +37 -16
  196. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -1
  197. package/dist/src/optimized/direction-optimized-bfs.js +39 -20
  198. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -1
  199. package/dist/src/optimized/graph-adapter.d.ts +58 -9
  200. package/dist/src/optimized/graph-adapter.d.ts.map +1 -1
  201. package/dist/src/optimized/graph-adapter.js +58 -10
  202. package/dist/src/optimized/graph-adapter.js.map +1 -1
  203. package/dist/src/optimized/index.d.ts +1 -1
  204. package/dist/src/optimized/index.d.ts.map +1 -1
  205. package/dist/src/optimized/index.js +3 -1
  206. package/dist/src/optimized/index.js.map +1 -1
  207. package/dist/src/pathfinding/astar.d.ts +25 -9
  208. package/dist/src/pathfinding/astar.d.ts.map +1 -1
  209. package/dist/src/pathfinding/astar.js +25 -10
  210. package/dist/src/pathfinding/astar.js.map +1 -1
  211. package/dist/src/pathfinding/utils.d.ts +15 -6
  212. package/dist/src/pathfinding/utils.d.ts.map +1 -1
  213. package/dist/src/pathfinding/utils.js +19 -7
  214. package/dist/src/pathfinding/utils.js.map +1 -1
  215. package/dist/src/research/grsbm.d.ts +0 -1
  216. package/dist/src/research/grsbm.d.ts.map +1 -1
  217. package/dist/src/research/grsbm.js +22 -9
  218. package/dist/src/research/grsbm.js.map +1 -1
  219. package/dist/src/research/index.d.ts.map +1 -1
  220. package/dist/src/research/index.js.map +1 -1
  221. package/dist/src/research/sync.d.ts +0 -1
  222. package/dist/src/research/sync.d.ts.map +1 -1
  223. package/dist/src/research/sync.js +28 -7
  224. package/dist/src/research/sync.js.map +1 -1
  225. package/dist/src/research/terahac.d.ts +0 -1
  226. package/dist/src/research/terahac.d.ts.map +1 -1
  227. package/dist/src/research/terahac.js +32 -4
  228. package/dist/src/research/terahac.js.map +1 -1
  229. package/dist/src/utils/graph-converters.d.ts +31 -0
  230. package/dist/src/utils/graph-converters.d.ts.map +1 -1
  231. package/dist/src/utils/graph-converters.js +31 -0
  232. package/dist/src/utils/graph-converters.js.map +1 -1
  233. package/dist/src/utils/graph-utilities.d.ts.map +1 -1
  234. package/dist/src/utils/graph-utilities.js.map +1 -1
  235. package/dist/src/utils/math-utilities.d.ts +11 -0
  236. package/dist/src/utils/math-utilities.d.ts.map +1 -1
  237. package/dist/src/utils/math-utilities.js +14 -5
  238. package/dist/src/utils/math-utilities.js.map +1 -1
  239. package/dist/src/utils/optimization-helpers.d.ts +9 -0
  240. package/dist/src/utils/optimization-helpers.d.ts.map +1 -1
  241. package/dist/src/utils/optimization-helpers.js +12 -0
  242. package/dist/src/utils/optimization-helpers.js.map +1 -1
  243. package/dist/src/utils/priorityQueue.d.ts +24 -0
  244. package/dist/src/utils/priorityQueue.d.ts.map +1 -1
  245. package/dist/src/utils/priorityQueue.js +34 -4
  246. package/dist/src/utils/priorityQueue.js.map +1 -1
  247. package/package.json +49 -45
  248. package/src/algorithms/centrality/betweenness.ts +34 -17
  249. package/src/algorithms/centrality/closeness.ts +34 -17
  250. package/src/algorithms/centrality/degree.ts +15 -19
  251. package/src/algorithms/centrality/delta-pagerank-simple.ts +36 -28
  252. package/src/algorithms/centrality/delta-pagerank.ts +34 -11
  253. package/src/algorithms/centrality/eigenvector.ts +14 -15
  254. package/src/algorithms/centrality/hits.ts +17 -17
  255. package/src/algorithms/centrality/index.ts +20 -15
  256. package/src/algorithms/centrality/katz.ts +17 -25
  257. package/src/algorithms/centrality/pagerank.ts +26 -17
  258. package/src/algorithms/community/girvan-newman.ts +39 -28
  259. package/src/algorithms/community/index.ts +6 -7
  260. package/src/algorithms/community/label-propagation.ts +20 -28
  261. package/src/algorithms/community/leiden.ts +61 -37
  262. package/src/algorithms/community/louvain-optimized.ts +49 -20
  263. package/src/algorithms/community/louvain.ts +35 -25
  264. package/src/algorithms/community/modularity-utils.ts +5 -17
  265. package/src/algorithms/components/connected.ts +40 -17
  266. package/src/algorithms/matching/bipartite.ts +17 -10
  267. package/src/algorithms/matching/index.ts +4 -4
  268. package/src/algorithms/matching/isomorphism.ts +53 -23
  269. package/src/algorithms/mst/index.ts +3 -4
  270. package/src/algorithms/mst/kruskal.ts +21 -6
  271. package/src/algorithms/mst/prim.ts +13 -4
  272. package/src/algorithms/shortest-path/bellman-ford.ts +16 -15
  273. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +28 -28
  274. package/src/algorithms/shortest-path/dijkstra.ts +23 -17
  275. package/src/algorithms/shortest-path/floyd-warshall.ts +21 -4
  276. package/src/algorithms/shortest-path/index.ts +5 -5
  277. package/src/algorithms/traversal/bfs-unified.ts +64 -60
  278. package/src/algorithms/traversal/bfs-variants.ts +61 -37
  279. package/src/algorithms/traversal/bfs.ts +1 -7
  280. package/src/algorithms/traversal/dfs.ts +61 -42
  281. package/src/algorithms/traversal/index.ts +3 -3
  282. package/src/benchmark-all-algorithms.ts +57 -25
  283. package/src/clustering/hierarchical.ts +40 -34
  284. package/src/clustering/index.ts +8 -8
  285. package/src/clustering/k-core.ts +26 -42
  286. package/src/clustering/mcl.ts +53 -23
  287. package/src/clustering/spectral.ts +91 -57
  288. package/src/core/graph.ts +54 -14
  289. package/src/data-structures/index.ts +2 -2
  290. package/src/data-structures/priority-queue.ts +36 -11
  291. package/src/data-structures/union-find.ts +22 -1
  292. package/src/flow/ford-fulkerson.ts +62 -35
  293. package/src/flow/min-cut.ts +43 -45
  294. package/src/index.ts +3 -2
  295. package/src/link-prediction/adamic-adar.ts +65 -51
  296. package/src/link-prediction/common-neighbors.ts +45 -36
  297. package/src/link-prediction/index.ts +1 -1
  298. package/src/optimized/bit-packed.ts +106 -56
  299. package/src/optimized/csr-graph.ts +93 -30
  300. package/src/optimized/direction-optimized-bfs.ts +44 -25
  301. package/src/optimized/graph-adapter.ts +64 -16
  302. package/src/optimized/index.ts +7 -9
  303. package/src/pathfinding/astar.ts +40 -25
  304. package/src/pathfinding/utils.ts +20 -13
  305. package/src/research/grsbm.ts +30 -24
  306. package/src/research/index.ts +4 -4
  307. package/src/research/sync.ts +39 -23
  308. package/src/research/terahac.ts +54 -20
  309. package/src/utils/graph-converters.ts +42 -14
  310. package/src/utils/graph-utilities.ts +11 -37
  311. package/src/utils/math-utilities.ts +17 -8
  312. package/src/utils/optimization-helpers.ts +27 -21
  313. package/src/utils/priorityQueue.ts +40 -6
@@ -1,5 +1,5 @@
1
- import {Graph} from "../../core/graph.js";
2
- import type {NodeId, TraversalOptions, TraversalResult} from "../../types/index.js";
1
+ import { Graph } from "../../core/graph.js";
2
+ import type { NodeId, TraversalOptions, TraversalResult } from "../../types/index.js";
3
3
 
4
4
  /**
5
5
  * Depth-First Search (DFS) implementation
@@ -18,12 +18,12 @@ export interface DFSOptions extends TraversalOptions {
18
18
 
19
19
  /**
20
20
  * Perform depth-first search starting from a given node
21
+ * @param graph - The input graph to traverse
22
+ * @param startNode - The node to start the DFS from
23
+ * @param options - DFS options (recursive mode, pre/post order, etc.)
24
+ * @returns Traversal result with visited nodes, order, and tree structure
21
25
  */
22
- export function depthFirstSearch(
23
- graph: Graph,
24
- startNode: NodeId,
25
- options: DFSOptions = {},
26
- ): TraversalResult {
26
+ export function depthFirstSearch(graph: Graph, startNode: NodeId, options: DFSOptions = {}): TraversalResult {
27
27
  if (!graph.hasNode(startNode)) {
28
28
  throw new Error(`Start node ${String(startNode)} not found in graph`);
29
29
  }
@@ -38,11 +38,17 @@ export function depthFirstSearch(
38
38
  dfsIterative(graph, startNode, visited, order, tree, options);
39
39
  }
40
40
 
41
- return {visited, order, tree};
41
+ return { visited, order, tree };
42
42
  }
43
43
 
44
44
  /**
45
45
  * Iterative DFS implementation (safer for browsers)
46
+ * @param graph - The input graph to traverse
47
+ * @param startNode - The node to start the DFS from
48
+ * @param visited - Set to track visited nodes
49
+ * @param order - Array to store traversal order
50
+ * @param tree - Map to store parent relationships
51
+ * @param options - DFS options (recursive mode, pre/post order, etc.)
46
52
  */
47
53
  function dfsIterative(
48
54
  graph: Graph,
@@ -58,8 +64,8 @@ function dfsIterative(
58
64
  return;
59
65
  }
60
66
 
61
- const stack: {node: NodeId, parent: NodeId | null, depth: number}[] = [];
62
- stack.push({node: startNode, parent: null, depth: 0});
67
+ const stack: { node: NodeId; parent: NodeId | null; depth: number }[] = [];
68
+ stack.push({ node: startNode, parent: null, depth: 0 });
63
69
 
64
70
  while (stack.length > 0) {
65
71
  const current = stack.pop();
@@ -89,7 +95,7 @@ function dfsIterative(
89
95
  for (let i = neighbors.length - 1; i >= 0; i--) {
90
96
  const neighbor = neighbors[i];
91
97
  if (neighbor !== undefined && !visited.has(neighbor)) {
92
- stack.push({node: neighbor, parent: current.node, depth: current.depth + 1});
98
+ stack.push({ node: neighbor, parent: current.node, depth: current.depth + 1 });
93
99
  }
94
100
  }
95
101
  }
@@ -98,6 +104,14 @@ function dfsIterative(
98
104
 
99
105
  /**
100
106
  * Recursive DFS implementation
107
+ * @param graph - The input graph to traverse
108
+ * @param node - Current node being visited
109
+ * @param visited - Set to track visited nodes
110
+ * @param order - Array to store traversal order
111
+ * @param tree - Map to store parent relationships
112
+ * @param options - DFS options (recursive mode, pre/post order, etc.)
113
+ * @param depth - Current depth in the traversal tree
114
+ * @param parent - Parent node of the current node
101
115
  */
102
116
  function dfsRecursive(
103
117
  graph: Graph,
@@ -145,6 +159,8 @@ function dfsRecursive(
145
159
 
146
160
  /**
147
161
  * Detect cycles in a graph using DFS
162
+ * @param graph - The input graph to check for cycles
163
+ * @returns True if the graph contains a cycle, false otherwise
148
164
  */
149
165
  export function hasCycleDFS(graph: Graph): boolean {
150
166
  const visited = new Set<NodeId>();
@@ -170,13 +186,13 @@ export function hasCycleDFS(graph: Graph): boolean {
170
186
 
171
187
  /**
172
188
  * Utility function for cycle detection in directed graphs
189
+ * @param graph - The directed graph to check
190
+ * @param node - Current node being visited
191
+ * @param visited - Set of all visited nodes
192
+ * @param recursionStack - Set of nodes in the current recursion path
193
+ * @returns True if a cycle is found, false otherwise
173
194
  */
174
- function hasCycleUtilDirected(
175
- graph: Graph,
176
- node: NodeId,
177
- visited: Set<NodeId>,
178
- recursionStack: Set<NodeId>,
179
- ): boolean {
195
+ function hasCycleUtilDirected(graph: Graph, node: NodeId, visited: Set<NodeId>, recursionStack: Set<NodeId>): boolean {
180
196
  visited.add(node);
181
197
  recursionStack.add(node);
182
198
 
@@ -198,13 +214,13 @@ function hasCycleUtilDirected(
198
214
 
199
215
  /**
200
216
  * Utility function for cycle detection in undirected graphs
217
+ * @param graph - The undirected graph to check
218
+ * @param node - Current node being visited
219
+ * @param visited - Set of all visited nodes
220
+ * @param parent - Parent node of the current node
221
+ * @returns True if a cycle is found, false otherwise
201
222
  */
202
- function hasCycleUtilUndirected(
203
- graph: Graph,
204
- node: NodeId,
205
- visited: Set<NodeId>,
206
- parent: NodeId | null,
207
- ): boolean {
223
+ function hasCycleUtilUndirected(graph: Graph, node: NodeId, visited: Set<NodeId>, parent: NodeId | null): boolean {
208
224
  visited.add(node);
209
225
 
210
226
  // Check all neighbors
@@ -224,6 +240,8 @@ function hasCycleUtilUndirected(
224
240
 
225
241
  /**
226
242
  * Topological sorting using DFS (for directed acyclic graphs)
243
+ * @param graph - The directed acyclic graph to sort
244
+ * @returns Array of node IDs in topological order, or null if graph has cycles
227
245
  */
228
246
  export function topologicalSort(graph: Graph): NodeId[] | null {
229
247
  if (!graph.isDirected) {
@@ -251,13 +269,12 @@ export function topologicalSort(graph: Graph): NodeId[] | null {
251
269
 
252
270
  /**
253
271
  * Utility function for topological sorting
272
+ * @param graph - The directed graph being sorted
273
+ * @param node - Current node being visited
274
+ * @param visited - Set of visited nodes
275
+ * @param stack - Stack to store nodes in reverse topological order
254
276
  */
255
- function topologicalSortUtil(
256
- graph: Graph,
257
- node: NodeId,
258
- visited: Set<NodeId>,
259
- stack: NodeId[],
260
- ): void {
277
+ function topologicalSortUtil(graph: Graph, node: NodeId, visited: Set<NodeId>, stack: NodeId[]): void {
261
278
  visited.add(node);
262
279
 
263
280
  // Visit all neighbors first
@@ -273,6 +290,8 @@ function topologicalSortUtil(
273
290
 
274
291
  /**
275
292
  * Find strongly connected components using DFS (for directed graphs)
293
+ * @param graph - The directed graph to analyze
294
+ * @returns Array of strongly connected components (each is an array of node IDs)
276
295
  */
277
296
  export function findStronglyConnectedComponents(graph: Graph): NodeId[][] {
278
297
  if (!graph.isDirected) {
@@ -310,13 +329,12 @@ export function findStronglyConnectedComponents(graph: Graph): NodeId[][] {
310
329
 
311
330
  /**
312
331
  * DFS to record finish order
332
+ * @param graph - The graph being traversed
333
+ * @param node - Current node being visited
334
+ * @param visited - Set of visited nodes
335
+ * @param finishOrder - Array to store nodes in order of completion
313
336
  */
314
- function dfsFinishOrder(
315
- graph: Graph,
316
- node: NodeId,
317
- visited: Set<NodeId>,
318
- finishOrder: NodeId[],
319
- ): void {
337
+ function dfsFinishOrder(graph: Graph, node: NodeId, visited: Set<NodeId>, finishOrder: NodeId[]): void {
320
338
  visited.add(node);
321
339
 
322
340
  for (const neighbor of Array.from(graph.neighbors(node))) {
@@ -330,13 +348,12 @@ function dfsFinishOrder(
330
348
 
331
349
  /**
332
350
  * DFS to collect nodes in a component
351
+ * @param graph - The graph being traversed
352
+ * @param node - Current node being visited
353
+ * @param visited - Set of visited nodes
354
+ * @param component - Array to collect nodes in the current component
333
355
  */
334
- function dfsCollectComponent(
335
- graph: Graph,
336
- node: NodeId,
337
- visited: Set<NodeId>,
338
- component: NodeId[],
339
- ): void {
356
+ function dfsCollectComponent(graph: Graph, node: NodeId, visited: Set<NodeId>, component: NodeId[]): void {
340
357
  visited.add(node);
341
358
  component.push(node);
342
359
 
@@ -349,9 +366,11 @@ function dfsCollectComponent(
349
366
 
350
367
  /**
351
368
  * Create transpose (reverse) of a directed graph
369
+ * @param graph - The directed graph to transpose
370
+ * @returns A new graph with all edges reversed
352
371
  */
353
372
  function createTransposeGraph(graph: Graph): Graph {
354
- const transpose = new Graph({directed: true});
373
+ const transpose = new Graph({ directed: true });
355
374
 
356
375
  // Add all nodes
357
376
  for (const node of Array.from(graph.nodes())) {
@@ -2,6 +2,6 @@
2
2
  * Graph traversal algorithms
3
3
  */
4
4
 
5
- export {breadthFirstSearch, isBipartite, shortestPathBFS, singleSourceShortestPathBFS} from "./bfs.js";
6
- export type {DFSOptions} from "./dfs.js";
7
- export {depthFirstSearch, findStronglyConnectedComponents, hasCycleDFS, topologicalSort} from "./dfs.js";
5
+ export { breadthFirstSearch, isBipartite, shortestPathBFS, singleSourceShortestPathBFS } from "./bfs.js";
6
+ export type { DFSOptions } from "./dfs.js";
7
+ export { depthFirstSearch, findStronglyConnectedComponents, hasCycleDFS, topologicalSort } from "./dfs.js";
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import * as algorithms from "./algorithms/index.js";
11
- import {Graph} from "./core/graph.js";
11
+ import { Graph } from "./core/graph.js";
12
12
 
13
13
  interface BenchmarkResult {
14
14
  algorithm: string;
@@ -35,8 +35,8 @@ const ALGORITHM_CATEGORIES = {
35
35
  ],
36
36
  config: {
37
37
  name: "Traversal",
38
- quick: {nodes: 1000, edges: 5000, runs: 3},
39
- full: {nodes: 10000, edges: 50000, runs: 10},
38
+ quick: { nodes: 1000, edges: 5000, runs: 3 },
39
+ full: { nodes: 10000, edges: 50000, runs: 10 },
40
40
  },
41
41
  },
42
42
  shortestPath: {
@@ -54,8 +54,8 @@ const ALGORITHM_CATEGORIES = {
54
54
  ],
55
55
  config: {
56
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},
57
+ quick: { nodes: 100, edges: 500, runs: 1 }, // Smaller for O(V³) algorithms
58
+ full: { nodes: 500, edges: 2500, runs: 3 },
59
59
  },
60
60
  },
61
61
  centrality: {
@@ -71,8 +71,8 @@ const ALGORITHM_CATEGORIES = {
71
71
  ],
72
72
  config: {
73
73
  name: "Centrality",
74
- quick: {nodes: 500, edges: 2500, runs: 1},
75
- full: {nodes: 2000, edges: 10000, runs: 3},
74
+ quick: { nodes: 500, edges: 2500, runs: 1 },
75
+ full: { nodes: 2000, edges: 10000, runs: 3 },
76
76
  },
77
77
  },
78
78
  components: {
@@ -90,44 +90,48 @@ const ALGORITHM_CATEGORIES = {
90
90
  ],
91
91
  config: {
92
92
  name: "Components",
93
- quick: {nodes: 2000, edges: 10000, runs: 3},
94
- full: {nodes: 10000, edges: 50000, runs: 10},
93
+ quick: { nodes: 2000, edges: 10000, runs: 3 },
94
+ full: { nodes: 10000, edges: 50000, runs: 10 },
95
95
  },
96
96
  },
97
97
  mst: {
98
98
  algorithms: ["kruskalMST", "primMST", "minimumSpanningTree"],
99
99
  config: {
100
100
  name: "Minimum Spanning Tree",
101
- quick: {nodes: 1000, edges: 5000, runs: 5},
102
- full: {nodes: 5000, edges: 25000, runs: 10},
101
+ quick: { nodes: 1000, edges: 5000, runs: 5 },
102
+ full: { nodes: 5000, edges: 25000, runs: 10 },
103
103
  },
104
104
  },
105
105
  community: {
106
106
  algorithms: ["girvanNewman", "labelPropagation", "leiden", "louvain"],
107
107
  config: {
108
108
  name: "Community Detection",
109
- quick: {nodes: 200, edges: 1000, runs: 1}, // Very expensive algorithms
110
- full: {nodes: 1000, edges: 5000, runs: 2},
109
+ quick: { nodes: 200, edges: 1000, runs: 1 }, // Very expensive algorithms
110
+ full: { nodes: 1000, edges: 5000, runs: 2 },
111
111
  },
112
112
  },
113
113
  matching: {
114
114
  algorithms: ["bipartitePartition", "greedyBipartiteMatching", "maximumBipartiteMatching"],
115
115
  config: {
116
116
  name: "Matching",
117
- quick: {nodes: 500, edges: 1000, runs: 3},
118
- full: {nodes: 2000, edges: 4000, runs: 5},
117
+ quick: { nodes: 500, edges: 1000, runs: 3 },
118
+ full: { nodes: 2000, edges: 4000, runs: 5 },
119
119
  },
120
120
  },
121
121
  } as const;
122
122
 
123
123
  /**
124
124
  * Main benchmark runner
125
+ * @param mode - The benchmark mode: "quick" for fast tests or "full" for comprehensive tests
126
+ * @returns Array of benchmark results for all tested algorithms
125
127
  */
126
128
  export function runAllAlgorithmsBenchmark(mode: "quick" | "full" = "full"): BenchmarkResult[] {
127
129
  const startTime = Date.now();
128
130
  const timeLimit = mode === "quick" ? 2 * 60 * 1000 : 60 * 60 * 1000; // 2 min or 1 hour
129
131
 
130
- console.log(`🚀 ${mode === "quick" ? "Quick" : "Comprehensive"} Benchmark - All ${String(getTotalAlgorithmCount())} Algorithms`);
132
+ console.log(
133
+ `🚀 ${mode === "quick" ? "Quick" : "Comprehensive"} Benchmark - All ${String(getTotalAlgorithmCount())} Algorithms`,
134
+ );
131
135
  console.log(`=${"=".repeat(60)}`);
132
136
  console.log(`Time limit: ${mode === "quick" ? "2 minutes" : "1 hour"}`);
133
137
  console.log(`Start time: ${new Date().toLocaleTimeString()}\n`);
@@ -175,7 +179,9 @@ export function runAllAlgorithmsBenchmark(mode: "quick" | "full" = "full"): Benc
175
179
  console.log("===================");
176
180
  console.log(`Total time: ${totalTime.toFixed(1)}s`);
177
181
  console.log(`Algorithms tested: ${String(totalTested)}`);
178
- console.log(`Success rate: ${String(totalPassed)}/${String(totalTested)} (${(totalPassed / totalTested * 100).toFixed(1)}%)`);
182
+ console.log(
183
+ `Success rate: ${String(totalPassed)}/${String(totalTested)} (${((totalPassed / totalTested) * 100).toFixed(1)}%)`,
184
+ );
179
185
 
180
186
  if (mode === "full") {
181
187
  displayDetailedResults(results);
@@ -186,6 +192,12 @@ export function runAllAlgorithmsBenchmark(mode: "quick" | "full" = "full"): Benc
186
192
 
187
193
  /**
188
194
  * Benchmark a single algorithm
195
+ * @param algoName - The name of the algorithm to benchmark
196
+ * @param category - The category the algorithm belongs to
197
+ * @param graph - The test graph to run the algorithm on
198
+ * @param runs - Number of times to run the algorithm for averaging
199
+ * @param mode - The benchmark mode (quick or full)
200
+ * @returns The benchmark result containing timing and success information
189
201
  */
190
202
  function benchmarkAlgorithm(
191
203
  algoName: string,
@@ -216,7 +228,7 @@ function benchmarkAlgorithm(
216
228
  const args = getAlgorithmArgs(algoName, graph);
217
229
  const start = performance.now();
218
230
 
219
- (algo as (... args: unknown[]) => unknown)(... args);
231
+ (algo as (...args: unknown[]) => unknown)(...args);
220
232
 
221
233
  const time = performance.now() - start;
222
234
  times.push(time);
@@ -251,6 +263,9 @@ function benchmarkAlgorithm(
251
263
 
252
264
  /**
253
265
  * Get appropriate arguments for each algorithm
266
+ * @param algoName - The name of the algorithm to get arguments for
267
+ * @param graph - The base graph to use for generating arguments
268
+ * @returns Array of arguments to pass to the algorithm function
254
269
  */
255
270
  function getAlgorithmArgs(algoName: string, graph: Graph): unknown[] {
256
271
  // Get random nodes for algorithms that need them
@@ -326,6 +341,10 @@ function getAlgorithmArgs(algoName: string, graph: Graph): unknown[] {
326
341
 
327
342
  /**
328
343
  * Create test graph appropriate for each algorithm category
344
+ * @param nodes - Number of nodes in the test graph
345
+ * @param edges - Target number of edges in the test graph
346
+ * @param category - The algorithm category to optimize the graph structure for
347
+ * @returns A new test graph with the specified structure
329
348
  */
330
349
  function createTestGraph(nodes: number, edges: number, category: string): Graph {
331
350
  const graph = new Graph();
@@ -362,6 +381,8 @@ function createTestGraph(nodes: number, edges: number, category: string): Graph
362
381
 
363
382
  /**
364
383
  * Create a connected random graph
384
+ * @param graph - The graph to add edges to
385
+ * @param targetEdges - Target number of edges to create
365
386
  */
366
387
  function createConnectedGraph(graph: Graph, targetEdges: number): void {
367
388
  const nodes = graph.nodeCount;
@@ -387,6 +408,8 @@ function createConnectedGraph(graph: Graph, targetEdges: number): void {
387
408
 
388
409
  /**
389
410
  * Create small-world graph (Watts-Strogatz model)
411
+ * @param graph - The graph to add edges to
412
+ * @param avgDegree - Target average degree for each node
390
413
  */
391
414
  function createSmallWorldGraph(graph: Graph, avgDegree: number): void {
392
415
  const nodes = graph.nodeCount;
@@ -418,6 +441,8 @@ function createSmallWorldGraph(graph: Graph, avgDegree: number): void {
418
441
 
419
442
  /**
420
443
  * Create graph with community structure
444
+ * @param graph - The graph to add edges to
445
+ * @param targetEdges - Target number of edges to create
421
446
  */
422
447
  function createCommunityGraph(graph: Graph, targetEdges: number): void {
423
448
  const nodes = graph.nodeCount;
@@ -433,7 +458,8 @@ function createCommunityGraph(graph: Graph, targetEdges: number): void {
433
458
 
434
459
  for (let i = start; i < end && edgesAdded < targetEdges; i++) {
435
460
  for (let j = i + 1; j < end && edgesAdded < targetEdges; j++) {
436
- if (Math.random() < 0.8) { // High probability within community
461
+ if (Math.random() < 0.8) {
462
+ // High probability within community
437
463
  graph.addEdge(i, j);
438
464
  edgesAdded++;
439
465
  }
@@ -455,9 +481,11 @@ function createCommunityGraph(graph: Graph, targetEdges: number): void {
455
481
 
456
482
  /**
457
483
  * Create directed version of graph
484
+ * @param undirectedGraph - The undirected graph to convert
485
+ * @returns A new directed graph with the same nodes and edges
458
486
  */
459
487
  function createDirectedGraph(undirectedGraph: Graph): Graph {
460
- const directedGraph = new Graph({directed: true});
488
+ const directedGraph = new Graph({ directed: true });
461
489
 
462
490
  // Copy nodes
463
491
  for (const node of undirectedGraph.nodes()) {
@@ -474,6 +502,8 @@ function createDirectedGraph(undirectedGraph: Graph): Graph {
474
502
 
475
503
  /**
476
504
  * Create bipartite graph
505
+ * @param nodesPerPartition - Number of nodes in each partition
506
+ * @returns A new bipartite graph with sparse connections between partitions
477
507
  */
478
508
  function createBipartiteGraph(nodesPerPartition: number): Graph {
479
509
  const graph = new Graph();
@@ -486,7 +516,8 @@ function createBipartiteGraph(nodesPerPartition: number): Graph {
486
516
  // Add edges only between partitions
487
517
  for (let i = 0; i < nodesPerPartition; i++) {
488
518
  for (let j = nodesPerPartition; j < nodesPerPartition * 2; j++) {
489
- if (Math.random() < 0.3) { // Sparse bipartite graph
519
+ if (Math.random() < 0.3) {
520
+ // Sparse bipartite graph
490
521
  graph.addEdge(i, j);
491
522
  }
492
523
  }
@@ -497,14 +528,15 @@ function createBipartiteGraph(nodesPerPartition: number): Graph {
497
528
 
498
529
  /**
499
530
  * Get total algorithm count
531
+ * @returns The total number of algorithms across all categories
500
532
  */
501
533
  function getTotalAlgorithmCount(): number {
502
- return Object.values(ALGORITHM_CATEGORIES).reduce((total, category) =>
503
- total + category.algorithms.length, 0);
534
+ return Object.values(ALGORITHM_CATEGORIES).reduce((total, category) => total + category.algorithms.length, 0);
504
535
  }
505
536
 
506
537
  /**
507
538
  * Display detailed results for full benchmark
539
+ * @param results - Array of benchmark results to display
508
540
  */
509
541
  function displayDetailedResults(results: BenchmarkResult[]): void {
510
542
  console.log("\n📊 Detailed Results");
@@ -530,8 +562,8 @@ function displayDetailedResults(results: BenchmarkResult[]): void {
530
562
  if (successful.length > 0) {
531
563
  const avgTime = successful.reduce((sum, r) => sum + r.executionTime, 0) / successful.length;
532
564
  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));
565
+ const minTime = Math.min(...successful.map((r) => r.executionTime));
566
+ const maxTime = Math.max(...successful.map((r) => r.executionTime));
535
567
  console.log(` Range: ${minTime.toFixed(2)}ms - ${maxTime.toFixed(2)}ms`);
536
568
  }
537
569
 
@@ -6,10 +6,12 @@
6
6
  * structure in graphs.
7
7
  */
8
8
 
9
- import type {Graph} from "../core/graph.js";
9
+ import type { Graph } from "../core/graph.js";
10
10
 
11
11
  /**
12
12
  * Convert Graph to adjacency set representation for clustering
13
+ * @param graph - The input graph to convert
14
+ * @returns Map of node IDs to sets of neighbor node IDs
13
15
  */
14
16
  function graphToAdjacencySet(graph: Graph): Map<string, Set<string>> {
15
17
  const adjacency = new Map<string, Set<string>>();
@@ -62,11 +64,10 @@ export type LinkageMethod = "single" | "complete" | "average" | "ward";
62
64
 
63
65
  /**
64
66
  * Compute distance between two nodes based on graph structure
67
+ * @param graph - Adjacency map representation of the graph
68
+ * @param distances - Map to store computed distances between nodes
65
69
  */
66
- function computeGraphDistance<T>(
67
- graph: Map<T, Set<T>>,
68
- distances: Map<T, Map<T, number>>,
69
- ): void {
70
+ function computeGraphDistance<T>(graph: Map<T, Set<T>>, distances: Map<T, Map<T, number>>): void {
70
71
  // Use BFS to compute shortest path distances
71
72
  for (const start of graph.keys()) {
72
73
  const dist = new Map<T, number>();
@@ -97,6 +98,11 @@ function computeGraphDistance<T>(
97
98
 
98
99
  /**
99
100
  * Compute distance between two clusters based on linkage method
101
+ * @param cluster1 - First cluster node
102
+ * @param cluster2 - Second cluster node
103
+ * @param distances - Precomputed distance matrix between nodes
104
+ * @param linkage - Linkage method to use for computing cluster distance
105
+ * @returns The distance between the two clusters
100
106
  */
101
107
  function clusterDistance<T>(
102
108
  cluster1: ClusterNode<T>,
@@ -126,9 +132,9 @@ function clusterDistance<T>(
126
132
 
127
133
  switch (linkage) {
128
134
  case "single":
129
- return Math.min(... allDistances);
135
+ return Math.min(...allDistances);
130
136
  case "complete":
131
- return Math.max(... allDistances);
137
+ return Math.max(...allDistances);
132
138
  case "average":
133
139
  return allDistances.reduce((a, b) => a + b, 0) / allDistances.length;
134
140
  case "ward": {
@@ -139,12 +145,15 @@ function clusterDistance<T>(
139
145
  return avgDist * ((size1 * size2) / (size1 + size2));
140
146
  }
141
147
  default:
142
- return Math.min(... allDistances);
148
+ return Math.min(...allDistances);
143
149
  }
144
150
  }
145
151
 
146
152
  /**
147
153
  * Internal implementation of agglomerative hierarchical clustering
154
+ * @param graph - Adjacency map representation of the graph
155
+ * @param linkage - Linkage method for cluster distance computation
156
+ * @returns Hierarchical clustering result with dendrogram and cluster assignments
148
157
  */
149
158
  function hierarchicalClusteringImpl<T>(
150
159
  graph: Map<T, Set<T>>,
@@ -155,7 +164,7 @@ function hierarchicalClusteringImpl<T>(
155
164
 
156
165
  if (n === 0) {
157
166
  return {
158
- root: {id: "empty", members: new Set(), distance: 0, height: 0},
167
+ root: { id: "empty", members: new Set(), distance: 0, height: 0 },
159
168
  dendrogram: [],
160
169
  clusters: new Map(),
161
170
  };
@@ -173,7 +182,7 @@ function hierarchicalClusteringImpl<T>(
173
182
  height: 0,
174
183
  }));
175
184
 
176
- const dendrogram: ClusterNode<T>[] = [... clusters];
185
+ const dendrogram: ClusterNode<T>[] = [...clusters];
177
186
  let clusterCount = n;
178
187
 
179
188
  // Distance matrix between clusters
@@ -220,9 +229,8 @@ function hierarchicalClusteringImpl<T>(
220
229
  continue;
221
230
  }
222
231
 
223
- const dist = distMap.get(cluster2.id) ??
224
- clusterDistances.get(cluster2.id)?.get(cluster1.id) ??
225
- Infinity;
232
+ const dist =
233
+ distMap.get(cluster2.id) ?? clusterDistances.get(cluster2.id)?.get(cluster1.id) ?? Infinity;
226
234
 
227
235
  if (dist < minDist) {
228
236
  minDist = dist;
@@ -239,7 +247,7 @@ function hierarchicalClusteringImpl<T>(
239
247
  id: `forest-${String(clusterCount++)}`,
240
248
  members: new Set(nodes),
241
249
  distance: Infinity,
242
- height: Math.max(... trees.map((t) => t.height)) + 1,
250
+ height: Math.max(...trees.map((t) => t.height)) + 1,
243
251
  trees,
244
252
  };
245
253
  dendrogram.push(forestRoot);
@@ -251,7 +259,7 @@ function hierarchicalClusteringImpl<T>(
251
259
  // Create new cluster
252
260
  const newCluster: ClusterNode<T> = {
253
261
  id: `cluster-${String(clusterCount++)}`,
254
- members: new Set([... mergeCluster1.members, ... mergeCluster2.members]),
262
+ members: new Set([...mergeCluster1.members, ...mergeCluster2.members]),
255
263
  left: mergeCluster1,
256
264
  right: mergeCluster2,
257
265
  distance: minDist,
@@ -301,7 +309,7 @@ function hierarchicalClusteringImpl<T>(
301
309
 
302
310
  if (!root) {
303
311
  return {
304
- root: {id: "empty", members: new Set(), distance: 0, height: 0},
312
+ root: { id: "empty", members: new Set(), distance: 0, height: 0 },
305
313
  dendrogram: [],
306
314
  clusters: new Map(),
307
315
  };
@@ -320,11 +328,11 @@ function hierarchicalClusteringImpl<T>(
320
328
 
321
329
  /**
322
330
  * Cut dendrogram at specific height to get clusters
331
+ * @param root - Root node of the dendrogram
332
+ * @param height - Height at which to cut the dendrogram
333
+ * @returns Array of sets representing clusters at the specified height
323
334
  */
324
- export function cutDendrogram<T>(
325
- root: ClusterNode<T>,
326
- height: number,
327
- ): Set<T>[] {
335
+ export function cutDendrogram<T>(root: ClusterNode<T>, height: number): Set<T>[] {
328
336
  const clusters: Set<T>[] = [];
329
337
 
330
338
  function traverse(node: ClusterNode<T>): void {
@@ -354,11 +362,11 @@ export function cutDendrogram<T>(
354
362
 
355
363
  /**
356
364
  * Cut dendrogram to get exactly k clusters
365
+ * @param root - Root node of the dendrogram
366
+ * @param k - Target number of clusters
367
+ * @returns Array of sets representing exactly k clusters
357
368
  */
358
- export function cutDendrogramKClusters<T>(
359
- root: ClusterNode<T>,
360
- k: number,
361
- ): Set<T>[] {
369
+ export function cutDendrogramKClusters<T>(root: ClusterNode<T>, k: number): Set<T>[] {
362
370
  if (k <= 0) {
363
371
  return [];
364
372
  }
@@ -390,17 +398,17 @@ export function cutDendrogramKClusters<T>(
390
398
  /**
391
399
  * Compute modularity-based hierarchical clustering
392
400
  * Uses modularity gain to decide merges
401
+ * @param graph - The input graph to cluster
402
+ * @returns Hierarchical clustering result with dendrogram and cluster assignments
393
403
  */
394
- export function modularityHierarchicalClustering(
395
- graph: Graph,
396
- ): HierarchicalClusteringResult<string> {
404
+ export function modularityHierarchicalClustering(graph: Graph): HierarchicalClusteringResult<string> {
397
405
  const adjacencySet = graphToAdjacencySet(graph);
398
406
  const nodes = Array.from(adjacencySet.keys());
399
407
  const n = nodes.length;
400
408
 
401
409
  if (n === 0) {
402
410
  return {
403
- root: {id: "empty", members: new Set(), distance: 0, height: 0},
411
+ root: { id: "empty", members: new Set(), distance: 0, height: 0 },
404
412
  dendrogram: [],
405
413
  clusters: new Map(),
406
414
  };
@@ -426,7 +434,7 @@ export function modularityHierarchicalClustering(
426
434
  height: 0,
427
435
  }));
428
436
 
429
- const dendrogram: ClusterNode<string>[] = [... clusters];
437
+ const dendrogram: ClusterNode<string>[] = [...clusters];
430
438
  let clusterCount = n;
431
439
 
432
440
  // Active clusters
@@ -466,8 +474,7 @@ export function modularityHierarchicalClustering(
466
474
  }
467
475
  }
468
476
 
469
- const gain = (edgesBetween / totalEdges) -
470
- (degreeProduct / (4 * totalEdges * totalEdges));
477
+ const gain = edgesBetween / totalEdges - degreeProduct / (4 * totalEdges * totalEdges);
471
478
 
472
479
  if (gain > maxGain) {
473
480
  maxGain = gain;
@@ -484,7 +491,7 @@ export function modularityHierarchicalClustering(
484
491
  // Create new cluster
485
492
  const newCluster: ClusterNode<string> = {
486
493
  id: `cluster-${String(clusterCount++)}`,
487
- members: new Set([... mergeCluster1.members, ... mergeCluster2.members]),
494
+ members: new Set([...mergeCluster1.members, ...mergeCluster2.members]),
488
495
  left: mergeCluster1,
489
496
  right: mergeCluster2,
490
497
  distance: -maxGain, // Use negative gain as distance
@@ -507,7 +514,7 @@ export function modularityHierarchicalClustering(
507
514
 
508
515
  if (!root) {
509
516
  return {
510
- root: {id: "empty", members: new Set(), distance: 0, height: 0},
517
+ root: { id: "empty", members: new Set(), distance: 0, height: 0 },
511
518
  dendrogram: [],
512
519
  clusters: new Map(),
513
520
  };
@@ -527,7 +534,6 @@ export function modularityHierarchicalClustering(
527
534
  /**
528
535
  * Agglomerative hierarchical clustering
529
536
  * Builds clusters bottom-up by merging closest pairs
530
- *
531
537
  * @param graph - Undirected graph - accepts Graph class or Map<T, Set<T>>
532
538
  * @param linkage - Linkage method for cluster distance
533
539
  * @returns Hierarchical clustering result