@graphty/algorithms 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/README.md +490 -336
  2. package/dist/algorithms.d.ts +42 -2
  3. package/dist/algorithms.js +11099 -2
  4. package/dist/algorithms.js.map +1 -1
  5. package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +124 -170
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
  10. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  11. package/dist/src/algorithms/centrality/closeness.js +56 -149
  12. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  13. package/dist/src/algorithms/centrality/degree.js +3 -3
  14. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  15. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
  16. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
  17. package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
  18. package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
  19. package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
  20. package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
  21. package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
  22. package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
  23. package/dist/src/algorithms/centrality/index.d.ts +2 -0
  24. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  25. package/dist/src/algorithms/centrality/index.js +1 -0
  26. package/dist/src/algorithms/centrality/index.js.map +1 -1
  27. package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
  28. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  29. package/dist/src/algorithms/centrality/pagerank.js +45 -0
  30. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  31. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  32. package/dist/src/algorithms/community/girvan-newman.js +47 -54
  33. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  34. package/dist/src/algorithms/community/index.d.ts +2 -0
  35. package/dist/src/algorithms/community/index.d.ts.map +1 -1
  36. package/dist/src/algorithms/community/index.js.map +1 -1
  37. package/dist/src/algorithms/community/label-propagation.d.ts +13 -3
  38. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  39. package/dist/src/algorithms/community/label-propagation.js +50 -35
  40. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  41. package/dist/src/algorithms/community/leiden.d.ts +3 -2
  42. package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
  43. package/dist/src/algorithms/community/leiden.js +34 -39
  44. package/dist/src/algorithms/community/leiden.js.map +1 -1
  45. package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
  46. package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
  47. package/dist/src/algorithms/community/louvain-optimized.js +303 -0
  48. package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
  49. package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
  50. package/dist/src/algorithms/community/louvain.js +17 -76
  51. package/dist/src/algorithms/community/louvain.js.map +1 -1
  52. package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
  53. package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
  54. package/dist/src/algorithms/community/modularity-utils.js +112 -0
  55. package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
  56. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
  57. package/dist/src/algorithms/matching/bipartite.js +8 -40
  58. package/dist/src/algorithms/matching/bipartite.js.map +1 -1
  59. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  60. package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -12
  61. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  62. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
  63. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
  64. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
  65. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
  66. package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
  67. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  68. package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
  69. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  70. package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
  71. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
  72. package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
  73. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
  74. package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
  75. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
  76. package/dist/src/algorithms/traversal/bfs-variants.js +368 -0
  77. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
  78. package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
  79. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  80. package/dist/src/algorithms/traversal/bfs.js +5 -182
  81. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  82. package/dist/src/benchmark-all-algorithms.d.ts +23 -0
  83. package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
  84. package/dist/src/benchmark-all-algorithms.js +462 -0
  85. package/dist/src/benchmark-all-algorithms.js.map +1 -0
  86. package/dist/src/clustering/hierarchical.d.ts +16 -15
  87. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  88. package/dist/src/clustering/hierarchical.js +209 -223
  89. package/dist/src/clustering/hierarchical.js.map +1 -1
  90. package/dist/src/clustering/index.d.ts +4 -2
  91. package/dist/src/clustering/index.d.ts.map +1 -1
  92. package/dist/src/clustering/index.js +2 -2
  93. package/dist/src/clustering/index.js.map +1 -1
  94. package/dist/src/clustering/k-core.d.ts +16 -15
  95. package/dist/src/clustering/k-core.d.ts.map +1 -1
  96. package/dist/src/clustering/k-core.js +57 -21
  97. package/dist/src/clustering/k-core.js.map +1 -1
  98. package/dist/src/clustering/spectral.d.ts +8 -0
  99. package/dist/src/clustering/spectral.d.ts.map +1 -1
  100. package/dist/src/clustering/spectral.js +40 -21
  101. package/dist/src/clustering/spectral.js.map +1 -1
  102. package/dist/src/core/graph.js +4 -4
  103. package/dist/src/core/graph.js.map +1 -1
  104. package/dist/src/flow/ford-fulkerson.d.ts +17 -11
  105. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
  106. package/dist/src/flow/ford-fulkerson.js +141 -217
  107. package/dist/src/flow/ford-fulkerson.js.map +1 -1
  108. package/dist/src/flow/min-cut.d.ts +6 -5
  109. package/dist/src/flow/min-cut.d.ts.map +1 -1
  110. package/dist/src/flow/min-cut.js +17 -8
  111. package/dist/src/flow/min-cut.js.map +1 -1
  112. package/dist/src/index.d.ts +1 -0
  113. package/dist/src/index.d.ts.map +1 -1
  114. package/dist/src/index.js +4 -0
  115. package/dist/src/index.js.map +1 -1
  116. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
  117. package/dist/src/link-prediction/adamic-adar.js +17 -26
  118. package/dist/src/link-prediction/adamic-adar.js.map +1 -1
  119. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  120. package/dist/src/link-prediction/common-neighbors.js +7 -11
  121. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  122. package/dist/src/optimized/bit-packed.d.ts +143 -0
  123. package/dist/src/optimized/bit-packed.d.ts.map +1 -0
  124. package/dist/src/optimized/bit-packed.js +292 -0
  125. package/dist/src/optimized/bit-packed.js.map +1 -0
  126. package/dist/src/optimized/csr-graph.d.ts +86 -0
  127. package/dist/src/optimized/csr-graph.d.ts.map +1 -0
  128. package/dist/src/optimized/csr-graph.js +341 -0
  129. package/dist/src/optimized/csr-graph.js.map +1 -0
  130. package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
  131. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
  132. package/dist/src/optimized/direction-optimized-bfs.js +223 -0
  133. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
  134. package/dist/src/optimized/graph-adapter.d.ts +62 -0
  135. package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
  136. package/dist/src/optimized/graph-adapter.js +146 -0
  137. package/dist/src/optimized/graph-adapter.js.map +1 -0
  138. package/dist/src/optimized/index.d.ts +14 -0
  139. package/dist/src/optimized/index.d.ts.map +1 -0
  140. package/dist/src/optimized/index.js +28 -0
  141. package/dist/src/optimized/index.js.map +1 -0
  142. package/dist/src/research/grsbm.d.ts.map +1 -1
  143. package/dist/src/research/grsbm.js +6 -14
  144. package/dist/src/research/grsbm.js.map +1 -1
  145. package/dist/src/research/sync.d.ts.map +1 -1
  146. package/dist/src/research/sync.js +3 -29
  147. package/dist/src/research/sync.js.map +1 -1
  148. package/dist/src/research/terahac.d.ts +2 -0
  149. package/dist/src/research/terahac.d.ts.map +1 -1
  150. package/dist/src/research/terahac.js +7 -3
  151. package/dist/src/research/terahac.js.map +1 -1
  152. package/dist/src/types/index.d.ts +8 -0
  153. package/dist/src/types/index.d.ts.map +1 -1
  154. package/dist/src/utils/algorithm-utilities.d.ts +2 -0
  155. package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
  156. package/dist/src/utils/algorithm-utilities.js +2 -0
  157. package/dist/src/utils/algorithm-utilities.js.map +1 -0
  158. package/dist/src/utils/graph-converters.d.ts +79 -0
  159. package/dist/src/utils/graph-converters.d.ts.map +1 -0
  160. package/dist/src/utils/graph-converters.js +196 -0
  161. package/dist/src/utils/graph-converters.js.map +1 -0
  162. package/dist/src/utils/graph-utilities.d.ts +62 -0
  163. package/dist/src/utils/graph-utilities.d.ts.map +1 -0
  164. package/dist/src/utils/graph-utilities.js +148 -0
  165. package/dist/src/utils/graph-utilities.js.map +1 -0
  166. package/dist/src/utils/index.d.ts +5 -0
  167. package/dist/src/utils/index.d.ts.map +1 -0
  168. package/dist/src/utils/index.js +5 -0
  169. package/dist/src/utils/index.js.map +1 -0
  170. package/dist/src/utils/math-utilities.d.ts +52 -0
  171. package/dist/src/utils/math-utilities.d.ts.map +1 -0
  172. package/dist/src/utils/math-utilities.js +123 -0
  173. package/dist/src/utils/math-utilities.js.map +1 -0
  174. package/dist/src/utils/matrix-utilities.d.ts +2 -0
  175. package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
  176. package/dist/src/utils/matrix-utilities.js +2 -0
  177. package/dist/src/utils/matrix-utilities.js.map +1 -0
  178. package/dist/src/utils/optimization-helpers.d.ts +33 -0
  179. package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
  180. package/dist/src/utils/optimization-helpers.js +47 -0
  181. package/dist/src/utils/optimization-helpers.js.map +1 -0
  182. package/package.json +18 -3
  183. package/src/algorithms/centrality/betweenness.ts +167 -199
  184. package/src/algorithms/centrality/closeness.ts +73 -191
  185. package/src/algorithms/centrality/degree.ts +3 -3
  186. package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
  187. package/src/algorithms/centrality/delta-pagerank.ts +435 -0
  188. package/src/algorithms/centrality/index.ts +2 -0
  189. package/src/algorithms/centrality/pagerank.ts +66 -0
  190. package/src/algorithms/community/girvan-newman.ts +52 -59
  191. package/src/algorithms/community/index.ts +2 -0
  192. package/src/algorithms/community/label-propagation.ts +64 -35
  193. package/src/algorithms/community/leiden.ts +40 -41
  194. package/src/algorithms/community/louvain-optimized.ts +445 -0
  195. package/src/algorithms/community/louvain.ts +24 -104
  196. package/src/algorithms/community/modularity-utils.ts +146 -0
  197. package/src/algorithms/matching/bipartite.ts +8 -44
  198. package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
  199. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
  200. package/src/algorithms/shortest-path/dijkstra.ts +17 -15
  201. package/src/algorithms/traversal/bfs-unified.ts +433 -0
  202. package/src/algorithms/traversal/bfs-variants.ts +496 -0
  203. package/src/algorithms/traversal/bfs.ts +10 -228
  204. package/src/benchmark-all-algorithms.ts +548 -0
  205. package/src/clustering/hierarchical.ts +241 -251
  206. package/src/clustering/index.ts +4 -2
  207. package/src/clustering/k-core.ts +87 -39
  208. package/src/clustering/spectral.ts +44 -20
  209. package/src/core/graph.ts +4 -4
  210. package/src/flow/ford-fulkerson.ts +186 -254
  211. package/src/flow/min-cut.ts +21 -11
  212. package/src/index.ts +6 -0
  213. package/src/link-prediction/adamic-adar.ts +17 -30
  214. package/src/link-prediction/common-neighbors.ts +7 -16
  215. package/src/optimized/bit-packed.ts +340 -0
  216. package/src/optimized/csr-graph.ts +455 -0
  217. package/src/optimized/direction-optimized-bfs.ts +291 -0
  218. package/src/optimized/graph-adapter.ts +200 -0
  219. package/src/optimized/index.ts +36 -0
  220. package/src/research/grsbm.ts +7 -16
  221. package/src/research/sync.ts +3 -32
  222. package/src/research/terahac.ts +10 -2
  223. package/src/types/index.ts +8 -0
  224. package/src/utils/algorithm-utilities.ts +2 -0
  225. package/src/utils/graph-converters.ts +241 -0
  226. package/src/utils/graph-utilities.ts +199 -0
  227. package/src/utils/index.ts +4 -0
  228. package/src/utils/math-utilities.ts +140 -0
  229. package/src/utils/matrix-utilities.ts +2 -0
  230. package/src/utils/optimization-helpers.ts +81 -0
