@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
@@ -4,21 +4,20 @@
4
4
  * Various algorithms for finding minimum cuts in graphs
5
5
  */
6
6
 
7
- import type {Graph} from "../core/graph.js";
8
- import {graphToMap} from "../utils/graph-converters.js";
9
- import {fordFulkerson} from "./ford-fulkerson.js";
7
+ import type { Graph } from "../core/graph.js";
8
+ import { graphToMap } from "../utils/graph-converters.js";
9
+ import { fordFulkerson } from "./ford-fulkerson.js";
10
10
 
11
11
  export interface MinCutResult {
12
12
  cutValue: number;
13
13
  partition1: Set<string>;
14
14
  partition2: Set<string>;
15
- cutEdges: {from: string, to: string, weight: number}[];
15
+ cutEdges: { from: string; to: string; weight: number }[];
16
16
  }
17
17
 
18
18
  /**
19
19
  * Find minimum s-t cut using max flow
20
20
  * The minimum cut value equals the maximum flow value (max-flow min-cut theorem)
21
- *
22
21
  * @param graph - Weighted graph
23
22
  * @param source - Source node
24
23
  * @param sink - Sink node
@@ -26,11 +25,7 @@ export interface MinCutResult {
26
25
  *
27
26
  * Time Complexity: Same as max flow algorithm used
28
27
  */
