@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.
- package/README.md +827 -60
- package/dist/algorithms.d.ts +2 -0
- package/dist/algorithms.d.ts.map +1 -0
- package/dist/algorithms.js +2 -0
- package/dist/algorithms.js.map +1 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +22 -7
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +7 -7
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +1 -1
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.d.ts +27 -0
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/eigenvector.js +113 -0
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -0
- package/dist/src/algorithms/centrality/hits.d.ts +35 -0
- package/dist/src/algorithms/centrality/hits.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/hits.js +146 -0
- package/dist/src/algorithms/centrality/hits.js.map +1 -0
- package/dist/src/algorithms/centrality/index.d.ts +6 -0
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +3 -0
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/katz.d.ts +30 -0
- package/dist/src/algorithms/centrality/katz.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/katz.js +85 -0
- package/dist/src/algorithms/centrality/katz.js.map +1 -0
- package/dist/src/algorithms/centrality/pagerank.js +3 -3
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts +23 -0
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -0
- package/dist/src/algorithms/community/girvan-newman.js +297 -0
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -0
- package/dist/src/algorithms/community/index.d.ts +12 -0
- package/dist/src/algorithms/community/index.d.ts.map +1 -0
- package/dist/src/algorithms/community/index.js +12 -0
- package/dist/src/algorithms/community/index.js.map +1 -0
- package/dist/src/algorithms/community/label-propagation.d.ts +42 -0
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -0
- package/dist/src/algorithms/community/label-propagation.js +307 -0
- package/dist/src/algorithms/community/label-propagation.js.map +1 -0
- package/dist/src/algorithms/community/leiden.d.ts +33 -0
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -0
- package/dist/src/algorithms/community/leiden.js +434 -0
- package/dist/src/algorithms/community/leiden.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts +19 -0
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain.js +219 -0
- package/dist/src/algorithms/community/louvain.js.map +1 -0
- package/dist/src/algorithms/components/connected.js +7 -7
- package/dist/src/algorithms/components/connected.js.map +1 -1
- package/dist/src/algorithms/index.d.ts +7 -0
- package/dist/src/algorithms/index.d.ts.map +1 -1
- package/dist/src/algorithms/index.js +14 -0
- package/dist/src/algorithms/index.js.map +1 -1
- package/dist/src/algorithms/matching/bipartite.d.ts +37 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -0
- package/dist/src/algorithms/matching/bipartite.js +127 -0
- package/dist/src/algorithms/matching/bipartite.js.map +1 -0
- package/dist/src/algorithms/matching/index.d.ts +8 -0
- package/dist/src/algorithms/matching/index.d.ts.map +1 -0
- package/dist/src/algorithms/matching/index.js +6 -0
- package/dist/src/algorithms/matching/index.js.map +1 -0
- package/dist/src/algorithms/matching/isomorphism.d.ts +32 -0
- package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -0
- package/dist/src/algorithms/matching/isomorphism.js +291 -0
- package/dist/src/algorithms/matching/isomorphism.js.map +1 -0
- package/dist/src/algorithms/mst/index.d.ts +4 -0
- package/dist/src/algorithms/mst/index.d.ts.map +1 -0
- package/dist/src/algorithms/mst/index.js +3 -0
- package/dist/src/algorithms/mst/index.js.map +1 -0
- package/dist/src/algorithms/mst/kruskal.d.ts +9 -0
- package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -0
- package/dist/src/algorithms/mst/kruskal.js +43 -0
- package/dist/src/algorithms/mst/kruskal.js.map +1 -0
- package/dist/src/algorithms/mst/prim.d.ts +5 -0
- package/dist/src/algorithms/mst/prim.d.ts.map +1 -0
- package/dist/src/algorithms/mst/prim.js +63 -0
- package/dist/src/algorithms/mst/prim.js.map +1 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.js +2 -2
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +5 -5
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +14 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.js +129 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -0
- package/dist/src/algorithms/shortest-path/index.d.ts +2 -0
- package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/index.js +1 -0
- package/dist/src/algorithms/shortest-path/index.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +2 -2
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +11 -11
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/clustering/hierarchical.d.ts +48 -0
- package/dist/src/clustering/hierarchical.d.ts.map +1 -0
- package/dist/src/clustering/hierarchical.js +439 -0
- package/dist/src/clustering/hierarchical.js.map +1 -0
- package/dist/src/clustering/index.d.ts +7 -0
- package/dist/src/clustering/index.d.ts.map +1 -0
- package/dist/src/clustering/index.js +5 -0
- package/dist/src/clustering/index.js.map +1 -0
- package/dist/src/clustering/k-core.d.ts +63 -0
- package/dist/src/clustering/k-core.d.ts.map +1 -0
- package/dist/src/clustering/k-core.js +377 -0
- package/dist/src/clustering/k-core.js.map +1 -0
- package/dist/src/clustering/mcl.d.ts +36 -0
- package/dist/src/clustering/mcl.d.ts.map +1 -0
- package/dist/src/clustering/mcl.js +343 -0
- package/dist/src/clustering/mcl.js.map +1 -0
- package/dist/src/clustering/spectral.d.ts +28 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -0
- package/dist/src/clustering/spectral.js +447 -0
- package/dist/src/clustering/spectral.js.map +1 -0
- package/dist/src/core/graph.d.ts +9 -0
- package/dist/src/core/graph.d.ts.map +1 -1
- package/dist/src/core/graph.js +31 -11
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/data-structures/priority-queue.js +0 -2
- package/dist/src/data-structures/priority-queue.js.map +1 -1
- package/dist/src/data-structures/union-find.js +2 -5
- package/dist/src/data-structures/union-find.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +53 -0
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -0
- package/dist/src/flow/ford-fulkerson.js +355 -0
- package/dist/src/flow/ford-fulkerson.js.map +1 -0
- package/dist/src/flow/index.d.ts +3 -0
- package/dist/src/flow/index.d.ts.map +1 -0
- package/dist/src/flow/index.js +3 -0
- package/dist/src/flow/index.js.map +1 -0
- package/dist/src/flow/min-cut.d.ts +49 -0
- package/dist/src/flow/min-cut.d.ts.map +1 -0
- package/dist/src/flow/min-cut.js +383 -0
- package/dist/src/flow/min-cut.js.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts +56 -0
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -0
- package/dist/src/link-prediction/adamic-adar.js +256 -0
- package/dist/src/link-prediction/adamic-adar.js.map +1 -0
- package/dist/src/link-prediction/common-neighbors.d.ts +50 -0
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -0
- package/dist/src/link-prediction/common-neighbors.js +155 -0
- package/dist/src/link-prediction/common-neighbors.js.map +1 -0
- package/dist/src/link-prediction/index.d.ts +7 -0
- package/dist/src/link-prediction/index.d.ts.map +1 -0
- package/dist/src/link-prediction/index.js +6 -0
- package/dist/src/link-prediction/index.js.map +1 -0
- package/dist/src/pathfinding/astar.d.ts +50 -0
- package/dist/src/pathfinding/astar.d.ts.map +1 -0
- package/dist/src/pathfinding/astar.js +180 -0
- package/dist/src/pathfinding/astar.js.map +1 -0
- package/dist/src/pathfinding/index.d.ts +3 -0
- package/dist/src/pathfinding/index.d.ts.map +1 -0
- package/dist/src/pathfinding/index.js +3 -0
- package/dist/src/pathfinding/index.js.map +1 -0
- package/dist/src/pathfinding/utils.d.ts +18 -0
- package/dist/src/pathfinding/utils.d.ts.map +1 -0
- package/dist/src/pathfinding/utils.js +68 -0
- package/dist/src/pathfinding/utils.js.map +1 -0
- package/dist/src/types/index.d.ts +9 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/graphNode.d.ts +8 -0
- package/dist/src/utils/graphNode.d.ts.map +1 -0
- package/dist/src/utils/graphNode.js +2 -0
- package/dist/src/utils/graphNode.js.map +1 -0
- package/dist/src/utils/priorityQueue.d.ts +21 -0
- package/dist/src/utils/priorityQueue.d.ts.map +1 -0
- package/dist/src/utils/priorityQueue.js +101 -0
- package/dist/src/utils/priorityQueue.js.map +1 -0
- package/package.json +3 -1
- package/src/algorithms/centrality/betweenness.ts +25 -7
- package/src/algorithms/centrality/closeness.ts +7 -7
- package/src/algorithms/centrality/degree.ts +1 -1
- package/src/algorithms/centrality/eigenvector.ts +162 -0
- package/src/algorithms/centrality/hits.ts +210 -0
- package/src/algorithms/centrality/index.ts +6 -0
- package/src/algorithms/centrality/katz.ts +139 -0
- package/src/algorithms/centrality/pagerank.ts +3 -3
- package/src/algorithms/community/girvan-newman.ts +372 -0
- package/src/algorithms/community/index.ts +13 -0
- package/src/algorithms/community/label-propagation.ts +392 -0
- package/src/algorithms/community/leiden.ts +572 -0
- package/src/algorithms/community/louvain.ts +298 -0
- package/src/algorithms/components/connected.ts +7 -7
- package/src/algorithms/index.ts +21 -0
- package/src/algorithms/matching/bipartite.ts +179 -0
- package/src/algorithms/matching/index.ts +8 -0
- package/src/algorithms/matching/isomorphism.ts +392 -0
- package/src/algorithms/mst/index.ts +4 -0
- package/src/algorithms/mst/kruskal.ts +61 -0
- package/src/algorithms/mst/prim.ts +80 -0
- package/src/algorithms/shortest-path/bellman-ford.ts +2 -2
- package/src/algorithms/shortest-path/dijkstra.ts +5 -5
- package/src/algorithms/shortest-path/floyd-warshall.ts +170 -0
- package/src/algorithms/shortest-path/index.ts +2 -0
- package/src/algorithms/traversal/bfs.ts +2 -2
- package/src/algorithms/traversal/dfs.ts +11 -11
- package/src/clustering/hierarchical.ts +555 -0
- package/src/clustering/index.ts +6 -0
- package/src/clustering/k-core.ts +460 -0
- package/src/clustering/mcl.ts +454 -0
- package/src/clustering/spectral.ts +545 -0
- package/src/core/graph.ts +34 -6
- package/src/data-structures/union-find.ts +2 -2
- package/src/flow/ford-fulkerson.ts +459 -0
- package/src/flow/index.ts +2 -0
- package/src/flow/min-cut.ts +482 -0
- package/src/index.ts +2 -0
- package/src/link-prediction/adamic-adar.ts +353 -0
- package/src/link-prediction/common-neighbors.ts +252 -0
- package/src/link-prediction/index.ts +20 -0
- package/src/pathfinding/astar.ts +229 -0
- package/src/pathfinding/index.ts +2 -0
- package/src/pathfinding/utils.ts +87 -0
- package/src/types/index.ts +11 -0
- package/src/utils/graphNode.ts +7 -0
- package/src/utils/priorityQueue.ts +120 -0
- package/dist/test/browser/basic.test.d.ts +0 -2
- package/dist/test/browser/basic.test.d.ts.map +0 -1
- package/dist/test/browser/basic.test.js +0 -70
- package/dist/test/browser/basic.test.js.map +0 -1
- package/dist/test/unit/bellman-ford.test.d.ts +0 -2
- package/dist/test/unit/bellman-ford.test.d.ts.map +0 -1
- package/dist/test/unit/bellman-ford.test.js +0 -231
- package/dist/test/unit/bellman-ford.test.js.map +0 -1
- package/dist/test/unit/betweenness-centrality.test.d.ts +0 -2
- package/dist/test/unit/betweenness-centrality.test.d.ts.map +0 -1
- package/dist/test/unit/betweenness-centrality.test.js +0 -311
- package/dist/test/unit/betweenness-centrality.test.js.map +0 -1
- package/dist/test/unit/bfs.test.d.ts +0 -2
- package/dist/test/unit/bfs.test.d.ts.map +0 -1
- package/dist/test/unit/bfs.test.js +0 -277
- package/dist/test/unit/bfs.test.js.map +0 -1
- package/dist/test/unit/closeness.test.d.ts +0 -2
- package/dist/test/unit/closeness.test.d.ts.map +0 -1
- package/dist/test/unit/closeness.test.js +0 -266
- package/dist/test/unit/closeness.test.js.map +0 -1
- package/dist/test/unit/connected-components.test.d.ts +0 -2
- package/dist/test/unit/connected-components.test.d.ts.map +0 -1
- package/dist/test/unit/connected-components.test.js +0 -355
- package/dist/test/unit/connected-components.test.js.map +0 -1
- package/dist/test/unit/degree-centrality.test.d.ts +0 -2
- package/dist/test/unit/degree-centrality.test.d.ts.map +0 -1
- package/dist/test/unit/degree-centrality.test.js +0 -260
- package/dist/test/unit/degree-centrality.test.js.map +0 -1
- package/dist/test/unit/dfs.test.d.ts +0 -2
- package/dist/test/unit/dfs.test.d.ts.map +0 -1
- package/dist/test/unit/dfs.test.js +0 -350
- package/dist/test/unit/dfs.test.js.map +0 -1
- package/dist/test/unit/dijkstra.test.d.ts +0 -2
- package/dist/test/unit/dijkstra.test.d.ts.map +0 -1
- package/dist/test/unit/dijkstra.test.js +0 -311
- package/dist/test/unit/dijkstra.test.js.map +0 -1
- package/dist/test/unit/graph.test.d.ts +0 -2
- package/dist/test/unit/graph.test.d.ts.map +0 -1
- package/dist/test/unit/graph.test.js +0 -175
- package/dist/test/unit/graph.test.js.map +0 -1
- package/dist/test/unit/pagerank.test.d.ts +0 -2
- package/dist/test/unit/pagerank.test.d.ts.map +0 -1
- package/dist/test/unit/pagerank.test.js +0 -281
- package/dist/test/unit/pagerank.test.js.map +0 -1
- package/dist/test/unit/priority-queue.test.d.ts +0 -2
- package/dist/test/unit/priority-queue.test.d.ts.map +0 -1
- package/dist/test/unit/priority-queue.test.js +0 -189
- package/dist/test/unit/priority-queue.test.js.map +0 -1
- package/dist/test/unit/union-find.test.d.ts +0 -2
- package/dist/test/unit/union-find.test.d.ts.map +0 -1
- package/dist/test/unit/union-find.test.js +0 -245
- package/dist/test/unit/union-find.test.js.map +0 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Louvain community detection algorithm
|
|
3
|
+
*
|
|
4
|
+
* Implements the Louvain method for community detection in graphs.
|
|
5
|
+
* Uses modularity optimization to find community structure.
|
|
6
|
+
*
|
|
7
|
+
* References:
|
|
8
|
+
* - Blondel, V. D., Guillaume, J. L., Lambiotte, R., & Lefebvre, E. (2008).
|
|
9
|
+
* Fast unfolding of communities in large networks.
|
|
10
|
+
* Journal of statistical mechanics: theory and experiment, 2008(10), P10008.
|
|
11
|
+
*
|
|
12
|
+
* @param graph - The input graph
|
|
13
|
+
* @param options - Algorithm options
|
|
14
|
+
* @returns Community detection result with communities, modularity, and iterations
|
|
15
|
+
*/
|
|
16
|
+
export function louvain(graph, options = {}) {
|
|
17
|
+
const resolution = options.resolution ?? 1.0;
|
|
18
|
+
const maxIterations = options.maxIterations ?? 100;
|
|
19
|
+
const tolerance = options.tolerance ?? 1e-6;
|
|
20
|
+
// Initialize: each node in its own community
|
|
21
|
+
const communities = initializeCommunities(graph);
|
|
22
|
+
let modularity = calculateModularity(graph, communities, resolution);
|
|
23
|
+
let iteration = 0;
|
|
24
|
+
let improved = true;
|
|
25
|
+
while (iteration < maxIterations && improved) {
|
|
26
|
+
// Phase 1: Local optimization
|
|
27
|
+
improved = louvainPhase1(graph, communities, resolution);
|
|
28
|
+
if (improved) {
|
|
29
|
+
const newModularity = calculateModularity(graph, communities, resolution);
|
|
30
|
+
// Check for convergence
|
|
31
|
+
if ((newModularity - modularity) < tolerance) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
modularity = newModularity;
|
|
35
|
+
iteration++;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
communities: extractCommunities(communities),
|
|
40
|
+
modularity: calculateModularity(graph, communities, resolution),
|
|
41
|
+
iterations: iteration,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Initialize communities: each node in its own community
|
|
46
|
+
*/
|
|
47
|
+
function initializeCommunities(graph) {
|
|
48
|
+
const communities = new Map();
|
|
49
|
+
let communityId = 0;
|
|
50
|
+
for (const node of graph.nodes()) {
|
|
51
|
+
communities.set(node.id, communityId++);
|
|
52
|
+
}
|
|
53
|
+
return communities;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Phase 1 of Louvain algorithm: Local optimization
|
|
57
|
+
* For each node, try moving to neighboring communities and keep the move
|
|
58
|
+
* that provides the best modularity gain.
|
|
59
|
+
*/
|
|
60
|
+
function louvainPhase1(graph, communities, resolution) {
|
|
61
|
+
let globalImprovement = false;
|
|
62
|
+
let localImprovement = true;
|
|
63
|
+
while (localImprovement) {
|
|
64
|
+
localImprovement = false;
|
|
65
|
+
for (const node of graph.nodes()) {
|
|
66
|
+
const nodeId = node.id;
|
|
67
|
+
const currentCommunity = communities.get(nodeId);
|
|
68
|
+
if (currentCommunity === undefined) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// Calculate current modularity contribution
|
|
72
|
+
const currentModularity = nodeModularityContribution(graph, nodeId, currentCommunity, communities, resolution);
|
|
73
|
+
let bestCommunity = currentCommunity;
|
|
74
|
+
let bestModularity = currentModularity;
|
|
75
|
+
// Try moving to neighboring communities
|
|
76
|
+
const neighborCommunities = getNeighborCommunities(graph, nodeId, communities);
|
|
77
|
+
for (const neighborCommunity of neighborCommunities) {
|
|
78
|
+
if (neighborCommunity === currentCommunity) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const newModularity = nodeModularityContribution(graph, nodeId, neighborCommunity, communities, resolution);
|
|
82
|
+
if (newModularity > bestModularity) {
|
|
83
|
+
bestModularity = newModularity;
|
|
84
|
+
bestCommunity = neighborCommunity;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Move node if improvement found
|
|
88
|
+
if (bestCommunity !== currentCommunity) {
|
|
89
|
+
communities.set(nodeId, bestCommunity);
|
|
90
|
+
localImprovement = true;
|
|
91
|
+
globalImprovement = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return globalImprovement;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Calculate modularity contribution of a node to a specific community
|
|
99
|
+
*/
|
|
100
|
+
function nodeModularityContribution(graph, nodeId, community, communities, resolution) {
|
|
101
|
+
const totalEdgeWeight = getTotalEdgeWeight(graph);
|
|
102
|
+
if (totalEdgeWeight === 0) {
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
let internalLinks = 0;
|
|
106
|
+
let nodeDegree = 0;
|
|
107
|
+
let communityDegree = 0;
|
|
108
|
+
// Calculate node's connections to the community
|
|
109
|
+
for (const neighbor of graph.neighbors(nodeId)) {
|
|
110
|
+
const edge = graph.getEdge(nodeId, neighbor);
|
|
111
|
+
const weight = edge?.weight ?? 1;
|
|
112
|
+
nodeDegree += weight;
|
|
113
|
+
if (communities.get(neighbor) === community) {
|
|
114
|
+
internalLinks += weight;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Calculate total degree of the community (excluding the node if it's currently in it)
|
|
118
|
+
for (const [otherNodeId, otherCommunity] of communities) {
|
|
119
|
+
if (otherCommunity === community && otherNodeId !== nodeId) {
|
|
120
|
+
communityDegree += getNodeDegree(graph, otherNodeId);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Modularity formula: Q = (1/2m) * Σ[A_ij - (k_i * k_j)/(2m)] * δ(c_i, c_j)
|
|
124
|
+
const modularityIncrease = (internalLinks - ((resolution * nodeDegree * communityDegree) / (2 * totalEdgeWeight))) / totalEdgeWeight;
|
|
125
|
+
return modularityIncrease;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get communities of neighboring nodes
|
|
129
|
+
*/
|
|
130
|
+
function getNeighborCommunities(graph, nodeId, communities) {
|
|
131
|
+
const neighborCommunities = new Set();
|
|
132
|
+
for (const neighbor of graph.neighbors(nodeId)) {
|
|
133
|
+
const community = communities.get(neighbor);
|
|
134
|
+
if (community !== undefined) {
|
|
135
|
+
neighborCommunities.add(community);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return neighborCommunities;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Calculate total modularity of the current community assignment
|
|
142
|
+
*/
|
|
143
|
+
function calculateModularity(graph, communities, resolution) {
|
|
144
|
+
const totalEdgeWeight = getTotalEdgeWeight(graph);
|
|
145
|
+
if (totalEdgeWeight === 0) {
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
let modularity = 0;
|
|
149
|
+
// For undirected graphs, we need to be careful not to double-count edges
|
|
150
|
+
const countedEdges = new Set();
|
|
151
|
+
// Calculate modularity: Q = (1/2m) * Σ[A_ij - γ(k_i * k_j)/(2m)] * δ(c_i, c_j)
|
|
152
|
+
for (const nodeI of graph.nodes()) {
|
|
153
|
+
for (const nodeJ of graph.nodes()) {
|
|
154
|
+
// Skip if already counted this pair in undirected graph
|
|
155
|
+
if (!graph.isDirected) {
|
|
156
|
+
const nodeIStr = String(nodeI.id);
|
|
157
|
+
const nodeJStr = String(nodeJ.id);
|
|
158
|
+
const edgeKey = nodeIStr <= nodeJStr ? `${nodeIStr}-${nodeJStr}` : `${nodeJStr}-${nodeIStr}`;
|
|
159
|
+
if (countedEdges.has(edgeKey)) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
countedEdges.add(edgeKey);
|
|
163
|
+
}
|
|
164
|
+
if (communities.get(nodeI.id) === communities.get(nodeJ.id)) {
|
|
165
|
+
const edge = graph.getEdge(nodeI.id, nodeJ.id);
|
|
166
|
+
const reverseEdge = !graph.isDirected ? graph.getEdge(nodeJ.id, nodeI.id) : null;
|
|
167
|
+
let edgeWeight = 0;
|
|
168
|
+
if (edge) {
|
|
169
|
+
edgeWeight += edge.weight ?? 1;
|
|
170
|
+
}
|
|
171
|
+
if (reverseEdge && nodeI.id !== nodeJ.id) {
|
|
172
|
+
edgeWeight += reverseEdge.weight ?? 1;
|
|
173
|
+
}
|
|
174
|
+
const degreeI = getNodeDegree(graph, nodeI.id);
|
|
175
|
+
const degreeJ = getNodeDegree(graph, nodeJ.id);
|
|
176
|
+
modularity += edgeWeight - ((resolution * degreeI * degreeJ) / (2 * totalEdgeWeight));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return modularity / (2 * totalEdgeWeight);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Extract final community structure
|
|
184
|
+
*/
|
|
185
|
+
function extractCommunities(communities) {
|
|
186
|
+
const communityMap = new Map();
|
|
187
|
+
for (const [nodeId, community] of communities) {
|
|
188
|
+
if (!communityMap.has(community)) {
|
|
189
|
+
communityMap.set(community, []);
|
|
190
|
+
}
|
|
191
|
+
const communityNodes = communityMap.get(community);
|
|
192
|
+
if (communityNodes) {
|
|
193
|
+
communityNodes.push(nodeId);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return Array.from(communityMap.values());
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Calculate total edge weight in the graph
|
|
200
|
+
*/
|
|
201
|
+
function getTotalEdgeWeight(graph) {
|
|
202
|
+
let totalWeight = 0;
|
|
203
|
+
for (const edge of graph.edges()) {
|
|
204
|
+
totalWeight += edge.weight ?? 1;
|
|
205
|
+
}
|
|
206
|
+
return totalWeight;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get the total degree (sum of edge weights) for a node
|
|
210
|
+
*/
|
|
211
|
+
function getNodeDegree(graph, nodeId) {
|
|
212
|
+
let degree = 0;
|
|
213
|
+
for (const neighbor of graph.neighbors(nodeId)) {
|
|
214
|
+
const edge = graph.getEdge(nodeId, neighbor);
|
|
215
|
+
degree += edge?.weight ?? 1;
|
|
216
|
+
}
|
|
217
|
+
return degree;
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=louvain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"louvain.js","sourceRoot":"","sources":["../../../../src/algorithms/community/louvain.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ export function connectedComponents(graph) {
|
|
|
18
18
|
}
|
|
19
19
|
const unionFind = new UnionFind(nodes);
|
|
20
20
|
// Union connected nodes
|
|
21
|
-
for (const edge of graph.edges()) {
|
|
21
|
+
for (const edge of Array.from(graph.edges())) {
|
|
22
22
|
unionFind.union(edge.source, edge.target);
|
|
23
23
|
}
|
|
24
24
|
return unionFind.getAllComponents();
|
|
@@ -32,7 +32,7 @@ export function connectedComponentsDFS(graph) {
|
|
|
32
32
|
}
|
|
33
33
|
const visited = new Set();
|
|
34
34
|
const components = [];
|
|
35
|
-
for (const node of graph.nodes()) {
|
|
35
|
+
for (const node of Array.from(graph.nodes())) {
|
|
36
36
|
if (!visited.has(node.id)) {
|
|
37
37
|
const component = [];
|
|
38
38
|
dfsComponent(graph, node.id, visited, component);
|
|
@@ -47,7 +47,7 @@ export function connectedComponentsDFS(graph) {
|
|
|
47
47
|
function dfsComponent(graph, nodeId, visited, component) {
|
|
48
48
|
visited.add(nodeId);
|
|
49
49
|
component.push(nodeId);
|
|
50
|
-
for (const neighbor of graph.neighbors(nodeId)) {
|
|
50
|
+
for (const neighbor of Array.from(graph.neighbors(nodeId))) {
|
|
51
51
|
if (!visited.has(neighbor)) {
|
|
52
52
|
dfsComponent(graph, neighbor, visited, component);
|
|
53
53
|
}
|
|
@@ -112,7 +112,7 @@ export function stronglyConnectedComponents(graph) {
|
|
|
112
112
|
stack.push(nodeId);
|
|
113
113
|
onStack.add(nodeId);
|
|
114
114
|
// Consider successors
|
|
115
|
-
for (const neighbor of graph.neighbors(nodeId)) {
|
|
115
|
+
for (const neighbor of Array.from(graph.neighbors(nodeId))) {
|
|
116
116
|
if (!indices.has(neighbor)) {
|
|
117
117
|
// Successor has not yet been visited; recurse on it
|
|
118
118
|
tarjanSCC(neighbor);
|
|
@@ -176,7 +176,7 @@ export function weaklyConnectedComponents(graph) {
|
|
|
176
176
|
}
|
|
177
177
|
const unionFind = new UnionFind(nodes);
|
|
178
178
|
// Union nodes connected by edges (ignore direction)
|
|
179
|
-
for (const edge of graph.edges()) {
|
|
179
|
+
for (const edge of Array.from(graph.edges())) {
|
|
180
180
|
unionFind.union(edge.source, edge.target);
|
|
181
181
|
}
|
|
182
182
|
return unionFind.getAllComponents();
|
|
@@ -213,12 +213,12 @@ export function condensationGraph(graph) {
|
|
|
213
213
|
}
|
|
214
214
|
// Add edges between components
|
|
215
215
|
const addedEdges = new Set();
|
|
216
|
-
for (const edge of graph.edges()) {
|
|
216
|
+
for (const edge of Array.from(graph.edges())) {
|
|
217
217
|
const sourceComponent = componentMap.get(edge.source);
|
|
218
218
|
const targetComponent = componentMap.get(edge.target);
|
|
219
219
|
if (sourceComponent !== undefined && targetComponent !== undefined &&
|
|
220
220
|
sourceComponent !== targetComponent) {
|
|
221
|
-
const edgeKey = `${sourceComponent}-${targetComponent}`;
|
|
221
|
+
const edgeKey = `${String(sourceComponent)}-${String(targetComponent)}`;
|
|
222
222
|
if (!addedEdges.has(edgeKey)) {
|
|
223
223
|
condensedGraph.addEdge(sourceComponent, targetComponent);
|
|
224
224
|
addedEdges.add(edgeKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connected.js","sourceRoot":"","sources":["../../../../src/algorithms/components/connected.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,qCAAqC,CAAC;AAG9D;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAY;IAC5C,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,mHAAmH,CAAC,CAAC;IACzI,CAAC;IAED,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,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;IAEvC,wBAAwB;IACxB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"connected.js","sourceRoot":"","sources":["../../../../src/algorithms/components/connected.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,4 +5,11 @@ export * from "./traversal/index.js";
|
|
|
5
5
|
export * from "./shortest-path/index.js";
|
|
6
6
|
export * from "./centrality/index.js";
|
|
7
7
|
export * from "./components/index.js";
|
|
8
|
+
export * from "./mst/index.js";
|
|
9
|
+
export * from "./community/index.js";
|
|
10
|
+
export * from "../pathfinding/index.js";
|
|
11
|
+
export * from "../flow/index.js";
|
|
12
|
+
export * from "../clustering/index.js";
|
|
13
|
+
export * from "./matching/index.js";
|
|
14
|
+
export * from "../link-prediction/index.js";
|
|
8
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +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"}
|
|
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;AAGtC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,sBAAsB,CAAC;AAGrC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,6BAA6B,CAAC"}
|
|
@@ -9,4 +9,18 @@ export * from "./shortest-path/index.js";
|
|
|
9
9
|
export * from "./centrality/index.js";
|
|
10
10
|
// Connected components algorithms
|
|
11
11
|
export * from "./components/index.js";
|
|
12
|
+
// Minimum spanning tree algorithms
|
|
13
|
+
export * from "./mst/index.js";
|
|
14
|
+
// Community detection algorithms
|
|
15
|
+
export * from "./community/index.js";
|
|
16
|
+
// Pathfinding algorithms
|
|
17
|
+
export * from "../pathfinding/index.js";
|
|
18
|
+
// Flow algorithms
|
|
19
|
+
export * from "../flow/index.js";
|
|
20
|
+
// Clustering algorithms
|
|
21
|
+
export * from "../clustering/index.js";
|
|
22
|
+
// Matching algorithms
|
|
23
|
+
export * from "./matching/index.js";
|
|
24
|
+
// Link prediction algorithms
|
|
25
|
+
export * from "../link-prediction/index.js";
|
|
12
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +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"}
|
|
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;AAEtC,mCAAmC;AACnC,cAAc,gBAAgB,CAAC;AAE/B,iCAAiC;AACjC,cAAc,sBAAsB,CAAC;AAErC,yBAAyB;AACzB,cAAc,yBAAyB,CAAC;AAExC,kBAAkB;AAClB,cAAc,kBAAkB,CAAC;AAEjC,wBAAwB;AACxB,cAAc,wBAAwB,CAAC;AAEvC,sBAAsB;AACtB,cAAc,qBAAqB,CAAC;AAEpC,6BAA6B;AAC7B,cAAc,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Maximum Bipartite Matching implementation using Hopcroft-Karp algorithm
|
|
5
|
+
*
|
|
6
|
+
* Finds the maximum matching in a bipartite graph. A matching is a set of edges
|
|
7
|
+
* without common vertices. Maximum matching has the largest possible number of edges.
|
|
8
|
+
*
|
|
9
|
+
* Time complexity: O(√V × E)
|
|
10
|
+
* Space complexity: O(V)
|
|
11
|
+
*/
|
|
12
|
+
export interface BipartiteMatchingResult {
|
|
13
|
+
matching: Map<NodeId, NodeId>;
|
|
14
|
+
size: number;
|
|
15
|
+
}
|
|
16
|
+
export interface BipartiteMatchingOptions {
|
|
17
|
+
leftNodes?: Set<NodeId>;
|
|
18
|
+
rightNodes?: Set<NodeId>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Find maximum matching in a bipartite graph using augmenting path algorithm
|
|
22
|
+
* (simplified implementation that's more reliable than Hopcroft-Karp for this context)
|
|
23
|
+
*/
|
|
24
|
+
export declare function maximumBipartiteMatching(graph: Graph, options?: BipartiteMatchingOptions): BipartiteMatchingResult;
|
|
25
|
+
/**
|
|
26
|
+
* Check if graph is bipartite and return the partition
|
|
27
|
+
*/
|
|
28
|
+
export declare function bipartitePartition(graph: Graph): {
|
|
29
|
+
left: Set<NodeId>;
|
|
30
|
+
right: Set<NodeId>;
|
|
31
|
+
} | null;
|
|
32
|
+
/**
|
|
33
|
+
* Simple greedy bipartite matching algorithm
|
|
34
|
+
* Useful for comparison or when Hopcroft-Karp is overkill
|
|
35
|
+
*/
|
|
36
|
+
export declare function greedyBipartiteMatching(graph: Graph, options?: BipartiteMatchingOptions): BipartiteMatchingResult;
|
|
37
|
+
//# sourceMappingURL=bipartite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bipartite.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/matching/bipartite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAEjD;;;;;;;;GAQG;AAEH,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACrC,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,KAAK,EACZ,OAAO,GAAE,wBAA6B,GACvC,uBAAuB,CAsDzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG;IAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAC,GAAG,IAAI,CAgD/F;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACnC,KAAK,EAAE,KAAK,EACZ,OAAO,GAAE,wBAA6B,GACvC,uBAAuB,CAgCzB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find maximum matching in a bipartite graph using augmenting path algorithm
|
|
3
|
+
* (simplified implementation that's more reliable than Hopcroft-Karp for this context)
|
|
4
|
+
*/
|
|
5
|
+
export function maximumBipartiteMatching(graph, options = {}) {
|
|
6
|
+
// If partitions not provided, try to infer them
|
|
7
|
+
let { leftNodes, rightNodes } = options;
|
|
8
|
+
if (!leftNodes || !rightNodes) {
|
|
9
|
+
const partition = bipartitePartition(graph);
|
|
10
|
+
if (!partition) {
|
|
11
|
+
throw new Error("Graph is not bipartite");
|
|
12
|
+
}
|
|
13
|
+
leftNodes = partition.left;
|
|
14
|
+
rightNodes = partition.right;
|
|
15
|
+
}
|
|
16
|
+
const matching = new Map();
|
|
17
|
+
const matchRight = new Map(); // Right to left matching
|
|
18
|
+
// Find augmenting paths using DFS
|
|
19
|
+
const visited = new Set();
|
|
20
|
+
const dfs = (u) => {
|
|
21
|
+
const neighbors = Array.from(graph.neighbors(u));
|
|
22
|
+
for (const v of neighbors) {
|
|
23
|
+
if (!rightNodes.has(v) || visited.has(v)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
visited.add(v);
|
|
27
|
+
// If v is unmatched or we can find augmenting path from match of v
|
|
28
|
+
const matchedNode = matchRight.get(v);
|
|
29
|
+
if (!matchRight.has(v) || (matchedNode !== undefined && dfs(matchedNode))) {
|
|
30
|
+
matching.set(u, v);
|
|
31
|
+
matchRight.set(v, u);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
};
|
|
37
|
+
// Try to find augmenting path for each left node
|
|
38
|
+
let matchingSize = 0;
|
|
39
|
+
for (const u of leftNodes) {
|
|
40
|
+
visited.clear();
|
|
41
|
+
if (dfs(u)) {
|
|
42
|
+
matchingSize++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
matching,
|
|
47
|
+
size: matchingSize,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if graph is bipartite and return the partition
|
|
52
|
+
*/
|
|
53
|
+
export function bipartitePartition(graph) {
|
|
54
|
+
const color = new Map();
|
|
55
|
+
const left = new Set();
|
|
56
|
+
const right = new Set();
|
|
57
|
+
const nodes = Array.from(graph.nodes());
|
|
58
|
+
for (const startNode of nodes) {
|
|
59
|
+
if (color.has(startNode.id)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
// BFS to color the component
|
|
63
|
+
const queue = [startNode.id];
|
|
64
|
+
color.set(startNode.id, true);
|
|
65
|
+
left.add(startNode.id);
|
|
66
|
+
while (queue.length > 0) {
|
|
67
|
+
const u = queue.shift();
|
|
68
|
+
if (u === undefined) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const uColor = color.get(u);
|
|
72
|
+
if (uColor === undefined) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const neighbors = Array.from(graph.neighbors(u));
|
|
76
|
+
for (const v of neighbors) {
|
|
77
|
+
if (!color.has(v)) {
|
|
78
|
+
color.set(v, !uColor);
|
|
79
|
+
if (!uColor) {
|
|
80
|
+
left.add(v);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
right.add(v);
|
|
84
|
+
}
|
|
85
|
+
queue.push(v);
|
|
86
|
+
}
|
|
87
|
+
else if (color.get(v) === uColor) {
|
|
88
|
+
// Same color as neighbor - not bipartite
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { left, right };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Simple greedy bipartite matching algorithm
|
|
98
|
+
* Useful for comparison or when Hopcroft-Karp is overkill
|
|
99
|
+
*/
|
|
100
|
+
export function greedyBipartiteMatching(graph, options = {}) {
|
|
101
|
+
let { leftNodes, rightNodes } = options;
|
|
102
|
+
if (!leftNodes || !rightNodes) {
|
|
103
|
+
const partition = bipartitePartition(graph);
|
|
104
|
+
if (!partition) {
|
|
105
|
+
throw new Error("Graph is not bipartite");
|
|
106
|
+
}
|
|
107
|
+
leftNodes = partition.left;
|
|
108
|
+
rightNodes = partition.right;
|
|
109
|
+
}
|
|
110
|
+
const matching = new Map();
|
|
111
|
+
const matched = new Set();
|
|
112
|
+
for (const u of leftNodes) {
|
|
113
|
+
const neighbors = Array.from(graph.neighbors(u));
|
|
114
|
+
for (const v of neighbors) {
|
|
115
|
+
if (rightNodes.has(v) && !matched.has(v)) {
|
|
116
|
+
matching.set(u, v);
|
|
117
|
+
matched.add(v);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
matching,
|
|
124
|
+
size: matching.size,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=bipartite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bipartite.js","sourceRoot":"","sources":["../../../../src/algorithms/matching/bipartite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph matching algorithms
|
|
3
|
+
*/
|
|
4
|
+
export type { BipartiteMatchingOptions, BipartiteMatchingResult } from "./bipartite.js";
|
|
5
|
+
export { bipartitePartition, greedyBipartiteMatching, maximumBipartiteMatching } from "./bipartite.js";
|
|
6
|
+
export type { IsomorphismOptions, IsomorphismResult } from "./isomorphism.js";
|
|
7
|
+
export { findAllIsomorphisms, isGraphIsomorphic } from "./isomorphism.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/matching/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAC,wBAAwB,EAAE,uBAAuB,EAAC,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAC,kBAAkB,EAAE,uBAAuB,EAAE,wBAAwB,EAAC,MAAM,gBAAgB,CAAC;AACrG,YAAY,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAC,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/algorithms/matching/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAC,kBAAkB,EAAE,uBAAuB,EAAE,wBAAwB,EAAC,MAAM,gBAAgB,CAAC;AAErG,OAAO,EAAC,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Graph Isomorphism (VF2) algorithm implementation
|
|
5
|
+
*
|
|
6
|
+
* Determines if two graphs are isomorphic (structurally identical).
|
|
7
|
+
* Two graphs are isomorphic if there exists a bijection between their vertices
|
|
8
|
+
* that preserves adjacency.
|
|
9
|
+
*
|
|
10
|
+
* Based on the VF2 algorithm by Cordella et al. (2004)
|
|
11
|
+
*
|
|
12
|
+
* Time complexity: O(n! × n) worst case, but typically much faster
|
|
13
|
+
* Space complexity: O(n)
|
|
14
|
+
*/
|
|
15
|
+
export interface IsomorphismResult {
|
|
16
|
+
isIsomorphic: boolean;
|
|
17
|
+
mapping?: Map<NodeId, NodeId>;
|
|
18
|
+
}
|
|
19
|
+
export interface IsomorphismOptions {
|
|
20
|
+
nodeMatch?: (node1: NodeId, node2: NodeId, g1: Graph, g2: Graph) => boolean;
|
|
21
|
+
edgeMatch?: (edge1: [NodeId, NodeId], edge2: [NodeId, NodeId], g1: Graph, g2: Graph) => boolean;
|
|
22
|
+
findAllMappings?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if two graphs are isomorphic using VF2 algorithm
|
|
26
|
+
*/
|
|
27
|
+
export declare function isGraphIsomorphic(graph1: Graph, graph2: Graph, options?: IsomorphismOptions): IsomorphismResult;
|
|
28
|
+
/**
|
|
29
|
+
* Find all isomorphisms between two graphs
|
|
30
|
+
*/
|
|
31
|
+
export declare function findAllIsomorphisms(graph1: Graph, graph2: Graph, options?: IsomorphismOptions): Map<NodeId, NodeId>[];
|
|
32
|
+
//# sourceMappingURL=isomorphism.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isomorphism.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/matching/isomorphism.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAEjD;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,iBAAiB;IAC9B,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC;IAC5E,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC;IAChG,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAYD;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,KAAK,EACb,MAAM,EAAE,KAAK,EACb,OAAO,GAAE,kBAAuB,GACjC,iBAAiB,CA8CnB;AA0PD;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,KAAK,EACb,MAAM,EAAE,KAAK,EACb,OAAO,GAAE,kBAAuB,GACjC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CA4CvB"}
|