@graphty/algorithms 1.0.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.
- package/LICENSE +21 -0
- package/README.md +193 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts +34 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/betweenness.js +223 -0
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -0
- package/dist/src/algorithms/centrality/closeness.d.ts +43 -0
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/closeness.js +202 -0
- package/dist/src/algorithms/centrality/closeness.js.map +1 -0
- package/dist/src/algorithms/centrality/degree.d.ts +17 -0
- package/dist/src/algorithms/centrality/degree.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/degree.js +86 -0
- package/dist/src/algorithms/centrality/degree.js.map +1 -0
- package/dist/src/algorithms/centrality/index.d.ts +11 -0
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/index.js +8 -0
- package/dist/src/algorithms/centrality/index.js.map +1 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts +74 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/pagerank.js +191 -0
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -0
- package/dist/src/algorithms/components/connected.d.ts +58 -0
- package/dist/src/algorithms/components/connected.d.ts.map +1 -0
- package/dist/src/algorithms/components/connected.js +234 -0
- package/dist/src/algorithms/components/connected.js.map +1 -0
- package/dist/src/algorithms/components/index.d.ts +5 -0
- package/dist/src/algorithms/components/index.d.ts.map +1 -0
- package/dist/src/algorithms/components/index.js +5 -0
- package/dist/src/algorithms/components/index.js.map +1 -0
- package/dist/src/algorithms/index.d.ts +8 -0
- package/dist/src/algorithms/index.d.ts.map +1 -0
- package/dist/src/algorithms/index.js +12 -0
- package/dist/src/algorithms/index.js.map +1 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +52 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.js +131 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +26 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.js +199 -0
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/index.d.ts +7 -0
- package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/index.js +6 -0
- package/dist/src/algorithms/shortest-path/index.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs.d.ts +25 -0
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs.js +189 -0
- package/dist/src/algorithms/traversal/bfs.js.map +1 -0
- package/dist/src/algorithms/traversal/dfs.d.ts +32 -0
- package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/dfs.js +259 -0
- package/dist/src/algorithms/traversal/dfs.js.map +1 -0
- package/dist/src/algorithms/traversal/index.d.ts +7 -0
- package/dist/src/algorithms/traversal/index.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/index.js +6 -0
- package/dist/src/algorithms/traversal/index.js.map +1 -0
- package/dist/src/core/graph.d.ts +100 -0
- package/dist/src/core/graph.d.ts.map +1 -0
- package/dist/src/core/graph.js +276 -0
- package/dist/src/core/graph.js.map +1 -0
- package/dist/src/data-structures/index.d.ts +6 -0
- package/dist/src/data-structures/index.d.ts.map +1 -0
- package/dist/src/data-structures/index.js +6 -0
- package/dist/src/data-structures/index.js.map +1 -0
- package/dist/src/data-structures/priority-queue.d.ts +60 -0
- package/dist/src/data-structures/priority-queue.d.ts.map +1 -0
- package/dist/src/data-structures/priority-queue.js +152 -0
- package/dist/src/data-structures/priority-queue.js.map +1 -0
- package/dist/src/data-structures/union-find.d.ts +54 -0
- package/dist/src/data-structures/union-find.d.ts.map +1 -0
- package/dist/src/data-structures/union-find.js +145 -0
- package/dist/src/data-structures/union-find.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +13 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/types/index.d.ts +74 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +5 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/test/browser/basic.test.d.ts +2 -0
- package/dist/test/browser/basic.test.d.ts.map +1 -0
- package/dist/test/browser/basic.test.js +70 -0
- package/dist/test/browser/basic.test.js.map +1 -0
- package/dist/test/unit/bellman-ford.test.d.ts +2 -0
- package/dist/test/unit/bellman-ford.test.d.ts.map +1 -0
- package/dist/test/unit/bellman-ford.test.js +231 -0
- package/dist/test/unit/bellman-ford.test.js.map +1 -0
- package/dist/test/unit/betweenness-centrality.test.d.ts +2 -0
- package/dist/test/unit/betweenness-centrality.test.d.ts.map +1 -0
- package/dist/test/unit/betweenness-centrality.test.js +311 -0
- package/dist/test/unit/betweenness-centrality.test.js.map +1 -0
- package/dist/test/unit/bfs.test.d.ts +2 -0
- package/dist/test/unit/bfs.test.d.ts.map +1 -0
- package/dist/test/unit/bfs.test.js +277 -0
- package/dist/test/unit/bfs.test.js.map +1 -0
- package/dist/test/unit/closeness.test.d.ts +2 -0
- package/dist/test/unit/closeness.test.d.ts.map +1 -0
- package/dist/test/unit/closeness.test.js +266 -0
- package/dist/test/unit/closeness.test.js.map +1 -0
- package/dist/test/unit/connected-components.test.d.ts +2 -0
- package/dist/test/unit/connected-components.test.d.ts.map +1 -0
- package/dist/test/unit/connected-components.test.js +355 -0
- package/dist/test/unit/connected-components.test.js.map +1 -0
- package/dist/test/unit/degree-centrality.test.d.ts +2 -0
- package/dist/test/unit/degree-centrality.test.d.ts.map +1 -0
- package/dist/test/unit/degree-centrality.test.js +260 -0
- package/dist/test/unit/degree-centrality.test.js.map +1 -0
- package/dist/test/unit/dfs.test.d.ts +2 -0
- package/dist/test/unit/dfs.test.d.ts.map +1 -0
- package/dist/test/unit/dfs.test.js +350 -0
- package/dist/test/unit/dfs.test.js.map +1 -0
- package/dist/test/unit/dijkstra.test.d.ts +2 -0
- package/dist/test/unit/dijkstra.test.d.ts.map +1 -0
- package/dist/test/unit/dijkstra.test.js +311 -0
- package/dist/test/unit/dijkstra.test.js.map +1 -0
- package/dist/test/unit/graph.test.d.ts +2 -0
- package/dist/test/unit/graph.test.d.ts.map +1 -0
- package/dist/test/unit/graph.test.js +175 -0
- package/dist/test/unit/graph.test.js.map +1 -0
- package/dist/test/unit/pagerank.test.d.ts +2 -0
- package/dist/test/unit/pagerank.test.d.ts.map +1 -0
- package/dist/test/unit/pagerank.test.js +281 -0
- package/dist/test/unit/pagerank.test.js.map +1 -0
- package/dist/test/unit/priority-queue.test.d.ts +2 -0
- package/dist/test/unit/priority-queue.test.d.ts.map +1 -0
- package/dist/test/unit/priority-queue.test.js +189 -0
- package/dist/test/unit/priority-queue.test.js.map +1 -0
- package/dist/test/unit/union-find.test.d.ts +2 -0
- package/dist/test/unit/union-find.test.d.ts.map +1 -0
- package/dist/test/unit/union-find.test.js +245 -0
- package/dist/test/unit/union-find.test.js.map +1 -0
- package/package.json +100 -0
- package/src/algorithms/centrality/betweenness.ts +303 -0
- package/src/algorithms/centrality/closeness.ts +296 -0
- package/src/algorithms/centrality/degree.ts +105 -0
- package/src/algorithms/centrality/index.ts +11 -0
- package/src/algorithms/centrality/pagerank.ts +302 -0
- package/src/algorithms/components/connected.ts +298 -0
- package/src/algorithms/components/index.ts +17 -0
- package/src/algorithms/index.ts +15 -0
- package/src/algorithms/shortest-path/bellman-ford.ts +214 -0
- package/src/algorithms/shortest-path/dijkstra.ts +256 -0
- package/src/algorithms/shortest-path/index.ts +7 -0
- package/src/algorithms/traversal/bfs.ts +236 -0
- package/src/algorithms/traversal/dfs.ts +367 -0
- package/src/algorithms/traversal/index.ts +7 -0
- package/src/core/graph.ts +326 -0
- package/src/data-structures/index.ts +6 -0
- package/src/data-structures/priority-queue.ts +180 -0
- package/src/data-structures/union-find.ts +170 -0
- package/src/index.ts +35 -0
- package/src/types/index.ts +95 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Connected components algorithms
|
|
5
|
+
*
|
|
6
|
+
* Finds connected components in undirected graphs and strongly connected
|
|
7
|
+
* components in directed graphs using various efficient algorithms.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Find connected components in an undirected graph using Union-Find
|
|
11
|
+
*/
|
|
12
|
+
export declare function connectedComponents(graph: Graph): NodeId[][];
|
|
13
|
+
/**
|
|
14
|
+
* Find connected components using DFS (alternative implementation)
|
|
15
|
+
*/
|
|
16
|
+
export declare function connectedComponentsDFS(graph: Graph): NodeId[][];
|
|
17
|
+
/**
|
|
18
|
+
* Find the number of connected components
|
|
19
|
+
*/
|
|
20
|
+
export declare function numberOfConnectedComponents(graph: Graph): number;
|
|
21
|
+
/**
|
|
22
|
+
* Check if the graph is connected (has exactly one connected component)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isConnected(graph: Graph): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Find the largest connected component
|
|
27
|
+
*/
|
|
28
|
+
export declare function largestConnectedComponent(graph: Graph): NodeId[];
|
|
29
|
+
/**
|
|
30
|
+
* Get the connected component containing a specific node
|
|
31
|
+
*/
|
|
32
|
+
export declare function getConnectedComponent(graph: Graph, nodeId: NodeId): NodeId[];
|
|
33
|
+
/**
|
|
34
|
+
* Find strongly connected components using Tarjan's algorithm
|
|
35
|
+
*/
|
|
36
|
+
export declare function stronglyConnectedComponents(graph: Graph): NodeId[][];
|
|
37
|
+
/**
|
|
38
|
+
* Check if a directed graph is strongly connected
|
|
39
|
+
*/
|
|
40
|
+
export declare function isStronglyConnected(graph: Graph): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Find weakly connected components in a directed graph
|
|
43
|
+
* (treat the graph as undirected for connectivity)
|
|
44
|
+
*/
|
|
45
|
+
export declare function weaklyConnectedComponents(graph: Graph): NodeId[][];
|
|
46
|
+
/**
|
|
47
|
+
* Check if a directed graph is weakly connected
|
|
48
|
+
*/
|
|
49
|
+
export declare function isWeaklyConnected(graph: Graph): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Find condensation graph (quotient graph of strongly connected components)
|
|
52
|
+
*/
|
|
53
|
+
export declare function condensationGraph(graph: Graph): {
|
|
54
|
+
condensedGraph: Graph;
|
|
55
|
+
componentMap: Map<NodeId, number>;
|
|
56
|
+
components: NodeId[][];
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=connected.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connected.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/components/connected.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAE/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAEjD;;;;;GAKG;AAEH;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,EAAE,CAmB5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,EAAE,CAiB/D;AAqBD;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAUhE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAe5E;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,EAAE,CAoEpE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAOzD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,EAAE,CAmBlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAMvD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG;IAC7C,cAAc,EAAE,KAAK,CAAC;IACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC;CAC1B,CA4CA"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { UnionFind } from "../../data-structures/union-find.js";
|
|
2
|
+
/**
|
|
3
|
+
* Connected components algorithms
|
|
4
|
+
*
|
|
5
|
+
* Finds connected components in undirected graphs and strongly connected
|
|
6
|
+
* components in directed graphs using various efficient algorithms.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Find connected components in an undirected graph using Union-Find
|
|
10
|
+
*/
|
|
11
|
+
export function connectedComponents(graph) {
|
|
12
|
+
if (graph.isDirected) {
|
|
13
|
+
throw new Error("Connected components algorithm requires an undirected graph. Use stronglyConnectedComponents for directed graphs.");
|
|
14
|
+
}
|
|
15
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
16
|
+
if (nodes.length === 0) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const unionFind = new UnionFind(nodes);
|
|
20
|
+
// Union connected nodes
|
|
21
|
+
for (const edge of graph.edges()) {
|
|
22
|
+
unionFind.union(edge.source, edge.target);
|
|
23
|
+
}
|
|
24
|
+
return unionFind.getAllComponents();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Find connected components using DFS (alternative implementation)
|
|
28
|
+
*/
|
|
29
|
+
export function connectedComponentsDFS(graph) {
|
|
30
|
+
if (graph.isDirected) {
|
|
31
|
+
throw new Error("Connected components algorithm requires an undirected graph");
|
|
32
|
+
}
|
|
33
|
+
const visited = new Set();
|
|
34
|
+
const components = [];
|
|
35
|
+
for (const node of graph.nodes()) {
|
|
36
|
+
if (!visited.has(node.id)) {
|
|
37
|
+
const component = [];
|
|
38
|
+
dfsComponent(graph, node.id, visited, component);
|
|
39
|
+
components.push(component);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return components;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* DFS helper for connected components
|
|
46
|
+
*/
|
|
47
|
+
function dfsComponent(graph, nodeId, visited, component) {
|
|
48
|
+
visited.add(nodeId);
|
|
49
|
+
component.push(nodeId);
|
|
50
|
+
for (const neighbor of graph.neighbors(nodeId)) {
|
|
51
|
+
if (!visited.has(neighbor)) {
|
|
52
|
+
dfsComponent(graph, neighbor, visited, component);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Find the number of connected components
|
|
58
|
+
*/
|
|
59
|
+
export function numberOfConnectedComponents(graph) {
|
|
60
|
+
return connectedComponents(graph).length;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if the graph is connected (has exactly one connected component)
|
|
64
|
+
*/
|
|
65
|
+
export function isConnected(graph) {
|
|
66
|
+
return numberOfConnectedComponents(graph) <= 1;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Find the largest connected component
|
|
70
|
+
*/
|
|
71
|
+
export function largestConnectedComponent(graph) {
|
|
72
|
+
const components = connectedComponents(graph);
|
|
73
|
+
if (components.length === 0) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
return components.reduce((largest, current) => current.length > largest.length ? current : largest);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the connected component containing a specific node
|
|
80
|
+
*/
|
|
81
|
+
export function getConnectedComponent(graph, nodeId) {
|
|
82
|
+
if (!graph.hasNode(nodeId)) {
|
|
83
|
+
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
84
|
+
}
|
|
85
|
+
if (graph.isDirected) {
|
|
86
|
+
throw new Error("Connected components algorithm requires an undirected graph");
|
|
87
|
+
}
|
|
88
|
+
const visited = new Set();
|
|
89
|
+
const component = [];
|
|
90
|
+
dfsComponent(graph, nodeId, visited, component);
|
|
91
|
+
return component;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Find strongly connected components using Tarjan's algorithm
|
|
95
|
+
*/
|
|
96
|
+
export function stronglyConnectedComponents(graph) {
|
|
97
|
+
if (!graph.isDirected) {
|
|
98
|
+
throw new Error("Strongly connected components require a directed graph");
|
|
99
|
+
}
|
|
100
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
101
|
+
const components = [];
|
|
102
|
+
const indices = new Map();
|
|
103
|
+
const lowLinks = new Map();
|
|
104
|
+
const onStack = new Set();
|
|
105
|
+
const stack = [];
|
|
106
|
+
let index = 0;
|
|
107
|
+
function tarjanSCC(nodeId) {
|
|
108
|
+
// Set the depth index for this node
|
|
109
|
+
indices.set(nodeId, index);
|
|
110
|
+
lowLinks.set(nodeId, index);
|
|
111
|
+
index++;
|
|
112
|
+
stack.push(nodeId);
|
|
113
|
+
onStack.add(nodeId);
|
|
114
|
+
// Consider successors
|
|
115
|
+
for (const neighbor of graph.neighbors(nodeId)) {
|
|
116
|
+
if (!indices.has(neighbor)) {
|
|
117
|
+
// Successor has not yet been visited; recurse on it
|
|
118
|
+
tarjanSCC(neighbor);
|
|
119
|
+
const nodeLL = lowLinks.get(nodeId) ?? 0;
|
|
120
|
+
const neighborLL = lowLinks.get(neighbor) ?? 0;
|
|
121
|
+
lowLinks.set(nodeId, Math.min(nodeLL, neighborLL));
|
|
122
|
+
}
|
|
123
|
+
else if (onStack.has(neighbor)) {
|
|
124
|
+
// Successor is in stack and hence in the current SCC
|
|
125
|
+
const nodeLL = lowLinks.get(nodeId) ?? 0;
|
|
126
|
+
const neighborIndex = indices.get(neighbor) ?? 0;
|
|
127
|
+
lowLinks.set(nodeId, Math.min(nodeLL, neighborIndex));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// If nodeId is a root node, pop the stack and create an SCC
|
|
131
|
+
const nodeIndex = indices.get(nodeId) ?? 0;
|
|
132
|
+
const nodeLowLink = lowLinks.get(nodeId) ?? 0;
|
|
133
|
+
if (nodeLowLink === nodeIndex) {
|
|
134
|
+
const component = [];
|
|
135
|
+
let w;
|
|
136
|
+
do {
|
|
137
|
+
const popped = stack.pop();
|
|
138
|
+
if (popped === undefined) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
w = popped;
|
|
142
|
+
onStack.delete(w);
|
|
143
|
+
component.push(w);
|
|
144
|
+
} while (w !== nodeId);
|
|
145
|
+
components.push(component);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const nodeId of nodes) {
|
|
149
|
+
if (!indices.has(nodeId)) {
|
|
150
|
+
tarjanSCC(nodeId);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return components;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if a directed graph is strongly connected
|
|
157
|
+
*/
|
|
158
|
+
export function isStronglyConnected(graph) {
|
|
159
|
+
if (!graph.isDirected) {
|
|
160
|
+
throw new Error("Strong connectivity check requires a directed graph");
|
|
161
|
+
}
|
|
162
|
+
const components = stronglyConnectedComponents(graph);
|
|
163
|
+
return components.length <= 1;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Find weakly connected components in a directed graph
|
|
167
|
+
* (treat the graph as undirected for connectivity)
|
|
168
|
+
*/
|
|
169
|
+
export function weaklyConnectedComponents(graph) {
|
|
170
|
+
if (!graph.isDirected) {
|
|
171
|
+
throw new Error("Weakly connected components are for directed graphs. Use connectedComponents for undirected graphs.");
|
|
172
|
+
}
|
|
173
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
174
|
+
if (nodes.length === 0) {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
const unionFind = new UnionFind(nodes);
|
|
178
|
+
// Union nodes connected by edges (ignore direction)
|
|
179
|
+
for (const edge of graph.edges()) {
|
|
180
|
+
unionFind.union(edge.source, edge.target);
|
|
181
|
+
}
|
|
182
|
+
return unionFind.getAllComponents();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if a directed graph is weakly connected
|
|
186
|
+
*/
|
|
187
|
+
export function isWeaklyConnected(graph) {
|
|
188
|
+
if (!graph.isDirected) {
|
|
189
|
+
throw new Error("Weak connectivity check requires a directed graph");
|
|
190
|
+
}
|
|
191
|
+
return weaklyConnectedComponents(graph).length <= 1;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Find condensation graph (quotient graph of strongly connected components)
|
|
195
|
+
*/
|
|
196
|
+
export function condensationGraph(graph) {
|
|
197
|
+
if (!graph.isDirected) {
|
|
198
|
+
throw new Error("Condensation graph requires a directed graph");
|
|
199
|
+
}
|
|
200
|
+
const components = stronglyConnectedComponents(graph);
|
|
201
|
+
const componentMap = new Map();
|
|
202
|
+
const condensedGraph = new graph.constructor({ directed: true });
|
|
203
|
+
// Map each node to its component index
|
|
204
|
+
for (let i = 0; i < components.length; i++) {
|
|
205
|
+
const component = components[i];
|
|
206
|
+
if (component) {
|
|
207
|
+
for (const nodeId of component) {
|
|
208
|
+
componentMap.set(nodeId, i);
|
|
209
|
+
}
|
|
210
|
+
// Add component as a node in condensed graph
|
|
211
|
+
condensedGraph.addNode(i);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Add edges between components
|
|
215
|
+
const addedEdges = new Set();
|
|
216
|
+
for (const edge of graph.edges()) {
|
|
217
|
+
const sourceComponent = componentMap.get(edge.source);
|
|
218
|
+
const targetComponent = componentMap.get(edge.target);
|
|
219
|
+
if (sourceComponent !== undefined && targetComponent !== undefined &&
|
|
220
|
+
sourceComponent !== targetComponent) {
|
|
221
|
+
const edgeKey = `${sourceComponent}-${targetComponent}`;
|
|
222
|
+
if (!addedEdges.has(edgeKey)) {
|
|
223
|
+
condensedGraph.addEdge(sourceComponent, targetComponent);
|
|
224
|
+
addedEdges.add(edgeKey);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
condensedGraph,
|
|
230
|
+
componentMap,
|
|
231
|
+
components,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=connected.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connected.js","sourceRoot":"","sources":["../../../../src/algorithms/components/connected.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connected components algorithms
|
|
3
|
+
*/
|
|
4
|
+
export { condensationGraph, connectedComponents, connectedComponentsDFS, getConnectedComponent, isConnected, isStronglyConnected, isWeaklyConnected, largestConnectedComponent, numberOfConnectedComponents, stronglyConnectedComponents, weaklyConnectedComponents, } from "./connected.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,EACzB,2BAA2B,EAC3B,2BAA2B,EAC3B,yBAAyB,GAC5B,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connected components algorithms
|
|
3
|
+
*/
|
|
4
|
+
export { condensationGraph, connectedComponents, connectedComponentsDFS, getConnectedComponent, isConnected, isStronglyConnected, isWeaklyConnected, largestConnectedComponent, numberOfConnectedComponents, stronglyConnectedComponents, weaklyConnectedComponents, } from "./connected.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/algorithms/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,EACzB,2BAA2B,EAC3B,2BAA2B,EAC3B,yBAAyB,GAC5B,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/algorithms/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,cAAc,sBAAsB,CAAC;AAGrC,cAAc,0BAA0B,CAAC;AAGzC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph algorithms collection
|
|
3
|
+
*/
|
|
4
|
+
// Traversal algorithms
|
|
5
|
+
export * from "./traversal/index.js";
|
|
6
|
+
// Shortest path algorithms
|
|
7
|
+
export * from "./shortest-path/index.js";
|
|
8
|
+
// Centrality algorithms
|
|
9
|
+
export * from "./centrality/index.js";
|
|
10
|
+
// Connected components algorithms
|
|
11
|
+
export * from "./components/index.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/algorithms/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,uBAAuB;AACvB,cAAc,sBAAsB,CAAC;AAErC,2BAA2B;AAC3B,cAAc,0BAA0B,CAAC;AAEzC,wBAAwB;AACxB,cAAc,uBAAuB,CAAC;AAEtC,kCAAkC;AAClC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId, ShortestPathResult } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Bellman-Ford algorithm implementation for single-source shortest paths
|
|
5
|
+
*
|
|
6
|
+
* Finds shortest paths from a source node to all other nodes in a weighted graph.
|
|
7
|
+
* Unlike Dijkstra's algorithm, it can handle negative edge weights and detect
|
|
8
|
+
* negative cycles.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Bellman-Ford algorithm options
|
|
12
|
+
*/
|
|
13
|
+
export interface BellmanFordOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Target node for early termination (optional)
|
|
16
|
+
*/
|
|
17
|
+
target?: NodeId;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Result of Bellman-Ford algorithm
|
|
21
|
+
*/
|
|
22
|
+
export interface BellmanFordResult {
|
|
23
|
+
/**
|
|
24
|
+
* Distance from source to each reachable node
|
|
25
|
+
*/
|
|
26
|
+
distances: Map<NodeId, number>;
|
|
27
|
+
/**
|
|
28
|
+
* Predecessor of each node in shortest path tree
|
|
29
|
+
*/
|
|
30
|
+
predecessors: Map<NodeId, NodeId | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Whether a negative cycle was detected
|
|
33
|
+
*/
|
|
34
|
+
hasNegativeCycle: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Nodes involved in negative cycle (if any)
|
|
37
|
+
*/
|
|
38
|
+
negativeCycleNodes: NodeId[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Find shortest paths from source using Bellman-Ford algorithm
|
|
42
|
+
*/
|
|
43
|
+
export declare function bellmanFord(graph: Graph, source: NodeId, options?: BellmanFordOptions): BellmanFordResult;
|
|
44
|
+
/**
|
|
45
|
+
* Find shortest path between two specific nodes using Bellman-Ford
|
|
46
|
+
*/
|
|
47
|
+
export declare function bellmanFordPath(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null;
|
|
48
|
+
/**
|
|
49
|
+
* Check if graph has negative cycles using Bellman-Ford
|
|
50
|
+
*/
|
|
51
|
+
export declare function hasNegativeCycle(graph: Graph): boolean;
|
|
52
|
+
//# sourceMappingURL=bellman-ford.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bellman-ford.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/bellman-ford.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAE,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAErE;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B;;OAEG;IACH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;OAEG;IACH,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,wBAAgB,WAAW,CACvB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GACjC,iBAAiB,CA6EnB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CA6B3B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CA4BtD"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find shortest paths from source using Bellman-Ford algorithm
|
|
3
|
+
*/
|
|
4
|
+
export function bellmanFord(graph, source, options = {}) {
|
|
5
|
+
if (!graph.hasNode(source)) {
|
|
6
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
7
|
+
}
|
|
8
|
+
const distances = new Map();
|
|
9
|
+
const predecessors = new Map();
|
|
10
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
11
|
+
// Initialize distances
|
|
12
|
+
for (const nodeId of nodes) {
|
|
13
|
+
distances.set(nodeId, nodeId === source ? 0 : Infinity);
|
|
14
|
+
predecessors.set(nodeId, null);
|
|
15
|
+
}
|
|
16
|
+
// Relax edges |V| - 1 times
|
|
17
|
+
for (let i = 0; i < nodes.length - 1; i++) {
|
|
18
|
+
let updated = false;
|
|
19
|
+
for (const edge of graph.edges()) {
|
|
20
|
+
const u = edge.source;
|
|
21
|
+
const v = edge.target;
|
|
22
|
+
const weight = edge.weight ?? 1;
|
|
23
|
+
const distanceU = distances.get(u);
|
|
24
|
+
const distanceV = distances.get(v);
|
|
25
|
+
if (distanceU !== undefined && distanceV !== undefined && distanceU !== Infinity) {
|
|
26
|
+
const newDistance = distanceU + weight;
|
|
27
|
+
if (newDistance < distanceV) {
|
|
28
|
+
distances.set(v, newDistance);
|
|
29
|
+
predecessors.set(v, u);
|
|
30
|
+
updated = true;
|
|
31
|
+
// Early termination if target reached
|
|
32
|
+
if (options.target && v === options.target) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// If no update in this iteration, we can stop early
|
|
39
|
+
if (!updated) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Check for negative cycles
|
|
44
|
+
const negativeCycleNodes = [];
|
|
45
|
+
let hasNegativeCycle = false;
|
|
46
|
+
for (const edge of graph.edges()) {
|
|
47
|
+
const u = edge.source;
|
|
48
|
+
const v = edge.target;
|
|
49
|
+
const weight = edge.weight ?? 1;
|
|
50
|
+
const distanceU = distances.get(u);
|
|
51
|
+
const distanceV = distances.get(v);
|
|
52
|
+
if (distanceU !== undefined && distanceV !== undefined && distanceU !== Infinity) {
|
|
53
|
+
const newDistance = distanceU + weight;
|
|
54
|
+
if (newDistance < distanceV) {
|
|
55
|
+
hasNegativeCycle = true;
|
|
56
|
+
negativeCycleNodes.push(v);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
distances,
|
|
62
|
+
predecessors,
|
|
63
|
+
hasNegativeCycle,
|
|
64
|
+
negativeCycleNodes,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Find shortest path between two specific nodes using Bellman-Ford
|
|
69
|
+
*/
|
|
70
|
+
export function bellmanFordPath(graph, source, target) {
|
|
71
|
+
if (!graph.hasNode(source)) {
|
|
72
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
73
|
+
}
|
|
74
|
+
if (!graph.hasNode(target)) {
|
|
75
|
+
throw new Error(`Target node ${String(target)} not found in graph`);
|
|
76
|
+
}
|
|
77
|
+
const result = bellmanFord(graph, source, { target });
|
|
78
|
+
if (result.hasNegativeCycle) {
|
|
79
|
+
throw new Error("Graph contains a negative cycle");
|
|
80
|
+
}
|
|
81
|
+
const distance = result.distances.get(target);
|
|
82
|
+
if (distance === undefined || distance === Infinity) {
|
|
83
|
+
return null; // No path exists
|
|
84
|
+
}
|
|
85
|
+
// Reconstruct path
|
|
86
|
+
const path = reconstructPath(target, result.predecessors);
|
|
87
|
+
return {
|
|
88
|
+
distance,
|
|
89
|
+
path,
|
|
90
|
+
predecessor: result.predecessors,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if graph has negative cycles using Bellman-Ford
|
|
95
|
+
*/
|
|
96
|
+
export function hasNegativeCycle(graph) {
|
|
97
|
+
const nodes = Array.from(graph.nodes());
|
|
98
|
+
if (nodes.length === 0) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
// Need to check from multiple sources in case of disconnected components
|
|
102
|
+
const checked = new Set();
|
|
103
|
+
for (const node of nodes) {
|
|
104
|
+
if (!checked.has(node.id)) {
|
|
105
|
+
const result = bellmanFord(graph, node.id);
|
|
106
|
+
if (result.hasNegativeCycle) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
// Mark all reachable nodes as checked
|
|
110
|
+
for (const [nodeId, distance] of result.distances) {
|
|
111
|
+
if (distance !== Infinity) {
|
|
112
|
+
checked.add(nodeId);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Reconstruct path from predecessor map
|
|
121
|
+
*/
|
|
122
|
+
function reconstructPath(target, predecessors) {
|
|
123
|
+
const path = [];
|
|
124
|
+
let current = target;
|
|
125
|
+
while (current !== null) {
|
|
126
|
+
path.unshift(current);
|
|
127
|
+
current = predecessors.get(current) ?? null;
|
|
128
|
+
}
|
|
129
|
+
return path;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=bellman-ford.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bellman-ford.js","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/bellman-ford.ts"],"names":[],"mappings":"AA2CA;;GAEG;AACH,MAAM,UAAU,WAAW,CACvB,KAAY,EACZ,MAAc,EACd,UAA8B,EAAE;IAEhC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,eAAe,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE/D,uBAAuB;IACvB,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QACzB,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACxD,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,4BAA4B;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACtB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YAEhC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAEnC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC/E,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;gBAEvC,IAAI,WAAW,GAAG,SAAS,EAAE,CAAC;oBAC1B,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;oBAC9B,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACvB,OAAO,GAAG,IAAI,CAAC;oBAEf,sCAAsC;oBACtC,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;wBACzC,MAAM;oBACV,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;QAED,oDAAoD;QACpD,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,MAAM;QACV,CAAC;IACL,CAAC;IAED,4BAA4B;IAC5B,MAAM,kBAAkB,GAAa,EAAE,CAAC;IACxC,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QAEhC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAEnC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC/E,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;YAEvC,IAAI,WAAW,GAAG,SAAS,EAAE,CAAC;gBAC1B,gBAAgB,GAAG,IAAI,CAAC;gBACxB,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO;QACH,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,kBAAkB;KACrB,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC3B,KAAY,EACZ,MAAc,EACd,MAAc;IAEd,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,eAAe,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,eAAe,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAC,MAAM,EAAC,CAAC,CAAC;IAEpD,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE9C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,CAAC,iBAAiB;IAClC,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAE1D,OAAO;QACH,QAAQ;QACR,IAAI;QACJ,WAAW,EAAE,MAAM,CAAC,YAAY;KACnC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAY;IACzC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAExC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,yEAAyE;IACzE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAE3C,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;YAChB,CAAC;YAED,sCAAsC;YACtC,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBAChD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBACxB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc,EAAE,YAAwC;IAC7E,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,OAAO,GAAkB,MAAM,CAAC;IAEpC,OAAO,OAAO,KAAK,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IAChD,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { DijkstraOptions, NodeId, ShortestPathResult } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Dijkstra's algorithm implementation for single-source shortest paths
|
|
5
|
+
*
|
|
6
|
+
* Finds shortest paths from a source node to all other nodes in a weighted graph
|
|
7
|
+
* with non-negative edge weights using a priority queue for efficiency.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Find shortest paths from source to all reachable nodes using Dijkstra's algorithm
|
|
11
|
+
*/
|
|
12
|
+
export declare function dijkstra(graph: Graph, source: NodeId, options?: DijkstraOptions): Map<NodeId, ShortestPathResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Find shortest path between two specific nodes using Dijkstra's algorithm
|
|
15
|
+
*/
|
|
16
|
+
export declare function dijkstraPath(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null;
|
|
17
|
+
/**
|
|
18
|
+
* Single-source shortest paths with early termination optimization
|
|
19
|
+
*/
|
|
20
|
+
export declare function singleSourceShortestPath(graph: Graph, source: NodeId, cutoff?: number): Map<NodeId, number>;
|
|
21
|
+
/**
|
|
22
|
+
* All-pairs shortest paths using repeated Dijkstra
|
|
23
|
+
* Note: For dense graphs, consider Floyd-Warshall algorithm instead
|
|
24
|
+
*/
|
|
25
|
+
export declare function allPairsShortestPath(graph: Graph): Map<NodeId, Map<NodeId, number>>;
|
|
26
|
+
//# sourceMappingURL=dijkstra.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dijkstra.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/dijkstra.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAE/C,OAAO,KAAK,EAAC,eAAe,EAAE,MAAM,EAAE,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAEtF;;;;;GAKG;AAEH;;GAEG;AACH,wBAAgB,QAAQ,CACpB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC9B,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CA8FjC;AAED;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAoB3B;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA2ErB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASnF"}
|