@graphty/algorithms 1.1.0 → 1.2.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 +464 -33
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +123 -19
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- 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 +411 -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 +342 -0
- package/dist/src/research/sync.js.map +1 -0
- package/dist/src/research/terahac.d.ts +63 -0
- package/dist/src/research/terahac.d.ts.map +1 -0
- package/dist/src/research/terahac.js +375 -0
- package/dist/src/research/terahac.js.map +1 -0
- package/package.json +11 -2
- package/src/clustering/spectral.ts +147 -20
- package/src/index.ts +3 -0
- package/src/research/grsbm.ts +589 -0
- package/src/research/index.ts +17 -0
- package/src/research/sync.ts +469 -0
- package/src/research/terahac.ts +506 -0
package/README.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
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)
|
|
6
7
|
|
|
7
|
-
A comprehensive TypeScript graph algorithms library with
|
|
8
|
+
A comprehensive TypeScript graph algorithms library with 100+ algorithms optimized for browser environments and visualization applications.
|
|
8
9
|
|
|
9
10
|
## Features
|
|
10
11
|
|
|
11
12
|
- **TypeScript-first**: Full type safety with comprehensive type definitions
|
|
12
13
|
- **Browser-optimized**: Designed to run efficiently in web browsers
|
|
13
14
|
- **Modular**: Import only the algorithms you need
|
|
14
|
-
- **Comprehensive**:
|
|
15
|
+
- **Comprehensive**: 100+ graph algorithms including traversal, shortest paths, centrality, clustering, flow, matching, link prediction, and more
|
|
15
16
|
- **Well-tested**: Extensive test suite with high coverage
|
|
16
17
|
- **Standards-compliant**: Follows conventional commits and semantic versioning
|
|
17
18
|
|
|
@@ -46,7 +47,9 @@ const traversal = breadthFirstSearch(graph, 'A');
|
|
|
46
47
|
console.log(traversal.order); // ['A', 'B', 'C']
|
|
47
48
|
|
|
48
49
|
const shortestPaths = dijkstra(graph, 'A');
|
|
49
|
-
|
|
50
|
+
// Get distance to C
|
|
51
|
+
const pathToC = shortestPaths.get('C');
|
|
52
|
+
console.log(pathToC?.distance); // 3
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
## API Reference
|
|
@@ -171,7 +174,7 @@ graph.clear(): void
|
|
|
171
174
|
#### Breadth-First Search (BFS)
|
|
172
175
|
|
|
173
176
|
```typescript
|
|
174
|
-
import { breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS } from '@graphty/algorithms';
|
|
177
|
+
import { breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS, isBipartite } from '@graphty/algorithms';
|
|
175
178
|
|
|
176
179
|
// Basic BFS traversal
|
|
177
180
|
const result = breadthFirstSearch(graph, startNode, {
|
|
@@ -196,7 +199,7 @@ const bipartite = isBipartite(graph);
|
|
|
196
199
|
#### Depth-First Search (DFS)
|
|
197
200
|
|
|
198
201
|
```typescript
|
|
199
|
-
import { depthFirstSearch, topologicalSort, hasCycleDFS } from '@graphty/algorithms';
|
|
202
|
+
import { depthFirstSearch, topologicalSort, hasCycleDFS, findStronglyConnectedComponents } from '@graphty/algorithms';
|
|
200
203
|
|
|
201
204
|
// Basic DFS traversal
|
|
202
205
|
const result = depthFirstSearch(graph, startNode, {
|
|
@@ -212,6 +215,10 @@ const sorted = topologicalSort(graph);
|
|
|
212
215
|
// Cycle detection
|
|
213
216
|
const hasCycle = hasCycleDFS(graph);
|
|
214
217
|
// Returns: boolean
|
|
218
|
+
|
|
219
|
+
// Find strongly connected components using DFS
|
|
220
|
+
const sccs = findStronglyConnectedComponents(graph);
|
|
221
|
+
// Returns: NodeId[][]
|
|
215
222
|
```
|
|
216
223
|
|
|
217
224
|
### Shortest Path Algorithms
|
|
@@ -225,19 +232,20 @@ import { dijkstra, dijkstraPath, singleSourceShortestPath, allPairsShortestPath
|
|
|
225
232
|
const result = dijkstra(graph, source, {
|
|
226
233
|
target?: NodeId // Optional: stop when target is reached
|
|
227
234
|
});
|
|
228
|
-
// Returns: Map<NodeId,
|
|
235
|
+
// Returns: Map<NodeId, ShortestPathResult>
|
|
236
|
+
// ShortestPathResult = { distance: number, path: NodeId[], predecessor: Map<NodeId, NodeId | null> }
|
|
229
237
|
|
|
230
238
|
// Get specific path
|
|
231
239
|
const path = dijkstraPath(graph, source, target);
|
|
232
|
-
// Returns:
|
|
240
|
+
// Returns: ShortestPathResult | null
|
|
233
241
|
|
|
234
242
|
// All shortest paths from source
|
|
235
243
|
const paths = singleSourceShortestPath(graph, source);
|
|
236
|
-
// Returns: Map<NodeId,
|
|
244
|
+
// Returns: Map<NodeId, ShortestPathResult>
|
|
237
245
|
|
|
238
246
|
// All pairs shortest paths
|
|
239
247
|
const allPairs = allPairsShortestPath(graph);
|
|
240
|
-
// Returns: Map<NodeId, Map<NodeId,
|
|
248
|
+
// Returns: Map<NodeId, Map<NodeId, ShortestPathResult>>
|
|
241
249
|
```
|
|
242
250
|
|
|
243
251
|
#### Bellman-Ford Algorithm
|
|
@@ -256,7 +264,7 @@ const result = bellmanFord(graph, source);
|
|
|
256
264
|
|
|
257
265
|
// Get specific path
|
|
258
266
|
const path = bellmanFordPath(graph, source, target);
|
|
259
|
-
// Returns:
|
|
267
|
+
// Returns: ShortestPathResult | null
|
|
260
268
|
|
|
261
269
|
// Check for negative cycles
|
|
262
270
|
const result = hasNegativeCycle(graph);
|
|
@@ -293,7 +301,7 @@ const centralities = degreeCentrality(graph, {
|
|
|
293
301
|
normalized?: boolean, // Default: false
|
|
294
302
|
weight?: string // Optional: edge property for weighted degree
|
|
295
303
|
});
|
|
296
|
-
// Returns: CentralityResult (
|
|
304
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
297
305
|
|
|
298
306
|
// Calculate for single node
|
|
299
307
|
const centrality = nodeDegreeCentrality(graph, nodeId, { normalized?: boolean });
|
|
@@ -311,7 +319,7 @@ const centralities = betweennessCentrality(graph, {
|
|
|
311
319
|
weight?: string, // Optional: use weighted shortest paths
|
|
312
320
|
endpoints?: boolean // Default: false, include endpoints in paths
|
|
313
321
|
});
|
|
314
|
-
// Returns: CentralityResult
|
|
322
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
315
323
|
|
|
316
324
|
// Single node betweenness
|
|
317
325
|
const centrality = nodeBetweennessCentrality(graph, nodeId, options);
|
|
@@ -331,7 +339,7 @@ import { closenessCentrality, nodeClosenessCentrality, weightedClosenessCentrali
|
|
|
331
339
|
const centralities = closenessCentrality(graph, {
|
|
332
340
|
normalized?: boolean // Default: false
|
|
333
341
|
});
|
|
334
|
-
// Returns: CentralityResult
|
|
342
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
335
343
|
|
|
336
344
|
// Single node closeness
|
|
337
345
|
const centrality = nodeClosenessCentrality(graph, nodeId, { normalized?: boolean });
|
|
@@ -342,7 +350,7 @@ const centralities = weightedClosenessCentrality(graph, {
|
|
|
342
350
|
normalized?: boolean,
|
|
343
351
|
weight?: string // Edge property for weights
|
|
344
352
|
});
|
|
345
|
-
// Returns: CentralityResult
|
|
353
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
346
354
|
```
|
|
347
355
|
|
|
348
356
|
#### PageRank
|
|
@@ -363,13 +371,67 @@ const result = pageRank(graph, {
|
|
|
363
371
|
// Personalized PageRank (with bias)
|
|
364
372
|
const ranks = personalizedPageRank(graph, personalization, options);
|
|
365
373
|
// personalization: Map<NodeId, number> - restart probabilities
|
|
366
|
-
// Returns: CentralityResult
|
|
374
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
367
375
|
|
|
368
376
|
// Get top N nodes by PageRank
|
|
369
377
|
const topNodes = topPageRankNodes(graph, n, options);
|
|
370
378
|
// Returns: Array<{ node: NodeId, rank: number }>
|
|
371
379
|
```
|
|
372
380
|
|
|
381
|
+
#### Eigenvector Centrality
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
import { eigenvectorCentrality, nodeEigenvectorCentrality } from '@graphty/algorithms';
|
|
385
|
+
|
|
386
|
+
// Calculate eigenvector centrality for all nodes
|
|
387
|
+
const centralities = eigenvectorCentrality(graph, {
|
|
388
|
+
maxIterations?: number, // Default: 100
|
|
389
|
+
tolerance?: number // Default: 1e-6
|
|
390
|
+
});
|
|
391
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
392
|
+
|
|
393
|
+
// Single node eigenvector centrality
|
|
394
|
+
const centrality = nodeEigenvectorCentrality(graph, nodeId, options);
|
|
395
|
+
// Returns: number
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### Katz Centrality
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
import { katzCentrality, nodeKatzCentrality } from '@graphty/algorithms';
|
|
402
|
+
|
|
403
|
+
// Calculate Katz centrality for all nodes
|
|
404
|
+
const centralities = katzCentrality(graph, {
|
|
405
|
+
alpha?: number, // Attenuation factor (default: 0.1)
|
|
406
|
+
beta?: number, // Weight for direct connections (default: 1.0)
|
|
407
|
+
maxIterations?: number, // Default: 100
|
|
408
|
+
tolerance?: number, // Default: 1e-6
|
|
409
|
+
normalized?: boolean // Default: true
|
|
410
|
+
});
|
|
411
|
+
// Returns: CentralityResult (Record<string, number>)
|
|
412
|
+
|
|
413
|
+
// Single node Katz centrality
|
|
414
|
+
const centrality = nodeKatzCentrality(graph, nodeId, options);
|
|
415
|
+
// Returns: number
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### HITS Algorithm
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
import { hits, nodeHITS } from '@graphty/algorithms';
|
|
422
|
+
|
|
423
|
+
// Calculate hub and authority scores
|
|
424
|
+
const result = hits(graph, {
|
|
425
|
+
maxIterations?: number, // Default: 100
|
|
426
|
+
tolerance?: number // Default: 1e-6
|
|
427
|
+
});
|
|
428
|
+
// Returns: HITSResult { hubs: CentralityResult, authorities: CentralityResult }
|
|
429
|
+
|
|
430
|
+
// Single node HITS scores
|
|
431
|
+
const scores = nodeHITS(graph, nodeId, options);
|
|
432
|
+
// Returns: { hub: number, authority: number }
|
|
433
|
+
```
|
|
434
|
+
|
|
373
435
|
### Connected Components
|
|
374
436
|
|
|
375
437
|
#### Basic Component Operations
|
|
@@ -429,6 +491,10 @@ const stronglyConnected = isStronglyConnected(graph);
|
|
|
429
491
|
// Create condensation graph (DAG of SCCs)
|
|
430
492
|
const condensation = condensationGraph(graph);
|
|
431
493
|
// Returns: { graph: Graph, componentMap: Map<NodeId, number> }
|
|
494
|
+
|
|
495
|
+
// Alternative DFS-based connected components
|
|
496
|
+
const components = connectedComponentsDFS(graph);
|
|
497
|
+
// Returns: ComponentResult
|
|
432
498
|
```
|
|
433
499
|
|
|
434
500
|
#### Weakly Connected Components
|
|
@@ -599,6 +665,10 @@ const flow = fordFulkerson(graph, source, sink, {
|
|
|
599
665
|
|
|
600
666
|
// Edmonds-Karp using BFS (better complexity)
|
|
601
667
|
const flow = edmondsKarp(graph, source, sink, options);
|
|
668
|
+
|
|
669
|
+
// Create bipartite flow network
|
|
670
|
+
const flowNetwork = createBipartiteFlowNetwork(leftNodes, rightNodes, edges, capacities?);
|
|
671
|
+
// Returns: FlowNetwork
|
|
602
672
|
```
|
|
603
673
|
|
|
604
674
|
#### Minimum Cut
|
|
@@ -627,29 +697,29 @@ const cut = kargerMinCut(graph, iterations?);
|
|
|
627
697
|
import { hierarchicalClustering, cutDendrogram, cutDendrogramKClusters } from '@graphty/algorithms';
|
|
628
698
|
|
|
629
699
|
// Agglomerative clustering
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
634
|
-
// Returns: Dendrogram structure
|
|
700
|
+
const result = hierarchicalClustering(graph, linkage);
|
|
701
|
+
// graph: Map<NodeId, Set<NodeId>>
|
|
702
|
+
// linkage: 'single' | 'complete' | 'average' | 'ward' (default: 'single')
|
|
703
|
+
// Returns: HierarchicalClusteringResult { root: ClusterNode, dendrogram: ClusterNode[], clusters: Map<number, Set<NodeId>[]> }
|
|
635
704
|
|
|
636
705
|
// Cut at specific height
|
|
637
|
-
const clusters = cutDendrogram(
|
|
638
|
-
// Returns: NodeId[]
|
|
706
|
+
const clusters = cutDendrogram(result.root, height);
|
|
707
|
+
// Returns: Set<NodeId>[]
|
|
639
708
|
|
|
640
709
|
// Get exactly k clusters
|
|
641
|
-
const clusters = cutDendrogramKClusters(
|
|
642
|
-
// Returns: NodeId[]
|
|
710
|
+
const clusters = cutDendrogramKClusters(result.root, k);
|
|
711
|
+
// Returns: Set<NodeId>[]
|
|
643
712
|
```
|
|
644
713
|
|
|
645
714
|
#### K-Core Decomposition
|
|
646
715
|
|
|
647
716
|
```typescript
|
|
648
|
-
import { kCoreDecomposition, getKCore, kTruss } from '@graphty/algorithms';
|
|
717
|
+
import { kCoreDecomposition, getKCore, kTruss, degeneracyOrdering } from '@graphty/algorithms';
|
|
649
718
|
|
|
650
719
|
// Find all k-cores
|
|
651
|
-
const
|
|
652
|
-
//
|
|
720
|
+
const result = kCoreDecomposition(graph);
|
|
721
|
+
// graph: Map<NodeId, Set<NodeId>>
|
|
722
|
+
// Returns: KCoreResult { cores: Map<number, Set<NodeId>>, coreness: Map<NodeId, number>, maxCore: number }
|
|
653
723
|
|
|
654
724
|
// Extract specific k-core subgraph
|
|
655
725
|
const kCore = getKCore(graph, k);
|
|
@@ -657,9 +727,231 @@ const kCore = getKCore(graph, k);
|
|
|
657
727
|
|
|
658
728
|
// Find k-truss (triangular cores)
|
|
659
729
|
const truss = kTruss(graph, k);
|
|
660
|
-
// Returns:
|
|
730
|
+
// Returns: Set<string> (edge strings)
|
|
731
|
+
|
|
732
|
+
// Degeneracy ordering
|
|
733
|
+
const ordering = degeneracyOrdering(graph);
|
|
734
|
+
// Returns: NodeId[]
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
#### Spectral Clustering
|
|
738
|
+
|
|
739
|
+
```typescript
|
|
740
|
+
import { spectralClustering } from '@graphty/algorithms';
|
|
741
|
+
|
|
742
|
+
// Spectral clustering using graph Laplacian
|
|
743
|
+
const result = spectralClustering(graph, {
|
|
744
|
+
k: number, // Number of clusters
|
|
745
|
+
laplacianType?: 'unnormalized' | 'normalized' | 'randomWalk', // Default: 'normalized'
|
|
746
|
+
maxIterations?: number, // Default: 100
|
|
747
|
+
tolerance?: number // Default: 1e-4
|
|
748
|
+
});
|
|
749
|
+
// Returns: SpectralClusteringResult { communities: NodeId[][], clusterAssignments: Map<NodeId, number> }
|
|
661
750
|
```
|
|
662
751
|
|
|
752
|
+
#### Markov Clustering (MCL)
|
|
753
|
+
|
|
754
|
+
```typescript
|
|
755
|
+
import { markovClustering } from '@graphty/algorithms';
|
|
756
|
+
|
|
757
|
+
// MCL algorithm for network clustering
|
|
758
|
+
const result = markovClustering(graph, {
|
|
759
|
+
expansion?: number, // Expansion parameter (default: 2)
|
|
760
|
+
inflation?: number, // Inflation parameter (default: 2)
|
|
761
|
+
maxIterations?: number, // Default: 100
|
|
762
|
+
tolerance?: number // Default: 1e-6
|
|
763
|
+
});
|
|
764
|
+
// Returns: MCLResult { communities: NodeId[][], attractors: Set<NodeId>, iterations: number, converged: boolean }
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### Matching Algorithms
|
|
768
|
+
|
|
769
|
+
#### Bipartite Matching
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
import { maximumBipartiteMatching, greedyBipartiteMatching, bipartitePartition } from '@graphty/algorithms';
|
|
773
|
+
|
|
774
|
+
// Maximum bipartite matching (Hungarian algorithm)
|
|
775
|
+
const matching = maximumBipartiteMatching(graph, {
|
|
776
|
+
leftNodes?: Set<NodeId>, // Optional: specify left partition
|
|
777
|
+
rightNodes?: Set<NodeId>, // Optional: specify right partition
|
|
778
|
+
});
|
|
779
|
+
// Returns: BipartiteMatchingResult { matching: Map<NodeId, NodeId>, size: number }
|
|
780
|
+
|
|
781
|
+
// Greedy bipartite matching (faster, approximate)
|
|
782
|
+
const matching = greedyBipartiteMatching(graph, options);
|
|
783
|
+
|
|
784
|
+
// Partition graph into bipartite sets
|
|
785
|
+
const partition = bipartitePartition(graph);
|
|
786
|
+
// Returns: { left: Set<NodeId>, right: Set<NodeId> } | null
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
#### Graph Isomorphism
|
|
790
|
+
|
|
791
|
+
```typescript
|
|
792
|
+
import { isGraphIsomorphic, findAllIsomorphisms } from '@graphty/algorithms';
|
|
793
|
+
|
|
794
|
+
// Check if two graphs are isomorphic
|
|
795
|
+
const result = isGraphIsomorphic(graph1, graph2, {
|
|
796
|
+
nodeMatch?: (node1: NodeId, node2: NodeId, g1: Graph, g2: Graph) => boolean,
|
|
797
|
+
edgeMatch?: (edge1: [NodeId, NodeId], edge2: [NodeId, NodeId], g1: Graph, g2: Graph) => boolean,
|
|
798
|
+
findAllMappings?: boolean // Find all possible isomorphisms
|
|
799
|
+
});
|
|
800
|
+
// Returns: IsomorphismResult { isIsomorphic: boolean, mapping?: Map<NodeId, NodeId> }
|
|
801
|
+
|
|
802
|
+
// Find all isomorphism mappings
|
|
803
|
+
const mappings = findAllIsomorphisms(graph1, graph2, options);
|
|
804
|
+
// Returns: Array<Map<NodeId, NodeId>>
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
### Link Prediction Algorithms
|
|
808
|
+
|
|
809
|
+
#### Common Neighbors
|
|
810
|
+
|
|
811
|
+
```typescript
|
|
812
|
+
import { commonNeighborsScore, commonNeighborsPrediction, commonNeighborsForPairs } from '@graphty/algorithms';
|
|
813
|
+
|
|
814
|
+
// Score for a specific pair
|
|
815
|
+
const score = commonNeighborsScore(graph, node1, node2);
|
|
816
|
+
// Returns: number
|
|
817
|
+
|
|
818
|
+
// Predict links for all non-connected pairs
|
|
819
|
+
const predictions = commonNeighborsPrediction(graph, {
|
|
820
|
+
directed?: boolean, // Consider direction
|
|
821
|
+
includeExisting?: boolean, // Include existing edges
|
|
822
|
+
topK?: number // Return only top K predictions
|
|
823
|
+
});
|
|
824
|
+
// Returns: LinkPredictionScore[]
|
|
825
|
+
|
|
826
|
+
// Score multiple specific pairs
|
|
827
|
+
const scores = commonNeighborsForPairs(graph, pairs, options);
|
|
828
|
+
// Returns: LinkPredictionScore[]
|
|
829
|
+
|
|
830
|
+
// Evaluate prediction performance
|
|
831
|
+
const evaluation = evaluateCommonNeighbors(graph, testEdges);
|
|
832
|
+
// Returns: { precision, recall, f1Score }
|
|
833
|
+
|
|
834
|
+
// Get top candidates for a node
|
|
835
|
+
const candidates = getTopCandidatesForNode(graph, nodeId, { topK?: number });
|
|
836
|
+
// Returns: LinkPredictionScore[]
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
#### Adamic-Adar Index
|
|
840
|
+
|
|
841
|
+
```typescript
|
|
842
|
+
import { adamicAdarScore, adamicAdarPrediction, adamicAdarForPairs } from '@graphty/algorithms';
|
|
843
|
+
|
|
844
|
+
// Adamic-Adar score for a pair (weighted by neighbor degrees)
|
|
845
|
+
const score = adamicAdarScore(graph, node1, node2);
|
|
846
|
+
// Returns: number
|
|
847
|
+
|
|
848
|
+
// Predict links using Adamic-Adar
|
|
849
|
+
const predictions = adamicAdarPrediction(graph, {
|
|
850
|
+
directed?: boolean,
|
|
851
|
+
includeExisting?: boolean,
|
|
852
|
+
topK?: number
|
|
853
|
+
});
|
|
854
|
+
// Returns: LinkPredictionScore[]
|
|
855
|
+
|
|
856
|
+
// Score multiple pairs
|
|
857
|
+
const scores = adamicAdarForPairs(graph, pairs, options);
|
|
858
|
+
// Returns: LinkPredictionScore[]
|
|
859
|
+
|
|
860
|
+
// Compare Adamic-Adar with Common Neighbors
|
|
861
|
+
const comparison = compareAdamicAdarWithCommonNeighbors(graph, pairs);
|
|
862
|
+
// Returns: Array<{ source, target, adamicAdar, commonNeighbors }>
|
|
863
|
+
|
|
864
|
+
// Evaluate prediction performance
|
|
865
|
+
const evaluation = evaluateAdamicAdar(graph, testEdges);
|
|
866
|
+
// Returns: { precision, recall, f1Score }
|
|
867
|
+
|
|
868
|
+
// Get top candidates for a node
|
|
869
|
+
const candidates = getTopAdamicAdarCandidatesForNode(graph, nodeId, { topK?: number });
|
|
870
|
+
// Returns: LinkPredictionScore[]
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### Research Algorithms (2023-2025)
|
|
874
|
+
|
|
875
|
+
Cutting-edge graph algorithms based on recent research.
|
|
876
|
+
|
|
877
|
+
#### SynC - Synergistic Deep Graph Clustering
|
|
878
|
+
|
|
879
|
+
```typescript
|
|
880
|
+
import { syncClustering } from '@graphty/algorithms';
|
|
881
|
+
|
|
882
|
+
// Deep learning based clustering
|
|
883
|
+
const result = syncClustering(graph, {
|
|
884
|
+
k: number, // Number of clusters
|
|
885
|
+
maxIterations?: number, // Default: 100
|
|
886
|
+
learningRate?: number, // Default: 0.01
|
|
887
|
+
hiddenDim?: number, // Default: 64
|
|
888
|
+
randomSeed?: number
|
|
889
|
+
});
|
|
890
|
+
// Returns: SynCResult {
|
|
891
|
+
// communities: NodeId[][],
|
|
892
|
+
// clusterAssignments: Map<NodeId, number>,
|
|
893
|
+
// embeddings: Map<NodeId, number[]>,
|
|
894
|
+
// iterations: number,
|
|
895
|
+
// converged: boolean
|
|
896
|
+
// }
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
#### TeraHAC - Scalable Hierarchical Agglomerative Clustering
|
|
900
|
+
|
|
901
|
+
```typescript
|
|
902
|
+
import { teraHAC } from '@graphty/algorithms';
|
|
903
|
+
|
|
904
|
+
// Scalable hierarchical clustering
|
|
905
|
+
const result = teraHAC(graph, {
|
|
906
|
+
linkage?: 'single' | 'complete' | 'average', // Default: 'average'
|
|
907
|
+
k?: number, // Target number of clusters
|
|
908
|
+
threshold?: number, // Distance threshold for merging
|
|
909
|
+
sampleSize?: number, // Default: 1000
|
|
910
|
+
randomSeed?: number
|
|
911
|
+
});
|
|
912
|
+
// Returns: TeraHACResult {
|
|
913
|
+
// root: TeraHACClusterNode,
|
|
914
|
+
// dendrogram: TeraHACClusterNode[],
|
|
915
|
+
// clusters: NodeId[][],
|
|
916
|
+
// mergeDistances: number[]
|
|
917
|
+
// }
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
#### GRSBM - Greedy Recursive Spectral Bisection with Modularity
|
|
921
|
+
|
|
922
|
+
```typescript
|
|
923
|
+
import { grsbm } from '@graphty/algorithms';
|
|
924
|
+
|
|
925
|
+
// Explainable community detection
|
|
926
|
+
const result = grsbm(graph, {
|
|
927
|
+
minClusterSize?: number, // Default: 5
|
|
928
|
+
maxDepth?: number, // Default: 10
|
|
929
|
+
modularityThreshold?: number, // Default: 0.1
|
|
930
|
+
explainClusters?: boolean // Default: true
|
|
931
|
+
});
|
|
932
|
+
// Returns: GRSBMResult {
|
|
933
|
+
// clusters: GRSBMCluster[], // Each cluster has id, nodes, modularity, explanation
|
|
934
|
+
// hierarchy: Map<number, number[]>,
|
|
935
|
+
// totalModularity: number
|
|
936
|
+
// }
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
## Algorithm Categories Summary
|
|
940
|
+
|
|
941
|
+
### Available Algorithms by Category:
|
|
942
|
+
|
|
943
|
+
- **Traversal**: BFS, DFS, Topological Sort, Cycle Detection, Bipartite Check
|
|
944
|
+
- **Shortest Path**: Dijkstra, Bellman-Ford, Floyd-Warshall, A*
|
|
945
|
+
- **Centrality**: Degree, Betweenness, Closeness, PageRank, Eigenvector, Katz, HITS
|
|
946
|
+
- **Components**: Connected, Strongly Connected, Weakly Connected, Condensation Graph
|
|
947
|
+
- **Community Detection**: Louvain, Leiden, Label Propagation, Girvan-Newman
|
|
948
|
+
- **Clustering**: Hierarchical, K-Core, Spectral, Markov (MCL)
|
|
949
|
+
- **Minimum Spanning Tree**: Kruskal, Prim
|
|
950
|
+
- **Network Flow**: Ford-Fulkerson, Edmonds-Karp, Min-Cut (Stoer-Wagner, Karger)
|
|
951
|
+
- **Matching**: Bipartite Matching, Graph Isomorphism
|
|
952
|
+
- **Link Prediction**: Common Neighbors, Adamic-Adar
|
|
953
|
+
- **Research Algorithms**: SynC, TeraHAC, GRSBM
|
|
954
|
+
|
|
663
955
|
## Examples
|
|
664
956
|
|
|
665
957
|
The library includes comprehensive examples demonstrating each algorithm. Find them in the [examples directory](https://github.com/graphty-org/algorithms/tree/main/examples):
|
|
@@ -676,6 +968,9 @@ The library includes comprehensive examples demonstrating each algorithm. Find t
|
|
|
676
968
|
- [Betweenness Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/betweenness-centrality-example.js) - Bridge nodes
|
|
677
969
|
- [Closeness Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/closeness-centrality-example.js) - Central nodes
|
|
678
970
|
- [PageRank](https://github.com/graphty-org/algorithms/blob/main/examples/pagerank-example.js) - Node ranking algorithm
|
|
971
|
+
- [Eigenvector Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/eigenvector-centrality-example.js) - Influence from important nodes
|
|
972
|
+
- [Katz Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/katz-centrality-example.js) - Weighted path counting
|
|
973
|
+
- [HITS Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/hits-algorithm-example.js) - Hub and authority scores
|
|
679
974
|
|
|
680
975
|
### Graph Structure
|
|
681
976
|
- [Connected Components](https://github.com/graphty-org/algorithms/blob/main/examples/connected-components-example.js) - Find graph components
|
|
@@ -688,13 +983,30 @@ The library includes comprehensive examples demonstrating each algorithm. Find t
|
|
|
688
983
|
- [Label Propagation](https://github.com/graphty-org/algorithms/blob/main/examples/label-propagation.ts) - Fast community detection
|
|
689
984
|
- [Girvan-Newman](https://github.com/graphty-org/algorithms/blob/main/examples/girvan-newman-example.js) - Hierarchical communities
|
|
690
985
|
|
|
986
|
+
### Clustering
|
|
987
|
+
- [Hierarchical Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/hierarchical-clustering.ts) - Graph clustering
|
|
988
|
+
- [K-Core Decomposition](https://github.com/graphty-org/algorithms/blob/main/examples/k-core-decomposition.ts) - Core analysis
|
|
989
|
+
- [Spectral Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/spectral-clustering-example.js) - Eigenvalue-based clustering
|
|
990
|
+
- [MCL Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/mcl-clustering-example.js) - Markov clustering
|
|
991
|
+
|
|
992
|
+
### Matching
|
|
993
|
+
- [Bipartite Matching](https://github.com/graphty-org/algorithms/blob/main/examples/bipartite-matching-example.js) - Job assignment, dating apps
|
|
994
|
+
- [Graph Isomorphism](https://github.com/graphty-org/algorithms/blob/main/examples/graph-isomorphism-example.js) - Structural equivalence
|
|
995
|
+
|
|
996
|
+
### Link Prediction
|
|
997
|
+
- [Common Neighbors](https://github.com/graphty-org/algorithms/blob/main/examples/common-neighbors-example.js) - Friend suggestions
|
|
998
|
+
- [Adamic-Adar](https://github.com/graphty-org/algorithms/blob/main/examples/adamic-adar-example.js) - Weighted predictions
|
|
999
|
+
|
|
691
1000
|
### Advanced Algorithms
|
|
692
1001
|
- [A* Pathfinding](https://github.com/graphty-org/algorithms/blob/main/examples/astar-pathfinding.ts) - Heuristic pathfinding
|
|
693
1002
|
- [Flow Algorithms](https://github.com/graphty-org/algorithms/blob/main/examples/flow-algorithms.ts) - Maximum flow and applications
|
|
694
1003
|
- [Ford-Fulkerson Flow](https://github.com/graphty-org/algorithms/blob/main/examples/ford-fulkerson-flow.ts) - Maximum flow implementation
|
|
695
1004
|
- [Minimum Cut](https://github.com/graphty-org/algorithms/blob/main/examples/min-cut.ts) - Graph partitioning
|
|
696
|
-
|
|
697
|
-
|
|
1005
|
+
|
|
1006
|
+
### Research Algorithms
|
|
1007
|
+
- [SynC Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/sync-example.js) - Deep learning based clustering
|
|
1008
|
+
- [TeraHAC](https://github.com/graphty-org/algorithms/blob/main/examples/terahac-example.js) - Scalable hierarchical clustering
|
|
1009
|
+
- [GRSBM](https://github.com/graphty-org/algorithms/blob/main/examples/grsbm-example.js) - Explainable community detection
|
|
698
1010
|
|
|
699
1011
|
## Advanced Usage Examples
|
|
700
1012
|
|
|
@@ -849,6 +1161,77 @@ interface CommunityResult {
|
|
|
849
1161
|
communities: Map<NodeId, number>;
|
|
850
1162
|
modularity: number;
|
|
851
1163
|
}
|
|
1164
|
+
|
|
1165
|
+
interface ComponentResult {
|
|
1166
|
+
components: NodeId[][];
|
|
1167
|
+
componentMap: Map<NodeId, number>;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
interface HITSResult {
|
|
1171
|
+
hubs: CentralityResult;
|
|
1172
|
+
authorities: CentralityResult;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
interface SpectralClusteringResult {
|
|
1176
|
+
communities: NodeId[][];
|
|
1177
|
+
clusterAssignments: Map<NodeId, number>;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
interface MCLResult {
|
|
1181
|
+
communities: NodeId[][];
|
|
1182
|
+
attractors: Set<NodeId>;
|
|
1183
|
+
iterations: number;
|
|
1184
|
+
converged: boolean;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
interface BipartiteMatchingResult {
|
|
1188
|
+
matching: Map<NodeId, NodeId>;
|
|
1189
|
+
size: number;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
interface LinkPredictionScore {
|
|
1193
|
+
source: NodeId;
|
|
1194
|
+
target: NodeId;
|
|
1195
|
+
score: number;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
interface HierarchicalClusteringResult<T> {
|
|
1199
|
+
root: ClusterNode<T>;
|
|
1200
|
+
dendrogram: ClusterNode<T>[];
|
|
1201
|
+
clusters: Map<number, Set<T>[]>;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
interface KCoreResult<T> {
|
|
1205
|
+
cores: Map<number, Set<T>>;
|
|
1206
|
+
coreness: Map<T, number>;
|
|
1207
|
+
maxCore: number;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
interface IsomorphismResult {
|
|
1211
|
+
isIsomorphic: boolean;
|
|
1212
|
+
mapping?: Map<NodeId, NodeId>;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
interface SynCResult {
|
|
1216
|
+
communities: NodeId[][];
|
|
1217
|
+
clusterAssignments: Map<NodeId, number>;
|
|
1218
|
+
embeddings: Map<NodeId, number[]>;
|
|
1219
|
+
iterations: number;
|
|
1220
|
+
converged: boolean;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
interface TeraHACResult {
|
|
1224
|
+
root: TeraHACClusterNode;
|
|
1225
|
+
dendrogram: TeraHACClusterNode[];
|
|
1226
|
+
clusters: NodeId[][];
|
|
1227
|
+
mergeDistances: number[];
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
interface GRSBMResult {
|
|
1231
|
+
clusters: GRSBMCluster[];
|
|
1232
|
+
hierarchy: Map<number, number[]>;
|
|
1233
|
+
totalModularity: number;
|
|
1234
|
+
}
|
|
852
1235
|
```
|
|
853
1236
|
|
|
854
1237
|
## Performance Considerations
|
|
@@ -868,6 +1251,9 @@ interface CommunityResult {
|
|
|
868
1251
|
- Edmonds-Karp: O(VE²)
|
|
869
1252
|
- Louvain/Leiden: O(n log n) average case
|
|
870
1253
|
- Hierarchical Clustering: O(n² log n)
|
|
1254
|
+
- SynC: O(kni) where k is clusters, n is nodes, i is iterations
|
|
1255
|
+
- TeraHAC: O(n log n) with sampling
|
|
1256
|
+
- GRSBM: O(m log n) where m is edges
|
|
871
1257
|
- **Memory Usage**: O(V + E) for graph storage
|
|
872
1258
|
- **Browser Optimization**: Algorithms use iterative approaches where possible to avoid stack overflow
|
|
873
1259
|
|
|
@@ -913,8 +1299,48 @@ npm run lint:pkg # Check for unused dependencies
|
|
|
913
1299
|
|
|
914
1300
|
# Git
|
|
915
1301
|
npm run commit # Conventional commit helper
|
|
1302
|
+
|
|
1303
|
+
# HTML Examples
|
|
1304
|
+
npm run examples:html # Run interactive HTML examples
|
|
1305
|
+
npm run build:gh-pages # Build for GitHub Pages deployment
|
|
916
1306
|
```
|
|
917
1307
|
|
|
1308
|
+
### Development Server
|
|
1309
|
+
|
|
1310
|
+
The project includes interactive HTML examples demonstrating each algorithm. To run them locally:
|
|
1311
|
+
|
|
1312
|
+
1. **Copy the environment configuration:**
|
|
1313
|
+
```bash
|
|
1314
|
+
cp .env.example .env
|
|
1315
|
+
```
|
|
1316
|
+
|
|
1317
|
+
2. **Configure the server (optional):**
|
|
1318
|
+
Edit `.env` to set your preferred host and port:
|
|
1319
|
+
```bash
|
|
1320
|
+
# Server host (defaults to true for network exposure)
|
|
1321
|
+
HOST=localhost # For local-only access
|
|
1322
|
+
# HOST=0.0.0.0 # For network access
|
|
1323
|
+
# HOST=my.server.com # Custom domain
|
|
1324
|
+
|
|
1325
|
+
# Server port (defaults to 9000)
|
|
1326
|
+
PORT=9000 # Must be between 9000-9099
|
|
1327
|
+
```
|
|
1328
|
+
|
|
1329
|
+
3. **Start the development server:**
|
|
1330
|
+
```bash
|
|
1331
|
+
npm run examples:html
|
|
1332
|
+
```
|
|
1333
|
+
|
|
1334
|
+
4. **Open your browser** to `http://localhost:9000` (or your configured host/port)
|
|
1335
|
+
|
|
1336
|
+
The HTML examples provide:
|
|
1337
|
+
- Interactive visualizations for each algorithm
|
|
1338
|
+
- Step-by-step execution with play/pause controls
|
|
1339
|
+
- Multiple graph types for testing
|
|
1340
|
+
- Real-time parameter adjustment
|
|
1341
|
+
- Educational information about complexity and use cases
|
|
1342
|
+
- Mobile debugging console (Eruda) for testing on mobile devices
|
|
1343
|
+
|
|
918
1344
|
### Project Structure
|
|
919
1345
|
|
|
920
1346
|
```
|
|
@@ -929,6 +1355,11 @@ src/
|
|
|
929
1355
|
├── types/ # TypeScript type definitions
|
|
930
1356
|
└── utils/ # Utility functions
|
|
931
1357
|
|
|
1358
|
+
examples/
|
|
1359
|
+
├── html/ # Interactive HTML examples
|
|
1360
|
+
│ ├── shared/ # Shared utilities and styles
|
|
1361
|
+
│ └── algorithms/ # Algorithm-specific examples
|
|
1362
|
+
|
|
932
1363
|
test/
|
|
933
1364
|
├── unit/ # Unit tests
|
|
934
1365
|
├── browser/ # Browser-specific tests
|
|
@@ -957,4 +1388,4 @@ MIT © Adam Powers
|
|
|
957
1388
|
## Related Projects
|
|
958
1389
|
|
|
959
1390
|
- [@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
|
|
1391
|
+
- [@graphty/graphty-element](https://github.com/graphty-org/graphty-element) - 3D graph visualization web component
|