@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
@@ -8,9 +8,9 @@
8
8
  * "From Louvain to Leiden: guaranteeing well-connected communities"
9
9
  */
10
10
 
11
- import type {Graph} from "../../core/graph.js";
12
- import {graphToMap} from "../../utils/graph-converters.js";
13
- import {SeededRandom, shuffle} from "../../utils/math-utilities.js";
11
+ import type { Graph } from "../../core/graph.js";
12
+ import { graphToMap } from "../../utils/graph-converters.js";
13
+ import { SeededRandom, shuffle } from "../../utils/math-utilities.js";
14
14
 
15
15
  export interface LeidenOptions {
16
16
  resolution?: number;
@@ -28,17 +28,12 @@ export interface LeidenResult {
28
28
  /**
29
29
  * Internal implementation of Leiden algorithm for community detection
30
30
  * Improves upon Louvain by ensuring well-connected communities
31
+ * @param inputGraph - Map representation of the graph (node to neighbors with weights)
32
+ * @param options - Algorithm configuration options
33
+ * @returns Community assignments, modularity score, and iteration count
31
34
  */
32
- function leidenImpl(
33
- inputGraph: Map<string, Map<string, number>>,
34
- options: LeidenOptions = {},
35
- ): LeidenResult {
36
- const {
37
- resolution = 1.0,
38
- randomSeed = 42,
39
- maxIterations = 100,
40
- threshold = 1e-7,
41
- } = options;
35
+ function leidenImpl(inputGraph: Map<string, Map<string, number>>, options: LeidenOptions = {}): LeidenResult {
36
+ const { resolution = 1.0, randomSeed = 42, maxIterations = 100, threshold = 1e-7 } = options;
42
37
 
43
38
  // Handle empty graph
44
39
  if (inputGraph.size === 0) {
@@ -85,7 +80,7 @@ function leidenImpl(
85
80
  let improved = false;
86
81
 
87
82
  // Phase 1: Local moving of nodes (fast)
88
- const nodeOrder = [... nodes];
83
+ const nodeOrder = [...nodes];
89
84
  shuffle(nodeOrder, random);
90
85
 
91
86
  for (const node of nodeOrder) {
@@ -106,7 +101,13 @@ function leidenImpl(
106
101
  }
107
102
 
108
103
  const gain = calculateModularityGain(
109
- node, community, currentGraph, communities, degrees, totalWeight, resolution,
104
+ node,
105
+ community,
106
+ currentGraph,
107
+ communities,
108
+ degrees,
109
+ totalWeight,
110
+ resolution,
110
111
  );
111
112
 
112
113
  if (gain > bestGain) {
@@ -128,9 +129,7 @@ function leidenImpl(
128
129
  createAggregateNetwork(currentGraph, communities);
129
130
 
130
131
  // Refine partition using aggregate network
131
- const subsetPartition = refinePartition(
132
- currentGraph, communities,
133
- );
132
+ const subsetPartition = refinePartition(currentGraph, communities);
134
133
 
135
134
  // Apply refined partition
136
135
  for (const [node, newCommunity] of subsetPartition) {
@@ -158,7 +157,7 @@ function leidenImpl(
158
157
  } // No aggregation possible
159
158
 
160
159
  // Continue with aggregated network
161
- const {graph: aggregatedGraph} = aggregated;
160
+ const { graph: aggregatedGraph } = aggregated;
162
161
  currentGraph = aggregatedGraph;
163
162
  communities.clear();
164
163
  let communityId = 0;
@@ -195,6 +194,12 @@ function leidenImpl(
195
194
 
196
195
  /**
197
196
  * Calculate modularity of a partition
197
+ * @param graph - Map representation of the graph
198
+ * @param communities - Map of node IDs to community IDs
199
+ * @param degrees - Map of node IDs to their weighted degrees
200
+ * @param totalWeight - Total weight of all edges in the graph
201
+ * @param resolution - Resolution parameter for modularity calculation
202
+ * @returns The modularity score of the partition
198
203
  */
199
204
  function calculateModularity(
200
205
  graph: Map<string, Map<string, number>>,
@@ -236,11 +241,11 @@ function calculateModularity(
236
241
  }
237
242
 
238
243
  // Normalize and apply resolution
239
- modularity /= (2 * totalWeight);
244
+ modularity /= 2 * totalWeight;
240
245
 
241
246
  // Subtract expected edges
242
247
  for (const weight of communityWeights.values()) {
243
- modularity -= resolution * ((weight / (2 * totalWeight)) ** 2);
248
+ modularity -= resolution * (weight / (2 * totalWeight)) ** 2;
244
249
  }
245
250
 
246
251
  return modularity;
@@ -248,6 +253,10 @@ function calculateModularity(
248
253
 
249
254
  /**
250
255
  * Get communities of neighbors
256
+ * @param node - The node ID to get neighbor communities for
257
+ * @param graph - Map representation of the graph
258
+ * @param communities - Map of node IDs to community IDs
259
+ * @returns Map of community IDs to total edge weight connecting to that community
251
260
  */
252
261
  function getNeighborCommunities(
253
262
  node: string,
@@ -271,6 +280,14 @@ function getNeighborCommunities(
271
280
 
272
281
  /**
273
282
  * Calculate modularity gain from moving a node to a community
283
+ * @param node - The node ID to move
284
+ * @param targetCommunity - The target community ID
285
+ * @param graph - Map representation of the graph
286
+ * @param communities - Map of node IDs to community IDs
287
+ * @param degrees - Map of node IDs to their weighted degrees
288
+ * @param totalWeight - Total weight of all edges in the graph
289
+ * @param resolution - Resolution parameter for modularity calculation
290
+ * @returns The modularity gain from moving the node to the target community
274
291
  */
275
292
  function calculateModularityGain(
276
293
  node: string,
@@ -327,22 +344,26 @@ function calculateModularityGain(
327
344
 
328
345
  // Modularity gain calculation
329
346
  const m2 = 2 * totalWeight;
330
- const gain = ((weightToTarget - weightToCurrent) / totalWeight) -
331
- (resolution * nodeDegree * (targetDegree - currentDegree) / (m2 * m2));
347
+ const gain =
348
+ (weightToTarget - weightToCurrent) / totalWeight -
349
+ (resolution * nodeDegree * (targetDegree - currentDegree)) / (m2 * m2);
332
350
 
333
351
  return gain;
334
352
  }
335
353
 
336
354
  /**
337
355
  * Create aggregate network where each community becomes a super-node
356
+ * @param graph - Map representation of the graph
357
+ * @param communities - Map of node IDs to community IDs
358
+ * @returns Object with aggregate graph and node-to-community mapping
338
359
  */
339
360
  function createAggregateNetwork(
340
361
  graph: Map<string, Map<string, number>>,
341
362
  communities: Map<string, number>,
342
363
  ): {
343
- aggregateGraph: Map<number, Map<number, number>>;
344
- nodeMapping: Map<string, number>;
345
- } {
364
+ aggregateGraph: Map<number, Map<number, number>>;
365
+ nodeMapping: Map<string, number>;
366
+ } {
346
367
  const aggregateGraph = new Map<number, Map<number, number>>();
347
368
  const nodeMapping = new Map<string, number>();
348
369
 
@@ -375,12 +396,15 @@ function createAggregateNetwork(
375
396
  }
376
397
  }
377
398
 
378
- return {aggregateGraph, nodeMapping};
399
+ return { aggregateGraph, nodeMapping };
379
400
  }
380
401
 
381
402
  /**
382
403
  * Refine partition (Leiden-specific improvement)
383
404
  * Ensures well-connected communities by considering subsets
405
+ * @param originalGraph - Map representation of the original graph
406
+ * @param communities - Map of node IDs to community IDs
407
+ * @returns Refined community assignments with well-connected communities
384
408
  */
385
409
  function refinePartition(
386
410
  originalGraph: Map<string, Map<string, number>>,
@@ -448,6 +472,8 @@ function refinePartition(
448
472
 
449
473
  /**
450
474
  * Find connected components in undirected graph
475
+ * @param graph - Map representation of the graph (node to set of neighbors)
476
+ * @returns Array of connected components (each is a set of node IDs)
451
477
  */
452
478
  function findConnectedComponents(graph: Map<string, Set<string>>): Set<string>[] {
453
479
  const visited = new Set<string>();
@@ -486,14 +512,17 @@ function findConnectedComponents(graph: Map<string, Set<string>>): Set<string>[]
486
512
 
487
513
  /**
488
514
  * Aggregate communities into super-nodes
515
+ * @param graph - Map representation of the graph
516
+ * @param communities - Map of node IDs to community IDs
517
+ * @returns Object with aggregated graph and node-to-supernode mapping
489
518
  */
490
519
  function aggregateCommunities(
491
520
  graph: Map<string, Map<string, number>>,
492
521
  communities: Map<string, number>,
493
522
  ): {
494
- graph: Map<string, Map<string, number>>;
495
- mapping: Map<string, string>;
496
- } {
523
+ graph: Map<string, Map<string, number>>;
524
+ mapping: Map<string, string>;
525
+ } {
497
526
  const aggregated = new Map<string, Map<string, number>>();
498
527
  const mapping = new Map<string, string>();
499
528
 
@@ -546,13 +575,12 @@ function aggregateCommunities(
546
575
  }
547
576
  }
548
577
 
549
- return {graph: aggregated, mapping};
578
+ return { graph: aggregated, mapping };
550
579
  }
551
580
 
552
581
  /**
553
582
  * Leiden algorithm for community detection
554
583
  * Improves upon Louvain by ensuring well-connected communities
555
- *
556
584
  * @param graph - Undirected weighted graph - accepts Graph class or Map representation
557
585
  * @param options - Algorithm options
558
586
  * @returns Community assignments and modularity
@@ -560,12 +588,8 @@ function aggregateCommunities(
560
588
  * Time Complexity: O(m) per iteration, typically O(m log m) total
561
589
  * Space Complexity: O(n + m)
562
590
  */
563
- export function leiden(
564
- graph: Graph,
565
- options: LeidenOptions = {},
566
- ): LeidenResult {
591
+ export function leiden(graph: Graph, options: LeidenOptions = {}): LeidenResult {
567
592
  // Convert Graph to Map representation
568
593
  const graphMap = graphToMap(graph);
569
594
  return leidenImpl(graphMap, options);
570
595
  }
571
-
@@ -1,5 +1,5 @@
1
- import type {Graph} from "../../core/graph.js";
2
- import type {CommunityResult, NodeId} from "../../types/index.js";
1
+ import type { Graph } from "../../core/graph.js";
2
+ import type { CommunityResult, NodeId } from "../../types/index.js";
3
3
 
4
4
  /**
5
5
  * Optimized Louvain community detection algorithm with early pruning and threshold cycling
@@ -50,6 +50,9 @@ interface PruningStats {
50
50
  stableNodesPruned: number;
51
51
  }
52
52
 
53
+ /**
54
+ * Optimized Louvain implementation with early pruning and threshold cycling
55
+ */
53
56
  export class OptimizedLouvain {
54
57
  private graph: Graph;
55
58
  private communities: Map<NodeId, number>;
@@ -59,6 +62,10 @@ export class OptimizedLouvain {
59
62
  private totalWeight: number;
60
63
  private pruningStats: PruningStats;
61
64
 
65
+ /**
66
+ * Create an optimized Louvain detector for the given graph
67
+ * @param graph - The input graph to detect communities in
68
+ */
62
69
  constructor(graph: Graph) {
63
70
  this.graph = graph;
64
71
  this.communities = new Map();
@@ -75,6 +82,8 @@ export class OptimizedLouvain {
75
82
 
76
83
  /**
77
84
  * Run optimized Louvain algorithm
85
+ * @param options - Algorithm configuration options
86
+ * @returns Community detection result with communities, modularity, and iterations
78
87
  */
79
88
  public detectCommunities(options: OptimizedLouvainOptions = {}): CommunityResult {
80
89
  const {
@@ -95,14 +104,12 @@ export class OptimizedLouvain {
95
104
 
96
105
  while (iteration < maxIterations && improved) {
97
106
  // Get nodes in optimal processing order
98
- const orderedNodes = importanceOrdering ?
99
- this.getNodesInImportanceOrder() :
100
- Array.from(this.graph.nodes()).map((n) => n.id);
107
+ const orderedNodes = importanceOrdering
108
+ ? this.getNodesInImportanceOrder()
109
+ : Array.from(this.graph.nodes()).map((n) => n.id);
101
110
 
102
111
  // Apply adaptive threshold
103
- const threshold = thresholdCycling ?
104
- this.getAdaptiveThreshold(iteration, pruningThreshold) :
105
- 0;
112
+ const threshold = thresholdCycling ? this.getAdaptiveThreshold(iteration, pruningThreshold) : 0;
106
113
 
107
114
  // Perform local optimization
108
115
  improved = this.performLocalMoving(orderedNodes, {
@@ -193,6 +200,7 @@ export class OptimizedLouvain {
193
200
 
194
201
  /**
195
202
  * Get nodes ordered by importance (degree * log(weight))
203
+ * @returns Array of node IDs sorted by descending importance
196
204
  */
197
205
  private getNodesInImportanceOrder(): NodeId[] {
198
206
  const nodeImportance = new Map<NodeId, number>();
@@ -213,6 +221,12 @@ export class OptimizedLouvain {
213
221
 
214
222
  /**
215
223
  * Perform local moving phase with optimizations
224
+ * @param nodes - Array of node IDs to process
225
+ * @param options - Local moving options
226
+ * @param options.pruneLeaves - Whether to skip leaf nodes
227
+ * @param options.threshold - Minimum gain threshold for moves
228
+ * @param options.resolution - Resolution parameter for modularity
229
+ * @returns True if any improvement was made, false otherwise
216
230
  */
217
231
  private performLocalMoving(
218
232
  nodes: NodeId[],
@@ -222,7 +236,7 @@ export class OptimizedLouvain {
222
236
  resolution: number;
223
237
  },
224
238
  ): boolean {
225
- const {pruneLeaves, threshold, resolution} = options;
239
+ const { pruneLeaves, threshold, resolution } = options;
226
240
  let improvement = false;
227
241
  let hasChanged = true;
228
242
 
@@ -284,6 +298,8 @@ export class OptimizedLouvain {
284
298
 
285
299
  /**
286
300
  * Check if node is a leaf (degree 1)
301
+ * @param nodeId - The node ID to check
302
+ * @returns True if the node has degree 1, false otherwise
287
303
  */
288
304
  private isLeafNode(nodeId: NodeId): boolean {
289
305
  const degree = this.nodeDegrees.get(nodeId) ?? 0;
@@ -292,6 +308,9 @@ export class OptimizedLouvain {
292
308
 
293
309
  /**
294
310
  * Get adaptive threshold that decreases with iterations
311
+ * @param iteration - Current iteration number
312
+ * @param baseThreshold - Base threshold value to scale
313
+ * @returns Adaptive threshold value that decays over iterations
295
314
  */
296
315
  private getAdaptiveThreshold(iteration: number, baseThreshold: number): number {
297
316
  // Exponentially decay threshold with iterations
@@ -301,12 +320,12 @@ export class OptimizedLouvain {
301
320
 
302
321
  /**
303
322
  * Calculate modularity gain from moving a node to a community
323
+ * @param nodeId - The node ID to move
324
+ * @param targetCommunity - The target community ID
325
+ * @param resolution - Resolution parameter for modularity calculation
326
+ * @returns The modularity gain from moving the node
304
327
  */
305
- private calculateModularityGain(
306
- nodeId: NodeId,
307
- targetCommunity: number,
308
- resolution: number,
309
- ): number {
328
+ private calculateModularityGain(nodeId: NodeId, targetCommunity: number, resolution: number): number {
310
329
  const nodeWeight = this.nodeWeights.get(nodeId) ?? 0;
311
330
 
312
331
  // Sum of weights from node to target community
@@ -333,13 +352,16 @@ export class OptimizedLouvain {
333
352
  const targetWeight = this.communityWeights.get(targetCommunity) ?? 0;
334
353
 
335
354
  // Modularity gain formula
336
- const gain = (weightToTarget - ((resolution * nodeWeight * targetWeight) / (2 * this.totalWeight))) / this.totalWeight;
355
+ const gain =
356
+ (weightToTarget - (resolution * nodeWeight * targetWeight) / (2 * this.totalWeight)) / this.totalWeight;
337
357
 
338
358
  return gain;
339
359
  }
340
360
 
341
361
  /**
342
362
  * Remove node from community (for gain calculation)
363
+ * @param nodeId - The node ID to remove
364
+ * @param community - The community ID to remove from
343
365
  */
344
366
  private removeNodeFromCommunity(nodeId: NodeId, community: number): void {
345
367
  const nodeWeight = this.nodeWeights.get(nodeId) ?? 0;
@@ -349,6 +371,8 @@ export class OptimizedLouvain {
349
371
 
350
372
  /**
351
373
  * Add node to community
374
+ * @param nodeId - The node ID to add
375
+ * @param community - The community ID to add to
352
376
  */
353
377
  private addNodeToCommunity(nodeId: NodeId, community: number): void {
354
378
  const nodeWeight = this.nodeWeights.get(nodeId) ?? 0;
@@ -358,6 +382,8 @@ export class OptimizedLouvain {
358
382
 
359
383
  /**
360
384
  * Get neighboring communities of a node
385
+ * @param nodeId - The node ID to find neighbor communities for
386
+ * @returns Set of community IDs that neighbors belong to
361
387
  */
362
388
  private getNeighborCommunities(nodeId: NodeId): Set<number> {
363
389
  const communities = new Set<number>();
@@ -384,6 +410,8 @@ export class OptimizedLouvain {
384
410
 
385
411
  /**
386
412
  * Calculate total modularity
413
+ * @param resolution - Resolution parameter for modularity calculation
414
+ * @returns The modularity score of the current partition
387
415
  */
388
416
  private calculateModularity(resolution: number): number {
389
417
  if (this.totalWeight === 0) {
@@ -427,19 +455,20 @@ export class OptimizedLouvain {
427
455
 
428
456
  /**
429
457
  * Get pruning statistics
458
+ * @returns Statistics about nodes pruned during optimization
430
459
  */
431
460
  public getPruningStats(): PruningStats {
432
- return {... this.pruningStats};
461
+ return { ...this.pruningStats };
433
462
  }
434
463
  }
435
464
 
436
465
  /**
437
466
  * Optimized Louvain algorithm with automatic optimization selection
467
+ * @param graph - The input graph to detect communities in
468
+ * @param options - Algorithm configuration options
469
+ * @returns Community detection result with communities, modularity, and iterations
438
470
  */
439
- export function louvainOptimized(
440
- graph: Graph,
441
- options: OptimizedLouvainOptions = {},
442
- ): CommunityResult {
471
+ export function louvainOptimized(graph: Graph, options: OptimizedLouvainOptions = {}): CommunityResult {
443
472
  const optimizer = new OptimizedLouvain(graph);
444
473
  return optimizer.detectCommunities(options);
445
474
  }
@@ -1,12 +1,7 @@
1
- import {Graph} from "../../core/graph.js";
2
- import type {CommunityResult, LouvainOptions, NodeId} from "../../types/index.js";
3
- import {louvainOptimized} from "./louvain-optimized.js";
4
- import {
5
- calculateModularity,
6
- getNeighborCommunities,
7
- getNodeDegree,
8
- getTotalEdgeWeight,
9
- } from "./modularity-utils.js";
1
+ import { Graph } from "../../core/graph.js";
2
+ import type { CommunityResult, LouvainOptions, NodeId } from "../../types/index.js";
3
+ import { louvainOptimized } from "./louvain-optimized.js";
4
+ import { calculateModularity, getNeighborCommunities, getNodeDegree, getTotalEdgeWeight } from "./modularity-utils.js";
10
5
 
11
6
  /**
12
7
  * Louvain community detection algorithm
@@ -16,17 +11,13 @@ import {
16
11
  *
17
12
  * References:
18
13
  * - Blondel, V. D., Guillaume, J. L., Lambiotte, R., & Lefebvre, E. (2008).
19
- * Fast unfolding of communities in large networks.
20
- * Journal of statistical mechanics: theory and experiment, 2008(10), P10008.
21
- *
14
+ * Fast unfolding of communities in large networks.
15
+ * Journal of statistical mechanics: theory and experiment, 2008(10), P10008.
22
16
  * @param graph - The input graph
23
17
  * @param options - Algorithm options
24
18
  * @returns Community detection result with communities, modularity, and iterations
25
19
  */
26
- export function louvain(
27
- graph: Graph,
28
- options: LouvainOptions = {},
29
- ): CommunityResult {
20
+ export function louvain(graph: Graph, options: LouvainOptions = {}): CommunityResult {
30
21
  const resolution = options.resolution ?? 1.0;
31
22
  const maxIterations = options.maxIterations ?? 100;
32
23
  const tolerance = options.tolerance ?? 1e-6;
@@ -62,7 +53,7 @@ export function louvain(
62
53
  const newModularity = calculateModularity(graph, communities, resolution);
63
54
 
64
55
  // Check for convergence
65
- if ((newModularity - modularity) < tolerance) {
56
+ if (newModularity - modularity < tolerance) {
66
57
  break;
67
58
  }
68
59
 
@@ -80,6 +71,8 @@ export function louvain(
80
71
 
81
72
  /**
82
73
  * Initialize communities: each node in its own community
74
+ * @param graph - The input graph
75
+ * @returns Map of node IDs to their initial community IDs
83
76
  */
84
77
  function initializeCommunities(graph: Graph): Map<NodeId, number> {
85
78
  const communities = new Map<NodeId, number>();
@@ -96,12 +89,12 @@ function initializeCommunities(graph: Graph): Map<NodeId, number> {
96
89
  * Phase 1 of Louvain algorithm: Local optimization
97
90
  * For each node, try moving to neighboring communities and keep the move
98
91
  * that provides the best modularity gain.
92
+ * @param graph - The input graph
93
+ * @param communities - Map of node IDs to community IDs
94
+ * @param resolution - Resolution parameter for modularity calculation
95
+ * @returns True if any improvement was made, false otherwise
99
96
  */
100
- function louvainPhase1(
101
- graph: Graph,
102
- communities: Map<NodeId, number>,
103
- resolution: number,
104
- ): boolean {
97
+ function louvainPhase1(graph: Graph, communities: Map<NodeId, number>, resolution: number): boolean {
105
98
  let globalImprovement = false;
106
99
  let localImprovement = true;
107
100
 
@@ -118,7 +111,11 @@ function louvainPhase1(
118
111
 
119
112
  // Calculate current modularity contribution
120
113
  const currentModularity = nodeModularityContribution(
121
- graph, nodeId, currentCommunity, communities, resolution,
114
+ graph,
115
+ nodeId,
116
+ currentCommunity,
117
+ communities,
118
+ resolution,
122
119
  );
123
120
 
124
121
  let bestCommunity = currentCommunity;
@@ -133,7 +130,11 @@ function louvainPhase1(
133
130
  }
134
131
 
135
132
  const newModularity = nodeModularityContribution(
136
- graph, nodeId, neighborCommunity, communities, resolution,
133
+ graph,
134
+ nodeId,
135
+ neighborCommunity,
136
+ communities,
137
+ resolution,
137
138
  );
138
139
 
139
140
  if (newModularity > bestModularity) {
@@ -156,6 +157,12 @@ function louvainPhase1(
156
157
 
157
158
  /**
158
159
  * Calculate modularity contribution of a node to a specific community
160
+ * @param graph - The input graph
161
+ * @param nodeId - The node ID to evaluate
162
+ * @param community - The community to measure contribution to
163
+ * @param communities - Map of all node IDs to community IDs
164
+ * @param resolution - Resolution parameter for modularity calculation
165
+ * @returns The modularity contribution of the node to the specified community
159
166
  */
160
167
  function nodeModularityContribution(
161
168
  graph: Graph,
@@ -192,13 +199,16 @@ function nodeModularityContribution(
192
199
  }
193
200
 
194
201
  // Modularity formula: Q = (1/2m) * Σ[A_ij - (k_i * k_j)/(2m)] * δ(c_i, c_j)
195
- const modularityIncrease = (internalLinks - ((resolution * nodeDegree * communityDegree) / (2 * totalEdgeWeight))) / totalEdgeWeight;
202
+ const modularityIncrease =
203
+ (internalLinks - (resolution * nodeDegree * communityDegree) / (2 * totalEdgeWeight)) / totalEdgeWeight;
196
204
 
197
205
  return modularityIncrease;
198
206
  }
199
207
 
200
208
  /**
201
209
  * Extract final community structure
210
+ * @param communities - Map of node IDs to community IDs
211
+ * @returns Array of communities (each is an array of node IDs)
202
212
  */
203
213
  function extractCommunities(communities: Map<NodeId, number>): NodeId[][] {
204
214
  const communityMap = new Map<number, NodeId[]>();
@@ -3,15 +3,14 @@
3
3
  *
4
4
  * Used by: Louvain, Leiden, Girvan-Newman
5
5
  */
6
- import type {Graph} from "../../core/graph.js";
7
- import type {NodeId} from "../../types/index.js";
6
+ import type { Graph } from "../../core/graph.js";
7
+ import type { NodeId } from "../../types/index.js";
8
8
 
9
9
  /**
10
10
  * Calculate total edge weight in the graph
11
11
  *
12
12
  * For undirected graphs, each edge is counted once.
13
13
  * For directed graphs, each directed edge is counted once.
14
- *
15
14
  * @param graph - The input graph
16
15
  * @returns Total sum of edge weights (default weight is 1)
17
16
  */
@@ -29,7 +28,6 @@ export function getTotalEdgeWeight(graph: Graph): number {
29
28
  * Get the total degree (sum of edge weights) for a node
30
29
  *
31
30
  * Computes the weighted degree by summing all edge weights incident to the node.
32
- *
33
31
  * @param graph - The input graph
34
32
  * @param nodeId - The node ID to compute degree for
35
33
  * @returns The weighted degree of the node
@@ -49,17 +47,12 @@ export function getNodeDegree(graph: Graph, nodeId: NodeId): number {
49
47
  * Get communities of neighboring nodes
50
48
  *
51
49
  * Returns the set of community IDs that neighbors of the given node belong to.
52
- *
53
50
  * @param graph - The input graph
54
51
  * @param nodeId - The node to get neighbor communities for
55
52
  * @param communities - Map from node IDs to community IDs
56
53
  * @returns Set of community IDs that neighbors belong to
57
54
  */
58
- export function getNeighborCommunities(
59
- graph: Graph,
60
- nodeId: NodeId,
61
- communities: Map<NodeId, number>,
62
- ): Set<number> {
55
+ export function getNeighborCommunities(graph: Graph, nodeId: NodeId, communities: Map<NodeId, number>): Set<number> {
63
56
  const neighborCommunities = new Set<number>();
64
57
 
65
58
  for (const neighbor of graph.neighbors(nodeId)) {
@@ -85,17 +78,12 @@ export function getNeighborCommunities(
85
78
  * - k_i, k_j = degrees of nodes i and j
86
79
  * - γ = resolution parameter (higher values favor smaller communities)
87
80
  * - δ = Kronecker delta (1 if same community, 0 otherwise)
88
- *
89
81
  * @param graph - The input graph
90
82
  * @param communities - Map from node IDs to community IDs
91
83
  * @param resolution - Resolution parameter (default: 1.0)
92
84
  * @returns Modularity score (range typically -0.5 to 1.0)
93
85
  */
94
- export function calculateModularity(
95
- graph: Graph,
96
- communities: Map<NodeId, number>,
97
- resolution = 1.0,
98
- ): number {
86
+ export function calculateModularity(graph: Graph, communities: Map<NodeId, number>, resolution = 1.0): number {
99
87
  const totalEdgeWeight = getTotalEdgeWeight(graph);
100
88
  if (totalEdgeWeight === 0) {
101
89
  return 0;
@@ -137,7 +125,7 @@ export function calculateModularity(
137
125
  const degreeI = getNodeDegree(graph, nodeI.id);
138
126
  const degreeJ = getNodeDegree(graph, nodeJ.id);
139
127
 
140
- modularity += edgeWeight - ((resolution * degreeI * degreeJ) / (2 * totalEdgeWeight));
128
+ modularity += edgeWeight - (resolution * degreeI * degreeJ) / (2 * totalEdgeWeight);
141
129
  }
142
130
  }
143
131
  }