@graphty/algorithms 1.2.0 → 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 (337) hide show
  1. package/README.md +375 -276
  2. package/dist/algorithms.d.ts +42 -2
  3. package/dist/algorithms.js +11402 -2
  4. package/dist/algorithms.js.map +1 -1
  5. package/dist/src/algorithms/centrality/betweenness.d.ts +14 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +144 -169
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.d.ts +35 -1
  10. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  11. package/dist/src/algorithms/centrality/closeness.js +70 -149
  12. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  13. package/dist/src/algorithms/centrality/degree.d.ts +7 -0
  14. package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
  15. package/dist/src/algorithms/centrality/degree.js +12 -9
  16. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  17. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +57 -0
  18. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
  19. package/dist/src/algorithms/centrality/delta-pagerank-simple.js +304 -0
  20. package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
  21. package/dist/src/algorithms/centrality/delta-pagerank.d.ts +106 -0
  22. package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
  23. package/dist/src/algorithms/centrality/delta-pagerank.js +320 -0
  24. package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
  25. package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -3
  26. package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
  27. package/dist/src/algorithms/centrality/eigenvector.js +11 -4
  28. package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
  29. package/dist/src/algorithms/centrality/hits.d.ts +10 -3
  30. package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
  31. package/dist/src/algorithms/centrality/hits.js +11 -4
  32. package/dist/src/algorithms/centrality/hits.js.map +1 -1
  33. package/dist/src/algorithms/centrality/index.d.ts +3 -1
  34. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  35. package/dist/src/algorithms/centrality/index.js +2 -1
  36. package/dist/src/algorithms/centrality/index.js.map +1 -1
  37. package/dist/src/algorithms/centrality/katz.d.ts +10 -3
  38. package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
  39. package/dist/src/algorithms/centrality/katz.js +13 -8
  40. package/dist/src/algorithms/centrality/katz.js.map +1 -1
  41. package/dist/src/algorithms/centrality/pagerank.d.ts +31 -0
  42. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  43. package/dist/src/algorithms/centrality/pagerank.js +61 -1
  44. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  45. package/dist/src/algorithms/community/girvan-newman.d.ts +2 -3
  46. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  47. package/dist/src/algorithms/community/girvan-newman.js +67 -57
  48. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  49. package/dist/src/algorithms/community/index.d.ts +2 -0
  50. package/dist/src/algorithms/community/index.d.ts.map +1 -1
  51. package/dist/src/algorithms/community/index.js.map +1 -1
  52. package/dist/src/algorithms/community/label-propagation.d.ts +11 -4
  53. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  54. package/dist/src/algorithms/community/label-propagation.js +60 -38
  55. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  56. package/dist/src/algorithms/community/leiden.d.ts +3 -3
  57. package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
  58. package/dist/src/algorithms/community/leiden.js +70 -44
  59. package/dist/src/algorithms/community/leiden.js.map +1 -1
  60. package/dist/src/algorithms/community/louvain-optimized.d.ts +149 -0
  61. package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
  62. package/dist/src/algorithms/community/louvain-optimized.js +338 -0
  63. package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
  64. package/dist/src/algorithms/community/louvain.d.ts +2 -3
  65. package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
  66. package/dist/src/algorithms/community/louvain.js +35 -81
  67. package/dist/src/algorithms/community/louvain.js.map +1 -1
  68. package/dist/src/algorithms/community/modularity-utils.d.ts +55 -0
  69. package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
  70. package/dist/src/algorithms/community/modularity-utils.js +108 -0
  71. package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
  72. package/dist/src/algorithms/components/connected.d.ts +23 -0
  73. package/dist/src/algorithms/components/connected.d.ts.map +1 -1
  74. package/dist/src/algorithms/components/connected.js +29 -3
  75. package/dist/src/algorithms/components/connected.js.map +1 -1
  76. package/dist/src/algorithms/matching/bipartite.d.ts +10 -0
  77. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
  78. package/dist/src/algorithms/matching/bipartite.js +18 -40
  79. package/dist/src/algorithms/matching/bipartite.js.map +1 -1
  80. package/dist/src/algorithms/matching/index.d.ts.map +1 -1
  81. package/dist/src/algorithms/matching/index.js.map +1 -1
  82. package/dist/src/algorithms/matching/isomorphism.d.ts +8 -0
  83. package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -1
  84. package/dist/src/algorithms/matching/isomorphism.js +36 -2
  85. package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
  86. package/dist/src/algorithms/mst/index.d.ts.map +1 -1
  87. package/dist/src/algorithms/mst/index.js.map +1 -1
  88. package/dist/src/algorithms/mst/kruskal.d.ts +14 -0
  89. package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
  90. package/dist/src/algorithms/mst/kruskal.js +17 -3
  91. package/dist/src/algorithms/mst/kruskal.js.map +1 -1
  92. package/dist/src/algorithms/mst/prim.d.ts +9 -0
  93. package/dist/src/algorithms/mst/prim.d.ts.map +1 -1
  94. package/dist/src/algorithms/mst/prim.js +9 -0
  95. package/dist/src/algorithms/mst/prim.js.map +1 -1
  96. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +10 -0
  97. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  98. package/dist/src/algorithms/shortest-path/bellman-ford.js +11 -12
  99. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  100. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +44 -0
  101. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
  102. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +195 -0
  103. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
  104. package/dist/src/algorithms/shortest-path/dijkstra.d.ts +20 -2
  105. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  106. package/dist/src/algorithms/shortest-path/dijkstra.js +30 -14
  107. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  108. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +17 -0
  109. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
  110. package/dist/src/algorithms/shortest-path/floyd-warshall.js +17 -0
  111. package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
  112. package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
  113. package/dist/src/algorithms/shortest-path/index.js.map +1 -1
  114. package/dist/src/algorithms/traversal/bfs-unified.d.ts +42 -0
  115. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
  116. package/dist/src/algorithms/traversal/bfs-unified.js +370 -0
  117. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
  118. package/dist/src/algorithms/traversal/bfs-variants.d.ts +77 -0
  119. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
  120. package/dist/src/algorithms/traversal/bfs-variants.js +402 -0
  121. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
  122. package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
  123. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  124. package/dist/src/algorithms/traversal/bfs.js +5 -182
  125. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  126. package/dist/src/algorithms/traversal/dfs.d.ts +10 -0
  127. package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
  128. package/dist/src/algorithms/traversal/dfs.js +48 -0
  129. package/dist/src/algorithms/traversal/dfs.js.map +1 -1
  130. package/dist/src/algorithms/traversal/index.d.ts.map +1 -1
  131. package/dist/src/algorithms/traversal/index.js.map +1 -1
  132. package/dist/src/benchmark-all-algorithms.d.ts +25 -0
  133. package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
  134. package/dist/src/benchmark-all-algorithms.js +491 -0
  135. package/dist/src/benchmark-all-algorithms.js.map +1 -0
  136. package/dist/src/clustering/hierarchical.d.ts +23 -15
  137. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  138. package/dist/src/clustering/hierarchical.js +226 -224
  139. package/dist/src/clustering/hierarchical.js.map +1 -1
  140. package/dist/src/clustering/index.d.ts +4 -2
  141. package/dist/src/clustering/index.d.ts.map +1 -1
  142. package/dist/src/clustering/index.js +2 -2
  143. package/dist/src/clustering/index.js.map +1 -1
  144. package/dist/src/clustering/k-core.d.ts +17 -19
  145. package/dist/src/clustering/k-core.d.ts.map +1 -1
  146. package/dist/src/clustering/k-core.js +68 -30
  147. package/dist/src/clustering/k-core.js.map +1 -1
  148. package/dist/src/clustering/mcl.d.ts +6 -0
  149. package/dist/src/clustering/mcl.d.ts.map +1 -1
  150. package/dist/src/clustering/mcl.js +34 -3
  151. package/dist/src/clustering/mcl.js.map +1 -1
  152. package/dist/src/clustering/spectral.d.ts +11 -0
  153. package/dist/src/clustering/spectral.d.ts.map +1 -1
  154. package/dist/src/clustering/spectral.js +99 -47
  155. package/dist/src/clustering/spectral.js.map +1 -1
  156. package/dist/src/core/graph.d.ts +45 -0
  157. package/dist/src/core/graph.d.ts.map +1 -1
  158. package/dist/src/core/graph.js +49 -5
  159. package/dist/src/core/graph.js.map +1 -1
  160. package/dist/src/data-structures/index.d.ts.map +1 -1
  161. package/dist/src/data-structures/index.js.map +1 -1
  162. package/dist/src/data-structures/priority-queue.d.ts +18 -1
  163. package/dist/src/data-structures/priority-queue.d.ts.map +1 -1
  164. package/dist/src/data-structures/priority-queue.js +26 -5
  165. package/dist/src/data-structures/priority-queue.js.map +1 -1
  166. package/dist/src/data-structures/union-find.d.ts +21 -0
  167. package/dist/src/data-structures/union-find.d.ts.map +1 -1
  168. package/dist/src/data-structures/union-find.js +21 -0
  169. package/dist/src/data-structures/union-find.js.map +1 -1
  170. package/dist/src/flow/ford-fulkerson.d.ts +20 -12
  171. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
  172. package/dist/src/flow/ford-fulkerson.js +170 -217
  173. package/dist/src/flow/ford-fulkerson.js.map +1 -1
  174. package/dist/src/flow/min-cut.d.ts +6 -8
  175. package/dist/src/flow/min-cut.d.ts.map +1 -1
  176. package/dist/src/flow/min-cut.js +34 -12
  177. package/dist/src/flow/min-cut.js.map +1 -1
  178. package/dist/src/index.d.ts +3 -1
  179. package/dist/src/index.d.ts.map +1 -1
  180. package/dist/src/index.js +6 -1
  181. package/dist/src/index.js.map +1 -1
  182. package/dist/src/link-prediction/adamic-adar.d.ts +26 -0
  183. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
  184. package/dist/src/link-prediction/adamic-adar.js +47 -30
  185. package/dist/src/link-prediction/adamic-adar.js.map +1 -1
  186. package/dist/src/link-prediction/common-neighbors.d.ts +21 -0
  187. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  188. package/dist/src/link-prediction/common-neighbors.js +31 -14
  189. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  190. package/dist/src/link-prediction/index.d.ts.map +1 -1
  191. package/dist/src/optimized/bit-packed.d.ts +193 -0
  192. package/dist/src/optimized/bit-packed.d.ts.map +1 -0
  193. package/dist/src/optimized/bit-packed.js +342 -0
  194. package/dist/src/optimized/bit-packed.js.map +1 -0
  195. package/dist/src/optimized/csr-graph.d.ts +149 -0
  196. package/dist/src/optimized/csr-graph.d.ts.map +1 -0
  197. package/dist/src/optimized/csr-graph.js +404 -0
  198. package/dist/src/optimized/csr-graph.js.map +1 -0
  199. package/dist/src/optimized/direction-optimized-bfs.d.ts +95 -0
  200. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
  201. package/dist/src/optimized/direction-optimized-bfs.js +242 -0
  202. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
  203. package/dist/src/optimized/graph-adapter.d.ts +111 -0
  204. package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
  205. package/dist/src/optimized/graph-adapter.js +194 -0
  206. package/dist/src/optimized/graph-adapter.js.map +1 -0
  207. package/dist/src/optimized/index.d.ts +14 -0
  208. package/dist/src/optimized/index.d.ts.map +1 -0
  209. package/dist/src/optimized/index.js +30 -0
  210. package/dist/src/optimized/index.js.map +1 -0
  211. package/dist/src/pathfinding/astar.d.ts +25 -9
  212. package/dist/src/pathfinding/astar.d.ts.map +1 -1
  213. package/dist/src/pathfinding/astar.js +25 -10
  214. package/dist/src/pathfinding/astar.js.map +1 -1
  215. package/dist/src/pathfinding/utils.d.ts +15 -6
  216. package/dist/src/pathfinding/utils.d.ts.map +1 -1
  217. package/dist/src/pathfinding/utils.js +19 -7
  218. package/dist/src/pathfinding/utils.js.map +1 -1
  219. package/dist/src/research/grsbm.d.ts +0 -1
  220. package/dist/src/research/grsbm.d.ts.map +1 -1
  221. package/dist/src/research/grsbm.js +28 -23
  222. package/dist/src/research/grsbm.js.map +1 -1
  223. package/dist/src/research/index.d.ts.map +1 -1
  224. package/dist/src/research/index.js.map +1 -1
  225. package/dist/src/research/sync.d.ts +0 -1
  226. package/dist/src/research/sync.d.ts.map +1 -1
  227. package/dist/src/research/sync.js +31 -36
  228. package/dist/src/research/sync.js.map +1 -1
  229. package/dist/src/research/terahac.d.ts +2 -1
  230. package/dist/src/research/terahac.d.ts.map +1 -1
  231. package/dist/src/research/terahac.js +39 -7
  232. package/dist/src/research/terahac.js.map +1 -1
  233. package/dist/src/types/index.d.ts +8 -0
  234. package/dist/src/types/index.d.ts.map +1 -1
  235. package/dist/src/utils/algorithm-utilities.d.ts +2 -0
  236. package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
  237. package/dist/src/utils/algorithm-utilities.js +2 -0
  238. package/dist/src/utils/algorithm-utilities.js.map +1 -0
  239. package/dist/src/utils/graph-converters.d.ts +110 -0
  240. package/dist/src/utils/graph-converters.d.ts.map +1 -0
  241. package/dist/src/utils/graph-converters.js +227 -0
  242. package/dist/src/utils/graph-converters.js.map +1 -0
  243. package/dist/src/utils/graph-utilities.d.ts +62 -0
  244. package/dist/src/utils/graph-utilities.d.ts.map +1 -0
  245. package/dist/src/utils/graph-utilities.js +148 -0
  246. package/dist/src/utils/graph-utilities.js.map +1 -0
  247. package/dist/src/utils/index.d.ts +5 -0
  248. package/dist/src/utils/index.d.ts.map +1 -0
  249. package/dist/src/utils/index.js +5 -0
  250. package/dist/src/utils/index.js.map +1 -0
  251. package/dist/src/utils/math-utilities.d.ts +63 -0
  252. package/dist/src/utils/math-utilities.d.ts.map +1 -0
  253. package/dist/src/utils/math-utilities.js +132 -0
  254. package/dist/src/utils/math-utilities.js.map +1 -0
  255. package/dist/src/utils/matrix-utilities.d.ts +2 -0
  256. package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
  257. package/dist/src/utils/matrix-utilities.js +2 -0
  258. package/dist/src/utils/matrix-utilities.js.map +1 -0
  259. package/dist/src/utils/optimization-helpers.d.ts +42 -0
  260. package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
  261. package/dist/src/utils/optimization-helpers.js +59 -0
  262. package/dist/src/utils/optimization-helpers.js.map +1 -0
  263. package/dist/src/utils/priorityQueue.d.ts +24 -0
  264. package/dist/src/utils/priorityQueue.d.ts.map +1 -1
  265. package/dist/src/utils/priorityQueue.js +34 -4
  266. package/dist/src/utils/priorityQueue.js.map +1 -1
  267. package/package.json +58 -39
  268. package/src/algorithms/centrality/betweenness.ts +185 -200
  269. package/src/algorithms/centrality/closeness.ts +93 -194
  270. package/src/algorithms/centrality/degree.ts +18 -22
  271. package/src/algorithms/centrality/delta-pagerank-simple.ts +374 -0
  272. package/src/algorithms/centrality/delta-pagerank.ts +458 -0
  273. package/src/algorithms/centrality/eigenvector.ts +14 -15
  274. package/src/algorithms/centrality/hits.ts +17 -17
  275. package/src/algorithms/centrality/index.ts +20 -13
  276. package/src/algorithms/centrality/katz.ts +17 -25
  277. package/src/algorithms/centrality/pagerank.ts +91 -16
  278. package/src/algorithms/community/girvan-newman.ts +90 -86
  279. package/src/algorithms/community/index.ts +6 -5
  280. package/src/algorithms/community/label-propagation.ts +69 -48
  281. package/src/algorithms/community/leiden.ts +88 -65
  282. package/src/algorithms/community/louvain-optimized.ts +474 -0
  283. package/src/algorithms/community/louvain.ts +52 -122
  284. package/src/algorithms/community/modularity-utils.ts +134 -0
  285. package/src/algorithms/components/connected.ts +40 -17
  286. package/src/algorithms/matching/bipartite.ts +24 -53
  287. package/src/algorithms/matching/index.ts +4 -4
  288. package/src/algorithms/matching/isomorphism.ts +53 -23
  289. package/src/algorithms/mst/index.ts +3 -4
  290. package/src/algorithms/mst/kruskal.ts +21 -6
  291. package/src/algorithms/mst/prim.ts +13 -4
  292. package/src/algorithms/shortest-path/bellman-ford.ts +16 -28
  293. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
  294. package/src/algorithms/shortest-path/dijkstra.ts +38 -30
  295. package/src/algorithms/shortest-path/floyd-warshall.ts +21 -4
  296. package/src/algorithms/shortest-path/index.ts +5 -5
  297. package/src/algorithms/traversal/bfs-unified.ts +437 -0
  298. package/src/algorithms/traversal/bfs-variants.ts +520 -0
  299. package/src/algorithms/traversal/bfs.ts +5 -229
  300. package/src/algorithms/traversal/dfs.ts +61 -42
  301. package/src/algorithms/traversal/index.ts +3 -3
  302. package/src/benchmark-all-algorithms.ts +580 -0
  303. package/src/clustering/hierarchical.ts +268 -272
  304. package/src/clustering/index.ts +8 -6
  305. package/src/clustering/k-core.ts +93 -61
  306. package/src/clustering/mcl.ts +53 -23
  307. package/src/clustering/spectral.ts +130 -72
  308. package/src/core/graph.ts +58 -18
  309. package/src/data-structures/index.ts +2 -2
  310. package/src/data-structures/priority-queue.ts +36 -11
  311. package/src/data-structures/union-find.ts +22 -1
  312. package/src/flow/ford-fulkerson.ts +221 -262
  313. package/src/flow/min-cut.ts +59 -51
  314. package/src/index.ts +9 -2
  315. package/src/link-prediction/adamic-adar.ts +75 -74
  316. package/src/link-prediction/common-neighbors.ts +49 -49
  317. package/src/link-prediction/index.ts +1 -1
  318. package/src/optimized/bit-packed.ts +390 -0
  319. package/src/optimized/csr-graph.ts +518 -0
  320. package/src/optimized/direction-optimized-bfs.ts +310 -0
  321. package/src/optimized/graph-adapter.ts +248 -0
  322. package/src/optimized/index.ts +34 -0
  323. package/src/pathfinding/astar.ts +40 -25
  324. package/src/pathfinding/utils.ts +20 -13
  325. package/src/research/grsbm.ts +36 -39
  326. package/src/research/index.ts +4 -4
  327. package/src/research/sync.ts +41 -54
  328. package/src/research/terahac.ts +63 -21
  329. package/src/types/index.ts +8 -0
  330. package/src/utils/algorithm-utilities.ts +2 -0
  331. package/src/utils/graph-converters.ts +269 -0
  332. package/src/utils/graph-utilities.ts +173 -0
  333. package/src/utils/index.ts +4 -0
  334. package/src/utils/math-utilities.ts +149 -0
  335. package/src/utils/matrix-utilities.ts +2 -0
  336. package/src/utils/optimization-helpers.ts +87 -0
  337. package/src/utils/priorityQueue.ts +40 -6
