@graphty/algorithms 1.1.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +820 -235
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11099 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +124 -170
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +56 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +3 -3
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/index.d.ts +2 -0
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +1 -0
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +45 -0
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +47 -54
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/index.d.ts +2 -0
- package/dist/src/algorithms/community/index.d.ts.map +1 -1
- package/dist/src/algorithms/community/index.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +13 -3
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +50 -35
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -2
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +34 -39
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +303 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +17 -76
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +112 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +8 -40
- package/dist/src/algorithms/matching/bipartite.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +368 -0
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +5 -182
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/benchmark-all-algorithms.d.ts +23 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +462 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +16 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +209 -223
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/index.d.ts +4 -2
- package/dist/src/clustering/index.d.ts.map +1 -1
- package/dist/src/clustering/index.js +2 -2
- package/dist/src/clustering/index.js.map +1 -1
- package/dist/src/clustering/k-core.d.ts +16 -15
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +57 -21
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +8 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +158 -35
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.js +4 -4
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +17 -11
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +141 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -5
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +17 -8
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +17 -26
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +7 -11
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +143 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +292 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +86 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +341 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +223 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +62 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +146 -0
- package/dist/src/optimized/graph-adapter.js.map +1 -0
- package/dist/src/optimized/index.d.ts +14 -0
- package/dist/src/optimized/index.d.ts.map +1 -0
- package/dist/src/optimized/index.js +28 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/research/grsbm.d.ts +83 -0
- package/dist/src/research/grsbm.d.ts.map +1 -0
- package/dist/src/research/grsbm.js +403 -0
- package/dist/src/research/grsbm.js.map +1 -0
- package/dist/src/research/index.d.ts +12 -0
- package/dist/src/research/index.d.ts.map +1 -0
- package/dist/src/research/index.js +14 -0
- package/dist/src/research/index.js.map +1 -0
- package/dist/src/research/sync.d.ts +49 -0
- package/dist/src/research/sync.d.ts.map +1 -0
- package/dist/src/research/sync.js +316 -0
- package/dist/src/research/sync.js.map +1 -0
- package/dist/src/research/terahac.d.ts +65 -0
- package/dist/src/research/terahac.d.ts.map +1 -0
- package/dist/src/research/terahac.js +379 -0
- package/dist/src/research/terahac.js.map +1 -0
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/algorithm-utilities.d.ts +2 -0
- package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
- package/dist/src/utils/algorithm-utilities.js +2 -0
- package/dist/src/utils/algorithm-utilities.js.map +1 -0
- package/dist/src/utils/graph-converters.d.ts +79 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +196 -0
- package/dist/src/utils/graph-converters.js.map +1 -0
- package/dist/src/utils/graph-utilities.d.ts +62 -0
- package/dist/src/utils/graph-utilities.d.ts.map +1 -0
- package/dist/src/utils/graph-utilities.js +148 -0
- package/dist/src/utils/graph-utilities.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +5 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/math-utilities.d.ts +52 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +123 -0
- package/dist/src/utils/math-utilities.js.map +1 -0
- package/dist/src/utils/matrix-utilities.d.ts +2 -0
- package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
- package/dist/src/utils/matrix-utilities.js +2 -0
- package/dist/src/utils/matrix-utilities.js.map +1 -0
- package/dist/src/utils/optimization-helpers.d.ts +33 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +47 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/package.json +28 -4
- package/src/algorithms/centrality/betweenness.ts +167 -199
- package/src/algorithms/centrality/closeness.ts +73 -191
- package/src/algorithms/centrality/degree.ts +3 -3
- package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
- package/src/algorithms/centrality/delta-pagerank.ts +435 -0
- package/src/algorithms/centrality/index.ts +2 -0
- package/src/algorithms/centrality/pagerank.ts +66 -0
- package/src/algorithms/community/girvan-newman.ts +52 -59
- package/src/algorithms/community/index.ts +2 -0
- package/src/algorithms/community/label-propagation.ts +64 -35
- package/src/algorithms/community/leiden.ts +40 -41
- package/src/algorithms/community/louvain-optimized.ts +445 -0
- package/src/algorithms/community/louvain.ts +24 -104
- package/src/algorithms/community/modularity-utils.ts +146 -0
- package/src/algorithms/matching/bipartite.ts +8 -44
- package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +17 -15
- package/src/algorithms/traversal/bfs-unified.ts +433 -0
- package/src/algorithms/traversal/bfs-variants.ts +496 -0
- package/src/algorithms/traversal/bfs.ts +10 -228
- package/src/benchmark-all-algorithms.ts +548 -0
- package/src/clustering/hierarchical.ts +241 -251
- package/src/clustering/index.ts +4 -2
- package/src/clustering/k-core.ts +87 -39
- package/src/clustering/spectral.ts +185 -34
- package/src/core/graph.ts +4 -4
- package/src/flow/ford-fulkerson.ts +186 -254
- package/src/flow/min-cut.ts +21 -11
- package/src/index.ts +9 -0
- package/src/link-prediction/adamic-adar.ts +17 -30
- package/src/link-prediction/common-neighbors.ts +7 -16
- package/src/optimized/bit-packed.ts +340 -0
- package/src/optimized/csr-graph.ts +455 -0
- package/src/optimized/direction-optimized-bfs.ts +291 -0
- package/src/optimized/graph-adapter.ts +200 -0
- package/src/optimized/index.ts +36 -0
- package/src/research/grsbm.ts +580 -0
- package/src/research/index.ts +17 -0
- package/src/research/sync.ts +440 -0
- package/src/research/terahac.ts +514 -0
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +241 -0
- package/src/utils/graph-utilities.ts +199 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +140 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +81 -0
package/README.md
CHANGED
|
@@ -1,20 +1,60 @@
|
|
|
1
1
|
# @graphty/algorithms
|
|
2
2
|
|
|
3
|
-
[](https://github.com/graphty-org/algorithms/actions/workflows/test.yml)
|
|
4
|
+
[](https://coveralls.io/github/graphty-org/algorithms)
|
|
5
5
|
[](https://www.npmjs.com/package/@graphty/algorithms)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://graphty-org.github.io/algorithms/)
|
|
6
8
|
|
|
7
|
-
A comprehensive TypeScript graph algorithms library with
|
|
9
|
+
A comprehensive TypeScript graph algorithms library with 98 algorithms optimized for browser environments and visualization applications.
|
|
8
10
|
|
|
9
11
|
## Features
|
|
10
12
|
|
|
11
13
|
- **TypeScript-first**: Full type safety with comprehensive type definitions
|
|
12
14
|
- **Browser-optimized**: Designed to run efficiently in web browsers
|
|
13
15
|
- **Modular**: Import only the algorithms you need
|
|
14
|
-
- **Comprehensive**:
|
|
16
|
+
- **Comprehensive**: 98 graph algorithms including traversal, shortest paths, centrality, clustering, flow, matching, link prediction, and more
|
|
17
|
+
- **Interactive Examples**: [Live demos](https://graphty-org.github.io/algorithms/) with visualizations for all algorithms
|
|
18
|
+
- **Performance Analysis**: [Detailed benchmarks](https://graphty-org.github.io/algorithms/benchmarks/) comparing algorithm performance
|
|
15
19
|
- **Well-tested**: Extensive test suite with high coverage
|
|
16
20
|
- **Standards-compliant**: Follows conventional commits and semantic versioning
|
|
17
21
|
|
|
22
|
+
## Performance Optimizations
|
|
23
|
+
|
|
24
|
+
The library automatically optimizes performance for large graphs (≥10,000 nodes) using:
|
|
25
|
+
|
|
26
|
+
- **Direction-Optimized BFS**: Dynamically switches between top-down and bottom-up search strategies, providing up to 42x speedup on large graphs
|
|
27
|
+
- **CSR Graph Format**: Compressed Sparse Row format for cache-efficient memory access
|
|
28
|
+
- **Bit-Packed Data Structures**: 8x memory reduction using bit arrays for boolean data
|
|
29
|
+
|
|
30
|
+
These optimizations are applied automatically - no configuration needed! Just use the standard API:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Automatically uses optimized implementation for large graphs
|
|
34
|
+
const result = breadthFirstSearch(largeGraph, startNode);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
All BFS-based algorithms benefit from these optimizations:
|
|
38
|
+
- `breadthFirstSearch`, `shortestPathBFS`, `singleSourceShortestPathBFS`
|
|
39
|
+
- `betweennessCentrality`, `closenessCentrality`
|
|
40
|
+
- Connected component algorithms
|
|
41
|
+
|
|
42
|
+
### Performance Benchmarks
|
|
43
|
+
|
|
44
|
+
| Graph Size | Standard BFS | Optimized BFS | Speedup |
|
|
45
|
+
|------------|--------------|---------------|---------|
|
|
46
|
+
| 10K nodes | 4.40ms | 6.34ms | 0.69x |
|
|
47
|
+
| 50K nodes | 158.64ms | 44.27ms | 3.58x |
|
|
48
|
+
| 100K nodes | 5,370ms | 126ms | 42.58x |
|
|
49
|
+
|
|
50
|
+
*Note: Optimizations activate automatically for graphs ≥10K nodes to avoid conversion overhead on smaller graphs.*
|
|
51
|
+
|
|
52
|
+
### Learn More
|
|
53
|
+
|
|
54
|
+
- 📖 [Performance Guide](docs/PERFORMANCE_GUIDE.md) - Detailed optimization explanations
|
|
55
|
+
- 🔄 [Migration Guide](docs/MIGRATION_GUIDE.md) - Upgrading from older versions
|
|
56
|
+
- 💾 [Memory vs Speed Tradeoffs](docs/PERFORMANCE_GUIDE.md#memory-vs-speed-tradeoffs) - Making the right choices
|
|
57
|
+
|
|
18
58
|
## Installation
|
|
19
59
|
|
|
20
60
|
```bash
|
|
@@ -24,29 +64,31 @@ npm install @graphty/algorithms
|
|
|
24
64
|
## Quick Start
|
|
25
65
|
|
|
26
66
|
```typescript
|
|
27
|
-
import { Graph, breadthFirstSearch, dijkstra } from '@graphty/algorithms'
|
|
67
|
+
import { Graph, breadthFirstSearch, dijkstra } from '@graphty/algorithms'
|
|
28
68
|
|
|
29
69
|
// Create a new graph
|
|
30
|
-
const graph = new Graph()
|
|
70
|
+
const graph = new Graph()
|
|
31
71
|
|
|
32
72
|
// Add nodes and edges
|
|
33
|
-
graph.addNode('A')
|
|
34
|
-
graph.addNode('B')
|
|
35
|
-
graph.addNode('C')
|
|
36
|
-
graph.addEdge('A', 'B', 1)
|
|
37
|
-
graph.addEdge('B', 'C', 2)
|
|
73
|
+
graph.addNode('A')
|
|
74
|
+
graph.addNode('B')
|
|
75
|
+
graph.addNode('C')
|
|
76
|
+
graph.addEdge('A', 'B', 1) // source, target, weight
|
|
77
|
+
graph.addEdge('B', 'C', 2)
|
|
38
78
|
|
|
39
79
|
// Basic graph operations
|
|
40
|
-
console.log(graph.nodeCount)
|
|
41
|
-
console.log(graph.totalEdgeCount)
|
|
42
|
-
console.log(graph.hasEdge('A', 'B'))
|
|
80
|
+
console.log(graph.nodeCount) // 3
|
|
81
|
+
console.log(graph.totalEdgeCount) // 2
|
|
82
|
+
console.log(graph.hasEdge('A', 'B')) // true
|
|
43
83
|
|
|
44
84
|
// Run algorithms
|
|
45
|
-
const traversal = breadthFirstSearch(graph, 'A')
|
|
46
|
-
console.log(traversal.order)
|
|
85
|
+
const traversal = breadthFirstSearch(graph, 'A')
|
|
86
|
+
console.log(traversal.order) // ['A', 'B', 'C']
|
|
47
87
|
|
|
48
|
-
const shortestPaths = dijkstra(graph, 'A')
|
|
49
|
-
|
|
88
|
+
const shortestPaths = dijkstra(graph, 'A')
|
|
89
|
+
// Get distance to C
|
|
90
|
+
const pathToC = shortestPaths.get('C')
|
|
91
|
+
console.log(pathToC?.distance) // 3
|
|
50
92
|
```
|
|
51
93
|
|
|
52
94
|
## API Reference
|
|
@@ -65,9 +107,9 @@ class Graph {
|
|
|
65
107
|
|
|
66
108
|
```typescript
|
|
67
109
|
interface GraphConfig {
|
|
68
|
-
directed: boolean
|
|
69
|
-
allowSelfLoops: boolean
|
|
70
|
-
allowParallelEdges: boolean
|
|
110
|
+
directed: boolean // Default: false
|
|
111
|
+
allowSelfLoops: boolean // Default: false
|
|
112
|
+
allowParallelEdges: boolean // Default: false
|
|
71
113
|
}
|
|
72
114
|
```
|
|
73
115
|
|
|
@@ -95,9 +137,9 @@ graph.nodes(): IterableIterator<Node>
|
|
|
95
137
|
```typescript
|
|
96
138
|
// Add an edge with optional weight and data
|
|
97
139
|
graph.addEdge(
|
|
98
|
-
source: NodeId,
|
|
99
|
-
target: NodeId,
|
|
100
|
-
weight?: number,
|
|
140
|
+
source: NodeId,
|
|
141
|
+
target: NodeId,
|
|
142
|
+
weight?: number,
|
|
101
143
|
data?: Record<string, unknown>
|
|
102
144
|
): void
|
|
103
145
|
|
|
@@ -164,6 +206,9 @@ graph.clone(): Graph
|
|
|
164
206
|
|
|
165
207
|
// Clear all nodes and edges
|
|
166
208
|
graph.clear(): void
|
|
209
|
+
|
|
210
|
+
// Get a copy of the graph configuration
|
|
211
|
+
graph.getConfig(): GraphConfig
|
|
167
212
|
```
|
|
168
213
|
|
|
169
214
|
### Traversal Algorithms
|
|
@@ -171,22 +216,28 @@ graph.clear(): void
|
|
|
171
216
|
#### Breadth-First Search (BFS)
|
|
172
217
|
|
|
173
218
|
```typescript
|
|
174
|
-
import { breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS } from '@graphty/algorithms';
|
|
219
|
+
import { breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS, isBipartite } from '@graphty/algorithms';
|
|
175
220
|
|
|
176
221
|
// Basic BFS traversal
|
|
177
222
|
const result = breadthFirstSearch(graph, startNode, {
|
|
178
|
-
|
|
179
|
-
visitCallback?: (node: NodeId,
|
|
223
|
+
targetNode?: NodeId, // Optional: stop when target is reached
|
|
224
|
+
visitCallback?: (node: NodeId, level: number) => void
|
|
180
225
|
});
|
|
181
|
-
// Returns: TraversalResult { visited: Set<NodeId>, order: NodeId[], tree?: Map<NodeId, NodeId> }
|
|
226
|
+
// Returns: TraversalResult { visited: Set<NodeId>, order: NodeId[], tree?: Map<NodeId, NodeId | null> }
|
|
227
|
+
|
|
228
|
+
// Note: For graphs with ≥10K nodes, BFS automatically uses:
|
|
229
|
+
// - Direction-Optimized BFS (switches between top-down/bottom-up)
|
|
230
|
+
// - CSR graph format for cache efficiency
|
|
231
|
+
// - Bit-packed data structures for memory efficiency
|
|
182
232
|
|
|
183
233
|
// Find shortest path between two nodes (unweighted)
|
|
184
234
|
const path = shortestPathBFS(graph, source, target);
|
|
185
|
-
// Returns:
|
|
235
|
+
// Returns: ShortestPathResult | null
|
|
236
|
+
// ShortestPathResult = { distance: number, path: NodeId[], predecessor: Map<NodeId, NodeId | null> }
|
|
186
237
|
|
|
187
238
|
// Find all shortest paths from a source
|
|
188
239
|
const paths = singleSourceShortestPathBFS(graph, source);
|
|
189
|
-
// Returns: Map<NodeId,
|
|
240
|
+
// Returns: Map<NodeId, ShortestPathResult>
|
|
190
241
|
|
|
191
242
|
// Check if graph is bipartite
|
|
192
243
|
const bipartite = isBipartite(graph);
|
|
@@ -196,12 +247,14 @@ const bipartite = isBipartite(graph);
|
|
|
196
247
|
#### Depth-First Search (DFS)
|
|
197
248
|
|
|
198
249
|
```typescript
|
|
199
|
-
import { depthFirstSearch, topologicalSort, hasCycleDFS } from '@graphty/algorithms';
|
|
250
|
+
import { depthFirstSearch, topologicalSort, hasCycleDFS, findStronglyConnectedComponents } from '@graphty/algorithms';
|
|
200
251
|
|
|
201
252
|
// Basic DFS traversal
|
|
202
253
|
const result = depthFirstSearch(graph, startNode, {
|
|
203
|
-
|
|
204
|
-
|
|
254
|
+
targetNode?: NodeId, // Optional: stop when target is reached
|
|
255
|
+
visitCallback?: (node: NodeId, level: number) => void,
|
|
256
|
+
recursive?: boolean, // Use recursive implementation (default: false)
|
|
257
|
+
preOrder?: boolean // Visit nodes in pre-order (default: true)
|
|
205
258
|
});
|
|
206
259
|
// Returns: TraversalResult
|
|
207
260
|
|
|
@@ -212,6 +265,10 @@ const sorted = topologicalSort(graph);
|
|
|
212
265
|
// Cycle detection
|
|
213
266
|
const hasCycle = hasCycleDFS(graph);
|
|
214
267
|
// Returns: boolean
|
|
268
|
+
|
|
269
|
+
// Find strongly connected components using DFS
|
|
270
|
+
const sccs = findStronglyConnectedComponents(graph);
|
|
271
|
+
// Returns: NodeId[][]
|
|
215
272
|
```
|
|
216
273
|
|
|
217
274
|
### Shortest Path Algorithms
|
|
@@ -219,65 +276,79 @@ const hasCycle = hasCycleDFS(graph);
|
|
|
219
276
|
#### Dijkstra's Algorithm
|
|
220
277
|
|
|
221
278
|
```typescript
|
|
222
|
-
import {
|
|
279
|
+
import {
|
|
280
|
+
dijkstra,
|
|
281
|
+
dijkstraPath,
|
|
282
|
+
singleSourceShortestPath,
|
|
283
|
+
allPairsShortestPath
|
|
284
|
+
} from '@graphty/algorithms'
|
|
223
285
|
|
|
224
286
|
// Single-source shortest paths
|
|
225
287
|
const result = dijkstra(graph, source, {
|
|
226
|
-
target?: NodeId
|
|
227
|
-
})
|
|
228
|
-
// Returns: Map<NodeId,
|
|
288
|
+
target?: NodeId // Optional: stop when target is reached
|
|
289
|
+
})
|
|
290
|
+
// Returns: Map<NodeId, ShortestPathResult>
|
|
291
|
+
// ShortestPathResult = { distance: number, path: NodeId[], predecessor: Map<NodeId, NodeId | null> }
|
|
229
292
|
|
|
230
293
|
// Get specific path
|
|
231
|
-
const path = dijkstraPath(graph, source, target)
|
|
232
|
-
// Returns:
|
|
294
|
+
const path = dijkstraPath(graph, source, target)
|
|
295
|
+
// Returns: ShortestPathResult | null
|
|
233
296
|
|
|
234
297
|
// All shortest paths from source
|
|
235
|
-
const paths = singleSourceShortestPath(graph, source)
|
|
236
|
-
// Returns: Map<NodeId,
|
|
298
|
+
const paths = singleSourceShortestPath(graph, source)
|
|
299
|
+
// Returns: Map<NodeId, ShortestPathResult>
|
|
237
300
|
|
|
238
301
|
// All pairs shortest paths
|
|
239
|
-
const allPairs = allPairsShortestPath(graph)
|
|
240
|
-
// Returns: Map<NodeId, Map<NodeId,
|
|
302
|
+
const allPairs = allPairsShortestPath(graph)
|
|
303
|
+
// Returns: Map<NodeId, Map<NodeId, ShortestPathResult>>
|
|
241
304
|
```
|
|
242
305
|
|
|
243
306
|
#### Bellman-Ford Algorithm
|
|
244
307
|
|
|
245
308
|
```typescript
|
|
246
|
-
import {
|
|
309
|
+
import {
|
|
310
|
+
bellmanFord,
|
|
311
|
+
bellmanFordPath,
|
|
312
|
+
hasNegativeCycle
|
|
313
|
+
} from '@graphty/algorithms'
|
|
247
314
|
|
|
248
315
|
// Single-source shortest paths (handles negative weights)
|
|
249
|
-
const result = bellmanFord(graph, source)
|
|
250
|
-
// Returns: BellmanFordResult {
|
|
251
|
-
// distances: Map<NodeId, number>,
|
|
316
|
+
const result = bellmanFord(graph, source)
|
|
317
|
+
// Returns: BellmanFordResult {
|
|
318
|
+
// distances: Map<NodeId, number>,
|
|
252
319
|
// predecessors: Map<NodeId, NodeId | null>,
|
|
253
320
|
// hasNegativeCycle: boolean,
|
|
254
321
|
// negativeCycleNodes?: Set<NodeId>
|
|
255
322
|
// }
|
|
256
323
|
|
|
257
324
|
// Get specific path
|
|
258
|
-
const path = bellmanFordPath(graph, source, target)
|
|
259
|
-
// Returns:
|
|
325
|
+
const path = bellmanFordPath(graph, source, target)
|
|
326
|
+
// Returns: ShortestPathResult | null
|
|
260
327
|
|
|
261
328
|
// Check for negative cycles
|
|
262
|
-
const result = hasNegativeCycle(graph)
|
|
329
|
+
const result = hasNegativeCycle(graph)
|
|
263
330
|
// Returns: BellmanFordResult with hasNegativeCycle boolean
|
|
264
331
|
```
|
|
265
332
|
|
|
266
333
|
#### Floyd-Warshall Algorithm
|
|
267
334
|
|
|
268
335
|
```typescript
|
|
269
|
-
import {
|
|
336
|
+
import {
|
|
337
|
+
floydWarshall,
|
|
338
|
+
floydWarshallPath,
|
|
339
|
+
transitiveClosure
|
|
340
|
+
} from '@graphty/algorithms'
|
|
270
341
|
|
|
271
342
|
// All pairs shortest paths
|
|
272
|
-
const result = floydWarshall(graph)
|
|
343
|
+
const result = floydWarshall(graph)
|
|
273
344
|
// Returns: { distances: Map<NodeId, Map<NodeId, number>>, next: Map<NodeId, Map<NodeId, NodeId | null>> }
|
|
274
345
|
|
|
275
346
|
// Get specific path between any pair
|
|
276
|
-
const path = floydWarshallPath(result, source, target)
|
|
347
|
+
const path = floydWarshallPath(result, source, target)
|
|
277
348
|
// Returns: NodeId[] | null
|
|
278
349
|
|
|
279
350
|
// Compute transitive closure
|
|
280
|
-
const closure = transitiveClosure(graph)
|
|
351
|
+
const closure = transitiveClosure(graph)
|
|
281
352
|
// Returns: Map<NodeId, Set<NodeId>>
|
|
282
353
|
```
|
|
283
354
|
|
|
@@ -286,88 +357,170 @@ const closure = transitiveClosure(graph);
|
|
|
286
357
|
#### Degree Centrality
|
|
287
358
|
|
|
288
359
|
```typescript
|
|
289
|
-
import { degreeCentrality, nodeDegreeCentrality } from '@graphty/algorithms'
|
|
360
|
+
import { degreeCentrality, nodeDegreeCentrality } from '@graphty/algorithms'
|
|
290
361
|
|
|
291
362
|
// Calculate for all nodes
|
|
292
363
|
const centralities = degreeCentrality(graph, {
|
|
293
|
-
normalized
|
|
294
|
-
weight
|
|
295
|
-
})
|
|
296
|
-
// Returns: CentralityResult (
|
|
364
|
+
normalized: boolean, // Default: false
|
|
365
|
+
weight: string // Optional: edge property for weighted degree
|
|
366
|
+
})
|
|
367
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
297
368
|
|
|
298
369
|
// Calculate for single node
|
|
299
|
-
const centrality = nodeDegreeCentrality(graph, nodeId, { normalized
|
|
370
|
+
const centrality = nodeDegreeCentrality(graph, nodeId, { normalized: boolean })
|
|
300
371
|
// Returns: number
|
|
301
372
|
```
|
|
302
373
|
|
|
303
374
|
#### Betweenness Centrality
|
|
304
375
|
|
|
305
376
|
```typescript
|
|
306
|
-
import {
|
|
377
|
+
import {
|
|
378
|
+
betweennessCentrality,
|
|
379
|
+
nodeBetweennessCentrality,
|
|
380
|
+
edgeBetweennessCentrality
|
|
381
|
+
} from '@graphty/algorithms'
|
|
307
382
|
|
|
308
383
|
// Node betweenness for all nodes
|
|
309
384
|
const centralities = betweennessCentrality(graph, {
|
|
310
|
-
normalized
|
|
311
|
-
weight
|
|
312
|
-
endpoints
|
|
313
|
-
})
|
|
314
|
-
// Returns: CentralityResult
|
|
385
|
+
normalized: boolean, // Default: false
|
|
386
|
+
weight: string, // Optional: use weighted shortest paths
|
|
387
|
+
endpoints: boolean // Default: false, include endpoints in paths
|
|
388
|
+
})
|
|
389
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
315
390
|
|
|
316
391
|
// Single node betweenness
|
|
317
|
-
const centrality = nodeBetweennessCentrality(graph, nodeId, options)
|
|
392
|
+
const centrality = nodeBetweennessCentrality(graph, nodeId, options)
|
|
318
393
|
// Returns: number
|
|
319
394
|
|
|
320
395
|
// Edge betweenness
|
|
321
|
-
const edgeCentralities = edgeBetweennessCentrality(graph, options)
|
|
396
|
+
const edgeCentralities = edgeBetweennessCentrality(graph, options)
|
|
322
397
|
// Returns: Map<string, number> (edge ID to centrality)
|
|
323
398
|
```
|
|
324
399
|
|
|
325
400
|
#### Closeness Centrality
|
|
326
401
|
|
|
327
402
|
```typescript
|
|
328
|
-
import {
|
|
403
|
+
import {
|
|
404
|
+
closenessCentrality,
|
|
405
|
+
nodeClosenessCentrality,
|
|
406
|
+
weightedClosenessCentrality
|
|
407
|
+
} from '@graphty/algorithms'
|
|
329
408
|
|
|
330
409
|
// Closeness for all nodes
|
|
331
410
|
const centralities = closenessCentrality(graph, {
|
|
332
|
-
normalized
|
|
333
|
-
})
|
|
334
|
-
// Returns: CentralityResult
|
|
411
|
+
normalized: boolean // Default: false
|
|
412
|
+
})
|
|
413
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
335
414
|
|
|
336
415
|
// Single node closeness
|
|
337
|
-
const centrality = nodeClosenessCentrality(graph, nodeId, {
|
|
416
|
+
const centrality = nodeClosenessCentrality(graph, nodeId, {
|
|
417
|
+
normalized: boolean
|
|
418
|
+
})
|
|
338
419
|
// Returns: number
|
|
339
420
|
|
|
340
421
|
// Weighted closeness
|
|
341
422
|
const centralities = weightedClosenessCentrality(graph, {
|
|
342
|
-
normalized
|
|
343
|
-
weight
|
|
344
|
-
})
|
|
345
|
-
// Returns: CentralityResult
|
|
423
|
+
normalized: boolean,
|
|
424
|
+
weight: string // Edge property for weights
|
|
425
|
+
})
|
|
426
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
427
|
+
|
|
428
|
+
// Single node weighted closeness
|
|
429
|
+
const centrality = nodeWeightedClosenessCentrality(graph, nodeId, {
|
|
430
|
+
normalized: boolean,
|
|
431
|
+
weight: string // Edge property for weights
|
|
432
|
+
})
|
|
433
|
+
// Returns: number
|
|
346
434
|
```
|
|
347
435
|
|
|
348
436
|
#### PageRank
|
|
349
437
|
|
|
350
438
|
```typescript
|
|
351
|
-
import {
|
|
439
|
+
import {
|
|
440
|
+
pageRank,
|
|
441
|
+
personalizedPageRank,
|
|
442
|
+
topPageRankNodes
|
|
443
|
+
} from '@graphty/algorithms'
|
|
352
444
|
|
|
353
445
|
// Standard PageRank
|
|
354
446
|
const result = pageRank(graph, {
|
|
355
|
-
dampingFactor
|
|
356
|
-
maxIterations
|
|
357
|
-
tolerance
|
|
358
|
-
initialRanks
|
|
359
|
-
personalization
|
|
360
|
-
})
|
|
447
|
+
dampingFactor: number, // Default: 0.85
|
|
448
|
+
maxIterations: number, // Default: 100
|
|
449
|
+
tolerance: number, // Default: 1e-6
|
|
450
|
+
initialRanks: Record<string, number>,
|
|
451
|
+
personalization: Record<string, number>
|
|
452
|
+
})
|
|
361
453
|
// Returns: { ranks: Record<string, number>, iterations: number, converged: boolean }
|
|
362
454
|
|
|
363
455
|
// Personalized PageRank (with bias)
|
|
364
|
-
const ranks = personalizedPageRank(graph, personalization, options)
|
|
456
|
+
const ranks = personalizedPageRank(graph, personalization, options)
|
|
365
457
|
// personalization: Map<NodeId, number> - restart probabilities
|
|
366
|
-
// Returns: CentralityResult
|
|
458
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
367
459
|
|
|
368
460
|
// Get top N nodes by PageRank
|
|
369
|
-
const topNodes = topPageRankNodes(graph, n, options)
|
|
461
|
+
const topNodes = topPageRankNodes(graph, n, options)
|
|
370
462
|
// Returns: Array<{ node: NodeId, rank: number }>
|
|
463
|
+
|
|
464
|
+
// Alternative PageRank that returns CentralityResult format
|
|
465
|
+
const centralities = pageRankCentrality(graph, options)
|
|
466
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### Eigenvector Centrality
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
import {
|
|
473
|
+
eigenvectorCentrality,
|
|
474
|
+
nodeEigenvectorCentrality
|
|
475
|
+
} from '@graphty/algorithms'
|
|
476
|
+
|
|
477
|
+
// Calculate eigenvector centrality for all nodes
|
|
478
|
+
const centralities = eigenvectorCentrality(graph, {
|
|
479
|
+
maxIterations: number, // Default: 100
|
|
480
|
+
tolerance: number // Default: 1e-6
|
|
481
|
+
})
|
|
482
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
483
|
+
|
|
484
|
+
// Single node eigenvector centrality
|
|
485
|
+
const centrality = nodeEigenvectorCentrality(graph, nodeId, options)
|
|
486
|
+
// Returns: number
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### Katz Centrality
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
import { katzCentrality, nodeKatzCentrality } from '@graphty/algorithms'
|
|
493
|
+
|
|
494
|
+
// Calculate Katz centrality for all nodes
|
|
495
|
+
const centralities = katzCentrality(graph, {
|
|
496
|
+
alpha: number, // Attenuation factor (default: 0.1)
|
|
497
|
+
beta: number, // Weight for direct connections (default: 1.0)
|
|
498
|
+
maxIterations: number, // Default: 100
|
|
499
|
+
tolerance: number, // Default: 1e-6
|
|
500
|
+
normalized: boolean // Default: true
|
|
501
|
+
})
|
|
502
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
503
|
+
|
|
504
|
+
// Single node Katz centrality
|
|
505
|
+
const centrality = nodeKatzCentrality(graph, nodeId, options)
|
|
506
|
+
// Returns: number
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### HITS Algorithm
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
import { hits, nodeHITS } from '@graphty/algorithms'
|
|
513
|
+
|
|
514
|
+
// Calculate hub and authority scores
|
|
515
|
+
const result = hits(graph, {
|
|
516
|
+
maxIterations: number, // Default: 100
|
|
517
|
+
tolerance: number // Default: 1e-6
|
|
518
|
+
})
|
|
519
|
+
// Returns: HITSResult { hubs: CentralityResult, authorities: CentralityResult }
|
|
520
|
+
|
|
521
|
+
// Single node HITS scores
|
|
522
|
+
const scores = nodeHITS(graph, nodeId, options)
|
|
523
|
+
// Returns: { hub: number, authority: number }
|
|
371
524
|
```
|
|
372
525
|
|
|
373
526
|
### Connected Components
|
|
@@ -375,73 +528,80 @@ const topNodes = topPageRankNodes(graph, n, options);
|
|
|
375
528
|
#### Basic Component Operations
|
|
376
529
|
|
|
377
530
|
```typescript
|
|
378
|
-
import {
|
|
379
|
-
connectedComponents,
|
|
380
|
-
isConnected,
|
|
531
|
+
import {
|
|
532
|
+
connectedComponents,
|
|
533
|
+
isConnected,
|
|
381
534
|
numberOfConnectedComponents,
|
|
382
535
|
largestConnectedComponent,
|
|
383
|
-
getConnectedComponent
|
|
384
|
-
} from '@graphty/algorithms'
|
|
536
|
+
getConnectedComponent
|
|
537
|
+
} from '@graphty/algorithms'
|
|
385
538
|
|
|
386
539
|
// Find all components
|
|
387
|
-
const components = connectedComponents(graph)
|
|
540
|
+
const components = connectedComponents(graph)
|
|
388
541
|
// Returns: NodeId[][] (array of component arrays)
|
|
389
542
|
|
|
390
543
|
// Check if graph is connected
|
|
391
|
-
const connected = isConnected(graph)
|
|
544
|
+
const connected = isConnected(graph)
|
|
392
545
|
// Returns: boolean
|
|
393
546
|
|
|
394
547
|
// Count components
|
|
395
|
-
const count = numberOfConnectedComponents(graph)
|
|
548
|
+
const count = numberOfConnectedComponents(graph)
|
|
396
549
|
// Returns: number
|
|
397
550
|
|
|
398
551
|
// Get largest component
|
|
399
|
-
const largest = largestConnectedComponent(graph)
|
|
552
|
+
const largest = largestConnectedComponent(graph)
|
|
400
553
|
// Returns: NodeId[]
|
|
401
554
|
|
|
402
555
|
// Get component containing a specific node
|
|
403
|
-
const component = getConnectedComponent(graph, nodeId)
|
|
556
|
+
const component = getConnectedComponent(graph, nodeId)
|
|
404
557
|
// Returns: Set<NodeId>
|
|
405
558
|
```
|
|
406
559
|
|
|
407
560
|
#### Strongly Connected Components
|
|
408
561
|
|
|
409
562
|
```typescript
|
|
410
|
-
import {
|
|
563
|
+
import {
|
|
411
564
|
stronglyConnectedComponents,
|
|
412
565
|
findStronglyConnectedComponents,
|
|
413
566
|
isStronglyConnected,
|
|
414
|
-
condensationGraph
|
|
415
|
-
} from '@graphty/algorithms'
|
|
567
|
+
condensationGraph
|
|
568
|
+
} from '@graphty/algorithms'
|
|
416
569
|
|
|
417
570
|
// Find SCCs using Tarjan's algorithm
|
|
418
|
-
const sccs = stronglyConnectedComponents(graph)
|
|
571
|
+
const sccs = stronglyConnectedComponents(graph)
|
|
419
572
|
// Returns: ComponentResult
|
|
420
573
|
|
|
421
574
|
// Alternative: using DFS
|
|
422
|
-
const sccs = findStronglyConnectedComponents(graph)
|
|
575
|
+
const sccs = findStronglyConnectedComponents(graph)
|
|
423
576
|
// Returns: NodeId[][]
|
|
424
577
|
|
|
425
578
|
// Check if directed graph is strongly connected
|
|
426
|
-
const stronglyConnected = isStronglyConnected(graph)
|
|
579
|
+
const stronglyConnected = isStronglyConnected(graph)
|
|
427
580
|
// Returns: boolean
|
|
428
581
|
|
|
429
582
|
// Create condensation graph (DAG of SCCs)
|
|
430
|
-
const condensation = condensationGraph(graph)
|
|
583
|
+
const condensation = condensationGraph(graph)
|
|
431
584
|
// Returns: { graph: Graph, componentMap: Map<NodeId, number> }
|
|
585
|
+
|
|
586
|
+
// Alternative DFS-based connected components
|
|
587
|
+
const components = connectedComponentsDFS(graph)
|
|
588
|
+
// Returns: ComponentResult
|
|
432
589
|
```
|
|
433
590
|
|
|
434
591
|
#### Weakly Connected Components
|
|
435
592
|
|
|
436
593
|
```typescript
|
|
437
|
-
import {
|
|
594
|
+
import {
|
|
595
|
+
weaklyConnectedComponents,
|
|
596
|
+
isWeaklyConnected
|
|
597
|
+
} from '@graphty/algorithms'
|
|
438
598
|
|
|
439
599
|
// Find WCCs (ignoring edge direction)
|
|
440
|
-
const wccs = weaklyConnectedComponents(graph)
|
|
600
|
+
const wccs = weaklyConnectedComponents(graph)
|
|
441
601
|
// Returns: ComponentResult
|
|
442
602
|
|
|
443
603
|
// Check if directed graph is weakly connected
|
|
444
|
-
const weaklyConnected = isWeaklyConnected(graph)
|
|
604
|
+
const weaklyConnected = isWeaklyConnected(graph)
|
|
445
605
|
// Returns: boolean
|
|
446
606
|
```
|
|
447
607
|
|
|
@@ -452,16 +612,16 @@ const weaklyConnected = isWeaklyConnected(graph);
|
|
|
452
612
|
Min-heap implementation used internally by algorithms.
|
|
453
613
|
|
|
454
614
|
```typescript
|
|
455
|
-
import { PriorityQueue } from '@graphty/algorithms'
|
|
615
|
+
import { PriorityQueue } from '@graphty/algorithms'
|
|
456
616
|
|
|
457
|
-
const pq = new PriorityQueue<T>((a, b) => a.priority - b.priority)
|
|
617
|
+
const pq = new PriorityQueue<T>((a, b) => a.priority - b.priority)
|
|
458
618
|
|
|
459
|
-
pq.enqueue(item)
|
|
460
|
-
pq.dequeue()
|
|
461
|
-
pq.peek()
|
|
462
|
-
pq.isEmpty()
|
|
463
|
-
pq.size
|
|
464
|
-
pq.clear()
|
|
619
|
+
pq.enqueue(item)
|
|
620
|
+
pq.dequeue()
|
|
621
|
+
pq.peek()
|
|
622
|
+
pq.isEmpty()
|
|
623
|
+
pq.size
|
|
624
|
+
pq.clear()
|
|
465
625
|
```
|
|
466
626
|
|
|
467
627
|
#### Union-Find (Disjoint Set)
|
|
@@ -469,16 +629,16 @@ pq.clear();
|
|
|
469
629
|
Efficient data structure for tracking connected components.
|
|
470
630
|
|
|
471
631
|
```typescript
|
|
472
|
-
import { UnionFind } from '@graphty/algorithms'
|
|
632
|
+
import { UnionFind } from '@graphty/algorithms'
|
|
473
633
|
|
|
474
|
-
const uf = new UnionFind<T>()
|
|
634
|
+
const uf = new UnionFind<T>()
|
|
475
635
|
|
|
476
|
-
uf.makeSet(item)
|
|
477
|
-
uf.find(item)
|
|
478
|
-
uf.union(item1, item2)
|
|
479
|
-
uf.connected(item1, item2)
|
|
480
|
-
uf.getSetSize(item)
|
|
481
|
-
uf.numberOfSets
|
|
636
|
+
uf.makeSet(item)
|
|
637
|
+
uf.find(item)
|
|
638
|
+
uf.union(item1, item2)
|
|
639
|
+
uf.connected(item1, item2)
|
|
640
|
+
uf.getSetSize(item)
|
|
641
|
+
uf.numberOfSets
|
|
482
642
|
```
|
|
483
643
|
|
|
484
644
|
### Minimum Spanning Tree Algorithms
|
|
@@ -486,14 +646,14 @@ uf.numberOfSets;
|
|
|
486
646
|
#### Kruskal's Algorithm
|
|
487
647
|
|
|
488
648
|
```typescript
|
|
489
|
-
import { kruskalMST, minimumSpanningTree } from '@graphty/algorithms'
|
|
649
|
+
import { kruskalMST, minimumSpanningTree } from '@graphty/algorithms'
|
|
490
650
|
|
|
491
651
|
// Find MST using Kruskal's algorithm
|
|
492
|
-
const mst = kruskalMST(graph)
|
|
652
|
+
const mst = kruskalMST(graph)
|
|
493
653
|
// Returns: { edges: Edge[], weight: number }
|
|
494
654
|
|
|
495
655
|
// Alternative alias
|
|
496
|
-
const mst = minimumSpanningTree(graph)
|
|
656
|
+
const mst = minimumSpanningTree(graph)
|
|
497
657
|
```
|
|
498
658
|
|
|
499
659
|
#### Prim's Algorithm
|
|
@@ -511,77 +671,79 @@ const mst = primMST(graph, startNode?);
|
|
|
511
671
|
#### Louvain Method
|
|
512
672
|
|
|
513
673
|
```typescript
|
|
514
|
-
import { louvain } from '@graphty/algorithms'
|
|
674
|
+
import { louvain } from '@graphty/algorithms'
|
|
515
675
|
|
|
516
676
|
// Detect communities using Louvain method
|
|
517
677
|
const communities = louvain(graph, {
|
|
518
|
-
resolution
|
|
519
|
-
randomSeed
|
|
520
|
-
})
|
|
678
|
+
resolution: number, // Default: 1.0
|
|
679
|
+
randomSeed: number
|
|
680
|
+
})
|
|
521
681
|
// Returns: { communities: Map<NodeId, number>, modularity: number }
|
|
522
682
|
```
|
|
523
683
|
|
|
524
684
|
#### Leiden Algorithm
|
|
525
685
|
|
|
526
686
|
```typescript
|
|
527
|
-
import { leiden } from '@graphty/algorithms'
|
|
687
|
+
import { leiden } from '@graphty/algorithms'
|
|
528
688
|
|
|
529
689
|
// Improved community detection
|
|
530
690
|
const communities = leiden(graph, {
|
|
531
|
-
resolution
|
|
532
|
-
iterations
|
|
533
|
-
randomSeed
|
|
534
|
-
})
|
|
691
|
+
resolution: number, // Default: 1.0
|
|
692
|
+
iterations: number, // Default: 10
|
|
693
|
+
randomSeed: number
|
|
694
|
+
})
|
|
535
695
|
// Returns: { communities: Map<NodeId, number>, modularity: number }
|
|
536
696
|
```
|
|
537
697
|
|
|
538
698
|
#### Label Propagation
|
|
539
699
|
|
|
540
700
|
```typescript
|
|
541
|
-
import {
|
|
701
|
+
import {
|
|
702
|
+
labelPropagation,
|
|
703
|
+
labelPropagationAsync,
|
|
704
|
+
labelPropagationSemiSupervised
|
|
705
|
+
} from '@graphty/algorithms'
|
|
542
706
|
|
|
543
707
|
// Basic label propagation
|
|
544
708
|
const labels = labelPropagation(graph, {
|
|
545
|
-
maxIterations
|
|
546
|
-
})
|
|
709
|
+
maxIterations: number // Default: 100
|
|
710
|
+
})
|
|
547
711
|
// Returns: Map<NodeId, number>
|
|
548
712
|
|
|
549
713
|
// Asynchronous version
|
|
550
|
-
const labels = labelPropagationAsync(graph, options)
|
|
714
|
+
const labels = labelPropagationAsync(graph, options)
|
|
551
715
|
|
|
552
716
|
// Semi-supervised with seed communities
|
|
553
|
-
const labels = labelPropagationSemiSupervised(graph, seedLabels, options)
|
|
717
|
+
const labels = labelPropagationSemiSupervised(graph, seedLabels, options)
|
|
554
718
|
```
|
|
555
719
|
|
|
556
720
|
#### Girvan-Newman Algorithm
|
|
557
721
|
|
|
558
722
|
```typescript
|
|
559
|
-
import { girvanNewman } from '@graphty/algorithms'
|
|
723
|
+
import { girvanNewman } from '@graphty/algorithms'
|
|
560
724
|
|
|
561
725
|
// Edge betweenness based community detection
|
|
562
726
|
const dendrogram = girvanNewman(graph, {
|
|
563
|
-
targetCommunities
|
|
564
|
-
})
|
|
727
|
+
targetCommunities: number // Stop at this many communities
|
|
728
|
+
})
|
|
565
729
|
// Returns: { levels: Array<{ modularity: number, communities: NodeId[][] }> }
|
|
566
730
|
```
|
|
567
731
|
|
|
568
732
|
### Pathfinding Algorithms
|
|
569
733
|
|
|
570
|
-
#### A
|
|
734
|
+
#### A\* Algorithm
|
|
571
735
|
|
|
572
736
|
```typescript
|
|
573
|
-
import { astar
|
|
737
|
+
import { astar } from '@graphty/algorithms'
|
|
574
738
|
|
|
575
739
|
// A* pathfinding with heuristic
|
|
576
|
-
const path = astar(
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
//
|
|
583
|
-
const result = astarWithDetails(graph, start, goal, options);
|
|
584
|
-
// Returns: { path: NodeId[], cost: number, explored: Set<NodeId>, parent: Map<NodeId, NodeId> } | null
|
|
740
|
+
const path = astar(
|
|
741
|
+
graph, // Map<T, Map<T, number>> adjacency list
|
|
742
|
+
start,
|
|
743
|
+
goal,
|
|
744
|
+
heuristic // (node: T, goal: T) => number
|
|
745
|
+
)
|
|
746
|
+
// Returns: { path: T[], cost: number } | null
|
|
585
747
|
```
|
|
586
748
|
|
|
587
749
|
### Flow Algorithms
|
|
@@ -599,6 +761,10 @@ const flow = fordFulkerson(graph, source, sink, {
|
|
|
599
761
|
|
|
600
762
|
// Edmonds-Karp using BFS (better complexity)
|
|
601
763
|
const flow = edmondsKarp(graph, source, sink, options);
|
|
764
|
+
|
|
765
|
+
// Create bipartite flow network
|
|
766
|
+
const flowNetwork = createBipartiteFlowNetwork(leftNodes, rightNodes, edges, capacities?);
|
|
767
|
+
// Returns: FlowNetwork
|
|
602
768
|
```
|
|
603
769
|
|
|
604
770
|
#### Minimum Cut
|
|
@@ -624,47 +790,308 @@ const cut = kargerMinCut(graph, iterations?);
|
|
|
624
790
|
#### Hierarchical Clustering
|
|
625
791
|
|
|
626
792
|
```typescript
|
|
627
|
-
import {
|
|
793
|
+
import {
|
|
794
|
+
hierarchicalClustering,
|
|
795
|
+
cutDendrogram,
|
|
796
|
+
cutDendrogramKClusters
|
|
797
|
+
} from '@graphty/algorithms'
|
|
628
798
|
|
|
629
799
|
// Agglomerative clustering
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
634
|
-
// Returns: Dendrogram structure
|
|
800
|
+
const result = hierarchicalClustering(graph, linkage)
|
|
801
|
+
// graph: Map<NodeId, Set<NodeId>>
|
|
802
|
+
// linkage: 'single' | 'complete' | 'average' | 'ward' (default: 'single')
|
|
803
|
+
// Returns: HierarchicalClusteringResult { root: ClusterNode, dendrogram: ClusterNode[], clusters: Map<number, Set<NodeId>[]> }
|
|
635
804
|
|
|
636
805
|
// Cut at specific height
|
|
637
|
-
const clusters = cutDendrogram(
|
|
638
|
-
// Returns: NodeId[]
|
|
806
|
+
const clusters = cutDendrogram(result.root, height)
|
|
807
|
+
// Returns: Set<NodeId>[]
|
|
639
808
|
|
|
640
809
|
// Get exactly k clusters
|
|
641
|
-
const clusters = cutDendrogramKClusters(
|
|
642
|
-
// Returns: NodeId[]
|
|
810
|
+
const clusters = cutDendrogramKClusters(result.root, k)
|
|
811
|
+
// Returns: Set<NodeId>[]
|
|
643
812
|
```
|
|
644
813
|
|
|
645
814
|
#### K-Core Decomposition
|
|
646
815
|
|
|
647
816
|
```typescript
|
|
648
|
-
import {
|
|
817
|
+
import {
|
|
818
|
+
kCoreDecomposition,
|
|
819
|
+
getKCore,
|
|
820
|
+
kTruss,
|
|
821
|
+
degeneracyOrdering
|
|
822
|
+
} from '@graphty/algorithms'
|
|
649
823
|
|
|
650
824
|
// Find all k-cores
|
|
651
|
-
const
|
|
652
|
-
//
|
|
825
|
+
const result = kCoreDecomposition(graph)
|
|
826
|
+
// graph: Map<NodeId, Set<NodeId>>
|
|
827
|
+
// Returns: KCoreResult { cores: Map<number, Set<NodeId>>, coreness: Map<NodeId, number>, maxCore: number }
|
|
653
828
|
|
|
654
829
|
// Extract specific k-core subgraph
|
|
655
|
-
const kCore = getKCore(graph, k)
|
|
830
|
+
const kCore = getKCore(graph, k)
|
|
656
831
|
// Returns: Set<NodeId>
|
|
657
832
|
|
|
658
833
|
// Find k-truss (triangular cores)
|
|
659
|
-
const truss = kTruss(graph, k)
|
|
660
|
-
// Returns:
|
|
834
|
+
const truss = kTruss(graph, k)
|
|
835
|
+
// Returns: Set<string> (edge strings)
|
|
836
|
+
|
|
837
|
+
// Degeneracy ordering
|
|
838
|
+
const ordering = degeneracyOrdering(graph)
|
|
839
|
+
// Returns: NodeId[]
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
#### Spectral Clustering
|
|
843
|
+
|
|
844
|
+
```typescript
|
|
845
|
+
import { spectralClustering } from '@graphty/algorithms'
|
|
846
|
+
|
|
847
|
+
// Spectral clustering using graph Laplacian
|
|
848
|
+
const result = spectralClustering(graph, {
|
|
849
|
+
k: number, // Number of clusters
|
|
850
|
+
laplacianType: 'unnormalized' | 'normalized' | 'randomWalk', // Default: 'normalized'
|
|
851
|
+
maxIterations: number, // Default: 100
|
|
852
|
+
tolerance: number // Default: 1e-4
|
|
853
|
+
})
|
|
854
|
+
// Returns: SpectralClusteringResult { communities: NodeId[][], clusterAssignments: Map<NodeId, number> }
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
#### Markov Clustering (MCL)
|
|
858
|
+
|
|
859
|
+
```typescript
|
|
860
|
+
import { markovClustering, calculateMCLModularity } from '@graphty/algorithms'
|
|
861
|
+
|
|
862
|
+
// MCL algorithm for network clustering
|
|
863
|
+
const result = markovClustering(graph, {
|
|
864
|
+
expansion: number, // Expansion parameter (default: 2)
|
|
865
|
+
inflation: number, // Inflation parameter (default: 2)
|
|
866
|
+
maxIterations: number, // Default: 100
|
|
867
|
+
tolerance: number // Default: 1e-6
|
|
868
|
+
})
|
|
869
|
+
// Returns: MCLResult { communities: NodeId[][], attractors: Set<NodeId>, iterations: number, converged: boolean }
|
|
870
|
+
|
|
871
|
+
// Calculate modularity of MCL clustering result
|
|
872
|
+
const modularity = calculateMCLModularity(graph, result.communities)
|
|
873
|
+
// Returns: number
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
### Matching Algorithms
|
|
877
|
+
|
|
878
|
+
#### Bipartite Matching
|
|
879
|
+
|
|
880
|
+
```typescript
|
|
881
|
+
import {
|
|
882
|
+
maximumBipartiteMatching,
|
|
883
|
+
greedyBipartiteMatching,
|
|
884
|
+
bipartitePartition
|
|
885
|
+
} from '@graphty/algorithms'
|
|
886
|
+
|
|
887
|
+
// Maximum bipartite matching (Hungarian algorithm)
|
|
888
|
+
const matching = maximumBipartiteMatching(graph, {
|
|
889
|
+
leftNodes: Set<NodeId>, // Optional: specify left partition
|
|
890
|
+
rightNodes: Set<NodeId> // Optional: specify right partition
|
|
891
|
+
})
|
|
892
|
+
// Returns: BipartiteMatchingResult { matching: Map<NodeId, NodeId>, size: number }
|
|
893
|
+
|
|
894
|
+
// Greedy bipartite matching (faster, approximate)
|
|
895
|
+
const matching = greedyBipartiteMatching(graph, options)
|
|
896
|
+
|
|
897
|
+
// Partition graph into bipartite sets
|
|
898
|
+
const partition = bipartitePartition(graph)
|
|
899
|
+
// Returns: { left: Set<NodeId>, right: Set<NodeId> } | null
|
|
661
900
|
```
|
|
662
901
|
|
|
663
|
-
|
|
902
|
+
#### Graph Isomorphism
|
|
903
|
+
|
|
904
|
+
```typescript
|
|
905
|
+
import { isGraphIsomorphic, findAllIsomorphisms } from '@graphty/algorithms'
|
|
906
|
+
|
|
907
|
+
// Check if two graphs are isomorphic
|
|
908
|
+
const result = isGraphIsomorphic(graph1, graph2, {
|
|
909
|
+
nodeMatch: (node1: NodeId, node2: NodeId, g1: Graph, g2: Graph) => boolean,
|
|
910
|
+
edgeMatch: (
|
|
911
|
+
edge1: [NodeId, NodeId],
|
|
912
|
+
edge2: [NodeId, NodeId],
|
|
913
|
+
g1: Graph,
|
|
914
|
+
g2: Graph
|
|
915
|
+
) => boolean,
|
|
916
|
+
findAllMappings: boolean // Find all possible isomorphisms
|
|
917
|
+
})
|
|
918
|
+
// Returns: IsomorphismResult { isIsomorphic: boolean, mapping?: Map<NodeId, NodeId> }
|
|
919
|
+
|
|
920
|
+
// Find all isomorphism mappings
|
|
921
|
+
const mappings = findAllIsomorphisms(graph1, graph2, options)
|
|
922
|
+
// Returns: Array<Map<NodeId, NodeId>>
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
### Link Prediction Algorithms
|
|
926
|
+
|
|
927
|
+
#### Common Neighbors
|
|
664
928
|
|
|
665
|
-
|
|
929
|
+
```typescript
|
|
930
|
+
import {
|
|
931
|
+
commonNeighborsScore,
|
|
932
|
+
commonNeighborsPrediction,
|
|
933
|
+
commonNeighborsForPairs
|
|
934
|
+
} from '@graphty/algorithms'
|
|
935
|
+
|
|
936
|
+
// Score for a specific pair
|
|
937
|
+
const score = commonNeighborsScore(graph, node1, node2)
|
|
938
|
+
// Returns: number
|
|
939
|
+
|
|
940
|
+
// Predict links for all non-connected pairs
|
|
941
|
+
const predictions = commonNeighborsPrediction(graph, {
|
|
942
|
+
directed: boolean, // Consider direction
|
|
943
|
+
includeExisting: boolean, // Include existing edges
|
|
944
|
+
topK: number // Return only top K predictions
|
|
945
|
+
})
|
|
946
|
+
// Returns: LinkPredictionScore[]
|
|
947
|
+
|
|
948
|
+
// Score multiple specific pairs
|
|
949
|
+
const scores = commonNeighborsForPairs(graph, pairs, options)
|
|
950
|
+
// Returns: LinkPredictionScore[]
|
|
951
|
+
|
|
952
|
+
// Evaluate prediction performance
|
|
953
|
+
const evaluation = evaluateCommonNeighbors(graph, testEdges)
|
|
954
|
+
// Returns: { precision, recall, f1Score }
|
|
955
|
+
|
|
956
|
+
// Get top candidates for a node
|
|
957
|
+
const candidates = getTopCandidatesForNode(graph, nodeId, { topK: number })
|
|
958
|
+
// Returns: LinkPredictionScore[]
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
#### Adamic-Adar Index
|
|
962
|
+
|
|
963
|
+
```typescript
|
|
964
|
+
import {
|
|
965
|
+
adamicAdarScore,
|
|
966
|
+
adamicAdarPrediction,
|
|
967
|
+
adamicAdarForPairs
|
|
968
|
+
} from '@graphty/algorithms'
|
|
969
|
+
|
|
970
|
+
// Adamic-Adar score for a pair (weighted by neighbor degrees)
|
|
971
|
+
const score = adamicAdarScore(graph, node1, node2)
|
|
972
|
+
// Returns: number
|
|
973
|
+
|
|
974
|
+
// Predict links using Adamic-Adar
|
|
975
|
+
const predictions = adamicAdarPrediction(graph, {
|
|
976
|
+
directed: boolean,
|
|
977
|
+
includeExisting: boolean,
|
|
978
|
+
topK: number
|
|
979
|
+
})
|
|
980
|
+
// Returns: LinkPredictionScore[]
|
|
981
|
+
|
|
982
|
+
// Score multiple pairs
|
|
983
|
+
const scores = adamicAdarForPairs(graph, pairs, options)
|
|
984
|
+
// Returns: LinkPredictionScore[]
|
|
985
|
+
|
|
986
|
+
// Compare Adamic-Adar with Common Neighbors
|
|
987
|
+
const comparison = compareAdamicAdarWithCommonNeighbors(graph, pairs)
|
|
988
|
+
// Returns: Array<{ source, target, adamicAdar, commonNeighbors }>
|
|
989
|
+
|
|
990
|
+
// Evaluate prediction performance
|
|
991
|
+
const evaluation = evaluateAdamicAdar(graph, testEdges)
|
|
992
|
+
// Returns: { precision, recall, f1Score }
|
|
993
|
+
|
|
994
|
+
// Get top candidates for a node
|
|
995
|
+
const candidates = getTopAdamicAdarCandidatesForNode(graph, nodeId, {
|
|
996
|
+
topK: number
|
|
997
|
+
})
|
|
998
|
+
// Returns: LinkPredictionScore[]
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
### Research Algorithms (2023-2025)
|
|
1002
|
+
|
|
1003
|
+
Cutting-edge graph algorithms based on recent research.
|
|
1004
|
+
|
|
1005
|
+
#### SynC - Synergistic Deep Graph Clustering
|
|
1006
|
+
|
|
1007
|
+
```typescript
|
|
1008
|
+
import { syncClustering } from '@graphty/algorithms'
|
|
1009
|
+
|
|
1010
|
+
// Deep learning based clustering
|
|
1011
|
+
const result = syncClustering(graph, {
|
|
1012
|
+
k: number, // Number of clusters
|
|
1013
|
+
maxIterations: number, // Default: 100
|
|
1014
|
+
learningRate: number, // Default: 0.01
|
|
1015
|
+
hiddenDim: number, // Default: 64
|
|
1016
|
+
randomSeed: number
|
|
1017
|
+
})
|
|
1018
|
+
// Returns: SynCResult {
|
|
1019
|
+
// communities: NodeId[][],
|
|
1020
|
+
// clusterAssignments: Map<NodeId, number>,
|
|
1021
|
+
// embeddings: Map<NodeId, number[]>,
|
|
1022
|
+
// iterations: number,
|
|
1023
|
+
// converged: boolean
|
|
1024
|
+
// }
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
#### TeraHAC - Scalable Hierarchical Agglomerative Clustering
|
|
1028
|
+
|
|
1029
|
+
```typescript
|
|
1030
|
+
import { teraHAC } from '@graphty/algorithms'
|
|
1031
|
+
|
|
1032
|
+
// Scalable hierarchical clustering
|
|
1033
|
+
const result = teraHAC(graph, {
|
|
1034
|
+
linkage: 'single' | 'complete' | 'average', // Default: 'average'
|
|
1035
|
+
k: number, // Target number of clusters
|
|
1036
|
+
threshold: number, // Distance threshold for merging
|
|
1037
|
+
sampleSize: number, // Default: 1000
|
|
1038
|
+
randomSeed: number
|
|
1039
|
+
})
|
|
1040
|
+
// Returns: TeraHACResult {
|
|
1041
|
+
// root: TeraHACClusterNode,
|
|
1042
|
+
// dendrogram: TeraHACClusterNode[],
|
|
1043
|
+
// clusters: NodeId[][],
|
|
1044
|
+
// mergeDistances: number[]
|
|
1045
|
+
// }
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
#### GRSBM - Greedy Recursive Spectral Bisection with Modularity
|
|
1049
|
+
|
|
1050
|
+
```typescript
|
|
1051
|
+
import { grsbm } from '@graphty/algorithms'
|
|
1052
|
+
|
|
1053
|
+
// Explainable community detection
|
|
1054
|
+
const result = grsbm(graph, {
|
|
1055
|
+
minClusterSize: number, // Default: 5
|
|
1056
|
+
maxDepth: number, // Default: 10
|
|
1057
|
+
modularityThreshold: number, // Default: 0.1
|
|
1058
|
+
explainClusters: boolean // Default: true
|
|
1059
|
+
})
|
|
1060
|
+
// Returns: GRSBMResult {
|
|
1061
|
+
// clusters: GRSBMCluster[], // Each cluster has id, nodes, modularity, explanation
|
|
1062
|
+
// hierarchy: Map<number, number[]>,
|
|
1063
|
+
// totalModularity: number
|
|
1064
|
+
// }
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
## Algorithm Categories Summary
|
|
1068
|
+
|
|
1069
|
+
### Available Algorithms by Category:
|
|
1070
|
+
|
|
1071
|
+
- **Traversal**: BFS, DFS, Topological Sort, Cycle Detection, Bipartite Check
|
|
1072
|
+
- **Shortest Path**: Dijkstra, Bellman-Ford, Floyd-Warshall, A\*
|
|
1073
|
+
- **Centrality**: Degree, Betweenness, Closeness, PageRank, Eigenvector, Katz, HITS
|
|
1074
|
+
- **Components**: Connected, Strongly Connected, Weakly Connected, Condensation Graph
|
|
1075
|
+
- **Community Detection**: Louvain, Leiden, Label Propagation, Girvan-Newman
|
|
1076
|
+
- **Clustering**: Hierarchical, K-Core, Spectral, Markov (MCL)
|
|
1077
|
+
- **Minimum Spanning Tree**: Kruskal, Prim
|
|
1078
|
+
- **Network Flow**: Ford-Fulkerson, Edmonds-Karp, Min-Cut (Stoer-Wagner, Karger)
|
|
1079
|
+
- **Matching**: Bipartite Matching, Graph Isomorphism
|
|
1080
|
+
- **Link Prediction**: Common Neighbors, Adamic-Adar
|
|
1081
|
+
- **Research Algorithms**: SynC, TeraHAC, GRSBM
|
|
1082
|
+
|
|
1083
|
+
## Interactive Examples
|
|
1084
|
+
|
|
1085
|
+
Try out all algorithms with interactive visualizations: **[Live Demo →](https://graphty-org.github.io/algorithms/)**
|
|
1086
|
+
|
|
1087
|
+
The library includes comprehensive examples demonstrating each algorithm. You can:
|
|
1088
|
+
|
|
1089
|
+
- **[Browse Interactive HTML Examples](https://graphty-org.github.io/algorithms/examples/)** - Visual demonstrations with step-by-step execution
|
|
1090
|
+
- **[View Performance Benchmarks](https://graphty-org.github.io/algorithms/benchmarks/)** - Comparative analysis of algorithm performance
|
|
1091
|
+
- **[Explore Code Examples](https://github.com/graphty-org/algorithms/tree/main/examples)** - Implementation examples for each algorithm
|
|
666
1092
|
|
|
667
1093
|
### Basic Algorithms
|
|
1094
|
+
|
|
668
1095
|
- [BFS Traversal](https://github.com/graphty-org/algorithms/blob/main/examples/bfs-example.js) - Breadth-first search and shortest paths
|
|
669
1096
|
- [DFS Traversal](https://github.com/graphty-org/algorithms/blob/main/examples/dfs-example.js) - Depth-first search and applications
|
|
670
1097
|
- [Dijkstra's Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/dijkstra-example.js) - Weighted shortest paths
|
|
@@ -672,111 +1099,139 @@ The library includes comprehensive examples demonstrating each algorithm. Find t
|
|
|
672
1099
|
- [Floyd-Warshall](https://github.com/graphty-org/algorithms/blob/main/examples/floyd-warshall-example.js) - All pairs shortest paths
|
|
673
1100
|
|
|
674
1101
|
### Centrality Measures
|
|
1102
|
+
|
|
675
1103
|
- [Degree Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/degree-centrality-example.js) - Node importance by connections
|
|
676
1104
|
- [Betweenness Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/betweenness-centrality-example.js) - Bridge nodes
|
|
677
1105
|
- [Closeness Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/closeness-centrality-example.js) - Central nodes
|
|
678
1106
|
- [PageRank](https://github.com/graphty-org/algorithms/blob/main/examples/pagerank-example.js) - Node ranking algorithm
|
|
1107
|
+
- [Eigenvector Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/eigenvector-centrality-example.js) - Influence from important nodes
|
|
1108
|
+
- [Katz Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/katz-centrality-example.js) - Weighted path counting
|
|
1109
|
+
- [HITS Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/hits-algorithm-example.js) - Hub and authority scores
|
|
679
1110
|
|
|
680
1111
|
### Graph Structure
|
|
1112
|
+
|
|
681
1113
|
- [Connected Components](https://github.com/graphty-org/algorithms/blob/main/examples/connected-components-example.js) - Find graph components
|
|
682
1114
|
- [Kruskal's MST](https://github.com/graphty-org/algorithms/blob/main/examples/kruskal-example.js) - Minimum spanning tree
|
|
683
1115
|
- [Prim's MST](https://github.com/graphty-org/algorithms/blob/main/examples/prim-example.js) - Alternative MST algorithm
|
|
684
1116
|
|
|
685
1117
|
### Community Detection
|
|
1118
|
+
|
|
686
1119
|
- [Louvain Method](https://github.com/graphty-org/algorithms/blob/main/examples/louvain-example.js) - Modularity-based communities
|
|
687
1120
|
- [Leiden Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/leiden-community.ts) - Improved Louvain
|
|
688
1121
|
- [Label Propagation](https://github.com/graphty-org/algorithms/blob/main/examples/label-propagation.ts) - Fast community detection
|
|
689
1122
|
- [Girvan-Newman](https://github.com/graphty-org/algorithms/blob/main/examples/girvan-newman-example.js) - Hierarchical communities
|
|
690
1123
|
|
|
1124
|
+
### Clustering
|
|
1125
|
+
|
|
1126
|
+
- [Hierarchical Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/hierarchical-clustering.ts) - Graph clustering
|
|
1127
|
+
- [K-Core Decomposition](https://github.com/graphty-org/algorithms/blob/main/examples/k-core-decomposition.ts) - Core analysis
|
|
1128
|
+
- [Spectral Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/spectral-clustering-example.js) - Eigenvalue-based clustering
|
|
1129
|
+
- [MCL Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/mcl-clustering-example.js) - Markov clustering
|
|
1130
|
+
|
|
1131
|
+
### Matching
|
|
1132
|
+
|
|
1133
|
+
- [Bipartite Matching](https://github.com/graphty-org/algorithms/blob/main/examples/bipartite-matching-example.js) - Job assignment, dating apps
|
|
1134
|
+
- [Graph Isomorphism](https://github.com/graphty-org/algorithms/blob/main/examples/graph-isomorphism-example.js) - Structural equivalence
|
|
1135
|
+
|
|
1136
|
+
### Link Prediction
|
|
1137
|
+
|
|
1138
|
+
- [Common Neighbors](https://github.com/graphty-org/algorithms/blob/main/examples/common-neighbors-example.js) - Friend suggestions
|
|
1139
|
+
- [Adamic-Adar](https://github.com/graphty-org/algorithms/blob/main/examples/adamic-adar-example.js) - Weighted predictions
|
|
1140
|
+
|
|
691
1141
|
### Advanced Algorithms
|
|
692
|
-
|
|
1142
|
+
|
|
1143
|
+
- [A\* Pathfinding](https://github.com/graphty-org/algorithms/blob/main/examples/astar-pathfinding.ts) - Heuristic pathfinding
|
|
693
1144
|
- [Flow Algorithms](https://github.com/graphty-org/algorithms/blob/main/examples/flow-algorithms.ts) - Maximum flow and applications
|
|
694
1145
|
- [Ford-Fulkerson Flow](https://github.com/graphty-org/algorithms/blob/main/examples/ford-fulkerson-flow.ts) - Maximum flow implementation
|
|
695
1146
|
- [Minimum Cut](https://github.com/graphty-org/algorithms/blob/main/examples/min-cut.ts) - Graph partitioning
|
|
696
|
-
|
|
697
|
-
|
|
1147
|
+
|
|
1148
|
+
### Research Algorithms
|
|
1149
|
+
|
|
1150
|
+
- [SynC Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/sync-example.js) - Deep learning based clustering
|
|
1151
|
+
- [TeraHAC](https://github.com/graphty-org/algorithms/blob/main/examples/terahac-example.js) - Scalable hierarchical clustering
|
|
1152
|
+
- [GRSBM](https://github.com/graphty-org/algorithms/blob/main/examples/grsbm-example.js) - Explainable community detection
|
|
698
1153
|
|
|
699
1154
|
## Advanced Usage Examples
|
|
700
1155
|
|
|
701
1156
|
### Working with Weighted Graphs
|
|
702
1157
|
|
|
703
1158
|
```typescript
|
|
704
|
-
const graph = new Graph()
|
|
1159
|
+
const graph = new Graph()
|
|
705
1160
|
|
|
706
1161
|
// Add weighted edges
|
|
707
|
-
graph.addEdge('A', 'B', 5)
|
|
708
|
-
graph.addEdge('B', 'C', 3)
|
|
709
|
-
graph.addEdge('A', 'C', 10)
|
|
1162
|
+
graph.addEdge('A', 'B', 5)
|
|
1163
|
+
graph.addEdge('B', 'C', 3)
|
|
1164
|
+
graph.addEdge('A', 'C', 10)
|
|
710
1165
|
|
|
711
1166
|
// Find shortest path considering weights
|
|
712
|
-
const result = dijkstra(graph, 'A')
|
|
713
|
-
const pathToC = dijkstraPath(graph, 'A', 'C')
|
|
714
|
-
console.log(pathToC)
|
|
1167
|
+
const result = dijkstra(graph, 'A')
|
|
1168
|
+
const pathToC = dijkstraPath(graph, 'A', 'C')
|
|
1169
|
+
console.log(pathToC) // { path: ['A', 'B', 'C'], distance: 8 }
|
|
715
1170
|
```
|
|
716
1171
|
|
|
717
1172
|
### Directed Graphs
|
|
718
1173
|
|
|
719
1174
|
```typescript
|
|
720
|
-
const directedGraph = new Graph({ directed: true })
|
|
1175
|
+
const directedGraph = new Graph({ directed: true })
|
|
721
1176
|
|
|
722
|
-
directedGraph.addEdge('A', 'B')
|
|
723
|
-
directedGraph.addEdge('B', 'C')
|
|
724
|
-
directedGraph.addEdge('C', 'A')
|
|
1177
|
+
directedGraph.addEdge('A', 'B')
|
|
1178
|
+
directedGraph.addEdge('B', 'C')
|
|
1179
|
+
directedGraph.addEdge('C', 'A')
|
|
725
1180
|
|
|
726
1181
|
// Check for cycles
|
|
727
|
-
console.log(hasCycleDFS(directedGraph))
|
|
1182
|
+
console.log(hasCycleDFS(directedGraph)) // true
|
|
728
1183
|
|
|
729
1184
|
// Find strongly connected components
|
|
730
|
-
const sccs = stronglyConnectedComponents(directedGraph)
|
|
731
|
-
console.log(sccs.components)
|
|
1185
|
+
const sccs = stronglyConnectedComponents(directedGraph)
|
|
1186
|
+
console.log(sccs.components) // [['A', 'B', 'C']]
|
|
732
1187
|
```
|
|
733
1188
|
|
|
734
1189
|
### Network Analysis
|
|
735
1190
|
|
|
736
1191
|
```typescript
|
|
737
1192
|
// Identify important nodes
|
|
738
|
-
const graph = createSocialNetwork()
|
|
1193
|
+
const graph = createSocialNetwork() // Your graph
|
|
739
1194
|
|
|
740
1195
|
// Find influencers (high PageRank)
|
|
741
|
-
const influencers = topPageRankNodes(graph, 10)
|
|
1196
|
+
const influencers = topPageRankNodes(graph, 10)
|
|
742
1197
|
|
|
743
1198
|
// Find bridges (high betweenness)
|
|
744
1199
|
const bridgers = Array.from(betweennessCentrality(graph).entries())
|
|
745
1200
|
.sort((a, b) => b[1] - a[1])
|
|
746
|
-
.slice(0, 10)
|
|
1201
|
+
.slice(0, 10)
|
|
747
1202
|
|
|
748
1203
|
// Find communities (connected components)
|
|
749
|
-
const communities = connectedComponents(graph)
|
|
750
|
-
console.log(`Found ${communities.components.length} communities`)
|
|
1204
|
+
const communities = connectedComponents(graph)
|
|
1205
|
+
console.log(`Found ${communities.components.length} communities`)
|
|
751
1206
|
```
|
|
752
1207
|
|
|
753
1208
|
### Custom Edge Properties
|
|
754
1209
|
|
|
755
1210
|
```typescript
|
|
756
|
-
const graph = new Graph()
|
|
1211
|
+
const graph = new Graph()
|
|
757
1212
|
|
|
758
1213
|
// Add edges with custom data
|
|
759
|
-
graph.addEdge('A', 'B', 1, {
|
|
760
|
-
type: 'road',
|
|
761
|
-
distance: 100,
|
|
762
|
-
traffic: 'heavy'
|
|
763
|
-
})
|
|
1214
|
+
graph.addEdge('A', 'B', 1, {
|
|
1215
|
+
type: 'road',
|
|
1216
|
+
distance: 100,
|
|
1217
|
+
traffic: 'heavy'
|
|
1218
|
+
})
|
|
764
1219
|
|
|
765
1220
|
// Use custom weight in algorithms
|
|
766
|
-
const result = dijkstra(graph, 'A', {
|
|
1221
|
+
const result = dijkstra(graph, 'A', {
|
|
767
1222
|
weightKey: 'distance' // Use 'distance' property as weight
|
|
768
|
-
})
|
|
1223
|
+
})
|
|
769
1224
|
```
|
|
770
1225
|
|
|
771
1226
|
### Graph Visualization Preparation
|
|
772
1227
|
|
|
773
1228
|
```typescript
|
|
774
1229
|
// Prepare data for visualization
|
|
775
|
-
const graph = loadGraph()
|
|
1230
|
+
const graph = loadGraph()
|
|
776
1231
|
|
|
777
1232
|
// Calculate layout metrics
|
|
778
|
-
const centralities = degreeCentrality(graph, { normalized: true })
|
|
779
|
-
const ranks = pageRank(graph)
|
|
1233
|
+
const centralities = degreeCentrality(graph, { normalized: true })
|
|
1234
|
+
const ranks = pageRank(graph)
|
|
780
1235
|
|
|
781
1236
|
// Export for visualization
|
|
782
1237
|
const nodes = Array.from(graph.nodes()).map(node => ({
|
|
@@ -784,14 +1239,14 @@ const nodes = Array.from(graph.nodes()).map(node => ({
|
|
|
784
1239
|
data: node.data,
|
|
785
1240
|
size: centralities.get(node.id) || 0,
|
|
786
1241
|
importance: ranks.get(node.id) || 0
|
|
787
|
-
}))
|
|
1242
|
+
}))
|
|
788
1243
|
|
|
789
1244
|
const edges = Array.from(graph.edges()).map(edge => ({
|
|
790
1245
|
source: edge.source,
|
|
791
1246
|
target: edge.target,
|
|
792
1247
|
weight: edge.weight || 1,
|
|
793
1248
|
data: edge.data
|
|
794
|
-
}))
|
|
1249
|
+
}))
|
|
795
1250
|
```
|
|
796
1251
|
|
|
797
1252
|
## Type Definitions
|
|
@@ -799,19 +1254,19 @@ const edges = Array.from(graph.edges()).map(edge => ({
|
|
|
799
1254
|
### Core Types
|
|
800
1255
|
|
|
801
1256
|
```typescript
|
|
802
|
-
type NodeId = string | number
|
|
1257
|
+
type NodeId = string | number
|
|
803
1258
|
|
|
804
1259
|
interface Node {
|
|
805
|
-
id: NodeId
|
|
806
|
-
data?: Record<string, unknown
|
|
1260
|
+
id: NodeId
|
|
1261
|
+
data?: Record<string, unknown>
|
|
807
1262
|
}
|
|
808
1263
|
|
|
809
1264
|
interface Edge {
|
|
810
|
-
source: NodeId
|
|
811
|
-
target: NodeId
|
|
812
|
-
weight?: number
|
|
813
|
-
id?: string
|
|
814
|
-
data?: Record<string, unknown
|
|
1265
|
+
source: NodeId
|
|
1266
|
+
target: NodeId
|
|
1267
|
+
weight?: number
|
|
1268
|
+
id?: string
|
|
1269
|
+
data?: Record<string, unknown>
|
|
815
1270
|
}
|
|
816
1271
|
```
|
|
817
1272
|
|
|
@@ -819,35 +1274,106 @@ interface Edge {
|
|
|
819
1274
|
|
|
820
1275
|
```typescript
|
|
821
1276
|
interface TraversalResult {
|
|
822
|
-
visited: Set<NodeId
|
|
823
|
-
order: NodeId[]
|
|
824
|
-
tree?: Map<NodeId, NodeId
|
|
1277
|
+
visited: Set<NodeId>
|
|
1278
|
+
order: NodeId[]
|
|
1279
|
+
tree?: Map<NodeId, NodeId | null>
|
|
825
1280
|
}
|
|
826
1281
|
|
|
827
1282
|
interface ShortestPathResult {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
predecessor: NodeId | null
|
|
1283
|
+
distance: number
|
|
1284
|
+
path: NodeId[]
|
|
1285
|
+
predecessor: Map<NodeId, NodeId | null>
|
|
831
1286
|
}
|
|
832
1287
|
|
|
833
1288
|
interface BellmanFordResult {
|
|
834
|
-
distances: Map<NodeId, number
|
|
835
|
-
|
|
836
|
-
hasNegativeCycle: boolean
|
|
837
|
-
negativeCycleNodes?:
|
|
1289
|
+
distances: Map<NodeId, number>
|
|
1290
|
+
previous: Map<NodeId, NodeId | null>
|
|
1291
|
+
hasNegativeCycle: boolean
|
|
1292
|
+
negativeCycleNodes?: NodeId[]
|
|
838
1293
|
}
|
|
839
1294
|
|
|
840
|
-
type CentralityResult = Record<string, number
|
|
1295
|
+
type CentralityResult = Record<string, number>
|
|
841
1296
|
|
|
842
1297
|
interface PageRankResult {
|
|
843
|
-
ranks: Record<string, number
|
|
844
|
-
iterations: number
|
|
845
|
-
converged: boolean
|
|
1298
|
+
ranks: Record<string, number>
|
|
1299
|
+
iterations: number
|
|
1300
|
+
converged: boolean
|
|
846
1301
|
}
|
|
847
1302
|
|
|
848
1303
|
interface CommunityResult {
|
|
849
|
-
communities: Map<NodeId, number
|
|
850
|
-
modularity: number
|
|
1304
|
+
communities: Map<NodeId, number>
|
|
1305
|
+
modularity: number
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
interface ComponentResult {
|
|
1309
|
+
components: NodeId[][]
|
|
1310
|
+
componentMap: Map<NodeId, number>
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
interface HITSResult {
|
|
1314
|
+
hubs: CentralityResult
|
|
1315
|
+
authorities: CentralityResult
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
interface SpectralClusteringResult {
|
|
1319
|
+
communities: NodeId[][]
|
|
1320
|
+
clusterAssignments: Map<NodeId, number>
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
interface MCLResult {
|
|
1324
|
+
communities: NodeId[][]
|
|
1325
|
+
attractors: Set<NodeId>
|
|
1326
|
+
iterations: number
|
|
1327
|
+
converged: boolean
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
interface BipartiteMatchingResult {
|
|
1331
|
+
matching: Map<NodeId, NodeId>
|
|
1332
|
+
size: number
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
interface LinkPredictionScore {
|
|
1336
|
+
source: NodeId
|
|
1337
|
+
target: NodeId
|
|
1338
|
+
score: number
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
interface HierarchicalClusteringResult<T> {
|
|
1342
|
+
root: ClusterNode<T>
|
|
1343
|
+
dendrogram: ClusterNode<T>[]
|
|
1344
|
+
clusters: Map<number, Set<T>[]>
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
interface KCoreResult<T> {
|
|
1348
|
+
cores: Map<number, Set<T>>
|
|
1349
|
+
coreness: Map<T, number>
|
|
1350
|
+
maxCore: number
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
interface IsomorphismResult {
|
|
1354
|
+
isIsomorphic: boolean
|
|
1355
|
+
mapping?: Map<NodeId, NodeId>
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
interface SynCResult {
|
|
1359
|
+
communities: NodeId[][]
|
|
1360
|
+
clusterAssignments: Map<NodeId, number>
|
|
1361
|
+
embeddings: Map<NodeId, number[]>
|
|
1362
|
+
iterations: number
|
|
1363
|
+
converged: boolean
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
interface TeraHACResult {
|
|
1367
|
+
root: TeraHACClusterNode
|
|
1368
|
+
dendrogram: TeraHACClusterNode[]
|
|
1369
|
+
clusters: NodeId[][]
|
|
1370
|
+
mergeDistances: number[]
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
interface GRSBMResult {
|
|
1374
|
+
clusters: GRSBMCluster[]
|
|
1375
|
+
hierarchy: Map<number, number[]>
|
|
1376
|
+
totalModularity: number
|
|
851
1377
|
}
|
|
852
1378
|
```
|
|
853
1379
|
|
|
@@ -863,19 +1389,23 @@ interface CommunityResult {
|
|
|
863
1389
|
- Connected Components: O(V + E)
|
|
864
1390
|
- Kruskal's MST: O(E log E)
|
|
865
1391
|
- Prim's MST: O((V + E) log V)
|
|
866
|
-
- A
|
|
867
|
-
- Ford-Fulkerson: O(E
|
|
1392
|
+
- A\*: O((V + E) log V) - depends on heuristic quality
|
|
1393
|
+
- Ford-Fulkerson: O(E \* f) where f is max flow
|
|
868
1394
|
- Edmonds-Karp: O(VE²)
|
|
869
1395
|
- Louvain/Leiden: O(n log n) average case
|
|
870
1396
|
- Hierarchical Clustering: O(n² log n)
|
|
1397
|
+
- SynC: O(kni) where k is clusters, n is nodes, i is iterations
|
|
1398
|
+
- TeraHAC: O(n log n) with sampling
|
|
1399
|
+
- GRSBM: O(m log n) where m is edges
|
|
871
1400
|
- **Memory Usage**: O(V + E) for graph storage
|
|
872
1401
|
- **Browser Optimization**: Algorithms use iterative approaches where possible to avoid stack overflow
|
|
1402
|
+
- **Performance Benchmarks**: View detailed performance comparisons at [https://graphty-org.github.io/algorithms/benchmarks/](https://graphty-org.github.io/algorithms/benchmarks/)
|
|
873
1403
|
|
|
874
1404
|
## Development
|
|
875
1405
|
|
|
876
1406
|
### Prerequisites
|
|
877
1407
|
|
|
878
|
-
- Node.js 18+
|
|
1408
|
+
- Node.js 18+
|
|
879
1409
|
- npm 9+
|
|
880
1410
|
|
|
881
1411
|
### Setup
|
|
@@ -911,10 +1441,60 @@ npm run lint # Run ESLint
|
|
|
911
1441
|
npm run lint:fix # Fix ESLint issues
|
|
912
1442
|
npm run lint:pkg # Check for unused dependencies
|
|
913
1443
|
|
|
1444
|
+
# Benchmarking
|
|
1445
|
+
npm run benchmark # Run full benchmark suite
|
|
1446
|
+
npm run benchmark:quick # Run quick benchmark
|
|
1447
|
+
npm run benchmark:report # Generate performance report
|
|
1448
|
+
|
|
1449
|
+
# HTML Examples & Documentation
|
|
1450
|
+
npm run examples:html # Run interactive HTML examples locally
|
|
1451
|
+
npm run build:gh-pages # Build for GitHub Pages deployment
|
|
1452
|
+
npm run examples:run # Run all code examples
|
|
1453
|
+
|
|
914
1454
|
# Git
|
|
915
1455
|
npm run commit # Conventional commit helper
|
|
916
1456
|
```
|
|
917
1457
|
|
|
1458
|
+
### Development Server
|
|
1459
|
+
|
|
1460
|
+
The project includes interactive HTML examples demonstrating each algorithm. To run them locally:
|
|
1461
|
+
|
|
1462
|
+
1. **Copy the environment configuration:**
|
|
1463
|
+
|
|
1464
|
+
```bash
|
|
1465
|
+
cp .env.example .env
|
|
1466
|
+
```
|
|
1467
|
+
|
|
1468
|
+
2. **Configure the server (optional):**
|
|
1469
|
+
Edit `.env` to set your preferred host and port:
|
|
1470
|
+
|
|
1471
|
+
```bash
|
|
1472
|
+
# Server host (defaults to true for network exposure)
|
|
1473
|
+
HOST=localhost # For local-only access
|
|
1474
|
+
# HOST=0.0.0.0 # For network access
|
|
1475
|
+
# HOST=my.server.com # Custom domain
|
|
1476
|
+
|
|
1477
|
+
# Server port (defaults to 9000)
|
|
1478
|
+
PORT=9000 # Must be between 9000-9099
|
|
1479
|
+
```
|
|
1480
|
+
|
|
1481
|
+
3. **Start the development server:**
|
|
1482
|
+
|
|
1483
|
+
```bash
|
|
1484
|
+
npm run examples:html
|
|
1485
|
+
```
|
|
1486
|
+
|
|
1487
|
+
4. **Open your browser** to `http://localhost:9000` (or your configured host/port)
|
|
1488
|
+
|
|
1489
|
+
The HTML examples provide:
|
|
1490
|
+
|
|
1491
|
+
- Interactive visualizations for each algorithm
|
|
1492
|
+
- Step-by-step execution with play/pause controls
|
|
1493
|
+
- Multiple graph types for testing
|
|
1494
|
+
- Real-time parameter adjustment
|
|
1495
|
+
- Educational information about complexity and use cases
|
|
1496
|
+
- Mobile debugging console (Eruda) for testing on mobile devices
|
|
1497
|
+
|
|
918
1498
|
### Project Structure
|
|
919
1499
|
|
|
920
1500
|
```
|
|
@@ -929,6 +1509,11 @@ src/
|
|
|
929
1509
|
├── types/ # TypeScript type definitions
|
|
930
1510
|
└── utils/ # Utility functions
|
|
931
1511
|
|
|
1512
|
+
examples/
|
|
1513
|
+
├── html/ # Interactive HTML examples
|
|
1514
|
+
│ ├── shared/ # Shared utilities and styles
|
|
1515
|
+
│ └── algorithms/ # Algorithm-specific examples
|
|
1516
|
+
|
|
932
1517
|
test/
|
|
933
1518
|
├── unit/ # Unit tests
|
|
934
1519
|
├── browser/ # Browser-specific tests
|
|
@@ -957,4 +1542,4 @@ MIT © Adam Powers
|
|
|
957
1542
|
## Related Projects
|
|
958
1543
|
|
|
959
1544
|
- [@graphty/layout](https://github.com/graphty-org/layout) - Graph layout algorithms
|
|
960
|
-
- [@graphty/graphty-element](https://github.com/graphty-org/graphty-element) - 3D graph visualization web component
|
|
1545
|
+
- [@graphty/graphty-element](https://github.com/graphty-org/graphty-element) - 3D graph visualization web component
|