A Go implementation of the groundbreaking O(m log^(2/3) n) algorithm for single-source shortest paths on directed graphs with non-negative edge weights.
This library implements the algorithm described in the paper:
"Breaking the Sorting Barrier for Directed Single-Source Shortest Paths"
by Ran Duan, Jiayi Mao, Xiao Mao, Xinkai Shu, and Longhui Yin
arXiv:2504.17033 (2024)
This is the first deterministic algorithm to break the classic O(m + n log n) time bound of Dijkstra's algorithm on sparse graphs in the comparison-addition model, achieving O(m log^(2/3) n) time complexity.
- Asymptotically faster than Dijkstra's algorithm on sparse graphs
- Deterministic algorithm (unlike some recent randomized improvements)
- Works with real non-negative edge weights
- Comparison-addition model - only uses comparisons and additions on edge weights
- Production-ready Go implementation with comprehensive tests
The algorithm combines ideas from:
- Dijkstra's algorithm: Maintains a priority queue frontier
- Bellman-Ford algorithm: Performs bounded relaxation steps
- Recursive partitioning: Reduces frontier size through pivot selection
Traditional Dijkstra's algorithm can have a frontier of size Θ(n), requiring Ω(n log n) time for sorting. This algorithm limits the frontier size to |Ũ|/log^Ω(1)(n) through:
- Pivot Selection: Identifies vertices with large shortest-path trees (≥k descendants)
- Bounded Relaxation: Runs k Bellman-Ford steps to complete vertices with short paths
- Recursive Structure: Applies this reduction at multiple levels
go get github.com/localrivet/bmssppackage main
import (
"fmt"
"github.com/localrivet/bmssp"
)
func main() {
// Create a graph with 4 vertices
g := bmssp.NewGraph(4)
// Add edges: (from, to, weight)
g.AddEdge(0, 1, 2.0)
g.AddEdge(0, 2, 4.0)
g.AddEdge(1, 2, 1.0)
g.AddEdge(1, 3, 7.0)
g.AddEdge(2, 3, 3.0)
// Compute shortest paths from vertex 0
distances, predecessors := bmssp.SSSP(g, 0, nil)
fmt.Printf("Distances: %v\n", distances)
fmt.Printf("Predecessors: %v\n", predecessors)
}// Create a new graph with n vertices
g := bmssp.NewGraph(n)
// Add a directed edge from u to v with weight w
err := g.AddEdge(u, v, w)// Use default parameters (recommended)
distances, predecessors := bmssp.SSSP(g, source)
// Use custom parameters
distances, predecessors := bmssp.SSSP(g, source, bmssp.WithK(5), bmssp.WithT(3))The algorithm uses two key parameters based on the paper:
- K: Frontier threshold ≈ floor(log(n)^(1/3))
- T: Recursion fanout per level ≈ floor(log(n)^(2/3))
These are automatically computed by DefaultOptions(n) based on graph size.
// BMSSP algorithm - O(m log^(2/3) n)
distances1, _ := bmssp.SSSP(g, source, nil)
// Classic Dijkstra - O(m + n log n)
distances2, _ := bmssp.Dijkstra(g, source)
// Results should be identical (within floating-point precision)The algorithm achieves O(m log^(2/3) n) time complexity, which beats Dijkstra's O(m + n log n) on sparse graphs where m = o(n log^(1/3) n).
- BMSSP: Better for very large sparse graphs (theoretical improvement)
- Dijkstra: Often faster in practice for small to medium graphs due to simpler operations and better constants
The implementation includes both algorithms for comparison and validation.
The algorithm works through a recursive divide-and-conquer approach:
- Level Structure: Creates ⌈log n / T⌉ levels of recursion
- Frontier Management: Each level maintains a frontier of vertices with distance bounds
- Pivot Selection: Identifies "heavy" vertices with large shortest-path subtrees
- Bounded Relaxation: Performs K rounds of edge relaxations
- Frontier Reduction: Limits frontier size to vertices that need further processing
- Time Complexity: O(m log^(2/3) n) deterministic
- Space Complexity: O(n + m)
- Correctness: Produces exact shortest distances (no approximation)
- Model: Comparison-addition model for real weights
Run the comprehensive test suite:
go test ./...The tests include:
- Correctness validation against Dijkstra's algorithm
- Edge cases (disconnected graphs, single vertices, etc.)
- Performance benchmarks comparing BMSSP vs Dijkstra
- Parameter validation for different graph sizes
Contributions are welcome! Please:
- Read the original paper to understand the algorithm
- Follow Go best practices and maintain test coverage
- Add benchmarks for performance-related changes
- Update documentation for API changes
-
Primary Paper: Duan, R., Mao, J., Mao, X., Shu, X., & Yin, L. (2024). "Breaking the Sorting Barrier for Directed Single-Source Shortest Paths." arXiv:2504.17033
-
Related Work:
- Dijkstra, E.W. (1959). "A note on two problems in connexion with graphs."
- Bellman, R. (1958). "On a routing problem."
- Duan, R., et al. (2023). "A randomized algorithm for single-source shortest path on undirected real-weighted graphs." FOCS 2023.
MIT License - see LICENSE file for details.
If you use this implementation in research, please cite:
@article{duan2024breaking,
title={Breaking the Sorting Barrier for Directed Single-Source Shortest Paths},
author={Duan, Ran and Mao, Jiayi and Mao, Xiao and Shu, Xinkai and Yin, Longhui},
journal={arXiv preprint arXiv:2504.17033},
year={2024}
}