@@ -1,3 +1,7 @@
1
+ import {bfsAugmentingPath} from "../algorithms/traversal/bfs-variants.js";
2
+ import type {Graph} from "../core/graph.js";
3
+ import {graphToMap} from "../utils/graph-converters.js";
4
+
1
5
  /**
2
6
  * Ford-Fulkerson Algorithm for Maximum Flow
3
7
  *
@@ -23,219 +27,6 @@ export interface MaxFlowResult {
23
27
  minCut?: {source: Set<string>, sink: Set<string>, edges: [string, string][]};
24
28
  }
25
29
 
26
- /**
27
- * Ford-Fulkerson algorithm using DFS for finding augmenting paths
28
- *
29
- * @param graph - Adjacency list representation with capacities
30
- * @param source - Source node
31
- * @param sink - Sink node
32
- * @returns Maximum flow value and flow graph
33
- *
34
- * Time Complexity: O(E * f) where f is the maximum flow
35
- * Space Complexity: O(V + E)
36
- */
37
- export function fordFulkerson(
38
- graph: Map<string, Map<string, number>>,
39
- source: string,
40
- sink: string,
41
- ): MaxFlowResult {
42
- if (!graph.has(source) || !graph.has(sink)) {
43
- return {maxFlow: 0, flowGraph: new Map()};
44
- }
45
-
46
- // Create residual graph
47
- const residualGraph = createResidualGraph(graph);
48
- const flowGraph = new Map<string, Map<string, number>>();
49
-
50
- // Initialize flow graph
51
- for (const [u, neighbors] of graph) {
52
- flowGraph.set(u, new Map());
53
- for (const v of neighbors.keys()) {
54
- const uFlowNeighbors = flowGraph.get(u);
55
- if (uFlowNeighbors) {
56
- uFlowNeighbors.set(v, 0);
57
- }
58
- }
59
- }
60
-
61
- let maxFlow = 0;
62
- let path = findAugmentingPath(residualGraph, source, sink);
63
-
64
- while (path !== null) {
65
- // Find minimum capacity along the path
66
- let pathFlow = Infinity;
67
- for (let i = 0; i < path.length - 1; i++) {
68
- const u = path[i];
69
- const v = path[i + 1];
70
- if (!u || !v) {
71
- continue;
72
- }
73
-
74
- const uEdges = residualGraph.get(u);
75
- if (!uEdges) {
76
- continue;
77
- }
78
-
79
- const capacity = uEdges.get(v);
80
- if (capacity !== undefined) {
81
- pathFlow = Math.min(pathFlow, capacity);
82
- }
83
- }
84
-
85
- // Update residual capacities
86
- for (let i = 0; i < path.length - 1; i++) {
87
- const u = path[i];
88
- const v = path[i + 1];
89
- if (!u || !v) {
90
- continue;
91
- }
92
-
93
- // Update residual graph
94
- const uEdges = residualGraph.get(u);
95
- if (uEdges) {
96
- const currentCapacity = uEdges.get(v);
97
- if (currentCapacity !== undefined) {
98
- uEdges.set(v, currentCapacity - pathFlow);
99
- }
100
- }
101
-
102
- // Add reverse edge
103
- if (!residualGraph.has(v)) {
104
- residualGraph.set(v, new Map());
105
- }
106
-
107
- const vEdges = residualGraph.get(v);
108
- if (vEdges) {
109
- vEdges.set(u, (vEdges.get(u) ?? 0) + pathFlow);
110
- }
111
-
112
- // Update flow graph
113
- if (graph.get(u)?.has(v)) {
114
- const uFlowEdges = flowGraph.get(u);
115
- if (uFlowEdges) {
116
- const currentFlow = uFlowEdges.get(v) ?? 0;
117
- uFlowEdges.set(v, currentFlow + pathFlow);
118
- }
119
- } else if (graph.get(v)?.has(u)) {
120
- // This is a reverse flow
121
- const vFlowEdges = flowGraph.get(v);
122
- if (vFlowEdges) {
123
- const currentFlow = vFlowEdges.get(u) ?? 0;
124
- vFlowEdges.set(u, currentFlow - pathFlow);
125
- }
126
- }
127
- }
128
-
129
- maxFlow += pathFlow;
130
- path = findAugmentingPath(residualGraph, source, sink);
131
- }
132
-
133
- // Find minimum cut
134
- const minCut = findMinCut(residualGraph, source);
135
-
136
- return {maxFlow, flowGraph, minCut};
137
- }
138
-
139
- /**
140
- * Edmonds-Karp algorithm (Ford-Fulkerson with BFS)
141
- * More efficient implementation with better time complexity
142
- *
143
- * Time Complexity: O(V * E²)
144
- */
145
- export function edmondsKarp(
146
- graph: Map<string, Map<string, number>>,
147
- source: string,
148
- sink: string,
149
- ): MaxFlowResult {
150
- if (!graph.has(source) || !graph.has(sink)) {
151
- return {maxFlow: 0, flowGraph: new Map()};
152
- }
153
-
154
- const residualGraph = createResidualGraph(graph);
155
- const flowGraph = new Map<string, Map<string, number>>();
156
-
157
- // Initialize flow graph
158
- for (const [u, neighbors] of graph) {
159
- flowGraph.set(u, new Map());
160
- for (const v of neighbors.keys()) {
161
- const uFlowNeighbors = flowGraph.get(u);
162
- if (uFlowNeighbors) {
163
- uFlowNeighbors.set(v, 0);
164
- }
165
- }
166
- }
167
-
168
- let maxFlow = 0;
169
- let path = findAugmentingPathBFS(residualGraph, source, sink);
170
-
171
- while (path !== null) {
172
- let pathFlow = Infinity;
173
- for (let i = 0; i < path.length - 1; i++) {
174
- const u = path[i];
175
- const v = path[i + 1];
176
- if (!u || !v) {
177
- continue;
178
- }
179
-
180
- const uEdges = residualGraph.get(u);
181
- if (!uEdges) {
182
- continue;
183
- }
184
-
185
- const capacity = uEdges.get(v);
186
- if (capacity !== undefined) {
187
- pathFlow = Math.min(pathFlow, capacity);
188
- }
189
- }
190
-
191
- for (let i = 0; i < path.length - 1; i++) {
192
- const u = path[i];
193
- const v = path[i + 1];
194
- if (!u || !v) {
195
- continue;
196
- }
197
-
198
- const uEdges = residualGraph.get(u);
199
- if (uEdges) {
200
- const currentCapacity = uEdges.get(v);
201
- if (currentCapacity !== undefined) {
202
- uEdges.set(v, currentCapacity - pathFlow);
203
- }
204
- }
205
-
206
- if (!residualGraph.has(v)) {
207
- residualGraph.set(v, new Map());
208
- }
209
-
210
- const vEdges = residualGraph.get(v);
211
- if (vEdges) {
212
- vEdges.set(u, (vEdges.get(u) ?? 0) + pathFlow);
213
- }
214
-
215
- if (graph.get(u)?.has(v)) {
216
- const uFlowEdges = flowGraph.get(u);
217
- if (uFlowEdges) {
218
- const currentFlow = uFlowEdges.get(v) ?? 0;
219
- uFlowEdges.set(v, currentFlow + pathFlow);
220
- }
221
- } else if (graph.get(v)?.has(u)) {
222
- const vFlowEdges = flowGraph.get(v);
223
- if (vFlowEdges) {
224
- const currentFlow = vFlowEdges.get(u) ?? 0;
225
- vFlowEdges.set(u, currentFlow - pathFlow);
226
- }
227
- }
228
- }
229
-
230
- maxFlow += pathFlow;
231
- path = findAugmentingPathBFS(residualGraph, source, sink);
232
- }
233
-
234
- const minCut = findMinCut(residualGraph, source);
235
-
236
- return {maxFlow, flowGraph, minCut};
237
- }
238
-
239
30
  /**
240
31
  * Create residual graph from original graph
241
32
  */
