Skip to content

Commit 3fef999

Browse files
committed
refactored
1 parent 65ef773 commit 3fef999

File tree

6 files changed

+836
-464
lines changed

6 files changed

+836
-464
lines changed

README.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# BMSSP-Go: Bounded Multi-Source Shortest Path Algorithm
2+
3+
[![Go Reference](https://pkg.go.dev/badge/github.com/mfreeman451/bmssp-go.svg)](https://pkg.go.dev/github.com/mfreeman451/bmssp-go)
4+
[![Go Report Card](https://goreportcard.com/badge/github.com/mfreeman451/bmssp-go)](https://goreportcard.com/report/github.com/mfreeman451/bmssp-go)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6+
7+
A high-performance Go implementation of the Bounded Multi-Source Shortest Path (BMSSP) algorithm, which provides significant speedups over traditional Dijkstra's algorithm for single-source shortest path problems.
8+
9+
## Overview
10+
11+
This implementation is based on the paper ["Breaking the Sorting Barrier for Directed Single-Source Shortest Paths"](https://arxiv.org/abs/2504.17033) by Ran Duan et al. The BMSSP algorithm achieves **O(m log^(2/3) n)** time complexity, breaking the traditional sorting barrier for shortest path algorithms.
12+
13+
## Performance
14+
15+
Our benchmarks show significant performance improvements over standard Dijkstra's algorithm:
16+
17+
| Graph Type | Dijkstra | BMSSP | **Speedup** |
18+
|------------|----------|-------|-------------|
19+
| Random 100 nodes | 37.1μs | 22.3μs | **1.66x** |
20+
| Random 1000 nodes | 453μs | 100μs | **4.53x** |
21+
| Grid 50×50 | 987μs | 180μs | **5.50x** |
22+
23+
Performance advantages increase with graph size and are particularly pronounced on structured graphs.
24+
25+
## Installation
26+
27+
```bash
28+
go get github.com/mfreeman451/bmssp-go
29+
```
30+
31+
## Quick Start
32+
33+
```go
34+
package main
35+
36+
import (
37+
"fmt"
38+
"math"
39+
40+
"github.com/mfreeman451/bmssp-go"
41+
)
42+
43+
func main() {
44+
// Create a new graph
45+
g := bmssp.NewGraph()
46+
47+
// Add edges (u, v, weight)
48+
g.AddEdge(0, 1, 2.0)
49+
g.AddEdge(0, 2, 5.0)
50+
g.AddEdge(1, 3, 4.0)
51+
g.AddEdge(2, 3, 1.0)
52+
53+
// Initialize distance map
54+
dhat := make(map[bmssp.NodeID]bmssp.Dist)
55+
for i := 0; i < 4; i++ {
56+
dhat[bmssp.NodeID(i)] = bmssp.Dist(math.Inf(1))
57+
}
58+
dhat[0] = 0 // source node
59+
60+
// Create source set
61+
S := bmssp.NewNodeSet()
62+
S.Add(0)
63+
64+
// Run BMSSP algorithm
65+
bound, visited := bmssp.BMSSP(
66+
2, // recursion levels (l)
67+
1000, // distance bound (B)
68+
S, // source set
69+
100, // expansion parameter (k)
70+
1, // branching parameter (t)
71+
g, // graph
72+
dhat, // distance map (modified in-place)
73+
)
74+
75+
fmt.Printf("Bound: %v\n", bound)
76+
fmt.Printf("Visited nodes: %v\n", visited)
77+
fmt.Printf("Distances: %v\n", dhat)
78+
}
79+
```
80+
81+
## API Reference
82+
83+
### Core Types
84+
85+
```go
86+
type NodeID int // Graph node identifier
87+
type Dist float64 // Distance/weight type
88+
type Graph struct { ... } // Directed graph structure
89+
type NodeSet map[NodeID]struct{} // Set of nodes
90+
```
91+
92+
### Main Functions
93+
94+
#### `BMSSP(l int, B Dist, S NodeSet, k, t int, g *Graph, dhat map[NodeID]Dist) (Dist, NodeSet)`
95+
The main BMSSP algorithm implementation.
96+
97+
**Parameters:**
98+
- `l`: Recursion depth levels
99+
- `B`: Distance bound for exploration
100+
- `S`: Set of source nodes
101+
- `k`: Expansion parameter (controls exploration breadth)
102+
- `t`: Branching parameter (affects data structure sizing)
103+
- `g`: Input graph
104+
- `dhat`: Distance map (modified in-place)
105+
106+
**Returns:**
107+
- Final bound and set of visited nodes
108+
109+
#### `BaseCase(B Dist, S NodeSet, k int, g *Graph, dhat map[NodeID]Dist) (Dist, NodeSet)`
110+
Bounded Dijkstra's algorithm used as the base case.
111+
112+
#### `Dijkstra(g *Graph, source NodeID) map[NodeID]Dist`
113+
Standard Dijkstra's algorithm for comparison.
114+
115+
### Graph Operations
116+
117+
```go
118+
g := NewGraph() // Create new graph
119+
g.AddEdge(u, v, weight) // Add directed edge
120+
edges := g.OutEdges(u) // Get outgoing edges from node u
121+
```
122+
123+
### Node Sets
124+
125+
```go
126+
s := NewNodeSet() // Create new node set
127+
s.Add(nodeID) // Add node to set
128+
count := s.Len() // Get set size
129+
clone := s.Clone() // Create copy of set
130+
```
131+
132+
## Algorithm Parameters
133+
134+
### Choosing Parameters
135+
136+
- **`l` (levels)**: Start with 1-2 for most graphs. Higher values may help on very large graphs.
137+
- **`k` (expansion)**: Use 50-200. Higher values explore more nodes but may be slower.
138+
- **`t` (branching)**: Usually 1 is sufficient.
139+
- **`B` (bound)**: Use a large value (e.g., 1000) to explore the full graph.
140+
141+
### Parameter Tuning
142+
143+
```go
144+
// For small graphs (< 1000 nodes)
145+
bound, visited := bmssp.BMSSP(1, 1000, sources, 50, 1, graph, distances)
146+
147+
// For large graphs (> 1000 nodes)
148+
bound, visited := bmssp.BMSSP(2, 1000, sources, 100, 1, graph, distances)
149+
150+
// For very structured graphs (grids, trees)
151+
bound, visited := bmssp.BMSSP(1, 1000, sources, 200, 1, graph, distances)
152+
```
153+
154+
## Examples
155+
156+
### Example 1: Random Graph
157+
158+
```go
159+
func ExampleRandomGraph() {
160+
g := bmssp.NewGraph()
161+
162+
// Create random graph
163+
edges := [][3]float64{
164+
{0, 1, 3}, {0, 2, 8}, {1, 2, 2}, {1, 3, 5},
165+
{2, 4, 4}, {3, 4, 1}, {3, 5, 6}, {4, 5, 2},
166+
}
167+
168+
for _, e := range edges {
169+
g.AddEdge(bmssp.NodeID(e[0]), bmssp.NodeID(e[1]), bmssp.Dist(e[2]))
170+
}
171+
172+
// Run BMSSP from node 0
173+
dhat := initializeDistances(g, 0)
174+
sources := bmssp.NewNodeSet()
175+
sources.Add(0)
176+
177+
bmssp.BMSSP(2, 1000, sources, 100, 1, g, dhat)
178+
179+
// dhat now contains shortest distances from node 0
180+
}
181+
```
182+
183+
### Example 2: Grid Graph
184+
185+
```go
186+
func ExampleGridGraph() {
187+
g := createGridGraph(10, 10) // 10x10 grid
188+
189+
dhat := initializeDistances(g, 0) // top-left corner
190+
sources := bmssp.NewNodeSet()
191+
sources.Add(0)
192+
193+
// BMSSP works particularly well on structured graphs
194+
bmssp.BMSSP(1, 1000, sources, 200, 1, g, dhat)
195+
}
196+
```
197+
198+
## Benchmarking
199+
200+
Run benchmarks to compare with Dijkstra:
201+
202+
```bash
203+
go test -bench=. -benchmem ./...
204+
```
205+
206+
This will run comprehensive benchmarks on various graph types and sizes.
207+
208+
## Development
209+
210+
### Testing
211+
212+
```bash
213+
go test ./... # Run all tests
214+
go test -v ./... # Verbose output
215+
go test -race ./... # Race condition detection
216+
```
217+
218+
### Benchmarking
219+
220+
```bash
221+
go test -bench=. ./... # Run all benchmarks
222+
go test -bench=Random ./... # Random graph benchmarks
223+
go test -bench=Grid ./... # Grid graph benchmarks
224+
```
225+
226+
### Documentation
227+
228+
Generate documentation:
229+
230+
```bash
231+
go doc -all # View all documentation
232+
godoc -http=:6060 # Local documentation server
233+
```
234+
235+
## Algorithm Details
236+
237+
The BMSSP algorithm works by:
238+
239+
1. **Finding Pivots**: Identifies key nodes for exploration using `FindPivots`
240+
2. **Hierarchical Processing**: Uses recursive calls with decreasing bounds
241+
3. **Bounded Exploration**: Each level only explores nodes within distance bounds
242+
4. **Efficient Data Structures**: Custom bucketed queue (`DStruct`) for fast operations
243+
244+
### Key Innovations
245+
246+
- **Breaking the sorting barrier**: Achieves sub-O(m log n) complexity
247+
- **Adaptive exploration**: Only visits relevant parts of the graph
248+
- **Memory efficiency**: Lower memory usage than traditional algorithms
249+
- **Structured graph optimization**: Excellent performance on grids, trees, etc.
250+
251+
## Contributing
252+
253+
1. Fork the repository
254+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
255+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
256+
4. Push to the branch (`git push origin feature/amazing-feature`)
257+
5. Open a Pull Request
258+
259+
## License
260+
261+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
262+
263+
## Citation
264+
265+
If you use this implementation in academic work, please cite:
266+
267+
```bibtex
268+
@article{duan2024breaking,
269+
title={Breaking the Sorting Barrier for Directed Single-Source Shortest Paths},
270+
author={Duan, Ran and others},
271+
journal={arXiv preprint arXiv:2504.17033},
272+
year={2024}
273+
}
274+
```
275+
276+
## Related Work
277+
278+
- [Original paper on arXiv](https://arxiv.org/abs/2504.17033)
279+
- [Dijkstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
280+
- [Single-source shortest path problem](https://en.wikipedia.org/wiki/Shortest_path_problem)

0 commit comments

Comments
 (0)