Skip to content

Performance ​

@graphty/algorithms is optimized for browser environments while maintaining excellent performance. This guide covers performance characteristics and optimization tips.

Automatic Optimization ​

The library automatically selects optimal algorithm implementations based on graph size:

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

// Small graph: uses simple implementation
const small = new Graph<number>();
for (let i = 0; i < 100; i++) {
  small.addNode(i);
}
// ... Automatically uses appropriate data structures

// Large graph: uses optimized implementation with better data structures
const large = new Graph<number>();
for (let i = 0; i < 100000; i++) {
  large.addNode(i);
}
// ... Automatically uses specialized priority queue, etc.

Time Complexity Reference ​

Traversal ​

AlgorithmTimeSpace
BFSO(V + E)O(V)
DFSO(V + E)O(V)
Topological SortO(V + E)O(V)

Shortest Path ​

AlgorithmTimeSpace
DijkstraO((V + E) log V)O(V)
Bellman-FordO(V × E)O(V)
Floyd-WarshallO(V³)O(V²)
A*O(E) to O(E log V)O(V)

Centrality ​

AlgorithmTimeSpace
DegreeO(V)O(V)
BetweennessO(V × E)O(V + E)
ClosenessO(V × E)O(V)
PageRankO(k × E)O(V)

Community Detection ​

AlgorithmTimeSpace
LouvainO(V log V)O(V + E)
Label PropagationO(E)O(V)
Girvan-NewmanO(V × E²)O(V + E)

Memory Optimization ​

Use Numeric Node IDs ​

typescript
// Less efficient: string IDs
const stringGraph = new Graph<string>();
stringGraph.addNode("node_12345");

// More efficient: numeric IDs
const numGraph = new Graph<number>();
numGraph.addNode(12345);

Streaming for Large Graphs ​

typescript
import { Graph } from "@graphty/algorithms";

// Process graph in chunks
async function* loadEdges() {
  // Load edges in batches from file/API
  for await (const batch of fetchEdgeBatches()) {
    yield* batch;
  }
}

const graph = new Graph<number>();
for await (const { source, target, weight } of loadEdges()) {
  graph.addEdge(source, target, { weight });
}

Benchmarks ​

Performance on common graph sizes (Intel i7, Chrome 120):

Dijkstra's Shortest Path ​

NodesEdgesTime
1,0005,0002ms
10,00050,00025ms
100,000500,000350ms

PageRank (100 iterations) ​

NodesEdgesTime
1,0005,0005ms
10,00050,00045ms
100,000500,000450ms

Louvain Community Detection ​

NodesEdgesTime
1,0005,00010ms
10,00050,00080ms
100,000500,000800ms

Best Practices ​

1. Choose the Right Algorithm ​

typescript
// For single source-target: use A* with good heuristic
const path = aStar(graph, source, target, heuristic);

// For single source to all: use Dijkstra
const allPaths = dijkstra(graph, source);

// For all pairs: use Floyd-Warshall (precomputes all)
const allPairs = floydWarshall(graph);

2. Early Termination ​

typescript
// Stop when target is found
const result = dijkstra(graph, "source", { target: "destination" });

// Limit depth
const bfsResult = bfs(graph, "start", { maxDepth: 5 });

3. Approximate for Large Graphs ​

typescript
// Sample for betweenness centrality
const betweenness = betweennessCentrality(graph, {
  k: 100, // Sample 100 nodes
});

// Limit iterations for PageRank
const pagerank = pageRank(graph, {
  maxIterations: 50,
  tolerance: 1e-4, // Stop early if converged
});

4. Avoid Recomputation ​

typescript
// Bad: recomputes for each query
for (const node of nodes) {
  const paths = dijkstra(graph, "source");
  console.log(paths.get(node));
}

// Good: compute once, query many
const paths = dijkstra(graph, "source");
for (const node of nodes) {
  console.log(paths.get(node));
}

5. Use Web Workers for Heavy Computation ​

typescript
// worker.js
import { Graph, louvain } from "@graphty/algorithms";

self.onmessage = (event) => {
  const { nodes, edges } = event.data;

  const graph = new Graph();
  edges.forEach(({ source, target }) => graph.addEdge(source, target));

  const result = louvain(graph);
  self.postMessage({ communities: [...result.communities] });
};

// main.js
const worker = new Worker("worker.js", { type: "module" });
worker.postMessage({ nodes, edges });
worker.onmessage = (event) => {
  console.log("Communities:", event.data.communities);
};

Profiling ​

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

const graph = new Graph<number>();
// ... populate graph

// Measure execution time
console.time("dijkstra");
const result = dijkstra(graph, 0);
console.timeEnd("dijkstra");

// Memory usage (if available)
if (performance.memory) {
  console.log(`Heap used: ${performance.memory.usedJSHeapSize / 1024 / 1024} MB`);
}