A high-performance library of standard graph algorithms for PHP. This library provides efficient implementations of essential graph algorithms with clean APIs, comprehensive error handling, and performance optimizations for production use.
- โก High Performance: Integer-indexed
AlgorithmGraphproxy for O(1) adjacency operations - ๐ฏ Comprehensive Coverage: Centrality, pathfinding, traversal, components, ordering, and MST algorithms
- ๐ Centrality Analysis: PageRank with damping and convergence, degree centrality with normalization
- ๐ฃ๏ธ Smart Pathfinding: Dijkstra and A* with heuristic support and negative weight detection
- ๐ Graph Traversal: BFS with
SplQueueand iterative DFS to prevent stack overflow - ๐ Component Analysis: Tarjan's single-pass strongly connected components algorithm
- ๐ Topological Ordering: Kahn's algorithm with cycle detection and meaningful exceptions
- ๐ฒ Minimum Spanning Tree: Prim's algorithm with connectivity validation
- ๐ Type-Safe: Leverages PHP 8.2+ features with strict typing and comprehensive contracts
- โ Production Ready: Extensive test coverage with canonical fixtures and edge case handling
- ๐ Zero External Dependencies: Only depends on
mbsoft/graph-core
- PHP 8.2 or higher
- mbsoft/graph-core ^1.0
Install via Composer:
composer require mbsoft/graph-algorithmsHere are the code snippets for each Quick Start and Advanced Features section:
use Mbsoft\Graph\Algorithms\Centrality\PageRank;
// Create PageRank with custom parameters
$pagerank = new PageRank(
dampingFactor: 0.85, // Link-following probability
maxIterations: 100, // Maximum iterations
tolerance: 1e-6 // Convergence threshold
);
// Compute centrality scores
$scores = $pagerank->compute($graph);
arsort($scores); // Sort by importance
// Results: ['nodeA' => 0.343, 'nodeB' => 0.289, 'nodeC' => 0.368]
foreach ($scores as $node => $importance) {
echo "Node {$node}: " . round($importance, 3) . "\n";
}use Mbsoft\Graph\Algorithms\Pathfinding\Dijkstra;
use Mbsoft\Graph\Algorithms\Pathfinding\AStar;
// Dijkstra's algorithm for guaranteed shortest path
$dijkstra = new Dijkstra();
$path = $dijkstra->find($graph, 'start', 'destination');
if ($path) {
echo "Path: " . implode(' โ ', $path->nodes) . "\n";
echo "Total cost: " . $path->cost . "\n";
echo "Hops: " . $path->edgeCount() . "\n";
}
// A* with heuristic for faster pathfinding
$astar = new AStar(
heuristicCallback: fn($from, $to) => manhattanDistance($from, $to)
);
$fasterPath = $astar->find($graph, 'start', 'destination');use Mbsoft\Graph\Algorithms\Traversal\Bfs;
use Mbsoft\Graph\Algorithms\Traversal\Dfs;
// Breadth-first search (level by level)
$bfs = new Bfs();
$bfsOrder = $bfs->traverse($graph, 'startNode');
echo "BFS: " . implode(' โ ', $bfsOrder) . "\n";
// Depth-first search (go deep first)
$dfs = new Dfs();
$dfsOrder = $dfs->traverse($graph, 'startNode');
echo "DFS: " . implode(' โ ', $dfsOrder) . "\n";
// Example output:
// BFS: A โ B โ C โ D โ E โ F (breadth-first)
// DFS: A โ B โ D โ F โ C โ E (depth-first)use Mbsoft\Graph\Algorithms\Components\StronglyConnected;
// Find strongly connected components using Tarjan's algorithm
$scc = new StronglyConnected();
$components = $scc->findComponents($graph);
echo "Found " . count($components) . " strongly connected components:\n";
foreach ($components as $i => $component) {
echo "Component " . ($i + 1) . ": [" . implode(', ', $component) . "]\n";
}
// Example output:
// Component 1: [A, B, C] <- These nodes can all reach each other
// Component 2: [D] <- Isolated node
// Component 3: [E, F] <- Another strongly connected pairuse Mbsoft\Graph\Algorithms\Pathfinding\Dijkstra;
// Extract weights from different edge attributes
$timeOptimized = new Dijkstra(
fn(array $attrs, string $from, string $to): float =>
$attrs['travel_time'] ?? 1.0
);
$distanceOptimized = new Dijkstra(
fn(array $attrs, string $from, string $to): float =>
$attrs['distance'] ?? 1.0
);
// Dynamic weight calculation based on node properties
$dynamicWeights = new Dijkstra(
function(array $attrs, string $from, string $to) use ($graph): float {
$fromElevation = $graph->nodeAttrs($from)['elevation'] ?? 0;
$toElevation = $graph->nodeAttrs($to)['elevation'] ?? 0;
$baseDistance = $attrs['distance'] ?? 1.0;
// Add penalty for uphill movement
$elevationPenalty = max(0, $toElevation - $fromElevation) * 0.1;
return $baseDistance + $elevationPenalty;
}
);use Mbsoft\Graph\Algorithms\Pathfinding\AStar;
// Manhattan distance heuristic for grid-based pathfinding
$gridPathfinder = new AStar(
heuristicCallback: function(string $from, string $to): float {
[$x1, $y1] = explode(',', $from);
[$x2, $y2] = explode(',', $to);
return abs($x2 - $x1) + abs($y2 - $y1);
}
);
// Euclidean distance for coordinate-based graphs
$coordinatePathfinder = new AStar(
heuristicCallback: function(string $from, string $to) use ($coordinates): float {
$fromCoord = $coordinates[$from];
$toCoord = $coordinates[$to];
return sqrt(
pow($toCoord['x'] - $fromCoord['x'], 2) +
pow($toCoord['y'] - $fromCoord['y'], 2)
);
}
);
// Zero heuristic (equivalent to Dijkstra)
$dijkstraEquivalent = new AStar(); // Default heuristic returns 0.0use Mbsoft\Graph\Algorithms\Centrality\PageRank;
// Fast convergence for real-time applications
$fastPageRank = new PageRank(
dampingFactor: 0.85,
maxIterations: 50, // Fewer iterations
tolerance: 0.01 // Less precision, faster results
);
// High precision for research/analysis
$precisePageRank = new PageRank(
dampingFactor: 0.85,
maxIterations: 1000, // More iterations allowed
tolerance: 1e-8 // Higher precision
);
// Monitor convergence
$scores = $precisePageRank->compute($graph);
echo "PageRank converged with high precision\n";
// Different damping factors for different behaviors
$surfingPageRank = new PageRank(dampingFactor: 0.85); // Traditional web surfing
$explorationPageRank = new PageRank(dampingFactor: 0.5); // More random explorationuse Mbsoft\Graph\Algorithms\Pathfinding\Dijkstra;
use Mbsoft\Graph\Algorithms\Topological\TopologicalSort;
use Mbsoft\Graph\Algorithms\Topological\CycleDetectedException;
use Mbsoft\Graph\Algorithms\Mst\Prim;
// Handle negative weights in Dijkstra
try {
$dijkstra = new Dijkstra();
$path = $dijkstra->find($graphWithNegativeWeights, 'A', 'B');
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage() . "\n";
echo "Use Bellman-Ford algorithm for negative weights\n";
}
// Handle cycles in topological sort
try {
$topo = new TopologicalSort();
$order = $topo->sort($cyclicGraph);
echo "Valid ordering: " . implode(' โ ', $order) . "\n";
} catch (CycleDetectedException $e) {
echo "Cannot sort: Graph contains cycles!\n";
// Alternative: Use strongly connected components to identify cycles
}
// Handle disconnected graphs in MST
$prim = new Prim();
$mst = $prim->findMst($disconnectedGraph);
if ($mst === null) {
echo "Cannot create MST: Graph is not connected\n";
echo "Consider finding MST for each connected component separately\n";
} else {
echo "MST total weight: " . $mst->totalWeight . "\n";
}
// Handle unreachable nodes in pathfinding
$path = $dijkstra->find($graph, 'island1', 'island2');
if ($path === null) {
echo "No path exists between the nodes\n";
// Alternative: Check connected components first
}These code snippets demonstrate practical usage patterns for each feature, showing both basic usage and real-world scenarios with proper error handling and parameter configuration.
AlgorithmGraph Proxy Pattern: All algorithms convert any GraphInterface to an optimized integer-indexed representation once, then perform all operations on fast adjacency lists.
CentralityAlgorithmInterface: Common interface for centrality calculationsPathfindingAlgorithmInterface: Standard pathfinding contract withPathResultreturn typeTraversalAlgorithmInterface: Graph traversal operations
PathResult: Immutable path representation with nodes, cost, and utility methodsMstResult: MST result with edges, total weight, and connectivity information
AlgorithmGraph: Internal proxy for integer-indexed graph operationsIndexMap: Bidirectional string-to-integer mapping for node ID management
Run the test suite with Pest:
composer testRun static analysis with PHPStan:
composer stanRun performance benchmarks:
composer benchThis library excels in:
- Network Analysis: Social network centrality, influence propagation, community detection
- Route Planning: GPS navigation, logistics optimization, shortest path queries
- Dependency Resolution: Package managers, build systems, task scheduling
- Web Analytics: PageRank-based ranking, link analysis, authority computation
- Game Development: Pathfinding AI, level connectivity, optimal route calculation
- Data Pipeline: Topological sorting for ETL processes, workflow orchestration
- Infrastructure Planning: Network design, minimal spanning trees, connectivity analysis
The library is optimized for high-performance graph processing:
AlgorithmGraph Conversion: One-time O(V + E) conversion to integer indices enables O(1) adjacency lookups throughout algorithm execution.
- BFS: Uses
SplQueuefor FIFO operations without array shifting overhead - DFS: Iterative implementation with
SplStackprevents recursion depth limits - Dijkstra/A*: Handles stale priority queue entries without expensive decrease-key operations
- Tarjan SCC: Single-pass algorithm with optimal time complexity
Lazy Predecessor Building: Only constructs reverse adjacency lists when algorithms require them, saving memory for algorithms that only need forward traversal.
Parallel Adjacency Lists: Neighbor and weight arrays stored in aligned structures for CPU cache efficiency.
Performance on a 1,000-node graph (100 iterations):
- PageRank convergence: ~5ms
- Dijkstra pathfinding: ~2ms
- BFS traversal: ~1ms
- Tarjan SCC: ~3ms
Identify influential users with PageRank, find shortest connection paths, and detect tightly-knit communities using strongly connected components.
Model supplier networks as graphs, find optimal routing with Dijkstra, ensure connectivity with MST algorithms, and identify critical dependencies.
Implement PageRank for page authority, use BFS for site structure analysis, and apply topological sorting for sitemap generation.
Integrate A* with custom heuristics for character movement, use BFS for area exploration, and apply DFS for maze solving.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-algorithm) - Ensure tests pass (
composer test) - Verify static analysis (
composer stan) - Push to the branch (
git push origin feature/amazing-algorithm) - Open a Pull Request
Follow the established patterns:
- Create algorithm in appropriate category directory
- Implement relevant interface contract
- Use
AlgorithmGraphproxy for performance - Include comprehensive tests with fixtures
- Document time/space complexity
This library is open-sourced software licensed under the MIT license.
- Algorithm implementations inspired by CLRS "Introduction to Algorithms"
- Performance patterns from NetworkX (Python) and JGraphT (Java)
- Built with modern PHP 8.2+ features and best practices
- Tested with Pest PHP testing framework
For bugs and feature requests, please use the GitHub issues page.
For algorithm-specific questions or performance optimization discussions, include graph characteristics (node count, edge density, directedness) in your issue description.
- mbsoft/graph-core - Core graph package that implement entities and exports to many graph plotting libraries formats.