29
- export function minSTCut(
30
- graph: Graph,
31
- source: string,
32
- sink: string,
33
- ): MinCutResult {
28
+ export function minSTCut(graph: Graph, source: string, sink: string): MinCutResult {
34
29
  const flowResult = fordFulkerson(graph, source, sink);
35
30
 
36
31
  if (!flowResult.minCut) {
@@ -42,14 +37,14 @@ export function minSTCut(
42
37
  };
43
38
  }
44
39
 
45
- const cutEdges: {from: string, to: string, weight: number}[] = [];
40
+ const cutEdges: { from: string; to: string; weight: number }[] = [];
46
41
 
47
42
  // Find actual cut edges and their weights
48
43
  for (const [u, v] of flowResult.minCut.edges) {
49
44
  const edge = graph.getEdge(u, v);
50
45
  const weight = edge?.weight ?? 0;
51
46
  if (weight > 0) {
52
- cutEdges.push({from: u, to: v, weight});
47
+ cutEdges.push({ from: u, to: v, weight });
53
48
  }
54
49
  }
55
50
 
@@ -64,15 +59,12 @@ export function minSTCut(
64
59
  /**
65
60
  * Stoer-Wagner algorithm for finding global minimum cut
66
61
  * Finds the minimum cut that separates the graph into two parts
67
- *
68
62
  * @param graph - Undirected weighted graph - accepts Graph class or Map representation
69
63
  * @returns Global minimum cut
70
64
  *
71
65
  * Time Complexity: O(V³) or O(VE + V² log V) with heap
72
66
  */
73
- export function stoerWagner(
74
- graph: Graph | Map<string, Map<string, number>>,
75
- ): MinCutResult {
67
+ export function stoerWagner(graph: Graph | Map<string, Map<string, number>>): MinCutResult {
76
68
  // Convert Graph to Map representation if needed
77
69
  const graphMap = graph instanceof Map ? graph : graphToMap(graph);
78
70
  // Convert to undirected if necessary
@@ -140,13 +132,13 @@ export function stoerWagner(
140
132
  }
141
133
 
142
134
  // Find cut edges
143
- const cutEdges: {from: string, to: string, weight: number}[] = [];
135
+ const cutEdges: { from: string; to: string; weight: number }[] = [];
144
136
  for (const u of partition1) {
145
137
  const neighbors = originalGraph.get(u);
146
138
  if (neighbors) {
147
139
  for (const [v, weight] of neighbors) {
148
140
  if (partition2.has(v)) {
149
- cutEdges.push({from: u, to: v, weight});
141
+ cutEdges.push({ from: u, to: v, weight });
150
142
  }
151
143
  }
152
144
  }
@@ -162,11 +154,14 @@ export function stoerWagner(
162
154
 
163
155
  /**
164
156
  * Minimum cut phase of Stoer-Wagner algorithm
157
+ * @param graph - The undirected weighted graph
158
+ * @param nodes - Array of remaining nodes in the graph
159
+ * @returns The cut result with last two nodes, cut value, and partition
165
160
  */
166
161
  function minimumCutPhase(
167
162
  graph: Map<string, Map<string, number>>,
168
163
  nodes: string[],
169
- ): {s: string, t: string, value: number, partition: string[]} {
164
+ ): { s: string; t: string; value: number; partition: string[] } {
170
165
  const n = nodes.length;
171
166
  const weight = new Map<string, number>();
172
167
  const added = new Set<string>();
@@ -180,7 +175,7 @@ function minimumCutPhase(
180
175
  // Start with arbitrary node
181
176
  let lastAdded = nodes[0];
182
177
  if (!lastAdded) {
183
- return {s: "", t: "", value: 0, partition: []};
178
+ return { s: "", t: "", value: 0, partition: [] };
184
179
  }
185
180
 
186
181
  added.add(lastAdded);
@@ -188,7 +183,7 @@ function minimumCutPhase(
188
183
 
189
184
  // Add remaining nodes
190
185
  for (let i = 1; i < n; i++) {
191
- // Update weights
186
+ // Update weights
192
187
  if (!lastAdded) {
193
188
  continue;
194
189
  }
@@ -225,7 +220,7 @@ function minimumCutPhase(
225
220
  const s = order[order.length - 2];
226
221
  const t = order[order.length - 1];
227
222
  if (!s || !t) {
228
- return {s: "", t: "", value: 0, partition: []};
223
+ return { s: "", t: "", value: 0, partition: [] };
229
224
  }
230
225
 
231
226
  const cutValue = weight.get(t) ?? 0;
@@ -233,18 +228,17 @@ function minimumCutPhase(
233
228
  // Partition is all nodes except t
234
229
  const partition = order.slice(0, -1);
235
230
 
236
- return {s, t, value: cutValue, partition};
231
+ return { s, t, value: cutValue, partition };
237
232
  }
238
233
 
239
234
  /**
240
235
  * Contract two nodes in the graph
236
+ * @param graph - The graph to modify by contracting nodes
237
+ * @param nodes - Array of nodes to update after contraction
238
+ * @param s - The node to keep after contraction
239
+ * @param t - The node to merge into s
241
240
  */
242
- function contractNodes(
243
- graph: Map<string, Map<string, number>>,
244
- nodes: string[],
245
- s: string,
246
- t: string,
247
- ): void {
241
+ function contractNodes(graph: Map<string, Map<string, number>>, nodes: string[], s: string, t: string): void {
248
242
  // Merge t into s
249
243
  const sNeighbors = graph.get(s);
250
244
  const tNeighbors = graph.get(t);
@@ -279,10 +273,10 @@ function contractNodes(
279
273
 
280
274
  /**
281
275
  * Convert directed graph to undirected
276
+ * @param graph - The directed graph to convert
277
+ * @returns An undirected graph with edges in both directions
282
278
  */
283
- function makeUndirected(
284
- graph: Map<string, Map<string, number>>,
285
- ): Map<string, Map<string, number>> {
279
+ function makeUndirected(graph: Map<string, Map<string, number>>): Map<string, Map<string, number>> {
286
280
  const undirected = new Map<string, Map<string, number>>();
287
281
 
288
282
  // Initialize all nodes
@@ -315,17 +309,13 @@ function makeUndirected(
315
309
  /**
316
310
  * Karger's randomized min-cut algorithm
317
311
  * Probabilistic algorithm that finds min cut with high probability
318
- *
319
312
  * @param graph - Undirected graph - accepts Graph class or Map representation
320
313
  * @param iterations - Number of iterations (higher = better accuracy)
321
314
  * @returns Minimum cut found
322
315
  *
323
316
  * Time Complexity: O(V² * iterations)
324
317
  */
325
- export function kargerMinCut(
326
- graph: Graph | Map<string, Map<string, number>>,
327
- iterations = 100,
328
- ): MinCutResult {
318
+ export function kargerMinCut(graph: Graph | Map<string, Map<string, number>>, iterations = 100): MinCutResult {
329
319
  // Convert Graph to Map representation if needed
330
320
  const graphMap = graph instanceof Map ? graph : graphToMap(graph);
331
321
  let minCutValue = Infinity;
@@ -343,13 +333,13 @@ export function kargerMinCut(
343
333
  }
344
334
 
345
335
  // Find cut edges
346
- const cutEdges: {from: string, to: string, weight: number}[] = [];
336
+ const cutEdges: { from: string; to: string; weight: number }[] = [];
347
337
  for (const u of bestPartition1) {
348
338
  const neighbors = graphMap.get(u);
349
339
  if (neighbors) {
350
340
  for (const [v, weight] of neighbors) {
351
341
  if (bestPartition2.has(v)) {
352
- cutEdges.push({from: u, to: v, weight});
342
+ cutEdges.push({ from: u, to: v, weight });
353
343
  }
354
344
  }
355
345
  }
@@ -365,10 +355,14 @@ export function kargerMinCut(
365
355
 
366
356
  /**
367
357
  * Single run of Karger's algorithm
358
+ * @param graph - The undirected weighted graph
359
+ * @returns The cut result with cut value and two partitions
368
360
  */
369
- function kargerSingleRun(
370
- graph: Map<string, Map<string, number>>,
371
- ): {cutValue: number, partition1: Set<string>, partition2: Set<string>} {
361
+ function kargerSingleRun(graph: Map<string, Map<string, number>>): {
362
+ cutValue: number;
363
+ partition1: Set<string>;
364
+ partition2: Set<string>;
365
+ } {
372
366
  // Create a copy of the graph
373
367
  const workGraph = new Map<string, Map<string, number>>();
374
368
  const superNodes = new Map<string, Set<string>>();
@@ -381,11 +375,12 @@ function kargerSingleRun(
381
375
 
382
376
  // Contract until 2 nodes remain
383
377
  while (workGraph.size > 2) {
384
- // Pick random edge
378
+ // Pick random edge
385
379
  const edges: [string, string, number][] = [];
386
380
  for (const [u, neighbors] of workGraph) {
387
381
  for (const [v, weight] of neighbors) {
388
- if (u < v) { // Avoid duplicates
382
+ if (u < v) {
383
+ // Avoid duplicates
389
384
  edges.push([u, v, weight]);
390
385
  }
391
386
  }
@@ -440,6 +435,10 @@ function kargerSingleRun(
440
435
 
441
436
  /**
442
437
  * Contract edge in Karger's algorithm
438
+ * @param graph - The working graph to modify
439
+ * @param superNodes - Map tracking which original nodes are in each super node
440
+ * @param u - First endpoint of the edge to contract
441
+ * @param v - Second endpoint of the edge to contract (merged into u)
443
442
  */
444
443
  function contractKarger(
445
444
  graph: Map<string, Map<string, number>>,
@@ -489,4 +488,3 @@ function contractKarger(
489
488
  graph.delete(v);
490
489
  superNodes.delete(v);
491
490
  }
492
-
package/src/index.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  /**
2
- * @graphty/algorithms - Graph algorithms library for browser environments
2
+ * graphty/algorithms - Graph algorithms library for browser environments
3
3
  *
4
4
  * A comprehensive TypeScript library implementing fundamental graph algorithms
5
5
  * optimized for browser environments and visualization applications.
6
+ * @module
6
7
  */
7
8
 
8
9
  // Core exports
9
- export {Graph} from "./core/graph.js";
10
+ export { Graph } from "./core/graph.js";
10
11
 
11
12
  // Type exports
12
13
  export type {
@@ -1,7 +1,7 @@
1
- import type {Graph} from "../core/graph.js";
2
- import type {NodeId} from "../types/index.js";
3
- import {getCommonNeighbors, getIntermediateNodes} from "../utils/graph-utilities.js";
4
- import type {LinkPredictionOptions, LinkPredictionScore} from "./common-neighbors.js";
1
+ import type { Graph } from "../core/graph.js";
2
+ import type { NodeId } from "../types/index.js";
3
+ import { getCommonNeighbors, getIntermediateNodes } from "../utils/graph-utilities.js";
4
+ import type { LinkPredictionOptions, LinkPredictionScore } from "./common-neighbors.js";
5
5
 
6
6
  /**
7
7
  * Adamic-Adar Index link prediction implementation
@@ -19,6 +19,11 @@ import type {LinkPredictionOptions, LinkPredictionScore} from "./common-neighbor
19
19
 
20
20
  /**
21
21
  * Calculate Adamic-Adar index for a pair of nodes
22
+ * @param graph - The input graph
23
+ * @param source - The source node ID
24
+ * @param target - The target node ID
25
+ * @param options - Link prediction options
26
+ * @returns The Adamic-Adar score for the node pair
22
27
  */
23
28
  export function adamicAdarScore(
24
29
  graph: Graph,
@@ -30,20 +35,20 @@ export function adamicAdarScore(
30
35
  return 0;
31
36
  }
32
37
 
33
- const {directed = false} = options;
38
+ const { directed = false } = options;
34
39
 
35
40
  // Use utility function to get common neighbors
36
41
  // For directed graphs, we want intermediate nodes that form paths source->X->target
37
- const commonNeighborsSet = directed ?
38
- getIntermediateNodes(graph, source, target) :
39
- getCommonNeighbors(graph, source, target, false);
42
+ const commonNeighborsSet = directed
43
+ ? getIntermediateNodes(graph, source, target)
44
+ : getCommonNeighbors(graph, source, target, false);
40
45
 
41
46
  // Calculate Adamic-Adar score
42
47
  let score = 0;
43
48
  for (const neighbor of commonNeighborsSet) {
44
- const degree = directed ?
45
- graph.outDegree(neighbor) : // Use out-degree for directed graphs
46
- graph.degree(neighbor); // Use total degree for undirected graphs
49
+ const degree = directed
50
+ ? graph.outDegree(neighbor) // Use out-degree for directed graphs
51
+ : graph.degree(neighbor); // Use total degree for undirected graphs
47
52
 
48
53
  if (degree > 1) {
49
54
  score += 1 / Math.log(degree);
@@ -58,16 +63,12 @@ export function adamicAdarScore(
58
63
 
59
64
  /**
60
65
  * Calculate Adamic-Adar scores for all possible node pairs
66
+ * @param graph - The input graph
67
+ * @param options - Link prediction options
68
+ * @returns Array of link prediction scores sorted by score descending
61
69
  */
62
- export function adamicAdarPrediction(
63
- graph: Graph,
64
- options: LinkPredictionOptions = {},
65
- ): LinkPredictionScore[] {
66
- const {
67
- directed = false,
68
- includeExisting = false,
69
- topK,
70
- } = options;
70
+ export function adamicAdarPrediction(graph: Graph, options: LinkPredictionOptions = {}): LinkPredictionScore[] {
71
+ const { directed = false, includeExisting = false, topK } = options;
71
72
 
72
73
  const scores: LinkPredictionScore[] = [];
73
74
  const nodes = Array.from(graph.nodes()).map((n) => n.id);
@@ -86,14 +87,14 @@ export function adamicAdarPrediction(
86
87
  continue;
87
88
  }
88
89
 
89
- const score = adamicAdarScore(graph, source, target, {directed});
90
+ const score = adamicAdarScore(graph, source, target, { directed });
90
91
 
91
92
  if (score > 0) {
92
- scores.push({source, target, score});
93
+ scores.push({ source, target, score });
93
94
 
94
95
  // For undirected graphs, also add the reverse pair
95
96
  if (!directed && source !== target) {
96
- scores.push({source: target, target: source, score});
97
+ scores.push({ source: target, target: source, score });
97
98
  }
98
99
  }
99
100
  }
@@ -112,6 +113,10 @@ export function adamicAdarPrediction(
112
113
 
113
114
  /**
114
115
  * Calculate Adamic-Adar scores for specific node pairs
116
+ * @param graph - The input graph
117
+ * @param pairs - Array of node ID pairs to calculate scores for
118
+ * @param options - Link prediction options
119
+ * @returns Array of link prediction scores for the specified pairs
115
120
  */
116
121
  export function adamicAdarForPairs(
117
122
  graph: Graph,
@@ -127,22 +132,21 @@ export function adamicAdarForPairs(
127
132
 
128
133
  /**
129
134
  * Get top Adamic-Adar candidates for link prediction for a specific node
135
+ * @param graph - The input graph
136
+ * @param node - The node ID to get candidates for
137
+ * @param options - Link prediction options with optional candidate list
138
+ * @returns Array of top link prediction candidates sorted by score descending
130
139
  */
131
140
  export function getTopAdamicAdarCandidatesForNode(
132
141
  graph: Graph,
133
142
  node: NodeId,
134
- options: LinkPredictionOptions & {candidates?: NodeId[]} = {},
143
+ options: LinkPredictionOptions & { candidates?: NodeId[] } = {},
135
144
  ): LinkPredictionScore[] {
136
145
  if (!graph.hasNode(node)) {
137
146
  return [];
138
147
  }
139
148
 
140
- const {
141
- directed = false,
142
- includeExisting = false,
143
- topK = 10,
144
- candidates,
145
- } = options;
149
+ const { directed = false, includeExisting = false, topK = 10, candidates } = options;
146
150
 
147
151
  const scores: LinkPredictionScore[] = [];
148
152
  const targetNodes = candidates ?? Array.from(graph.nodes()).map((n) => n.id);
@@ -157,10 +161,10 @@ export function getTopAdamicAdarCandidatesForNode(
157
161
  continue;
158
162
  }
159
163
 
160
- const score = adamicAdarScore(graph, node, target, {directed});
164
+ const score = adamicAdarScore(graph, node, target, { directed });
161
165
 
162
166
  if (score > 0) {
163
- scores.push({source: node, target, score});
167
+ scores.push({ source: node, target, score });
164
168
  }
165
169
  }
166
170
 
@@ -172,6 +176,11 @@ export function getTopAdamicAdarCandidatesForNode(
172
176
 
173
177
  /**
174
178
  * Calculate precision and recall for Adamic-Adar link prediction evaluation
179
+ * @param trainingGraph - The training graph without test edges
180
+ * @param testEdges - Array of node pairs that are actual edges
181
+ * @param nonEdges - Array of node pairs that are not edges
182
+ * @param options - Link prediction options
183
+ * @returns Evaluation metrics including precision, recall, F1 score, and AUC
175
184
  */
176
185
  export function evaluateAdamicAdar(
177
186
  trainingGraph: Graph,
@@ -179,19 +188,19 @@ export function evaluateAdamicAdar(
179
188
  nonEdges: [NodeId, NodeId][],
180
189
  options: LinkPredictionOptions = {},
181
190
  ): {
182
- precision: number;
183
- recall: number;
184
- f1Score: number;
185
- auc: number;
186
- } {
191
+ precision: number;
192
+ recall: number;
193
+ f1Score: number;
194
+ auc: number;
195
+ } {
187
196
  // Get scores for test edges and non-edges
188
197
  const testScores = adamicAdarForPairs(trainingGraph, testEdges, options);
189
198
  const nonEdgeScores = adamicAdarForPairs(trainingGraph, nonEdges, options);
190
199
 
191
200
  // Combine and sort all scores
192
201
  const allScores = [
193
- ... testScores.map((s) => ({... s, isActualEdge: true})),
194
- ... nonEdgeScores.map((s) => ({... s, isActualEdge: false})),
202
+ ...testScores.map((s) => ({ ...s, isActualEdge: true })),
203
+ ...nonEdgeScores.map((s) => ({ ...s, isActualEdge: false })),
195
204
  ].sort((a, b) => b.score - a.score);
196
205
 
197
206
  // Calculate precision and recall at different thresholds
@@ -212,7 +221,7 @@ export function evaluateAdamicAdar(
212
221
 
213
222
  const precision = truePositives / (truePositives + falsePositives);
214
223
  const recall = truePositives / totalPositives;
215
- const f1 = precision + recall > 0 ? 2 * (precision * recall) / (precision + recall) : 0;
224
+ const f1 = precision + recall > 0 ? (2 * (precision * recall)) / (precision + recall) : 0;
216
225
 
217
226
  if (f1 > bestF1) {
218
227
  bestF1 = f1;
@@ -251,6 +260,11 @@ export function evaluateAdamicAdar(
251
260
 
252
261
  /**
253
262
  * Compare Adamic-Adar with Common Neighbors for the same dataset
263
+ * @param graph - The input graph
264
+ * @param testEdges - Array of node pairs that are actual edges
265
+ * @param nonEdges - Array of node pairs that are not edges
266
+ * @param options - Link prediction options
267
+ * @returns Comparison of evaluation metrics for both algorithms
254
268
  */
255
269
  export function compareAdamicAdarWithCommonNeighbors(
256
270
  graph: Graph,
@@ -258,14 +272,14 @@ export function compareAdamicAdarWithCommonNeighbors(
258
272
  nonEdges: [NodeId, NodeId][],
259
273
  options: LinkPredictionOptions = {},
260
274
  ): {
261
- adamicAdar: ReturnType<typeof evaluateAdamicAdar>;
262
- commonNeighbors: {
263
- precision: number;
264
- recall: number;
265
- f1Score: number;
266
- auc: number;
267
- };
268
- } {
275
+ adamicAdar: ReturnType<typeof evaluateAdamicAdar>;
276
+ commonNeighbors: {
277
+ precision: number;
278
+ recall: number;
279
+ f1Score: number;
280
+ auc: number;
281
+ };
282
+ } {
269
283
  // Import common neighbors evaluation function
270
284
  // Since we're using ES modules, we can't use require. Instead, we'll implement a simple version here
271
285
  const commonNeighborsPairs = (pairs: [NodeId, NodeId][]): LinkPredictionScore[] =>
@@ -279,8 +293,8 @@ export function compareAdamicAdarWithCommonNeighbors(
279
293
  const nonEdgeScores = commonNeighborsPairs(nonEdges);
280
294
 
281
295
  const allScores = [
282
- ... testScores.map((s) => ({... s, isActualEdge: true})),
283
- ... nonEdgeScores.map((s) => ({... s, isActualEdge: false})),
296
+ ...testScores.map((s) => ({ ...s, isActualEdge: true })),
297
+ ...nonEdgeScores.map((s) => ({ ...s, isActualEdge: false })),
284
298
  ].sort((a, b) => b.score - a.score);
285
299
 
286
300
  let truePositives = 0;
@@ -299,7 +313,7 @@ export function compareAdamicAdarWithCommonNeighbors(
299
313
 
300
314
  const precision = truePositives / (truePositives + falsePositives);
301
315
  const recall = truePositives / totalPositives;
302
- const f1 = precision + recall > 0 ? 2 * (precision * recall) / (precision + recall) : 0;
316
+ const f1 = precision + recall > 0 ? (2 * (precision * recall)) / (precision + recall) : 0;
303
317
  if (f1 > bestF1) {
304
318
  bestF1 = f1;
305
319
  bestPrecision = precision;
@@ -1,6 +1,6 @@
1
- import type {Graph} from "../core/graph.js";
2
- import type {NodeId} from "../types/index.js";
3
- import {getCommonNeighbors, getIntermediateNodes} from "../utils/graph-utilities.js";
1
+ import type { Graph } from "../core/graph.js";
2
+ import type { NodeId } from "../types/index.js";
3
+ import { getCommonNeighbors, getIntermediateNodes } from "../utils/graph-utilities.js";
4
4
 
5
5
  /**
6
6
  * Common Neighbors link prediction implementation
@@ -27,6 +27,11 @@ export interface LinkPredictionOptions {
27
27
 
28
28
  /**
29
29
  * Calculate common neighbors score for a pair of nodes
30
+ * @param graph - The input graph
31
+ * @param source - The source node ID
32
+ * @param target - The target node ID
33
+ * @param options - Link prediction options
34
+ * @returns The number of common neighbors
30
35
  */
31
36
  export function commonNeighborsScore(
32
37
  graph: Graph,
@@ -38,29 +43,25 @@ export function commonNeighborsScore(
38
43
  return 0;
39
44
  }
40
45
 
41
- const {directed = false} = options;
46
+ const { directed = false } = options;
42
47
 
43
48
  // Use utility function to get common neighbors
44
49
  // For directed graphs, we want intermediate nodes that form paths source->X->target
45
- const commonNeighborsSet = directed ?
46
- getIntermediateNodes(graph, source, target) :
47
- getCommonNeighbors(graph, source, target, false);
50
+ const commonNeighborsSet = directed
51
+ ? getIntermediateNodes(graph, source, target)
52
+ : getCommonNeighbors(graph, source, target, false);
48
53
 
49
54
  return commonNeighborsSet.size;
50
55
  }
51
56
 
52
57
  /**
53
58
  * Calculate common neighbors scores for all possible node pairs
59
+ * @param graph - The input graph
60
+ * @param options - Link prediction options
61
+ * @returns Array of link prediction scores sorted by score descending
54
62
  */
55
- export function commonNeighborsPrediction(
56
- graph: Graph,
57
- options: LinkPredictionOptions = {},
58
- ): LinkPredictionScore[] {
59
- const {
60
- directed = false,
61
- includeExisting = false,
62
- topK,
63
- } = options;
63
+ export function commonNeighborsPrediction(graph: Graph, options: LinkPredictionOptions = {}): LinkPredictionScore[] {
64
+ const { directed = false, includeExisting = false, topK } = options;
64
65
 
65
66
  const scores: LinkPredictionScore[] = [];
66
67
  const nodes = Array.from(graph.nodes()).map((n) => n.id);
@@ -79,14 +80,14 @@ export function commonNeighborsPrediction(
79
80
  continue;
80
81
  }
81
82
 
82
- const score = commonNeighborsScore(graph, source, target, {directed});
83
+ const score = commonNeighborsScore(graph, source, target, { directed });
83
84
 
84
85
  if (score > 0) {
85
- scores.push({source, target, score});
86
+ scores.push({ source, target, score });
86
87
 
87
88
  // For undirected graphs, also add the reverse pair
88
89
  if (!directed && source !== target) {
89
- scores.push({source: target, target: source, score});
90
+ scores.push({ source: target, target: source, score });
90
91
  }
91
92
  }
92
93
  }
@@ -105,6 +106,10 @@ export function commonNeighborsPrediction(
105
106
 
106
107
  /**
107
108
  * Calculate common neighbors scores for specific node pairs
109
+ * @param graph - The input graph
110
+ * @param pairs - Array of node ID pairs to calculate scores for
111
+ * @param options - Link prediction options
112
+ * @returns Array of link prediction scores for the specified pairs
108
113
  */
109
114
  export function commonNeighborsForPairs(
110
115
  graph: Graph,
@@ -120,22 +125,21 @@ export function commonNeighborsForPairs(
120
125
 
121
126
  /**
122
127
  * Get top candidates for link prediction for a specific node
128
+ * @param graph - The input graph
129
+ * @param node - The node ID to get candidates for
130
+ * @param options - Link prediction options with optional candidate list
131
+ * @returns Array of top link prediction candidates sorted by score descending
123
132
  */
124
133
  export function getTopCandidatesForNode(
125
134
  graph: Graph,
126
135
  node: NodeId,
127
- options: LinkPredictionOptions & {candidates?: NodeId[]} = {},
136
+ options: LinkPredictionOptions & { candidates?: NodeId[] } = {},
128
137
  ): LinkPredictionScore[] {
129
138
  if (!graph.hasNode(node)) {
130
139
  return [];
131
140
  }
132
141
 
133
- const {
134
- directed = false,
135
- includeExisting = false,
136
- topK = 10,
137
- candidates,
138
- } = options;
142
+ const { directed = false, includeExisting = false, topK = 10, candidates } = options;
139
143
 
140
144
  const scores: LinkPredictionScore[] = [];
141
145
  const targetNodes = candidates ?? Array.from(graph.nodes()).map((n) => n.id);
@@ -150,10 +154,10 @@ export function getTopCandidatesForNode(
150
154
  continue;
151
155
  }
152
156
 
153
- const score = commonNeighborsScore(graph, node, target, {directed});
157
+ const score = commonNeighborsScore(graph, node, target, { directed });
154
158
 
155
159
  if (score > 0) {
156
- scores.push({source: node, target, score});
160
+ scores.push({ source: node, target, score });
157
161
  }
158
162
  }
159
163
 
@@ -165,6 +169,11 @@ export function getTopCandidatesForNode(
165
169
 
166
170
  /**
167
171
  * Calculate precision and recall for link prediction evaluation
172
+ * @param trainingGraph - The training graph without test edges
173
+ * @param testEdges - Array of node pairs that are actual edges
174
+ * @param nonEdges - Array of node pairs that are not edges
175
+ * @param options - Link prediction options
176
+ * @returns Evaluation metrics including precision, recall, F1 score, and AUC
168
177
  */
169
178
  export function evaluateCommonNeighbors(
170
179
  trainingGraph: Graph,
@@ -172,19 +181,19 @@ export function evaluateCommonNeighbors(
172
181
  nonEdges: [NodeId, NodeId][],
173
182
  options: LinkPredictionOptions = {},
174
183
  ): {
175
- precision: number;
176
- recall: number;
177
- f1Score: number;
178
- auc: number;
179
- } {
184
+ precision: number;
185
+ recall: number;
186
+ f1Score: number;
187
+ auc: number;
188
+ } {
180
189
  // Get scores for test edges and non-edges
181
190
  const testScores = commonNeighborsForPairs(trainingGraph, testEdges, options);
182
191
  const nonEdgeScores = commonNeighborsForPairs(trainingGraph, nonEdges, options);
183
192
 
184
193
  // Combine and sort all scores
185
194
  const allScores = [
186
- ... testScores.map((s) => ({... s, isActualEdge: true})),
187
- ... nonEdgeScores.map((s) => ({... s, isActualEdge: false})),
195
+ ...testScores.map((s) => ({ ...s, isActualEdge: true })),
196
+ ...nonEdgeScores.map((s) => ({ ...s, isActualEdge: false })),
188
197
  ].sort((a, b) => b.score - a.score);
189
198
 
190
199
  // Calculate precision and recall at different thresholds
@@ -205,7 +214,7 @@ export function evaluateCommonNeighbors(
205
214
 
206
215
  const precision = truePositives / (truePositives + falsePositives);
207
216
  const recall = truePositives / totalPositives;
208
- const f1 = precision + recall > 0 ? 2 * (precision * recall) / (precision + recall) : 0;
217
+ const f1 = precision + recall > 0 ? (2 * (precision * recall)) / (precision + recall) : 0;
209
218
 
210
219
  if (f1 > bestF1) {
211
220
  bestF1 = f1;