npm package: @graphty/algorithms
Description: Graph algorithms library for browser environments implemented in TypeScript
Author: Adam Powers
Latest version: 1.7.1

# @graphty/algorithms

[![CI](https://github.com/graphty-org/graphty-monorepo/actions/workflows/ci.yml/badge.svg)](https://github.com/graphty-org/graphty-monorepo/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/graphty-org/graphty-monorepo/badge.svg?branch=master)](https://coveralls.io/github/graphty-org/graphty-monorepo?branch=master)
[![npm version](https://img.shields.io/npm/v/@graphty/algorithms.svg)](https://www.npmjs.com/package/@graphty/algorithms)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Documentation](https://img.shields.io/badge/docs-vitepress-blue)](https://graphty.app/docs/algorithms/)
[![Storybook](https://img.shields.io/badge/storybook-interactive%20demos-ff4785)](https://graphty.app/storybook/algorithms/)
[![Examples](https://img.shields.io/badge/demo-github%20pages-blue)](https://graphty.app/algorithms/)

A comprehensive TypeScript graph algorithms library with 98 algorithms optimized for browser environments and visualization applications.

## Features

- **TypeScript-first**: Full type safety with comprehensive type definitions
- **Browser-optimized**: Designed to run efficiently in web browsers
- **Modular**: Import only the algorithms you need
- **Comprehensive**: 98 graph algorithms including traversal, shortest paths, centrality, clustering, flow, matching, link prediction, and more
- **Interactive Examples**: [Live demos](https://graphty.app/algorithms/) with visualizations for all algorithms
- **Performance Analysis**: [Detailed benchmarks](https://graphty.app/algorithms/benchmarks/) comparing algorithm performance
- **Well-tested**: Extensive test suite with high coverage
- **Standards-compliant**: Follows conventional commits and semantic versioning

## Performance Optimizations

The library automatically optimizes performance for large graphs (≥10,000 nodes) using:

- **Direction-Optimized BFS**: Dynamically switches between top-down and bottom-up search strategies, providing up to 42x speedup on large graphs
- **CSR Graph Format**: Compressed Sparse Row format for cache-efficient memory access
- **Bit-Packed Data Structures**: 8x memory reduction using bit arrays for boolean data

These optimizations are applied automatically - no configuration needed! Just use the standard API:

```typescript
// Automatically uses optimized implementation for large graphs
const result = breadthFirstSearch(largeGraph, startNode);
```

All BFS-based algorithms benefit from these optimizations:

- `breadthFirstSearch`, `shortestPathBFS`, `singleSourceShortestPathBFS`
- `betweennessCentrality`, `closenessCentrality`
- Connected component algorithms

### Performance Benchmarks

| Graph Size | Standard BFS | Optimized BFS | Speedup |
| ---------- | ------------ | ------------- | ------- |
| 10K nodes  | 4.40ms       | 6.34ms        | 0.69x   |
| 50K nodes  | 158.64ms     | 44.27ms       | 3.58x   |
| 100K nodes | 5,370ms      | 126ms         | 42.58x  |

_Note: Optimizations activate automatically for graphs ≥10K nodes to avoid conversion overhead on smaller graphs._

### Learn More

- 📖 [Performance Guide](docs/PERFORMANCE_GUIDE.md) - Detailed optimization explanations
- 🔄 [Migration Guide](docs/MIGRATION_GUIDE.md) - Upgrading from older versions
- 💾 [Memory vs Speed Tradeoffs](docs/PERFORMANCE_GUIDE.md#memory-vs-speed-tradeoffs) - Making the right choices

## Installation

```bash
npm install @graphty/algorithms
```

## Quick Start

```typescript
import { Graph, breadthFirstSearch, dijkstra } from "@graphty/algorithms";

// Create a new graph
const graph = new Graph();

// Add nodes and edges
graph.addNode("A");
graph.addNode("B");
graph.addNode("C");
graph.addEdge("A", "B", 1); // source, target, weight
graph.addEdge("B", "C", 2);

// Basic graph operations
console.log(graph.nodeCount); // 3
console.log(graph.totalEdgeCount); // 2
console.log(graph.hasEdge("A", "B")); // true

// Run algorithms
const traversal = breadthFirstSearch(graph, "A");
console.log(traversal.order); // ['A', 'B', 'C']

const shortestPaths = dijkstra(graph, "A");
// Get distance to C
const pathToC = shortestPaths.get("C");
console.log(pathToC?.distance); // 3
```

## API Reference

### Graph Class

The core data structure for representing graphs.

```typescript
class Graph {
    constructor(config?: Partial<GraphConfig>);
}
```

#### Configuration Options

```typescript
interface GraphConfig {
    directed: boolean; // Default: false
    allowSelfLoops: boolean; // Default: false
    allowParallelEdges: boolean; // Default: false
}
```

#### Node Operations

```typescript
// Add a node with optional data
graph.addNode(id: NodeId, data?: Record<string, unknown>): void

// Remove a node and all its edges
graph.removeNode(id: NodeId): boolean

// Check if a node exists
graph.hasNode(id: NodeId): boolean

// Get node details
graph.getNode(id: NodeId): Node | undefined

// Get all nodes
graph.nodes(): IterableIterator<Node>
```

#### Edge Operations

```typescript
// Add an edge with optional weight and data
graph.addEdge(
  source: NodeId,
  target: NodeId,
  weight?: number,
  data?: Record<string, unknown>
): void

// Remove an edge
graph.removeEdge(source: NodeId, target: NodeId): boolean

// Check if an edge exists
graph.hasEdge(source: NodeId, target: NodeId): boolean

// Get edge details
graph.getEdge(source: NodeId, target: NodeId): Edge | undefined

// Get all edges
graph.edges(): IterableIterator<Edge>
```

#### Graph Properties

```typescript
// Number of nodes
graph.nodeCount: number

// Total number of edges (counts both directions for undirected)
graph.totalEdgeCount: number

// Number of unique edges
graph.uniqueEdgeCount: number

// Check if graph is directed
graph.isDirected: boolean
```

#### Degree Operations

```typescript
// Total degree (in + out for directed)
graph.degree(nodeId: NodeId): number

// In-degree (directed graphs only)
graph.inDegree(nodeId: NodeId): number

// Out-degree
graph.outDegree(nodeId: NodeId): number
```

#### Neighbor Operations

```typescript
// Get neighboring nodes
graph.neighbors(nodeId: NodeId): IterableIterator<NodeId>

// Get incoming neighbors (directed graphs)
graph.inNeighbors(nodeId: NodeId): IterableIterator<NodeId>

// Get outgoing neighbors
graph.outNeighbors(nodeId: NodeId): IterableIterator<NodeId>
```

#### Utility Methods

```typescript
// Create a deep copy
graph.clone(): Graph

// Clear all nodes and edges
graph.clear(): void

// Get a copy of the graph configuration
graph.getConfig(): GraphConfig
```

### Traversal Algorithms

#### Breadth-First Search (BFS)

```typescript
import { breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS, isBipartite } from '@graphty/algorithms';

// Basic BFS traversal
const result = breadthFirstSearch(graph, startNode, {
  targetNode?: NodeId,     // Optional: stop when target is reached
  visitCallback?: (node: NodeId, level: number) => void
});
// Returns: TraversalResult { visited: Set<NodeId>, order: NodeId[], tree?: Map<NodeId, NodeId | null> }

// Note: For graphs with ≥10K nodes, BFS automatically uses:
// - Direction-Optimized BFS (switches between top-down/bottom-up)
// - CSR graph format for cache efficiency
// - Bit-packed data structures for memory efficiency

// Find shortest path between two nodes (unweighted)
const path = shortestPathBFS(graph, source, target);
// Returns: ShortestPathResult | null
// ShortestPathResult = { distance: number, path: NodeId[], predecessor: Map<NodeId, NodeId | null> }

// Find all shortest paths from a source
const paths = singleSourceShortestPathBFS(graph, source);
// Returns: Map<NodeId, ShortestPathResult>

// Check if graph is bipartite
const bipartite = isBipartite(graph);
// Returns: { isBipartite: boolean, coloring?: Map<NodeId, number> }
```

#### Depth-First Search (DFS)

```typescript
import { depthFirstSearch, topologicalSort, hasCycleDFS, findStronglyConnectedComponents } from '@graphty/algorithms';

// Basic DFS traversal
const result = depthFirstSearch(graph, startNode, {
  targetNode?: NodeId,      // Optional: stop when target is reached
  visitCallback?: (node: NodeId, level: number) => void,
  recursive?: boolean,      // Use recursive implementation (default: false)
  preOrder?: boolean        // Visit nodes in pre-order (default: true)
});
// Returns: TraversalResult

// Topological sort (for DAGs)
const sorted = topologicalSort(graph);
// Returns: NodeId[] | null (null if cycle detected)

// Cycle detection
const hasCycle = hasCycleDFS(graph);
// Returns: boolean

// Find strongly connected components using DFS
const sccs = findStronglyConnectedComponents(graph);
// Returns: NodeId[][]
```

### Shortest Path Algorithms

#### Dijkstra's Algorithm

```typescript
import {
  dijkstra,
  dijkstraPath,
  singleSourceShortestPath,
  allPairsShortestPath
} from '@graphty/algorithms'

// Single-source shortest paths
const result = dijkstra(graph, source, {
  target?: NodeId // Optional: stop when target is reached
})
// Returns: Map<NodeId, ShortestPathResult>
// ShortestPathResult = { distance: number, path: NodeId[], predecessor: Map<NodeId, NodeId | null> }

// Get specific path
const path = dijkstraPath(graph, source, target)
// Returns: ShortestPathResult | null

// All shortest paths from source
const paths = singleSourceShortestPath(graph, source)
// Returns: Map<NodeId, ShortestPathResult>

// All pairs shortest paths
const allPairs = allPairsShortestPath(graph)
// Returns: Map<NodeId, Map<NodeId, ShortestPathResult>>
```

#### Bellman-Ford Algorithm

```typescript
import { bellmanFord, bellmanFordPath, hasNegativeCycle } from "@graphty/algorithms";

// Single-source shortest paths (handles negative weights)
const result = bellmanFord(graph, source);
// Returns: BellmanFordResult {
//   distances: Map<NodeId, number>,
//   predecessors: Map<NodeId, NodeId | null>,
//   hasNegativeCycle: boolean,
//   negativeCycleNodes?: Set<NodeId>
// }

// Get specific path
const path = bellmanFordPath(graph, source, target);
// Returns: ShortestPathResult | null

// Check for negative cycles
const result = hasNegativeCycle(graph);
// Returns: BellmanFordResult with hasNegativeCycle boolean
```

#### Floyd-Warshall Algorithm

```typescript
import { floydWarshall, floydWarshallPath, transitiveClosure } from "@graphty/algorithms";

// All pairs shortest paths
const result = floydWarshall(graph);
// Returns: { distances: Map<NodeId, Map<NodeId, number>>, next: Map<NodeId, Map<NodeId, NodeId | null>> }

// Get specific path between any pair
const path = floydWarshallPath(result, source, target);
// Returns: NodeId[] | null

// Compute transitive closure
const closure = transitiveClosure(graph);
// Returns: Map<NodeId, Set<NodeId>>
```

### Centrality Algorithms

#### Degree Centrality

```typescript
import { degreeCentrality, nodeDegreeCentrality } from "@graphty/algorithms";

// Calculate for all nodes
const centralities = degreeCentrality(graph, {
    normalized: boolean, // Default: false
    weight: string, // Optional: edge property for weighted degree
});
// Returns: CentralityResult (Record<string, number>)

// Calculate for single node
const centrality = nodeDegreeCentrality(graph, nodeId, { normalized: boolean });
// Returns: number
```

#### Betweenness Centrality

```typescript
import { betweennessCentrality, nodeBetweennessCentrality, edgeBetweennessCentrality } from "@graphty/algorithms";

// Node betweenness for all nodes
const centralities = betweennessCentrality(graph, {
    normalized: boolean, // Default: false
    weight: string, // Optional: use weighted shortest paths
    endpoints: boolean, // Default: false, include endpoints in paths
});
// Returns: CentralityResult (Record<string, number>)

// Single node betweenness
const centrality = nodeBetweennessCentrality(graph, nodeId, options);
// Returns: number

// Edge betweenness
const edgeCentralities = edgeBetweennessCentrality(graph, options);
// Returns: Map<string, number> (edge ID to centrality)
```

#### Closeness Centrality

```typescript
import { closenessCentrality, nodeClosenessCentrality, weightedClosenessCentrality } from "@graphty/algorithms";

// Closeness for all nodes
const centralities = closenessCentrality(graph, {
    normalized: boolean, // Default: false
});
// Returns: CentralityResult (Record<string, number>)

// Single node closeness
const centrality = nodeClosenessCentrality(graph, nodeId, {
    normalized: boolean,
});
// Returns: number

// Weighted closeness
const centralities = weightedClosenessCentrality(graph, {
    normalized: boolean,
    weight: string, // Edge property for weights
});
// Returns: CentralityResult (Record<string, number>)

// Single node weighted closeness
const centrality = nodeWeightedClosenessCentrality(graph, nodeId, {
    normalized: boolean,
    weight: string, // Edge property for weights
});
// Returns: number
```

#### PageRank

```typescript
import { pageRank, personalizedPageRank, topPageRankNodes } from "@graphty/algorithms";

// Standard PageRank
const result = pageRank(graph, {
    dampingFactor: number, // Default: 0.85
    maxIterations: number, // Default: 100
    tolerance: number, // Default: 1e-6
    initialRanks: Record<string, number>,
    personalization: Record<string, number>,
});
// Returns: { ranks: Record<string, number>, iterations: number, converged: boolean }

// Personalized PageRank (with bias)
const ranks = personalizedPageRank(graph, personalization, options);
// personalization: Map<NodeId, number> - restart probabilities
// Returns: CentralityResult (Record<string, number>)

// Get top N nodes by PageRank
const topNodes = topPageRankNodes(graph, n, options);
// Returns: Array<{ node: NodeId, rank: number }>

// Alternative PageRank that returns CentralityResult format
const centralities = pageRankCentrality(graph, options);
// Returns: CentralityResult (Record<string, number>)
```

#### Eigenvector Centrality

```typescript
import { eigenvectorCentrality, nodeEigenvectorCentrality } from "@graphty/algorithms";

// Calculate eigenvector centrality for all nodes
const centralities = eigenvectorCentrality(graph, {
    maxIterations: number, // Default: 100
    tolerance: number, // Default: 1e-6
});
// Returns: CentralityResult (Record<string, number>)

// Single node eigenvector centrality
const centrality = nodeEigenvectorCentrality(graph, nodeId, options);
// Returns: number
```

#### Katz Centrality

```typescript
import { katzCentrality, nodeKatzCentrality } from "@graphty/algorithms";

// Calculate Katz centrality for all nodes
const centralities = katzCentrality(graph, {
    alpha: number, // Attenuation factor (default: 0.1)
    beta: number, // Weight for direct connections (default: 1.0)
    maxIterations: number, // Default: 100
    tolerance: number, // Default: 1e-6
    normalized: boolean, // Default: true
});
// Returns: CentralityResult (Record<string, number>)

// Single node Katz centrality
const centrality = nodeKatzCentrality(graph, nodeId, options);
// Returns: number
```

#### HITS Algorithm

```typescript
import { hits, nodeHITS } from "@graphty/algorithms";

// Calculate hub and authority scores
const result = hits(graph, {
    maxIterations: number, // Default: 100
    tolerance: number, // Default: 1e-6
});
// Returns: HITSResult { hubs: CentralityResult, authorities: CentralityResult }

// Single node HITS scores
const scores = nodeHITS(graph, nodeId, options);
// Returns: { hub: number, authority: number }
```

### Connected Components

#### Basic Component Operations

```typescript
import {
    connectedComponents,
    isConnected,
    numberOfConnectedComponents,
    largestConnectedComponent,
    getConnectedComponent,
} from "@graphty/algorithms";

// Find all components
const components = connectedComponents(graph);
// Returns: NodeId[][] (array of component arrays)

// Check if graph is connected
const connected = isConnected(graph);
// Returns: boolean

// Count components
const count = numberOfConnectedComponents(graph);
// Returns: number

// Get largest component
const largest = largestConnectedComponent(graph);
// Returns: NodeId[]

// Get component containing a specific node
const component = getConnectedComponent(graph, nodeId);
// Returns: Set<NodeId>
```

#### Strongly Connected Components

```typescript
import {
    stronglyConnectedComponents,
    findStronglyConnectedComponents,
    isStronglyConnected,
    condensationGraph,
} from "@graphty/algorithms";

// Find SCCs using Tarjan's algorithm
const sccs = stronglyConnectedComponents(graph);
// Returns: ComponentResult

// Alternative: using DFS
const sccs = findStronglyConnectedComponents(graph);
// Returns: NodeId[][]

// Check if directed graph is strongly connected
const stronglyConnected = isStronglyConnected(graph);
// Returns: boolean

// Create condensation graph (DAG of SCCs)
const condensation = condensationGraph(graph);
// Returns: { graph: Graph, componentMap: Map<NodeId, number> }

// Alternative DFS-based connected components
const components = connectedComponentsDFS(graph);
// Returns: ComponentResult
```

#### Weakly Connected Components

```typescript
import { weaklyConnectedComponents, isWeaklyConnected } from "@graphty/algorithms";

// Find WCCs (ignoring edge direction)
const wccs = weaklyConnectedComponents(graph);
// Returns: ComponentResult

// Check if directed graph is weakly connected
const weaklyConnected = isWeaklyConnected(graph);
// Returns: boolean
```

### Data Structures

#### Priority Queue

Min-heap implementation used internally by algorithms.

```typescript
import { PriorityQueue } from "@graphty/algorithms";

const pq = new PriorityQueue<T>((a, b) => a.priority - b.priority);

pq.enqueue(item);
pq.dequeue();
pq.peek();
pq.isEmpty();
pq.size;
pq.clear();
```

#### Union-Find (Disjoint Set)

Efficient data structure for tracking connected components.

```typescript
import { UnionFind } from "@graphty/algorithms";

const uf = new UnionFind<T>();

uf.makeSet(item);
uf.find(item);
uf.union(item1, item2);
uf.connected(item1, item2);
uf.getSetSize(item);
uf.numberOfSets;
```

### Minimum Spanning Tree Algorithms

#### Kruskal's Algorithm

```typescript
import { kruskalMST, minimumSpanningTree } from "@graphty/algorithms";

// Find MST using Kruskal's algorithm
const mst = kruskalMST(graph);
// Returns: { edges: Edge[], weight: number }

// Alternative alias
const mst = minimumSpanningTree(graph);
```

#### Prim's Algorithm

```typescript
import { primMST } from '@graphty/algorithms';

// Find MST using Prim's algorithm
const mst = primMST(graph, startNode?);
// Returns: { edges: Edge[], weight: number }
```

### Community Detection Algorithms

#### Louvain Method

```typescript
import { louvain } from "@graphty/algorithms";

// Detect communities using Louvain method
const communities = louvain(graph, {
    resolution: number, // Default: 1.0
    randomSeed: number,
});
// Returns: { communities: Map<NodeId, number>, modularity: number }
```

#### Leiden Algorithm

```typescript
import { leiden } from "@graphty/algorithms";

// Improved community detection
const communities = leiden(graph, {
    resolution: number, // Default: 1.0
    iterations: number, // Default: 10
    randomSeed: number,
});
// Returns: { communities: Map<NodeId, number>, modularity: number }
```

#### Label Propagation

```typescript
import { labelPropagation, labelPropagationAsync, labelPropagationSemiSupervised } from "@graphty/algorithms";

// Basic label propagation
const labels = labelPropagation(graph, {
    maxIterations: number, // Default: 100
});
// Returns: Map<NodeId, number>

// Asynchronous version
const labels = labelPropagationAsync(graph, options);

// Semi-supervised with seed communities
const labels = labelPropagationSemiSupervised(graph, seedLabels, options);
```

#### Girvan-Newman Algorithm

```typescript
import { girvanNewman } from "@graphty/algorithms";

// Edge betweenness based community detection
const dendrogram = girvanNewman(graph, {
    targetCommunities: number, // Stop at this many communities
});
// Returns: { levels: Array<{ modularity: number, communities: NodeId[][] }> }
```

### Pathfinding Algorithms

#### A\* Algorithm

```typescript
import { astar } from "@graphty/algorithms";

// A* pathfinding with heuristic
const path = astar(
    graph, // Map<T, Map<T, number>> adjacency list
    start,
    goal,
    heuristic, // (node: T, goal: T) => number
);
// Returns: { path: T[], cost: number } | null
```

### Flow Algorithms

#### Maximum Flow

```typescript
import { fordFulkerson, edmondsKarp } from '@graphty/algorithms';

// Ford-Fulkerson using DFS
const flow = fordFulkerson(graph, source, sink, {
  capacityKey?: string      // Edge property for capacity
});
// Returns: { maxFlow: number, flowGraph: Map<NodeId, Map<NodeId, number>> }

// Edmonds-Karp using BFS (better complexity)
const flow = edmondsKarp(graph, source, sink, options);

// Create bipartite flow network
const flowNetwork = createBipartiteFlowNetwork(leftNodes, rightNodes, edges, capacities?);
// Returns: FlowNetwork
```

#### Minimum Cut

```typescript
import { minSTCut, stoerWagner, kargerMinCut } from '@graphty/algorithms';

// Min s-t cut using max flow
const cut = minSTCut(graph, source, sink);
// Returns: { cutValue: number, sourcePartition: Set<NodeId>, sinkPartition: Set<NodeId> }

// Global minimum cut (Stoer-Wagner)
const cut = stoerWagner(graph);
// Returns: { cutValue: number, partition1: Set<NodeId>, partition2: Set<NodeId> }

// Randomized min cut (Karger)
const cut = kargerMinCut(graph, iterations?);
// Returns: { cutValue: number, partition1: Set<NodeId>, partition2: Set<NodeId> }
```

### Clustering Algorithms

#### Hierarchical Clustering

```typescript
import { hierarchicalClustering, cutDendrogram, cutDendrogramKClusters } from "@graphty/algorithms";

// Agglomerative clustering
const result = hierarchicalClustering(graph, linkage);
// graph: Map<NodeId, Set<NodeId>>
// linkage: 'single' | 'complete' | 'average' | 'ward' (default: 'single')
// Returns: HierarchicalClusteringResult { root: ClusterNode, dendrogram: ClusterNode[], clusters: Map<number, Set<NodeId>[]> }

// Cut at specific height
const clusters = cutDendrogram(result.root, height);
// Returns: Set<NodeId>[]

// Get exactly k clusters
const clusters = cutDendrogramKClusters(result.root, k);
// Returns: Set<NodeId>[]
```

#### K-Core Decomposition

```typescript
import { kCoreDecomposition, getKCore, kTruss, degeneracyOrdering } from "@graphty/algorithms";

// Find all k-cores
const result = kCoreDecomposition(graph);
// graph: Map<NodeId, Set<NodeId>>
// Returns: KCoreResult { cores: Map<number, Set<NodeId>>, coreness: Map<NodeId, number>, maxCore: number }

// Extract specific k-core subgraph
const kCore = getKCore(graph, k);
// Returns: Set<NodeId>

// Find k-truss (triangular cores)
const truss = kTruss(graph, k);
// Returns: Set<string> (edge strings)

// Degeneracy ordering
const ordering = degeneracyOrdering(graph);
// Returns: NodeId[]
```

#### Spectral Clustering

```typescript
import { spectralClustering } from "@graphty/algorithms";

// Spectral clustering using graph Laplacian
const result = spectralClustering(graph, {
    k: number, // Number of clusters
    laplacianType: "unnormalized" | "normalized" | "randomWalk", // Default: 'normalized'
    maxIterations: number, // Default: 100
    tolerance: number, // Default: 1e-4
});
// Returns: SpectralClusteringResult { communities: NodeId[][], clusterAssignments: Map<NodeId, number> }
```

#### Markov Clustering (MCL)

```typescript
import { markovClustering, calculateMCLModularity } from "@graphty/algorithms";

// MCL algorithm for network clustering
const result = markovClustering(graph, {
    expansion: number, // Expansion parameter (default: 2)
    inflation: number, // Inflation parameter (default: 2)
    maxIterations: number, // Default: 100
    tolerance: number, // Default: 1e-6
});
// Returns: MCLResult { communities: NodeId[][], attractors: Set<NodeId>, iterations: number, converged: boolean }

// Calculate modularity of MCL clustering result
const modularity = calculateMCLModularity(graph, result.communities);
// Returns: number
```

### Matching Algorithms

#### Bipartite Matching

```typescript
import { maximumBipartiteMatching, greedyBipartiteMatching, bipartitePartition } from "@graphty/algorithms";

// Maximum bipartite matching (Hungarian algorithm)
const matching = maximumBipartiteMatching(graph, {
    leftNodes: Set<NodeId>, // Optional: specify left partition
    rightNodes: Set<NodeId>, // Optional: specify right partition
});
// Returns: BipartiteMatchingResult { matching: Map<NodeId, NodeId>, size: number }

// Greedy bipartite matching (faster, approximate)
const matching = greedyBipartiteMatching(graph, options);

// Partition graph into bipartite sets
const partition = bipartitePartition(graph);
// Returns: { left: Set<NodeId>, right: Set<NodeId> } | null
```

#### Graph Isomorphism

```typescript
import { isGraphIsomorphic, findAllIsomorphisms } from "@graphty/algorithms";

// Check if two graphs are isomorphic
const result = isGraphIsomorphic(graph1, graph2, {
    nodeMatch: (node1: NodeId, node2: NodeId, g1: Graph, g2: Graph) => boolean,
    edgeMatch: (edge1: [NodeId, NodeId], edge2: [NodeId, NodeId], g1: Graph, g2: Graph) => boolean,
    findAllMappings: boolean, // Find all possible isomorphisms
});
// Returns: IsomorphismResult { isIsomorphic: boolean, mapping?: Map<NodeId, NodeId> }

// Find all isomorphism mappings
const mappings = findAllIsomorphisms(graph1, graph2, options);
// Returns: Array<Map<NodeId, NodeId>>
```

### Link Prediction Algorithms

#### Common Neighbors

```typescript
import { commonNeighborsScore, commonNeighborsPrediction, commonNeighborsForPairs } from "@graphty/algorithms";

// Score for a specific pair
const score = commonNeighborsScore(graph, node1, node2);
// Returns: number

// Predict links for all non-connected pairs
const predictions = commonNeighborsPrediction(graph, {
    directed: boolean, // Consider direction
    includeExisting: boolean, // Include existing edges
    topK: number, // Return only top K predictions
});
// Returns: LinkPredictionScore[]

// Score multiple specific pairs
const scores = commonNeighborsForPairs(graph, pairs, options);
// Returns: LinkPredictionScore[]

// Evaluate prediction performance
const evaluation = evaluateCommonNeighbors(graph, testEdges);
// Returns: { precision, recall, f1Score }

// Get top candidates for a node
const candidates = getTopCandidatesForNode(graph, nodeId, { topK: number });
// Returns: LinkPredictionScore[]
```

#### Adamic-Adar Index

```typescript
import { adamicAdarScore, adamicAdarPrediction, adamicAdarForPairs } from "@graphty/algorithms";

// Adamic-Adar score for a pair (weighted by neighbor degrees)
const score = adamicAdarScore(graph, node1, node2);
// Returns: number

// Predict links using Adamic-Adar
const predictions = adamicAdarPrediction(graph, {
    directed: boolean,
    includeExisting: boolean,
    topK: number,
});
// Returns: LinkPredictionScore[]

// Score multiple pairs
const scores = adamicAdarForPairs(graph, pairs, options);
// Returns: LinkPredictionScore[]

// Compare Adamic-Adar with Common Neighbors
const comparison = compareAdamicAdarWithCommonNeighbors(graph, pairs);
// Returns: Array<{ source, target, adamicAdar, commonNeighbors }>

// Evaluate prediction performance
const evaluation = evaluateAdamicAdar(graph, testEdges);
// Returns: { precision, recall, f1Score }

// Get top candidates for a node
const candidates = getTopAdamicAdarCandidatesForNode(graph, nodeId, {
    topK: number,
});
// Returns: LinkPredictionScore[]
```

### Research Algorithms (2023-2025)

Cutting-edge graph algorithms based on recent research.

#### SynC - Synergistic Deep Graph Clustering

```typescript
import { syncClustering } from "@graphty/algorithms";

// Deep learning based clustering
const result = syncClustering(graph, {
    k: number, // Number of clusters
    maxIterations: number, // Default: 100
    learningRate: number, // Default: 0.01
    hiddenDim: number, // Default: 64
    randomSeed: number,
});
// Returns: SynCResult {
//   communities: NodeId[][],
//   clusterAssignments: Map<NodeId, number>,
//   embeddings: Map<NodeId, number[]>,
//   iterations: number,
//   converged: boolean
// }
```

#### TeraHAC - Scalable Hierarchical Agglomerative Clustering

```typescript
import { teraHAC } from "@graphty/algorithms";

// Scalable hierarchical clustering
const result = teraHAC(graph, {
    linkage: "single" | "complete" | "average", // Default: 'average'
    k: number, // Target number of clusters
    threshold: number, // Distance threshold for merging
    sampleSize: number, // Default: 1000
    randomSeed: number,
});
// Returns: TeraHACResult {
//   root: TeraHACClusterNode,
//   dendrogram: TeraHACClusterNode[],
//   clusters: NodeId[][],
//   mergeDistances: number[]
// }
```

#### GRSBM - Greedy Recursive Spectral Bisection with Modularity

```typescript
import { grsbm } from "@graphty/algorithms";

// Explainable community detection
const result = grsbm(graph, {
    minClusterSize: number, // Default: 5
    maxDepth: number, // Default: 10
    modularityThreshold: number, // Default: 0.1
    explainClusters: boolean, // Default: true
});
// Returns: GRSBMResult {
//   clusters: GRSBMCluster[],   // Each cluster has id, nodes, modularity, explanation
//   hierarchy: Map<number, number[]>,
//   totalModularity: number
// }
```

## Algorithm Categories Summary

### Available Algorithms by Category:

- **Traversal**: BFS, DFS, Topological Sort, Cycle Detection, Bipartite Check
- **Shortest Path**: Dijkstra, Bellman-Ford, Floyd-Warshall, A\*
- **Centrality**: Degree, Betweenness, Closeness, PageRank, Eigenvector, Katz, HITS
- **Components**: Connected, Strongly Connected, Weakly Connected, Condensation Graph
- **Community Detection**: Louvain, Leiden, Label Propagation, Girvan-Newman
- **Clustering**: Hierarchical, K-Core, Spectral, Markov (MCL)
- **Minimum Spanning Tree**: Kruskal, Prim
- **Network Flow**: Ford-Fulkerson, Edmonds-Karp, Min-Cut (Stoer-Wagner, Karger)
- **Matching**: Bipartite Matching, Graph Isomorphism
- **Link Prediction**: Common Neighbors, Adamic-Adar
- **Research Algorithms**: SynC, TeraHAC, GRSBM

## Interactive Examples

### Storybook (Recommended)

Explore algorithms with interactive Storybook demos: **[View Storybook →](https://graphty.app/storybook/algorithms/)**

Storybook provides:
- **Animated visualizations** showing how each algorithm works step-by-step
- **Interactive controls** to modify parameters and graph types
- **Deterministic output** with seeded randomness for reproducibility
- **Visual testing** with Chromatic for regression detection

### Legacy HTML Examples

Try out all algorithms with interactive visualizations: **[Live Demo →](https://graphty.app/algorithms/)**

The library includes comprehensive examples demonstrating each algorithm. You can:

- **[Browse Interactive HTML Examples](https://graphty.app/algorithms/examples/)** - Visual demonstrations with step-by-step execution
- **[View Performance Benchmarks](https://graphty.app/algorithms/benchmarks/)** - Comparative analysis of algorithm performance
- **[Explore Code Examples](https://github.com/graphty-org/algorithms/tree/main/examples)** - Implementation examples for each algorithm

### Basic Algorithms

- [BFS Traversal](https://github.com/graphty-org/algorithms/blob/main/examples/bfs-example.js) - Breadth-first search and shortest paths
- [DFS Traversal](https://github.com/graphty-org/algorithms/blob/main/examples/dfs-example.js) - Depth-first search and applications
- [Dijkstra's Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/dijkstra-example.js) - Weighted shortest paths
- [Bellman-Ford](https://github.com/graphty-org/algorithms/blob/main/examples/bellman-ford-example.js) - Shortest paths with negative weights
- [Floyd-Warshall](https://github.com/graphty-org/algorithms/blob/main/examples/floyd-warshall-example.js) - All pairs shortest paths

### Centrality Measures

- [Degree Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/degree-centrality-example.js) - Node importance by connections
- [Betweenness Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/betweenness-centrality-example.js) - Bridge nodes
- [Closeness Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/closeness-centrality-example.js) - Central nodes
- [PageRank](https://github.com/graphty-org/algorithms/blob/main/examples/pagerank-example.js) - Node ranking algorithm
- [Eigenvector Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/eigenvector-centrality-example.js) - Influence from important nodes
- [Katz Centrality](https://github.com/graphty-org/algorithms/blob/main/examples/katz-centrality-example.js) - Weighted path counting
- [HITS Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/hits-algorithm-example.js) - Hub and authority scores

### Graph Structure

- [Connected Components](https://github.com/graphty-org/algorithms/blob/main/examples/connected-components-example.js) - Find graph components
- [Kruskal's MST](https://github.com/graphty-org/algorithms/blob/main/examples/kruskal-example.js) - Minimum spanning tree
- [Prim's MST](https://github.com/graphty-org/algorithms/blob/main/examples/prim-example.js) - Alternative MST algorithm

### Community Detection

- [Louvain Method](https://github.com/graphty-org/algorithms/blob/main/examples/louvain-example.js) - Modularity-based communities
- [Leiden Algorithm](https://github.com/graphty-org/algorithms/blob/main/examples/leiden-community.ts) - Improved Louvain
- [Label Propagation](https://github.com/graphty-org/algorithms/blob/main/examples/label-propagation.ts) - Fast community detection
- [Girvan-Newman](https://github.com/graphty-org/algorithms/blob/main/examples/girvan-newman-example.js) - Hierarchical communities

### Clustering

- [Hierarchical Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/hierarchical-clustering.ts) - Graph clustering
- [K-Core Decomposition](https://github.com/graphty-org/algorithms/blob/main/examples/k-core-decomposition.ts) - Core analysis
- [Spectral Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/spectral-clustering-example.js) - Eigenvalue-based clustering
- [MCL Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/mcl-clustering-example.js) - Markov clustering

### Matching

- [Bipartite Matching](https://github.com/graphty-org/algorithms/blob/main/examples/bipartite-matching-example.js) - Job assignment, dating apps
- [Graph Isomorphism](https://github.com/graphty-org/algorithms/blob/main/examples/graph-isomorphism-example.js) - Structural equivalence

### Link Prediction

- [Common Neighbors](https://github.com/graphty-org/algorithms/blob/main/examples/common-neighbors-example.js) - Friend suggestions
- [Adamic-Adar](https://github.com/graphty-org/algorithms/blob/main/examples/adamic-adar-example.js) - Weighted predictions

### Advanced Algorithms

- [A\* Pathfinding](https://github.com/graphty-org/algorithms/blob/main/examples/astar-pathfinding.ts) - Heuristic pathfinding
- [Flow Algorithms](https://github.com/graphty-org/algorithms/blob/main/examples/flow-algorithms.ts) - Maximum flow and applications
- [Ford-Fulkerson Flow](https://github.com/graphty-org/algorithms/blob/main/examples/ford-fulkerson-flow.ts) - Maximum flow implementation
- [Minimum Cut](https://github.com/graphty-org/algorithms/blob/main/examples/min-cut.ts) - Graph partitioning

### Research Algorithms

- [SynC Clustering](https://github.com/graphty-org/algorithms/blob/main/examples/sync-example.js) - Deep learning based clustering
- [TeraHAC](https://github.com/graphty-org/algorithms/blob/main/examples/terahac-example.js) - Scalable hierarchical clustering
- [GRSBM](https://github.com/graphty-org/algorithms/blob/main/examples/grsbm-example.js) - Explainable community detection

## Advanced Usage Examples

### Working with Weighted Graphs

```typescript
const graph = new Graph();

// Add weighted edges
graph.addEdge("A", "B", 5);
graph.addEdge("B", "C", 3);
graph.addEdge("A", "C", 10);

// Find shortest path considering weights
const result = dijkstra(graph, "A");
const pathToC = dijkstraPath(graph, "A", "C");
console.log(pathToC); // { path: ['A', 'B', 'C'], distance: 8 }
```

### Directed Graphs

```typescript
const directedGraph = new Graph({ directed: true });

directedGraph.addEdge("A", "B");
directedGraph.addEdge("B", "C");
directedGraph.addEdge("C", "A");

// Check for cycles
console.log(hasCycleDFS(directedGraph)); // true

// Find strongly connected components
const sccs = stronglyConnectedComponents(directedGraph);
console.log(sccs.components); // [['A', 'B', 'C']]
```

### Network Analysis

```typescript
// Identify important nodes
const graph = createSocialNetwork(); // Your graph

// Find influencers (high PageRank)
const influencers = topPageRankNodes(graph, 10);

// Find bridges (high betweenness)
const bridgers = Array.from(betweennessCentrality(graph).entries())
    .sort((a, b) => b[1] - a[1])
    .slice(0, 10);

// Find communities (connected components)
const communities = connectedComponents(graph);
console.log(`Found ${communities.components.length} communities`);
```

### Custom Edge Properties

```typescript
const graph = new Graph();

// Add edges with custom data
graph.addEdge("A", "B", 1, {
    type: "road",
    distance: 100,
    traffic: "heavy",
});

// Use custom weight in algorithms
const result = dijkstra(graph, "A", {
    weightKey: "distance", // Use 'distance' property as weight
});
```

### Graph Visualization Preparation

```typescript
// Prepare data for visualization
const graph = loadGraph();

// Calculate layout metrics
const centralities = degreeCentrality(graph, { normalized: true });
const ranks = pageRank(graph);

// Export for visualization
const nodes = Array.from(graph.nodes()).map((node) => ({
    id: node.id,
    data: node.data,
    size: centralities.get(node.id) || 0,
    importance: ranks.get(node.id) || 0,
}));

const edges = Array.from(graph.edges()).map((edge) => ({
    source: edge.source,
    target: edge.target,
    weight: edge.weight || 1,
    data: edge.data,
}));
```

## Type Definitions

### Core Types

```typescript
type NodeId = string | number;

interface Node {
    id: NodeId;
    data?: Record<string, unknown>;
}

interface Edge {
    source: NodeId;
    target: NodeId;
    weight?: number;
    id?: string;
    data?: Record<string, unknown>;
}
```

### Algorithm Result Types

```typescript
interface TraversalResult {
    visited: Set<NodeId>;
    order: NodeId[];
    tree?: Map<NodeId, NodeId | null>;
}

interface ShortestPathResult {
    distance: number;
    path: NodeId[];
    predecessor: Map<NodeId, NodeId | null>;
}

interface BellmanFordResult {
    distances: Map<NodeId, number>;
    previous: Map<NodeId, NodeId | null>;
    hasNegativeCycle: boolean;
    negativeCycleNodes?: NodeId[];
}

type CentralityResult = Record<string, number>;

interface PageRankResult {
    ranks: Record<string, number>;
    iterations: number;
    converged: boolean;
}

interface CommunityResult {
    communities: Map<NodeId, number>;
    modularity: number;
}

interface ComponentResult {
    components: NodeId[][];
    componentMap: Map<NodeId, number>;
}

interface HITSResult {
    hubs: CentralityResult;
    authorities: CentralityResult;
}

interface SpectralClusteringResult {
    communities: NodeId[][];
    clusterAssignments: Map<NodeId, number>;
}

interface MCLResult {
    communities: NodeId[][];
    attractors: Set<NodeId>;
    iterations: number;
    converged: boolean;
}

interface BipartiteMatchingResult {
    matching: Map<NodeId, NodeId>;
    size: number;
}

interface LinkPredictionScore {
    source: NodeId;
    target: NodeId;
    score: number;
}

interface HierarchicalClusteringResult<T> {
    root: ClusterNode<T>;
    dendrogram: ClusterNode<T>[];
    clusters: Map<number, Set<T>[]>;
}

interface KCoreResult<T> {
    cores: Map<number, Set<T>>;
    coreness: Map<T, number>;
    maxCore: number;
}

interface IsomorphismResult {
    isIsomorphic: boolean;
    mapping?: Map<NodeId, NodeId>;
}

interface SynCResult {
    communities: NodeId[][];
    clusterAssignments: Map<NodeId, number>;
    embeddings: Map<NodeId, number[]>;
    iterations: number;
    converged: boolean;
}

interface TeraHACResult {
    root: TeraHACClusterNode;
    dendrogram: TeraHACClusterNode[];
    clusters: NodeId[][];
    mergeDistances: number[];
}

interface GRSBMResult {
    clusters: GRSBMCluster[];
    hierarchy: Map<number, number[]>;
    totalModularity: number;
}
```

## Performance Considerations

- **Graph Representation**: Uses adjacency lists for O(1) neighbor access
- **Algorithm Complexity**:
    - BFS/DFS: O(V + E)
    - Dijkstra: O((V + E) log V) with binary heap
    - Bellman-Ford: O(VE)
    - Floyd-Warshall: O(V³)
    - PageRank: O(k(V + E)) where k is iterations
    - Connected Components: O(V + E)
    - Kruskal's MST: O(E log E)
    - Prim's MST: O((V + E) log V)
    - A\*: O((V + E) log V) - depends on heuristic quality
    - Ford-Fulkerson: O(E \* f) where f is max flow
    - Edmonds-Karp: O(VE²)
    - Louvain/Leiden: O(n log n) average case
    - Hierarchical Clustering: O(n² log n)
    - SynC: O(kni) where k is clusters, n is nodes, i is iterations
    - TeraHAC: O(n log n) with sampling
    - GRSBM: O(m log n) where m is edges
- **Memory Usage**: O(V + E) for graph storage
- **Browser Optimization**: Algorithms use iterative approaches where possible to avoid stack overflow
- **Performance Benchmarks**: View detailed performance comparisons at [https://graphty.app/algorithms/benchmarks/](https://graphty.app/algorithms/benchmarks/)

## Development

### Prerequisites

- Node.js 18+
- npm 9+

### Setup

```bash
# Clone the repository
git clone https://github.com/graphty-org/algorithms.git
cd algorithms

# Install dependencies
npm install

# Set up git hooks
npm run prepare
```

### Scripts

```bash
# Development
npm run dev          # Watch mode compilation
npm run build        # Build the library
npm run typecheck    # Type checking

# Testing
npm run test         # Run tests in watch mode
npm run test:run     # Run tests once
npm run test:coverage # Generate coverage report
npm run test:browser # Run browser tests

# Code Quality
npm run lint         # Run ESLint
npm run lint:fix     # Fix ESLint issues
npm run lint:pkg     # Check for unused dependencies

# Benchmarking
npm run benchmark    # Run full benchmark suite
npm run benchmark:quick # Run quick benchmark
npm run benchmark:report # Generate performance report

# HTML Examples & Documentation
npm run examples:html # Run interactive HTML examples locally
npm run build:gh-pages # Build for GitHub Pages deployment
npm run examples:run # Run all code examples

# Git
npm run commit       # Conventional commit helper
```

### Development Server

The project includes interactive HTML examples demonstrating each algorithm. To run them locally:

1. **Copy the environment configuration:**

    ```bash
    cp .env.example .env
    ```

2. **Configure the server (optional):**
   Edit `.env` to set your preferred host and port:

    ```bash
    # Server host (defaults to true for network exposure)
    HOST=localhost       # For local-only access
    # HOST=0.0.0.0       # For network access
    # HOST=my.server.com # Custom domain

    # Server port (defaults to 9000)
    PORT=9000           # Must be between 9000-9099
    ```

3. **Start the development server:**

    ```bash
    npm run examples:html
    ```

4. **Open your browser** to `http://localhost:9000` (or your configured host/port)

The HTML examples provide:

- Interactive visualizations for each algorithm
- Step-by-step execution with play/pause controls
- Multiple graph types for testing
- Real-time parameter adjustment
- Educational information about complexity and use cases
- Mobile debugging console (Eruda) for testing on mobile devices

### Project Structure

```
src/
├── core/              # Core graph data structures
├── algorithms/        # Algorithm implementations
│   ├── traversal/     # BFS, DFS
│   ├── shortest-path/ # Dijkstra, Bellman-Ford
│   ├── centrality/    # Degree, Betweenness, PageRank
│   └── components/    # Connected components
├── data-structures/   # Supporting data structures
├── types/            # TypeScript type definitions
└── utils/            # Utility functions

examples/
├── html/             # Interactive HTML examples
│   ├── shared/       # Shared utilities and styles
│   └── algorithms/   # Algorithm-specific examples

test/
├── unit/             # Unit tests
├── browser/          # Browser-specific tests
└── helpers/          # Test utilities
```

## Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

### Commit Convention

This project uses [Conventional Commits](https://www.conventionalcommits.org/):

```
feat(scope): add new algorithm
fix(scope): resolve edge case in traversal
docs(scope): update API documentation
test(scope): add coverage for centrality measures
```

## License

MIT © Adam Powers

## Related Projects

- [@graphty/layout](https://github.com/graphty-org/layout) - Graph layout algorithms
- [@graphty/graphty-element](https://github.com/graphty-org/graphty-element) - 3D graph visualization web component