@@ -1,5 +1,6 @@
1
- import type {Graph} from "../../core/graph.js";
2
- import type {NodeId} from "../../types/index.js";
1
+ import type { Graph } from "../../core/graph.js";
2
+ import type { NodeId } from "../../types/index.js";
3
+ import { bfsWithPathCounting } from "../traversal/bfs-variants.js";
3
4
 
4
5
  /**
5
6
  * Betweenness centrality implementation using Brandes' algorithm
@@ -20,151 +21,218 @@ export interface BetweennessCentralityOptions {
20
21
  * Whether to use endpoints in path counting (default: false)
21
22
  */
22
23
  endpoints?: boolean;
24
+ /**
25
+ * Whether to use optimized BFS implementation for large graphs
26
+ */
27
+ optimized?: boolean;
23
28
  }
24
29
 
25
30
  /**
26
- * Calculate betweenness centrality for all nodes using Brandes' algorithm
31
+ * Result of Brandes algorithm computation for a single source
27
32
  */
28
- export function betweennessCentrality(
29
- graph: Graph,
30
- options: BetweennessCentralityOptions = {},
31
- ): Record<string, number> {
32
- const nodes = Array.from(graph.nodes()).map((node) => node.id);
33
- const centrality: Record<string, number> = {};
33
+ interface BrandesResult {
34
+ stack: NodeId[];
35
+ predecessors: Map<NodeId, NodeId[]>;
36
+ sigma: Map<NodeId, number>;
37
+ distance: Map<NodeId, number>;
38
+ }
34
39
 
35
- // Initialize centrality scores
36
- for (const nodeId of nodes) {
37
- centrality[String(nodeId)] = 0;
38
- }
40
+ /**
41
+ * Run single-source shortest path computation using BFS
42
+ * @param graph - The input graph to analyze
43
+ * @param source - The source node for shortest path computation
44
+ * @param optimized - Whether to use optimized BFS implementation
45
+ * @returns The BFS result containing stack, predecessors, sigma, and distances
46
+ */
47
+ function brandesSingleSource(graph: Graph, source: NodeId, optimized?: boolean): BrandesResult {
48
+ const result = bfsWithPathCounting(graph, source, optimized !== undefined ? { optimized } : {});
49
+
50
+ return {
51
+ stack: result.stack,
52
+ predecessors: result.predecessors,
53
+ sigma: result.sigma,
54
+ distance: result.distances,
55
+ };
56
+ }
39
57
 
40
- // Brandes' algorithm
41
- for (const source of nodes) {
42
- const stack: NodeId[] = [];
43
- const predecessors = new Map<NodeId, NodeId[]>();
44
- const sigma = new Map<NodeId, number>(); // Number of shortest paths
45
- const distance = new Map<NodeId, number>();
46
- const delta = new Map<NodeId, number>();
58
+ /**
59
+ * Accumulate betweenness contributions from a single source
60
+ * @param result - The BFS result from brandesSingleSource
61
+ * @param source - The source node used in BFS
62
+ * @param centrality - The centrality map to update
63
+ * @param options - Algorithm configuration options
64
+ */
65
+ function accumulateBetweenness(
66
+ result: BrandesResult,
67
+ source: NodeId,
68
+ centrality: Record<string, number>,
69
+ options: BetweennessCentralityOptions,
70
+ ): void {
71
+ const { stack, predecessors, sigma } = result;
72
+ const delta = new Map<NodeId, number>();
73
+
74
+ // Initialize delta
75
+ for (const node of stack) {
76
+ delta.set(node, 0);
77
+ }
47
78
 
48
- // Initialize
49
- for (const nodeId of nodes) {
50
- predecessors.set(nodeId, []);
51
- sigma.set(nodeId, 0);
52
- distance.set(nodeId, -1);
53
- delta.set(nodeId, 0);
79
+ // Accumulation - back-propagation of dependencies
80
+ // Process nodes in reverse BFS order
81
+ for (let i = stack.length - 1; i >= 0; i--) {
82
+ const w = stack[i];
83
+ if (!w) {
84
+ continue;
54
85
  }
55
86
 
56
- sigma.set(source, 1);
57
- distance.set(source, 0);
58
-
59
- const queue: NodeId[] = [source];
60
-
61
- // BFS to find shortest paths
62
- while (queue.length > 0) {
63
- const current = queue.shift();
64
- if (!current) {
65
- break;
66
- }
87
+ const wPreds = predecessors.get(w) ?? [];
88
+ const wSigma = sigma.get(w) ?? 0;
89
+ const wDelta = delta.get(w) ?? 0;
67
90
 
68
- stack.push(current);
91
+ for (const v of wPreds) {
92
+ const vSigma = sigma.get(v) ?? 0;
93
+ const vDelta = delta.get(v) ?? 0;
69
94
 
70
- for (const neighbor of Array.from(graph.neighbors(current))) {
71
- const currentDistance = distance.get(current);
72
- let neighborDistance = distance.get(neighbor);
95
+ if (vSigma > 0 && wSigma > 0) {
96
+ let contribution = (vSigma / wSigma) * (1 + wDelta);
73
97
 
74
- if (currentDistance === undefined || neighborDistance === undefined) {
75
- continue;
76
- }
77
-
78
- // First time we reach this neighbor
79
- if (neighborDistance < 0) {
80
- queue.push(neighbor);
81
- distance.set(neighbor, currentDistance + 1);
82
- neighborDistance = currentDistance + 1; // Update local variable
83
- }
84
-
85
- // Shortest path to neighbor via current
86
- if (neighborDistance === currentDistance + 1) {
87
- const neighborSigma = sigma.get(neighbor) ?? 0;
88
- const currentSigma = sigma.get(current) ?? 0;
89
- sigma.set(neighbor, neighborSigma + currentSigma);
90
-
91
- const preds = predecessors.get(neighbor);
92
- if (preds) {
93
- preds.push(current);
98
+ // Apply endpoints option: when false, exclude endpoint contributions
99
+ if (!options.endpoints) {
100
+ // For standard betweenness, don't count paths that only involve endpoints
101
+ const isTargetEndpoint = wPreds.length === 0 && w !== source;
102
+ if (isTargetEndpoint) {
103
+ contribution = 0; // Exclude endpoint contributions
94
104
  }
95
105
  }
106
+
107
+ delta.set(v, vDelta + contribution);
96
108
  }
97
109
  }
98
110
 
99
- // Accumulation - back-propagation of dependencies
100
- while (stack.length > 0) {
101
- const w = stack.pop();
102
- if (!w) {
103
- break;
104
- }
111
+ if (w !== source) {
112
+ const currentCentrality = centrality[String(w)] ?? 0;
113
+ centrality[String(w)] = currentCentrality + wDelta;
114
+ }
115
+ }
116
+ }
105
117
 
106
- const wPreds = predecessors.get(w) ?? [];
107
- const wSigma = sigma.get(w) ?? 0;
108
- const wDelta = delta.get(w) ?? 0;
118
+ /**
119
+ * Accumulate edge betweenness contributions from a single source
120
+ * @param result - The BFS result from brandesSingleSource
121
+ * @param source - The source node used in BFS
122
+ * @param edgeCentrality - The edge centrality map to update
123
+ * @param options - Algorithm configuration options
124
+ */
125
+ function accumulateEdgeBetweenness(
126
+ result: BrandesResult,
127
+ source: NodeId,
128
+ edgeCentrality: Map<string, number>,
129
+ options: BetweennessCentralityOptions,
130
+ ): void {
131
+ const { stack, predecessors, sigma } = result;
132
+ const delta = new Map<NodeId, number>();
133
+
134
+ // Initialize delta
135
+ for (const node of stack) {
136
+ delta.set(node, 0);
137
+ }
109
138
 
110
- for (const v of wPreds) {
111
- const vSigma = sigma.get(v) ?? 0;
112
- const vDelta = delta.get(v) ?? 0;
139
+ // Accumulation for edges
140
+ // Process nodes in reverse BFS order
141
+ for (let i = stack.length - 1; i >= 0; i--) {
142
+ const w = stack[i];
143
+ if (!w) {
144
+ continue;
145
+ }
113
146
 
114
- if (vSigma > 0 && wSigma > 0) {
115
- let contribution = (vSigma / wSigma) * (1 + wDelta);
147
+ const wPreds = predecessors.get(w) ?? [];
148
+ const wSigma = sigma.get(w) ?? 0;
149
+ const wDelta = delta.get(w) ?? 0;
116
150
 
117
- // Apply endpoints option: when false, exclude endpoint contributions
118
- if (!options.endpoints) {
119
- // For standard betweenness, don't count paths that only involve endpoints
120
- const isTargetEndpoint = predecessors.get(w)?.length === 0 && w !== source;
121
- if (isTargetEndpoint) {
122
- contribution = 0; // Exclude endpoint contributions
123
- }
124
- }
151
+ for (const v of wPreds) {
152
+ const vSigma = sigma.get(v) ?? 0;
153
+
154
+ if (vSigma > 0 && wSigma > 0) {
155
+ let edgeContribution = (vSigma / wSigma) * (1 + wDelta);
125
156
 
126
- delta.set(v, vDelta + contribution);
157
+ // Apply endpoints option for edge betweenness
158
+ if (!options.endpoints) {
159
+ const isTargetEndpoint = wPreds.length === 0 && w !== source;
160
+ if (isTargetEndpoint) {
161
+ edgeContribution = 0; // Exclude endpoint contributions
162
+ }
127
163
  }
164
+
165
+ // Update edge centrality
166
+ const edgeKey = `${String(v)}-${String(w)}`;
167
+ const currentEdgeCentrality = edgeCentrality.get(edgeKey) ?? 0;
168
+ edgeCentrality.set(edgeKey, currentEdgeCentrality + edgeContribution);
169
+
170
+ // Update node delta
171
+ const vDelta = delta.get(v) ?? 0;
172
+ delta.set(v, vDelta + edgeContribution);
128
173
  }
174
+ }
175
+ }
176
+ }
129
177
 
130
- if (w !== source) {
131
- const currentCentrality = centrality[String(w)] ?? 0;
132
- centrality[String(w)] = currentCentrality + wDelta;
178
+ /**
179
+ * Apply normalization to centrality values
180
+ * @param centrality - The centrality map to normalize in place
181
+ * @param nodeCount - Total number of nodes in the graph
182
+ * @param isDirected - Whether the graph is directed
183
+ */
184
+ function normalizeCentrality(centrality: Record<string, number>, nodeCount: number, isDirected: boolean): void {
185
+ const n = nodeCount;
186
+ const normalizationFactor = isDirected ? (n - 1) * (n - 2) : ((n - 1) * (n - 2)) / 2;
187
+
188
+ if (normalizationFactor > 0) {
189
+ for (const key in centrality) {
190
+ const value = centrality[key];
191
+ if (value !== undefined) {
192
+ centrality[key] = value / normalizationFactor;
133
193
  }
134
194
  }
135
195
  }
196
+ }
197
+
198
+ /**
199
+ * Calculate betweenness centrality for all nodes using Brandes' algorithm
200
+ * @param graph - The input graph to analyze
201
+ * @param options - Algorithm configuration options
202
+ * @returns Centrality scores for each node keyed by node ID
203
+ */
204
+ export function betweennessCentrality(
205
+ graph: Graph,
206
+ options: BetweennessCentralityOptions = {},
207
+ ): Record<string, number> {
208
+ const nodes = Array.from(graph.nodes()).map((node) => node.id);
209
+ const centrality: Record<string, number> = {};
210
+
211
+ // Initialize centrality scores
212
+ for (const nodeId of nodes) {
213
+ centrality[String(nodeId)] = 0;
214
+ }
215
+
216
+ // Brandes' algorithm - run from each source
217
+ for (const source of nodes) {
218
+ const result = brandesSingleSource(graph, source, options.optimized);
219
+ accumulateBetweenness(result, source, centrality, options);
220
+ }
136
221
 
137
222
  // For undirected graphs, divide by 2 (each shortest path is counted twice)
138
223
  if (!graph.isDirected) {
139
224
  for (const nodeId of nodes) {
140
225
  const key = String(nodeId);
141
- const currentValue = centrality[key];
142
- if (currentValue !== undefined) {
143
- centrality[key] = currentValue / 2;
226
+ const value = centrality[key];
227
+ if (value !== undefined) {
228
+ centrality[key] = value / 2;
144
229
  }
145
230
  }
146
231
  }
147
232
 
148
233
  // Normalization
149
234
  if (options.normalized) {
150
- const n = nodes.length;
151
- let normalizationFactor: number;
152
-
153
- if (graph.isDirected) {
154
- normalizationFactor = (n - 1) * (n - 2);
155
- } else {
156
- normalizationFactor = ((n - 1) * (n - 2)) / 2;
157
- }
158
-
159
- if (normalizationFactor > 0) {
160
- for (const nodeId of nodes) {
161
- const key = String(nodeId);
162
- const currentValue = centrality[key];
163
- if (currentValue !== undefined) {
164
- centrality[key] = currentValue / normalizationFactor;
165
- }
166
- }
167
- }
235
+ normalizeCentrality(centrality, nodes.length, graph.isDirected);
168
236
  }
169
237
 
170
238
  return centrality;
@@ -172,6 +240,10 @@ export function betweennessCentrality(
172
240
 
173
241
  /**
174
242
  * Calculate betweenness centrality for a specific node
243
+ * @param graph - The input graph to analyze
244
+ * @param targetNode - The node to calculate centrality for
245
+ * @param options - Algorithm configuration options
246
+ * @returns The betweenness centrality score for the target node
175
247
  */
176
248
  export function nodeBetweennessCentrality(
177
249
  graph: Graph,
@@ -188,6 +260,9 @@ export function nodeBetweennessCentrality(
188
260
 
189
261
  /**
190
262
  * Calculate edge betweenness centrality
263
+ * @param graph - The input graph to analyze
264
+ * @param options - Algorithm configuration options
265
+ * @returns Edge centrality scores keyed by edge string representation
191
266
  */
192
267
  export function edgeBetweennessCentrality(
193
268
  graph: Graph,
@@ -204,97 +279,8 @@ export function edgeBetweennessCentrality(
204
279
 
205
280
  // Modified Brandes' algorithm for edge betweenness
206
281
  for (const source of nodes) {
207
- const stack: NodeId[] = [];
208
- const predecessors = new Map<NodeId, NodeId[]>();
209
- const sigma = new Map<NodeId, number>();
210
- const distance = new Map<NodeId, number>();
211
- const delta = new Map<NodeId, number>();
212
-
213
- // Initialize
214
- for (const nodeId of nodes) {
215
- predecessors.set(nodeId, []);
216
- sigma.set(nodeId, 0);
217
- distance.set(nodeId, -1);
218
- delta.set(nodeId, 0);
219
- }
220
-
221
- sigma.set(source, 1);
222
- distance.set(source, 0);
223
-
224
- const queue: NodeId[] = [source];
225
-
226
- // BFS to find shortest paths
227
- while (queue.length > 0) {
228
- const current = queue.shift();
229
- if (!current) {
230
- break;
231
- }
232
-
233
- stack.push(current);
234
-
235
- for (const neighbor of Array.from(graph.neighbors(current))) {
236
- const currentDistance = distance.get(current);
237
- let neighborDistance = distance.get(neighbor);
238
-
239
- if (currentDistance === undefined || neighborDistance === undefined) {
240
- continue;
241
- }
242
-
243
- if (neighborDistance < 0) {
244
- queue.push(neighbor);
245
- distance.set(neighbor, currentDistance + 1);
246
- neighborDistance = currentDistance + 1; // Update local variable
247
- }
248
-
249
- if (neighborDistance === currentDistance + 1) {
250
- const neighborSigma = sigma.get(neighbor) ?? 0;
251
- const currentSigma = sigma.get(current) ?? 0;
252
- sigma.set(neighbor, neighborSigma + currentSigma);
253
-
254
- const preds = predecessors.get(neighbor);
255
- if (preds) {
256
- preds.push(current);
257
- }
258
- }
259
- }
260
- }
261
-
262
- // Accumulation for edges
263
- while (stack.length > 0) {
264
- const w = stack.pop();
265
- if (!w) {
266
- break;
267
- }
268
-
269
- const wPreds = predecessors.get(w) ?? [];
270
- const wSigma = sigma.get(w) ?? 0;
271
- const wDelta = delta.get(w) ?? 0;
272
-
273
- for (const v of wPreds) {
274
- const vSigma = sigma.get(v) ?? 0;
275
-
276
- if (vSigma > 0 && wSigma > 0) {
277
- let edgeContribution = vSigma / wSigma * (1 + wDelta);
278
-
279
- // Apply endpoints option for edge betweenness
280
- if (!options.endpoints) {
281
- const isTargetEndpoint = predecessors.get(w)?.length === 0 && w !== source;
282
- if (isTargetEndpoint) {
283
- edgeContribution = 0; // Exclude endpoint contributions
284
- }
285
- }
286
-
287
- // Update edge centrality
288
- const edgeKey = `${String(v)}-${String(w)}`;
289
- const currentEdgeCentrality = edgeCentrality.get(edgeKey) ?? 0;
290
- edgeCentrality.set(edgeKey, currentEdgeCentrality + edgeContribution);
291
-
292
- // Update node delta
293
- const vDelta = delta.get(v) ?? 0;
294
- delta.set(v, vDelta + edgeContribution);
295
- }
296
- }
297
- }
282
+ const result = brandesSingleSource(graph, source, options.optimized);
283
+ accumulateEdgeBetweenness(result, source, edgeCentrality, options);
298
284
  }
299
285
 
300
286
  // For undirected graphs, divide by 2 (each shortest path is counted twice)
@@ -318,4 +304,3 @@ export function edgeBetweennessCentrality(
318
304
 
319
305
  return edgeCentrality;
320
306
  }
321
-