@@ -260,7 +51,7 @@ function createResidualGraph(
260
51
  /**
261
52
  * Find augmenting path using DFS
262
53
  */
263
- function findAugmentingPath(
54
+ function findAugmentingPathDFS(
264
55
  residualGraph: Map<string, Map<string, number>>,
265
56
  source: string,
266
57
  sink: string,
@@ -300,55 +91,57 @@ function findAugmentingPath(
300
91
  }
301
92
 
302
93
  /**
303
- * Find augmenting path using BFS (for Edmonds-Karp)
94
+ * Update flow along an augmenting path
304
95
  */
305
- function findAugmentingPathBFS(
96
+ function updateFlow(
306
97
  residualGraph: Map<string, Map<string, number>>,
307
- source: string,
308
- sink: string,
309
- ): string[] | null {
310
- const parent = new Map<string, string>();
311
- const visited = new Set<string>();
312
- const queue: string[] = [source];
313
- visited.add(source);
314
-
315
- while (queue.length > 0) {
316
- const current = queue.shift();
317
- if (!current) {
98
+ flowGraph: Map<string, Map<string, number>>,
99
+ originalGraph: Map<string, Map<string, number>>,
100
+ path: string[],
101
+ pathFlow: number,
102
+ ): void {
103
+ for (let i = 0; i < path.length - 1; i++) {
104
+ const u = path[i];
105
+ const v = path[i + 1];
106
+ if (!u || !v) {
318
107
  continue;
319
108
  }
320
109
 
321
- const neighbors = residualGraph.get(current);
322
- if (neighbors) {
323
- for (const [neighbor, capacity] of neighbors) {
324
- if (!visited.has(neighbor) && capacity > 0) {
325
- visited.add(neighbor);
326
- parent.set(neighbor, current);
327
-
328
- if (neighbor === sink) {
329
- // Reconstruct path
330
- const path: string[] = [];
331
- let node = sink;
332
- while (node !== source) {
333
- path.unshift(node);
334
- const parentNode = parent.get(node);
335
- if (!parentNode) {
336
- break;
337
- }
338
-
339
- node = parentNode;
340
- }
341
- path.unshift(source);
342
- return path;
343
- }
110
+ // Update residual graph
111
+ const uEdges = residualGraph.get(u);
112
+ if (uEdges) {
113
+ const currentCapacity = uEdges.get(v);
114
+ if (currentCapacity !== undefined) {
115
+ uEdges.set(v, currentCapacity - pathFlow);
116
+ }
117
+ }
344
118
 
345
- queue.push(neighbor);
346
- }
119
+ // Add reverse edge
120
+ if (!residualGraph.has(v)) {
121
+ residualGraph.set(v, new Map());
122
+ }
123
+
124
+ const vEdges = residualGraph.get(v);
125
+ if (vEdges) {
126
+ vEdges.set(u, (vEdges.get(u) ?? 0) + pathFlow);
127
+ }
128
+
129
+ // Update flow graph
130
+ if (originalGraph.get(u)?.has(v)) {
131
+ const uFlowEdges = flowGraph.get(u);
132
+ if (uFlowEdges) {
133
+ const currentFlow = uFlowEdges.get(v) ?? 0;
134
+ uFlowEdges.set(v, currentFlow + pathFlow);
135
+ }
136
+ } else if (originalGraph.get(v)?.has(u)) {
137
+ // This is a reverse flow
138
+ const vFlowEdges = flowGraph.get(v);
139
+ if (vFlowEdges) {
140
+ const currentFlow = vFlowEdges.get(u) ?? 0;
141
+ vFlowEdges.set(u, currentFlow - pathFlow);
347
142
  }
348
143
  }
349
144
  }
350
-
351
- return null;
352
145
  }
353
146
 
354
147
  /**
@@ -405,6 +198,104 @@ function findMinCut(
405
198
  return {source: sourceSet, sink: sinkSet, edges: cutEdges};
406
199
  }
407
200
 
201
+ /**
202
+ * Core max flow algorithm implementation
203
+ */
204
+ function maxFlowCore(
205
+ graph: Map<string, Map<string, number>>,
206
+ source: string,
207
+ sink: string,
208
+ findPath: (residual: Map<string, Map<string, number>>, src: string, snk: string) => {path: string[], pathCapacity: number} | null,
209
+ ): MaxFlowResult {
210
+ if (!graph.has(source) || !graph.has(sink)) {
211
+ return {maxFlow: 0, flowGraph: new Map()};
212
+ }
213
+
214
+ // Create residual graph
215
+ const residualGraph = createResidualGraph(graph);
216
+ const flowGraph = new Map<string, Map<string, number>>();
217
+
218
+ // Initialize flow graph
219
+ for (const [u, neighbors] of graph) {
220
+ flowGraph.set(u, new Map());
221
+ for (const v of neighbors.keys()) {
222
+ const uFlowNeighbors = flowGraph.get(u);
223
+ if (uFlowNeighbors) {
224
+ uFlowNeighbors.set(v, 0);
225
+ }
226
+ }
227
+ }
228
+
229
+ let maxFlow = 0;
230
+ let pathResult = findPath(residualGraph, source, sink);
231
+
232
+ while (pathResult !== null) {
233
+ const {path, pathCapacity} = pathResult;
234
+
235
+ // Update flow
236
+ updateFlow(residualGraph, flowGraph, graph, path, pathCapacity);
237
+ maxFlow += pathCapacity;
238
+
239
+ // Find next path
240
+ pathResult = findPath(residualGraph, source, sink);
241
+ }
242
+
243
+ // Find minimum cut
244
+ const minCut = findMinCut(residualGraph, source);
245
+
246
+ return {maxFlow, flowGraph, minCut};
247
+ }
248
+
249
+ /**
250
+ * Internal implementation of Ford-Fulkerson algorithm using DFS
251
+ */
252
+ function fordFulkersonImpl(
253
+ graph: Map<string, Map<string, number>>,
254
+ source: string,
255
+ sink: string,
256
+ ): MaxFlowResult {
257
+ // Adapter function for DFS path finding
258
+ const findPathDFS = (residual: Map<string, Map<string, number>>, src: string, snk: string): {path: string[], pathCapacity: number} | null => {
259
+ const path = findAugmentingPathDFS(residual, src, snk);
260
+ if (!path) {
261
+ return null;
262
+ }
263
+
264
+ // Calculate path capacity
265
+ let pathCapacity = Infinity;
266
+ for (let i = 0; i < path.length - 1; i++) {
267
+ const u = path[i];
268
+ const v = path[i + 1];
269
+ if (u && v) {
270
+ const capacity = residual.get(u)?.get(v);
271
+ if (capacity !== undefined) {
272
+ pathCapacity = Math.min(pathCapacity, capacity);
273
+ }
274
+ }
275
+ }
276
+
277
+ return {path, pathCapacity};
278
+ };
279
+
280
+ return maxFlowCore(graph, source, sink, findPathDFS);
281
+ }
282
+
283
+ /**
284
+ * Internal implementation of Edmonds-Karp algorithm
285
+ */
286
+ function edmondsKarpImpl(
287
+ graph: Map<string, Map<string, number>>,
288
+ source: string,
289
+ sink: string,
290
+ ): MaxFlowResult {
291
+ // Use BFS variant for path finding
292
+ const findPathBFS = (residual: Map<string, Map<string, number>>, src: string, snk: string): {path: string[], pathCapacity: number} | null => {
293
+ return bfsAugmentingPath(residual, src, snk);
294
+ };
295
+
296
+ return maxFlowCore(graph, source, sink, findPathBFS);
297
+ }
298
+
408
299
  /**
409
300
  * Utility function to create a flow network for bipartite matching
410
301
  */
@@ -457,3 +348,44 @@ export function createBipartiteFlowNetwork(
457
348
  return {graph, source, sink};
458
349
  }
459
350
 
351
+ /**
352
+ * Ford-Fulkerson algorithm using DFS for finding augmenting paths
353
+ *
354
+ * @param graph - Adjacency list representation with capacities - accepts Graph class or Map
355
+ * @param source - Source node
356
+ * @param sink - Sink node
357
+ * @returns Maximum flow value and flow graph
358
+ *
359
+ * Time Complexity: O(E * f) where f is the maximum flow
360
+ * Space Complexity: O(V + E)
361
+ */
362
+ export function fordFulkerson(
363
+ graph: Graph,
364
+ source: string,
365
+ sink: string,
366
+ ): MaxFlowResult {
367
+ // Convert Graph to Map representation
368
+ const graphMap = graphToMap(graph);
369
+ return fordFulkersonImpl(graphMap, source, sink);
370
+ }
371
+
372
+ /**
373
+ * Edmonds-Karp algorithm (Ford-Fulkerson with BFS)
374
+ * More efficient implementation with better time complexity
375
+ *
376
+ * @param graph - Adjacency list representation with capacities - accepts Graph class or Map
377
+ * @param source - Source node
378
+ * @param sink - Sink node
379
+ * @returns Maximum flow value and flow graph
380
+ *
381
+ * Time Complexity: O(V * E²)
382
+ */
383
+ export function edmondsKarp(
384
+ graph: Graph | Map<string, Map<string, number>>,
385
+ source: string,
386
+ sink: string,
387
+ ): MaxFlowResult {
388
+ // Convert Graph to Map representation if needed
389
+ const graphMap = graph instanceof Map ? graph : graphToMap(graph);
390
+ return edmondsKarpImpl(graphMap, source, sink);
391
+ }
@@ -4,6 +4,8 @@
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";
7
9
  import {fordFulkerson} from "./ford-fulkerson.js";
8
10
 
9
11
  export interface MinCutResult {
@@ -25,7 +27,7 @@ export interface MinCutResult {
25
27
  * Time Complexity: Same as max flow algorithm used
26
28
  */
27
29
  export function minSTCut(
28
- graph: Map<string, Map<string, number>>,
30
+ graph: Graph,
29
31
  source: string,
30
32
  sink: string,
31
33
  ): MinCutResult {
@@ -44,7 +46,8 @@ export function minSTCut(
44
46
 
45
47
  // Find actual cut edges and their weights
46
48
  for (const [u, v] of flowResult.minCut.edges) {
47
- const weight = graph.get(u)?.get(v) ?? 0;
49
+ const edge = graph.getEdge(u, v);
50
+ const weight = edge?.weight ?? 0;
48
51
  if (weight > 0) {
49
52
  cutEdges.push({from: u, to: v, weight});
50
53
  }
@@ -62,16 +65,20 @@ export function minSTCut(
62
65
  * Stoer-Wagner algorithm for finding global minimum cut
63
66
  * Finds the minimum cut that separates the graph into two parts
64
67
  *
65
- * @param graph - Undirected weighted graph
68
+ * @param graph - Undirected weighted graph - accepts Graph class or Map representation
66
69
  * @returns Global minimum cut
67
70
  *
68
71
  * Time Complexity: O(V³) or O(VE + V² log V) with heap
69
72
  */
70
73
  export function stoerWagner(
71
- graph: Map<string, Map<string, number>>,
74
+ graph: Graph | Map<string, Map<string, number>>,
72
75
  ): MinCutResult {
76
+ // Convert Graph to Map representation if needed
77
+ const graphMap = graph instanceof Map ? graph : graphToMap(graph);
73
78
  // Convert to undirected if necessary
74
- const undirectedGraph = makeUndirected(graph);
79
+ const undirectedGraph = makeUndirected(graphMap);
80
+ // Keep a copy for finding cut edges later
81
+ const originalGraph = makeUndirected(graphMap);
75
82
 
76
83
  if (undirectedGraph.size < 2) {
77
84
  return {
@@ -84,6 +91,7 @@ export function stoerWagner(
84
91
 
85
92
  // Initialize
86
93
  const nodes = Array.from(undirectedGraph.keys());
94
+ const originalNodes = new Set(nodes); // Keep track of original nodes
87
95
  let minCutValue = Infinity;
88
96
  let bestPartition = new Set<string>();
89
97
  const contractionMap = new Map<string, Set<string>>();
@@ -125,7 +133,7 @@ export function stoerWagner(
125
133
  const partition1 = bestPartition;
126
134
  const partition2 = new Set<string>();
127
135
 
128
- for (const node of graph.keys()) {
136
+ for (const node of originalNodes) {
129
137
  if (!partition1.has(node)) {
130
138
  partition2.add(node);
131
139
  }
@@ -134,7 +142,7 @@ export function stoerWagner(
134
142
  // Find cut edges
135
143
  const cutEdges: {from: string, to: string, weight: number}[] = [];
136
144
  for (const u of partition1) {
137
- const neighbors = graph.get(u);
145
+ const neighbors = originalGraph.get(u);
138
146
  if (neighbors) {
139
147
  for (const [v, weight] of neighbors) {
140
148
  if (partition2.has(v)) {
@@ -308,22 +316,24 @@ function makeUndirected(
308
316
  * Karger's randomized min-cut algorithm
309
317
  * Probabilistic algorithm that finds min cut with high probability
310
318
  *
311
- * @param graph - Undirected graph
319
+ * @param graph - Undirected graph - accepts Graph class or Map representation
312
320
  * @param iterations - Number of iterations (higher = better accuracy)
313
321
  * @returns Minimum cut found
314
322
  *
315
323
  * Time Complexity: O(V² * iterations)
316
324
  */
317
325
  export function kargerMinCut(
318
- graph: Map<string, Map<string, number>>,
326
+ graph: Graph | Map<string, Map<string, number>>,
319
327
  iterations = 100,
320
328
  ): MinCutResult {
329
+ // Convert Graph to Map representation if needed
330
+ const graphMap = graph instanceof Map ? graph : graphToMap(graph);
321
331
  let minCutValue = Infinity;
322
332
  let bestPartition1 = new Set<string>();
323
333
  let bestPartition2 = new Set<string>();
324
334
 
325
335
  for (let i = 0; i < iterations; i++) {
326
- const result = kargerSingleRun(graph);
336
+ const result = kargerSingleRun(graphMap);
327
337
 
328
338
  if (result.cutValue < minCutValue) {
329
339
  minCutValue = result.cutValue;
@@ -335,7 +345,7 @@ export function kargerMinCut(
335
345
  // Find cut edges
336
346
  const cutEdges: {from: string, to: string, weight: number}[] = [];
337
347
  for (const u of bestPartition1) {
338
- const neighbors = graph.get(u);
348
+ const neighbors = graphMap.get(u);
339
349
  if (neighbors) {
340
350
  for (const [v, weight] of neighbors) {
341
351
  if (bestPartition2.has(v)) {
package/src/index.ts CHANGED
@@ -38,3 +38,9 @@ export * from "./research/index.js";
38
38
 
39
39
  // Data structure exports
40
40
  export * from "./data-structures/index.js";
41
+
42
+ // Optimized algorithm exports
43
+ export * from "./optimized/index.js";
44
+
45
+ // Note: Configuration exports have been removed.
46
+ // The library now automatically optimizes based on graph size.
@@ -1,5 +1,6 @@
1
1
  import type {Graph} from "../core/graph.js";
2
2
  import type {NodeId} from "../types/index.js";
3
+ import {getCommonNeighbors, getIntermediateNodes} from "../utils/graph-utilities.js";
3
4
  import type {LinkPredictionOptions, LinkPredictionScore} from "./common-neighbors.js";
4
5
 
5
6
  /**
@@ -31,28 +32,24 @@ export function adamicAdarScore(
31
32
 
32
33
  const {directed = false} = options;
33
34
 
34
- // Get neighbors
35
- const sourceNeighbors = new Set(
36
- directed ? Array.from(graph.outNeighbors(source)) : Array.from(graph.neighbors(source)),
37
- );
38
- const targetNeighbors = new Set(
39
- directed ? Array.from(graph.inNeighbors(target)) : Array.from(graph.neighbors(target)),
40
- );
35
+ // Use utility function to get common neighbors
36
+ // 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);
41
40
 
42
41
  // Calculate Adamic-Adar score
43
42
  let score = 0;
44
- for (const neighbor of sourceNeighbors) {
45
- if (targetNeighbors.has(neighbor)) {
46
- const degree = directed ?
47
- graph.outDegree(neighbor) : // Use out-degree for directed graphs
48
- graph.degree(neighbor); // Use total degree for undirected graphs
49
-
50
- if (degree > 1) {
51
- score += 1 / Math.log(degree);
52
- } else if (degree === 1) {
53
- // For degree 1, we can't use log(1) = 0, so use a small constant
54
- score += 1; // or some other reasonable value
55
- }
43
+ 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
47
+
48
+ if (degree > 1) {
49
+ score += 1 / Math.log(degree);
50
+ } else if (degree === 1) {
51
+ // For degree 1, we can't use log(1) = 0, so use a small constant
52
+ score += 1; // or some other reasonable value
56
53
  }
57
54
  }
58
55
 
@@ -275,17 +272,7 @@ export function compareAdamicAdarWithCommonNeighbors(
275
272
  pairs.map(([source, target]) => ({
276
273
  source,
277
274
  target,
278
- score: (() => {
279
- const sourceNeighbors = new Set(Array.from(graph.neighbors(source)));
280
- const targetNeighbors = new Set(Array.from(graph.neighbors(target)));
281
- let count = 0;
282
- for (const n of sourceNeighbors) {
283
- if (targetNeighbors.has(n)) {
284
- count++;
285
- }
286
- }
287
- return count;
288
- })(),
275
+ score: getCommonNeighbors(graph, source, target, options.directed).size,
289
276
  }));
290
277
 
291
278
  const testScores = commonNeighborsPairs(testEdges);