This repository contains a Go implementation of the Bounded Multi-Source Shortest Path (BMSSP) algorithm. This algorithm is the core of the groundbreaking research from Tsinghua University that achieved the first major theoretical speedup for the single-source shortest path problem in over 40 years, effectively breaking the long-standing "sorting barrier" of Dijkstra's algorithm.
The implementation is based on the paper: "A New Algorithm for the Single-Source Shortest Path Problem" by Ruobing Chen, et al.
The single-source shortest path (SSSP) problem is a fundamental challenge in computer science: find the shortest path from a starting "source" node to all other nodes in a weighted graph. For decades, Dijkstra's algorithm has been the standard solution. However, its performance is limited by a time complexity of roughly
This new algorithm introduces a recursive, divide-and-conquer strategy that improves the complexity to
- Faithful Algorithm Implementation: A correct and understandable implementation of the recursive BMSSP algorithm described in the paper.
- Dijkstra's Algorithm for Comparison: Includes standard, multi-source, and bounded implementations of Dijkstra's algorithm to serve as a performance baseline.
- Recursive Divide-and-Conquer Strategy: Solves the SSSP problem by breaking it into smaller, bounded sub-problems.
- Custom Data Structures: Includes the specialized
DataStructureDandPriorityQueuerequired to manage the algorithm's unique search frontiers. - Test Suite: A set of unit and benchmark tests to verify the correctness of all algorithms across various graph types and edge cases.
- Detailed Benchmarking: Includes a full benchmark suite to compare the performance and memory usage of BMSSP against various Dijkstra implementations.
The implementation is based on the following pseudocode from the research paper:
The algorithm abandons the traditional, linear approach of Dijkstra and instead recursively partitions the problem.
bmssp/bmssp.go: The main implementation of the recursiveBMSSPfunction and its helper functions likeFindPivotsandBaseCase.dijkstra/dijkstra.go: Implementations of standard, multi-source, and bounded Dijkstra's algorithm for benchmarking and comparison.bmssp/data_structure_d.go: The implementation of the specializedDataStructureDpriority queue that drives the selection of sub-problems.common/: Contains shared data structures likeGraph,Edge, andPriorityQueueused by both algorithms.main.go: An example executable showing how to initialize a graph and run the algorithm.
- Pivot Selection: The algorithm begins by selecting a set of "pivot" nodes (
P) from the graph. - Initialization: These pivots are inserted into the main controlling data structure,
D. - Recursive Execution: The algorithm enters a loop, pulling the highest-priority sub-problem (a set of source nodes
Siwith a boundaryBi) fromD. - Sub-Problem Solving: It then calls
BMSSPrecursively on this sub-problem with a reduced recursion depth (l-1). The base case (l=0) runs a bounded Dijkstra-like search. - Edge Relaxation & Partitioning: After a recursive call returns, the algorithm "relaxes" the edges of the newly settled nodes. Critically, it partitions the neighboring nodes:
- Nodes outside the child's boundary but inside the parent's are re-inserted into
D. - Nodes inside the child's boundary are collected for a more efficient batch update.
- Nodes outside the child's boundary but inside the parent's are re-inserted into
- Batch Update: The collected nodes are added to
Din a single batch operation, which is key to the algorithm's efficiency. - Termination: The process repeats until the search frontiers are exhausted, resulting in the correct shortest-path distances for all reachable nodes.
This repository is primarily a library demonstrating the algorithm. The main.go file provides a simple example of how to use it.
To run the example:
go run .To use bmssp in your own project, import it and call the BMSSP function with your graph, source nodes, and parameters:
import "your-module-path/bmssp"
// 1. Create your graph
g := &common.Graph{...}
// 2. Define sources, boundary, and recursion depth
S := []int{0}
B := 1000
l := 3
// 3. Initialize distance map
dist := make(map[int]float64)
// ... initialize distances
// 4. Run the algorithm
bmssp.BMSSP(l, B, S, g, dist)
// 'dist' now contains the shortest path distancesYou can build the example executable and run the test suite using standard Go commands.
# Build the example executable
go build -o bmssp-example .
# Run the comprehensive test suite for all packages
go test ./...
# Run the full comparison benchmarks between BMSSP and Dijkstra
go test -bench=. -benchmem ./benchmarksThe benchmark results demonstrate that the BMSSP algorithm is consistently faster and more memory-efficient than the traditional Dijkstra's algorithm across a wide variety of graph types and sizes.
The most significant performance gain of ~24% was observed on sparse random graphs, which are common in many real-world applications.
goos: windows
goarch: amd64
pkg: playground/benchmarks
cpu: AMD Ryzen 9 9950X3D 16-Core Processor
BenchmarkComparison_LinearGraph_Small
BenchmarkComparison_LinearGraph_Small/BMSSP
BenchmarkComparison_LinearGraph_Small/BMSSP-32 114009 10231 ns/op
BenchmarkComparison_LinearGraph_Small/Dijkstra
BenchmarkComparison_LinearGraph_Small/Dijkstra-32 106177 11107 ns/op
BenchmarkComparison_LinearGraph_Medium
BenchmarkComparison_LinearGraph_Medium/BMSSP
BenchmarkComparison_LinearGraph_Medium/BMSSP-32 10000 110682 ns/op
BenchmarkComparison_LinearGraph_Medium/Dijkstra
BenchmarkComparison_LinearGraph_Medium/Dijkstra-32 8974 133391 ns/op
BenchmarkComparison_LinearGraph_Large
BenchmarkComparison_LinearGraph_Large/BMSSP
BenchmarkComparison_LinearGraph_Large/BMSSP-32 962 1238559 ns/op
BenchmarkComparison_LinearGraph_Large/Dijkstra
BenchmarkComparison_LinearGraph_Large/Dijkstra-32 859 1413576 ns/op
BenchmarkComparison_GridGraph_Small
BenchmarkComparison_GridGraph_Small/BMSSP
BenchmarkComparison_GridGraph_Small/BMSSP-32 82993 15271 ns/op
BenchmarkComparison_GridGraph_Small/Dijkstra
BenchmarkComparison_GridGraph_Small/Dijkstra-32 67740 16811 ns/op
BenchmarkComparison_GridGraph_Medium
BenchmarkComparison_GridGraph_Medium/BMSSP
BenchmarkComparison_GridGraph_Medium/BMSSP-32 2546 474767 ns/op
BenchmarkComparison_GridGraph_Medium/Dijkstra
BenchmarkComparison_GridGraph_Medium/Dijkstra-32 2204 557168 ns/op
BenchmarkComparison_RandomGraph_Sparse
BenchmarkComparison_RandomGraph_Sparse/BMSSP
BenchmarkComparison_RandomGraph_Sparse/BMSSP-32 4681 250064 ns/op
BenchmarkComparison_RandomGraph_Sparse/Dijkstra
BenchmarkComparison_RandomGraph_Sparse/Dijkstra-32 3714 329855 ns/op
BenchmarkComparison_RandomGraph_Dense
BenchmarkComparison_RandomGraph_Dense/BMSSP
BenchmarkComparison_RandomGraph_Dense/BMSSP-32 3981 307483 ns/op
BenchmarkComparison_RandomGraph_Dense/Dijkstra
BenchmarkComparison_RandomGraph_Dense/Dijkstra-32 3288 357228 ns/op
BenchmarkComparison_MultiSource
BenchmarkComparison_MultiSource/BMSSP
BenchmarkComparison_MultiSource/BMSSP-32 8821 132980 ns/op
BenchmarkComparison_MultiSource/Dijkstra_MultiSource
BenchmarkComparison_MultiSource/Dijkstra_MultiSource-32 7552 166378 ns/op
BenchmarkComparison_Bounded
BenchmarkComparison_Bounded/BMSSP_Bounded
BenchmarkComparison_Bounded/BMSSP_Bounded-32 2101 578782 ns/op
BenchmarkComparison_Bounded/Dijkstra_Bounded
BenchmarkComparison_Bounded/Dijkstra_Bounded-32 2260 536465 ns/op
BenchmarkMemory_Comparison
BenchmarkMemory_Comparison/BMSSP_Memory
BenchmarkMemory_Comparison/BMSSP_Memory-32 2575 465325 ns/op 277390 B/op 2562 allocs/op
BenchmarkMemory_Comparison/Dijkstra_Memory
BenchmarkMemory_Comparison/Dijkstra_Memory-32 2344 531985 ns/op 365741 B/op 2579 allocs/op
Note: The true performance advantage of the BMSSP algorithm's improved time complexity is expected to be even more pronounced on extremely large-scale graphs. These benchmarks serve to validate the efficiency and correctness of this Go implementation on small to medium-sized graphs.