@graphty/algorithms 1.0.1 → 1.1.0

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 (273) hide show
  1. package/README.md +827 -60
  2. package/dist/algorithms.d.ts +2 -0
  3. package/dist/algorithms.d.ts.map +1 -0
  4. package/dist/algorithms.js +2 -0
  5. package/dist/algorithms.js.map +1 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +22 -7
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.js +7 -7
  10. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  11. package/dist/src/algorithms/centrality/degree.js +1 -1
  12. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  13. package/dist/src/algorithms/centrality/eigenvector.d.ts +27 -0
  14. package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -0
  15. package/dist/src/algorithms/centrality/eigenvector.js +113 -0
  16. package/dist/src/algorithms/centrality/eigenvector.js.map +1 -0
  17. package/dist/src/algorithms/centrality/hits.d.ts +35 -0
  18. package/dist/src/algorithms/centrality/hits.d.ts.map +1 -0
  19. package/dist/src/algorithms/centrality/hits.js +146 -0
  20. package/dist/src/algorithms/centrality/hits.js.map +1 -0
  21. package/dist/src/algorithms/centrality/index.d.ts +6 -0
  22. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  23. package/dist/src/algorithms/centrality/index.js +3 -0
  24. package/dist/src/algorithms/centrality/index.js.map +1 -1
  25. package/dist/src/algorithms/centrality/katz.d.ts +30 -0
  26. package/dist/src/algorithms/centrality/katz.d.ts.map +1 -0
  27. package/dist/src/algorithms/centrality/katz.js +85 -0
  28. package/dist/src/algorithms/centrality/katz.js.map +1 -0
  29. package/dist/src/algorithms/centrality/pagerank.js +3 -3
  30. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  31. package/dist/src/algorithms/community/girvan-newman.d.ts +23 -0
  32. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -0
  33. package/dist/src/algorithms/community/girvan-newman.js +297 -0
  34. package/dist/src/algorithms/community/girvan-newman.js.map +1 -0
  35. package/dist/src/algorithms/community/index.d.ts +12 -0
  36. package/dist/src/algorithms/community/index.d.ts.map +1 -0
  37. package/dist/src/algorithms/community/index.js +12 -0
  38. package/dist/src/algorithms/community/index.js.map +1 -0
  39. package/dist/src/algorithms/community/label-propagation.d.ts +42 -0
  40. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -0
  41. package/dist/src/algorithms/community/label-propagation.js +307 -0
  42. package/dist/src/algorithms/community/label-propagation.js.map +1 -0
  43. package/dist/src/algorithms/community/leiden.d.ts +33 -0
  44. package/dist/src/algorithms/community/leiden.d.ts.map +1 -0
  45. package/dist/src/algorithms/community/leiden.js +434 -0
  46. package/dist/src/algorithms/community/leiden.js.map +1 -0
  47. package/dist/src/algorithms/community/louvain.d.ts +19 -0
  48. package/dist/src/algorithms/community/louvain.d.ts.map +1 -0
  49. package/dist/src/algorithms/community/louvain.js +219 -0
  50. package/dist/src/algorithms/community/louvain.js.map +1 -0
  51. package/dist/src/algorithms/components/connected.js +7 -7
  52. package/dist/src/algorithms/components/connected.js.map +1 -1
  53. package/dist/src/algorithms/index.d.ts +7 -0
  54. package/dist/src/algorithms/index.d.ts.map +1 -1
  55. package/dist/src/algorithms/index.js +14 -0
  56. package/dist/src/algorithms/index.js.map +1 -1
  57. package/dist/src/algorithms/matching/bipartite.d.ts +37 -0
  58. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -0
  59. package/dist/src/algorithms/matching/bipartite.js +127 -0
  60. package/dist/src/algorithms/matching/bipartite.js.map +1 -0
  61. package/dist/src/algorithms/matching/index.d.ts +8 -0
  62. package/dist/src/algorithms/matching/index.d.ts.map +1 -0
  63. package/dist/src/algorithms/matching/index.js +6 -0
  64. package/dist/src/algorithms/matching/index.js.map +1 -0
  65. package/dist/src/algorithms/matching/isomorphism.d.ts +32 -0
  66. package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -0
  67. package/dist/src/algorithms/matching/isomorphism.js +291 -0
  68. package/dist/src/algorithms/matching/isomorphism.js.map +1 -0
  69. package/dist/src/algorithms/mst/index.d.ts +4 -0
  70. package/dist/src/algorithms/mst/index.d.ts.map +1 -0
  71. package/dist/src/algorithms/mst/index.js +3 -0
  72. package/dist/src/algorithms/mst/index.js.map +1 -0
  73. package/dist/src/algorithms/mst/kruskal.d.ts +9 -0
  74. package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -0
  75. package/dist/src/algorithms/mst/kruskal.js +43 -0
  76. package/dist/src/algorithms/mst/kruskal.js.map +1 -0
  77. package/dist/src/algorithms/mst/prim.d.ts +5 -0
  78. package/dist/src/algorithms/mst/prim.d.ts.map +1 -0
  79. package/dist/src/algorithms/mst/prim.js +63 -0
  80. package/dist/src/algorithms/mst/prim.js.map +1 -0
  81. package/dist/src/algorithms/shortest-path/bellman-ford.js +2 -2
  82. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  83. package/dist/src/algorithms/shortest-path/dijkstra.js +5 -5
  84. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  85. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +14 -0
  86. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -0
  87. package/dist/src/algorithms/shortest-path/floyd-warshall.js +129 -0
  88. package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -0
  89. package/dist/src/algorithms/shortest-path/index.d.ts +2 -0
  90. package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
  91. package/dist/src/algorithms/shortest-path/index.js +1 -0
  92. package/dist/src/algorithms/shortest-path/index.js.map +1 -1
  93. package/dist/src/algorithms/traversal/bfs.js +2 -2
  94. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  95. package/dist/src/algorithms/traversal/dfs.js +11 -11
  96. package/dist/src/algorithms/traversal/dfs.js.map +1 -1
  97. package/dist/src/clustering/hierarchical.d.ts +48 -0
  98. package/dist/src/clustering/hierarchical.d.ts.map +1 -0
  99. package/dist/src/clustering/hierarchical.js +439 -0
  100. package/dist/src/clustering/hierarchical.js.map +1 -0
  101. package/dist/src/clustering/index.d.ts +7 -0
  102. package/dist/src/clustering/index.d.ts.map +1 -0
  103. package/dist/src/clustering/index.js +5 -0
  104. package/dist/src/clustering/index.js.map +1 -0
  105. package/dist/src/clustering/k-core.d.ts +63 -0
  106. package/dist/src/clustering/k-core.d.ts.map +1 -0
  107. package/dist/src/clustering/k-core.js +377 -0
  108. package/dist/src/clustering/k-core.js.map +1 -0
  109. package/dist/src/clustering/mcl.d.ts +36 -0
  110. package/dist/src/clustering/mcl.d.ts.map +1 -0
  111. package/dist/src/clustering/mcl.js +343 -0
  112. package/dist/src/clustering/mcl.js.map +1 -0
  113. package/dist/src/clustering/spectral.d.ts +28 -0
  114. package/dist/src/clustering/spectral.d.ts.map +1 -0
  115. package/dist/src/clustering/spectral.js +447 -0
  116. package/dist/src/clustering/spectral.js.map +1 -0
  117. package/dist/src/core/graph.d.ts +9 -0
  118. package/dist/src/core/graph.d.ts.map +1 -1
  119. package/dist/src/core/graph.js +31 -11
  120. package/dist/src/core/graph.js.map +1 -1
  121. package/dist/src/data-structures/priority-queue.js +0 -2
  122. package/dist/src/data-structures/priority-queue.js.map +1 -1
  123. package/dist/src/data-structures/union-find.js +2 -5
  124. package/dist/src/data-structures/union-find.js.map +1 -1
  125. package/dist/src/flow/ford-fulkerson.d.ts +53 -0
  126. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -0
  127. package/dist/src/flow/ford-fulkerson.js +355 -0
  128. package/dist/src/flow/ford-fulkerson.js.map +1 -0
  129. package/dist/src/flow/index.d.ts +3 -0
  130. package/dist/src/flow/index.d.ts.map +1 -0
  131. package/dist/src/flow/index.js +3 -0
  132. package/dist/src/flow/index.js.map +1 -0
  133. package/dist/src/flow/min-cut.d.ts +49 -0
  134. package/dist/src/flow/min-cut.d.ts.map +1 -0
  135. package/dist/src/flow/min-cut.js +383 -0
  136. package/dist/src/flow/min-cut.js.map +1 -0
  137. package/dist/src/index.d.ts +1 -1
  138. package/dist/src/index.d.ts.map +1 -1
  139. package/dist/src/index.js.map +1 -1
  140. package/dist/src/link-prediction/adamic-adar.d.ts +56 -0
  141. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -0
  142. package/dist/src/link-prediction/adamic-adar.js +256 -0
  143. package/dist/src/link-prediction/adamic-adar.js.map +1 -0
  144. package/dist/src/link-prediction/common-neighbors.d.ts +50 -0
  145. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -0
  146. package/dist/src/link-prediction/common-neighbors.js +155 -0
  147. package/dist/src/link-prediction/common-neighbors.js.map +1 -0
  148. package/dist/src/link-prediction/index.d.ts +7 -0
  149. package/dist/src/link-prediction/index.d.ts.map +1 -0
  150. package/dist/src/link-prediction/index.js +6 -0
  151. package/dist/src/link-prediction/index.js.map +1 -0
  152. package/dist/src/pathfinding/astar.d.ts +50 -0
  153. package/dist/src/pathfinding/astar.d.ts.map +1 -0
  154. package/dist/src/pathfinding/astar.js +180 -0
  155. package/dist/src/pathfinding/astar.js.map +1 -0
  156. package/dist/src/pathfinding/index.d.ts +3 -0
  157. package/dist/src/pathfinding/index.d.ts.map +1 -0
  158. package/dist/src/pathfinding/index.js +3 -0
  159. package/dist/src/pathfinding/index.js.map +1 -0
  160. package/dist/src/pathfinding/utils.d.ts +18 -0
  161. package/dist/src/pathfinding/utils.d.ts.map +1 -0
  162. package/dist/src/pathfinding/utils.js +68 -0
  163. package/dist/src/pathfinding/utils.js.map +1 -0
  164. package/dist/src/types/index.d.ts +9 -0
  165. package/dist/src/types/index.d.ts.map +1 -1
  166. package/dist/src/utils/graphNode.d.ts +8 -0
  167. package/dist/src/utils/graphNode.d.ts.map +1 -0
  168. package/dist/src/utils/graphNode.js +2 -0
  169. package/dist/src/utils/graphNode.js.map +1 -0
  170. package/dist/src/utils/priorityQueue.d.ts +21 -0
  171. package/dist/src/utils/priorityQueue.d.ts.map +1 -0
  172. package/dist/src/utils/priorityQueue.js +101 -0
  173. package/dist/src/utils/priorityQueue.js.map +1 -0
  174. package/package.json +3 -1
  175. package/src/algorithms/centrality/betweenness.ts +25 -7
  176. package/src/algorithms/centrality/closeness.ts +7 -7
  177. package/src/algorithms/centrality/degree.ts +1 -1
  178. package/src/algorithms/centrality/eigenvector.ts +162 -0
  179. package/src/algorithms/centrality/hits.ts +210 -0
  180. package/src/algorithms/centrality/index.ts +6 -0
  181. package/src/algorithms/centrality/katz.ts +139 -0
  182. package/src/algorithms/centrality/pagerank.ts +3 -3
  183. package/src/algorithms/community/girvan-newman.ts +372 -0
  184. package/src/algorithms/community/index.ts +13 -0
  185. package/src/algorithms/community/label-propagation.ts +392 -0
  186. package/src/algorithms/community/leiden.ts +572 -0
  187. package/src/algorithms/community/louvain.ts +298 -0
  188. package/src/algorithms/components/connected.ts +7 -7
  189. package/src/algorithms/index.ts +21 -0
  190. package/src/algorithms/matching/bipartite.ts +179 -0
  191. package/src/algorithms/matching/index.ts +8 -0
  192. package/src/algorithms/matching/isomorphism.ts +392 -0
  193. package/src/algorithms/mst/index.ts +4 -0
  194. package/src/algorithms/mst/kruskal.ts +61 -0
  195. package/src/algorithms/mst/prim.ts +80 -0
  196. package/src/algorithms/shortest-path/bellman-ford.ts +2 -2
  197. package/src/algorithms/shortest-path/dijkstra.ts +5 -5
  198. package/src/algorithms/shortest-path/floyd-warshall.ts +170 -0
  199. package/src/algorithms/shortest-path/index.ts +2 -0
  200. package/src/algorithms/traversal/bfs.ts +2 -2
  201. package/src/algorithms/traversal/dfs.ts +11 -11
  202. package/src/clustering/hierarchical.ts +555 -0
  203. package/src/clustering/index.ts +6 -0
  204. package/src/clustering/k-core.ts +460 -0
  205. package/src/clustering/mcl.ts +454 -0
  206. package/src/clustering/spectral.ts +545 -0
  207. package/src/core/graph.ts +34 -6
  208. package/src/data-structures/union-find.ts +2 -2
  209. package/src/flow/ford-fulkerson.ts +459 -0
  210. package/src/flow/index.ts +2 -0
  211. package/src/flow/min-cut.ts +482 -0
  212. package/src/index.ts +2 -0
  213. package/src/link-prediction/adamic-adar.ts +353 -0
  214. package/src/link-prediction/common-neighbors.ts +252 -0
  215. package/src/link-prediction/index.ts +20 -0
  216. package/src/pathfinding/astar.ts +229 -0
  217. package/src/pathfinding/index.ts +2 -0
  218. package/src/pathfinding/utils.ts +87 -0
  219. package/src/types/index.ts +11 -0
  220. package/src/utils/graphNode.ts +7 -0
  221. package/src/utils/priorityQueue.ts +120 -0
  222. package/dist/test/browser/basic.test.d.ts +0 -2
  223. package/dist/test/browser/basic.test.d.ts.map +0 -1
  224. package/dist/test/browser/basic.test.js +0 -70
  225. package/dist/test/browser/basic.test.js.map +0 -1
  226. package/dist/test/unit/bellman-ford.test.d.ts +0 -2
  227. package/dist/test/unit/bellman-ford.test.d.ts.map +0 -1
  228. package/dist/test/unit/bellman-ford.test.js +0 -231
  229. package/dist/test/unit/bellman-ford.test.js.map +0 -1
  230. package/dist/test/unit/betweenness-centrality.test.d.ts +0 -2
  231. package/dist/test/unit/betweenness-centrality.test.d.ts.map +0 -1
  232. package/dist/test/unit/betweenness-centrality.test.js +0 -311
  233. package/dist/test/unit/betweenness-centrality.test.js.map +0 -1
  234. package/dist/test/unit/bfs.test.d.ts +0 -2
  235. package/dist/test/unit/bfs.test.d.ts.map +0 -1
  236. package/dist/test/unit/bfs.test.js +0 -277
  237. package/dist/test/unit/bfs.test.js.map +0 -1
  238. package/dist/test/unit/closeness.test.d.ts +0 -2
  239. package/dist/test/unit/closeness.test.d.ts.map +0 -1
  240. package/dist/test/unit/closeness.test.js +0 -266
  241. package/dist/test/unit/closeness.test.js.map +0 -1
  242. package/dist/test/unit/connected-components.test.d.ts +0 -2
  243. package/dist/test/unit/connected-components.test.d.ts.map +0 -1
  244. package/dist/test/unit/connected-components.test.js +0 -355
  245. package/dist/test/unit/connected-components.test.js.map +0 -1
  246. package/dist/test/unit/degree-centrality.test.d.ts +0 -2
  247. package/dist/test/unit/degree-centrality.test.d.ts.map +0 -1
  248. package/dist/test/unit/degree-centrality.test.js +0 -260
  249. package/dist/test/unit/degree-centrality.test.js.map +0 -1
  250. package/dist/test/unit/dfs.test.d.ts +0 -2
  251. package/dist/test/unit/dfs.test.d.ts.map +0 -1
  252. package/dist/test/unit/dfs.test.js +0 -350
  253. package/dist/test/unit/dfs.test.js.map +0 -1
  254. package/dist/test/unit/dijkstra.test.d.ts +0 -2
  255. package/dist/test/unit/dijkstra.test.d.ts.map +0 -1
  256. package/dist/test/unit/dijkstra.test.js +0 -311
  257. package/dist/test/unit/dijkstra.test.js.map +0 -1
  258. package/dist/test/unit/graph.test.d.ts +0 -2
  259. package/dist/test/unit/graph.test.d.ts.map +0 -1
  260. package/dist/test/unit/graph.test.js +0 -175
  261. package/dist/test/unit/graph.test.js.map +0 -1
  262. package/dist/test/unit/pagerank.test.d.ts +0 -2
  263. package/dist/test/unit/pagerank.test.d.ts.map +0 -1
  264. package/dist/test/unit/pagerank.test.js +0 -281
  265. package/dist/test/unit/pagerank.test.js.map +0 -1
  266. package/dist/test/unit/priority-queue.test.d.ts +0 -2
  267. package/dist/test/unit/priority-queue.test.d.ts.map +0 -1
  268. package/dist/test/unit/priority-queue.test.js +0 -189
  269. package/dist/test/unit/priority-queue.test.js.map +0 -1
  270. package/dist/test/unit/union-find.test.d.ts +0 -2
  271. package/dist/test/unit/union-find.test.d.ts.map +0 -1
  272. package/dist/test/unit/union-find.test.js +0 -245
  273. package/dist/test/unit/union-find.test.js.map +0 -1
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Minimum Cut Algorithms
3
+ *
4
+ * Various algorithms for finding minimum cuts in graphs
5
+ */
6
+
7
+ import {fordFulkerson} from "./ford-fulkerson.js";
8
+
9
+ export interface MinCutResult {
10
+ cutValue: number;
11
+ partition1: Set<string>;
12
+ partition2: Set<string>;
13
+ cutEdges: {from: string, to: string, weight: number}[];
14
+ }
15
+
16
+ /**
17
+ * Find minimum s-t cut using max flow
18
+ * The minimum cut value equals the maximum flow value (max-flow min-cut theorem)
19
+ *
20
+ * @param graph - Weighted graph
21
+ * @param source - Source node
22
+ * @param sink - Sink node
23
+ * @returns Minimum cut information
24
+ *
25
+ * Time Complexity: Same as max flow algorithm used
26
+ */
27
+ export function minSTCut(
28
+ graph: Map<string, Map<string, number>>,
29
+ source: string,
30
+ sink: string,
31
+ ): MinCutResult {
32
+ const flowResult = fordFulkerson(graph, source, sink);
33
+
34
+ if (!flowResult.minCut) {
35
+ return {
36
+ cutValue: 0,
37
+ partition1: new Set(),
38
+ partition2: new Set(),
39
+ cutEdges: [],
40
+ };
41
+ }
42
+
43
+ const cutEdges: {from: string, to: string, weight: number}[] = [];
44
+
45
+ // Find actual cut edges and their weights
46
+ for (const [u, v] of flowResult.minCut.edges) {
47
+ const weight = graph.get(u)?.get(v) ?? 0;
48
+ if (weight > 0) {
49
+ cutEdges.push({from: u, to: v, weight});
50
+ }
51
+ }
52
+
53
+ return {
54
+ cutValue: flowResult.maxFlow,
55
+ partition1: flowResult.minCut.source,
56
+ partition2: flowResult.minCut.sink,
57
+ cutEdges,
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Stoer-Wagner algorithm for finding global minimum cut
63
+ * Finds the minimum cut that separates the graph into two parts
64
+ *
65
+ * @param graph - Undirected weighted graph
66
+ * @returns Global minimum cut
67
+ *
68
+ * Time Complexity: O(V³) or O(VE + V² log V) with heap
69
+ */
70
+ export function stoerWagner(
71
+ graph: Map<string, Map<string, number>>,
72
+ ): MinCutResult {
73
+ // Convert to undirected if necessary
74
+ const undirectedGraph = makeUndirected(graph);
75
+
76
+ if (undirectedGraph.size < 2) {
77
+ return {
78
+ cutValue: 0,
79
+ partition1: new Set(undirectedGraph.keys()),
80
+ partition2: new Set(),
81
+ cutEdges: [],
82
+ };
83
+ }
84
+
85
+ // Initialize
86
+ const nodes = Array.from(undirectedGraph.keys());
87
+ let minCutValue = Infinity;
88
+ let bestPartition = new Set<string>();
89
+ const contractionMap = new Map<string, Set<string>>();
90
+
91
+ // Initialize contraction map
92
+ for (const node of nodes) {
93
+ contractionMap.set(node, new Set([node]));
94
+ }
95
+
96
+ // Contract graph V-1 times
97
+ while (nodes.length > 1) {
98
+ const cut = minimumCutPhase(undirectedGraph, nodes);
99
+
100
+ if (cut.value < minCutValue) {
101
+ minCutValue = cut.value;
102
+ // Store the actual nodes that would be in partition with t
103
+ const cutTNodes = contractionMap.get(cut.t);
104
+ if (cutTNodes) {
105
+ bestPartition = new Set(cutTNodes);
106
+ }
107
+ }
108
+
109
+ // Contract the last two nodes
110
+ const tNodes = contractionMap.get(cut.t);
111
+ const sNodes = contractionMap.get(cut.s);
112
+ if (!tNodes || !sNodes) {
113
+ continue;
114
+ }
115
+
116
+ for (const node of tNodes) {
117
+ sNodes.add(node);
118
+ }
119
+ contractionMap.delete(cut.t);
120
+
121
+ contractNodes(undirectedGraph, nodes, cut.s, cut.t);
122
+ }
123
+
124
+ // Build result
125
+ const partition1 = bestPartition;
126
+ const partition2 = new Set<string>();
127
+
128
+ for (const node of graph.keys()) {
129
+ if (!partition1.has(node)) {
130
+ partition2.add(node);
131
+ }
132
+ }
133
+
134
+ // Find cut edges
135
+ const cutEdges: {from: string, to: string, weight: number}[] = [];
136
+ for (const u of partition1) {
137
+ const neighbors = graph.get(u);
138
+ if (neighbors) {
139
+ for (const [v, weight] of neighbors) {
140
+ if (partition2.has(v)) {
141
+ cutEdges.push({from: u, to: v, weight});
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ return {
148
+ cutValue: minCutValue,
149
+ partition1,
150
+ partition2,
151
+ cutEdges,
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Minimum cut phase of Stoer-Wagner algorithm
157
+ */
158
+ function minimumCutPhase(
159
+ graph: Map<string, Map<string, number>>,
160
+ nodes: string[],
161
+ ): {s: string, t: string, value: number, partition: string[]} {
162
+ const n = nodes.length;
163
+ const weight = new Map<string, number>();
164
+ const added = new Set<string>();
165
+ const order: string[] = [];
166
+
167
+ // Initialize weights to 0
168
+ for (const node of nodes) {
169
+ weight.set(node, 0);
170
+ }
171
+
172
+ // Start with arbitrary node
173
+ let lastAdded = nodes[0];
174
+ if (!lastAdded) {
175
+ return {s: "", t: "", value: 0, partition: []};
176
+ }
177
+
178
+ added.add(lastAdded);
179
+ order.push(lastAdded);
180
+
181
+ // Add remaining nodes
182
+ for (let i = 1; i < n; i++) {
183
+ // Update weights
184
+ if (!lastAdded) {
185
+ continue;
186
+ }
187
+
188
+ const neighbors = graph.get(lastAdded);
189
+ if (neighbors) {
190
+ for (const [neighbor, w] of neighbors) {
191
+ if (!added.has(neighbor) && nodes.includes(neighbor)) {
192
+ const currentWeight = weight.get(neighbor);
193
+ if (currentWeight !== undefined) {
194
+ weight.set(neighbor, currentWeight + w);
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ // Find maximum weight node not yet added
201
+ let maxWeight = -1;
202
+ let maxNode = "";
203
+
204
+ for (const node of nodes) {
205
+ const nodeWeight = weight.get(node);
206
+ if (!added.has(node) && nodeWeight !== undefined && nodeWeight > maxWeight) {
207
+ maxWeight = nodeWeight;
208
+ maxNode = node;
209
+ }
210
+ }
211
+
212
+ added.add(maxNode);
213
+ order.push(maxNode);
214
+ lastAdded = maxNode;
215
+ }
216
+
217
+ const s = order[order.length - 2];
218
+ const t = order[order.length - 1];
219
+ if (!s || !t) {
220
+ return {s: "", t: "", value: 0, partition: []};
221
+ }
222
+
223
+ const cutValue = weight.get(t) ?? 0;
224
+
225
+ // Partition is all nodes except t
226
+ const partition = order.slice(0, -1);
227
+
228
+ return {s, t, value: cutValue, partition};
229
+ }
230
+
231
+ /**
232
+ * Contract two nodes in the graph
233
+ */
234
+ function contractNodes(
235
+ graph: Map<string, Map<string, number>>,
236
+ nodes: string[],
237
+ s: string,
238
+ t: string,
239
+ ): void {
240
+ // Merge t into s
241
+ const sNeighbors = graph.get(s);
242
+ const tNeighbors = graph.get(t);
243
+ if (!sNeighbors || !tNeighbors) {
244
+ return;
245
+ }
246
+
247
+ // Add t's edges to s
248
+ for (const [neighbor, weight] of tNeighbors) {
249
+ if (neighbor !== s) {
250
+ sNeighbors.set(neighbor, (sNeighbors.get(neighbor) ?? 0) + weight);
251
+
252
+ // Update neighbor's edge to point to s instead of t
253
+ const neighborEdges = graph.get(neighbor);
254
+ if (neighborEdges?.has(t)) {
255
+ neighborEdges.delete(t);
256
+ neighborEdges.set(s, (neighborEdges.get(s) ?? 0) + weight);
257
+ }
258
+ }
259
+ }
260
+
261
+ // Remove t from graph
262
+ graph.delete(t);
263
+ sNeighbors.delete(t);
264
+
265
+ // Remove t from nodes array
266
+ const index = nodes.indexOf(t);
267
+ if (index > -1) {
268
+ nodes.splice(index, 1);
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Convert directed graph to undirected
274
+ */
275
+ function makeUndirected(
276
+ graph: Map<string, Map<string, number>>,
277
+ ): Map<string, Map<string, number>> {
278
+ const undirected = new Map<string, Map<string, number>>();
279
+
280
+ // Initialize all nodes
281
+ for (const node of graph.keys()) {
282
+ undirected.set(node, new Map());
283
+ }
284
+
285
+ // Add edges in both directions
286
+ for (const [u, neighbors] of graph) {
287
+ for (const [v, weight] of neighbors) {
288
+ const uNeighbors = undirected.get(u);
289
+ if (uNeighbors) {
290
+ uNeighbors.set(v, weight);
291
+ }
292
+
293
+ if (!undirected.has(v)) {
294
+ undirected.set(v, new Map());
295
+ }
296
+
297
+ const vNeighbors = undirected.get(v);
298
+ if (vNeighbors) {
299
+ vNeighbors.set(u, weight);
300
+ }
301
+ }
302
+ }
303
+
304
+ return undirected;
305
+ }
306
+
307
+ /**
308
+ * Karger's randomized min-cut algorithm
309
+ * Probabilistic algorithm that finds min cut with high probability
310
+ *
311
+ * @param graph - Undirected graph
312
+ * @param iterations - Number of iterations (higher = better accuracy)
313
+ * @returns Minimum cut found
314
+ *
315
+ * Time Complexity: O(V² * iterations)
316
+ */
317
+ export function kargerMinCut(
318
+ graph: Map<string, Map<string, number>>,
319
+ iterations = 100,
320
+ ): MinCutResult {
321
+ let minCutValue = Infinity;
322
+ let bestPartition1 = new Set<string>();
323
+ let bestPartition2 = new Set<string>();
324
+
325
+ for (let i = 0; i < iterations; i++) {
326
+ const result = kargerSingleRun(graph);
327
+
328
+ if (result.cutValue < minCutValue) {
329
+ minCutValue = result.cutValue;
330
+ bestPartition1 = result.partition1;
331
+ bestPartition2 = result.partition2;
332
+ }
333
+ }
334
+
335
+ // Find cut edges
336
+ const cutEdges: {from: string, to: string, weight: number}[] = [];
337
+ for (const u of bestPartition1) {
338
+ const neighbors = graph.get(u);
339
+ if (neighbors) {
340
+ for (const [v, weight] of neighbors) {
341
+ if (bestPartition2.has(v)) {
342
+ cutEdges.push({from: u, to: v, weight});
343
+ }
344
+ }
345
+ }
346
+ }
347
+
348
+ return {
349
+ cutValue: minCutValue,
350
+ partition1: bestPartition1,
351
+ partition2: bestPartition2,
352
+ cutEdges,
353
+ };
354
+ }
355
+
356
+ /**
357
+ * Single run of Karger's algorithm
358
+ */
359
+ function kargerSingleRun(
360
+ graph: Map<string, Map<string, number>>,
361
+ ): {cutValue: number, partition1: Set<string>, partition2: Set<string>} {
362
+ // Create a copy of the graph
363
+ const workGraph = new Map<string, Map<string, number>>();
364
+ const superNodes = new Map<string, Set<string>>();
365
+
366
+ // Initialize
367
+ for (const [node, neighbors] of graph) {
368
+ workGraph.set(node, new Map(neighbors));
369
+ superNodes.set(node, new Set([node]));
370
+ }
371
+
372
+ // Contract until 2 nodes remain
373
+ while (workGraph.size > 2) {
374
+ // Pick random edge
375
+ const edges: [string, string, number][] = [];
376
+ for (const [u, neighbors] of workGraph) {
377
+ for (const [v, weight] of neighbors) {
378
+ if (u < v) { // Avoid duplicates
379
+ edges.push([u, v, weight]);
380
+ }
381
+ }
382
+ }
383
+
384
+ if (edges.length === 0) {
385
+ break;
386
+ }
387
+
388
+ const randomIndex = Math.floor(Math.random() * edges.length);
389
+ const edge = edges[randomIndex];
390
+ if (!edge) {
391
+ continue;
392
+ }
393
+
394
+ const [u, v] = edge;
395
+
396
+ // Contract edge
397
+ if (u && v) {
398
+ contractKarger(workGraph, superNodes, u, v);
399
+ }
400
+ }
401
+
402
+ // Calculate cut value
403
+ const nodes = Array.from(workGraph.keys());
404
+ if (nodes.length < 2) {
405
+ return {
406
+ cutValue: 0,
407
+ partition1: new Set(),
408
+ partition2: new Set(),
409
+ };
410
+ }
411
+
412
+ const node1 = nodes[0];
413
+ const node2 = nodes[1];
414
+ if (!node1 || !node2) {
415
+ return {
416
+ cutValue: 0,
417
+ partition1: new Set(),
418
+ partition2: new Set(),
419
+ };
420
+ }
421
+
422
+ const cutValue = workGraph.get(node1)?.get(node2) ?? 0;
423
+
424
+ return {
425
+ cutValue,
426
+ partition1: superNodes.get(node1) ?? new Set(),
427
+ partition2: superNodes.get(node2) ?? new Set(),
428
+ };
429
+ }
430
+
431
+ /**
432
+ * Contract edge in Karger's algorithm
433
+ */
434
+ function contractKarger(
435
+ graph: Map<string, Map<string, number>>,
436
+ superNodes: Map<string, Set<string>>,
437
+ u: string,
438
+ v: string,
439
+ ): void {
440
+ // Merge v into u
441
+ const uNeighbors = graph.get(u);
442
+ const vNeighbors = graph.get(v);
443
+ if (!uNeighbors || !vNeighbors) {
444
+ return;
445
+ }
446
+
447
+ // Merge supernodes
448
+ const uSuper = superNodes.get(u);
449
+ const vSuper = superNodes.get(v);
450
+ if (!uSuper || !vSuper) {
451
+ return;
452
+ }
453
+
454
+ for (const node of vSuper) {
455
+ uSuper.add(node);
456
+ }
457
+
458
+ // Merge edges
459
+ for (const [neighbor, weight] of vNeighbors) {
460
+ if (neighbor !== u) {
461
+ uNeighbors.set(neighbor, (uNeighbors.get(neighbor) ?? 0) + weight);
462
+
463
+ // Update neighbor's edges
464
+ const neighborEdges = graph.get(neighbor);
465
+ if (neighborEdges) {
466
+ neighborEdges.delete(v);
467
+ if (neighbor !== u) {
468
+ neighborEdges.set(u, (neighborEdges.get(u) ?? 0) + weight);
469
+ }
470
+ }
471
+ }
472
+ }
473
+
474
+ // Remove self-loops
475
+ uNeighbors.delete(u);
476
+ uNeighbors.delete(v);
477
+
478
+ // Remove v
479
+ graph.delete(v);
480
+ superNodes.delete(v);
481
+ }
482
+
package/src/index.ts CHANGED
@@ -17,9 +17,11 @@ export type {
17
17
  ComponentResult,
18
18
  DijkstraOptions,
19
19
  Edge,
20
+ FloydWarshallResult,
20
21
  GirvanNewmanOptions,
21
22
  GraphConfig,
22
23
  LouvainOptions,
24
+ MSTResult,
23
25
  Node,
24
26
  NodeId,
25
27
  PageRankOptions,