New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speedup route search algorithm in RouteChoice class by ~60x #55
Conversation
…aphs Replaced the Floyd-Warshall algorithm in `route_search_all` with Dijkstra's algorithm using scipy's sparse matrix representation for improved performance in sparse graphs. This change addresses the performance bottleneck by leveraging Dijkstra's inherent efficiency for such structures and direct path reconstruction capabilities, significantly reducing computation time for shortest path routing. Updated relevant data structures and removed unnecessary post-processing steps for next node determination. In a real-world road graph with 3275 links and 1552 nodes, it reduced the time route_search_all from ~19 seconds to ~0.85 seconds, an over 20x speedup.
Refactor the route_search_all method in RouteChoice to utilize NumPy's vectorized operations and boolean indexing, eliminating nested loops for updating the next matrix. This significantly enhances performance by reducing Python loop overhead in sparse graph computations. In a real-world road graph with 3275 links and 1552 nodes, it reduced the time route_search_all from ~0.85 seconds to ~0.30 seconds, a ~3x speedup. Together with the previous commit, it reduced the time route_search_all from ~19 seconds to ~0.3 seconds, a ~60x speedup.
While manual inspection of a graph looks okay, a few of the tests are failing:
Summarized:
Here are the calculated percentage differences between the expected and actual values for each of the failed tests:
The differences could be due to a number of sources, including potentially noise. @toruseo, could you help me interpret these test failures and give guidance on how to resolve them? |
And,
this negative values are also strange. I am not sure, but this may mean initial placeholder value (-1) was not properly overwritten??? It is quite strange that this one passed the other tests in your local computer. I have no idea why. I recommend you to verify your implementation by using |
|
||
# Vectorized operation to copy `s.pred` into `s.next` where pred != -9999 | ||
valid_pred = s.pred != -9999 | ||
s.next[valid_pred] = s.pred[valid_pred] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? I think pred
and next
are different concept and cannot be mapped like this.
Thanks for the review. It's informative and I'm exploring different alternative options to speed it up. It's a hard problem to crack.
My suspicion is that's due to noise. |
Closing this for now. Maybe I will do another attempt, but if anyone has an idea on to how to speed this up that would be greatly appreciated. @toruseo, it might be useful to split the shortest path finding and the actual route selection (either in separate classes or separate methods) functionally, instead doing both in one method. What do you think of that? |
Thanks for trying. It is a kind of separated already. Additionally, if you set |
Maybe the class name |
This pull request introduces a significant optimization to the
RouteChoice
class'sroute_search_all
method. By shifting from the Floyd-Warshall algorithm to Dijkstra's algorithm and employing vectorized operations for matrix updates, performance is sped up by ~60x for a medium sized graph. These changes are particularly effective for sparse graphs, which are common in road network simulations.Changes
scipy.sparse.csgraph.dijkstra
. This change leverages the sparsity of the road network graphs, reducing computational complexity from (O(V^3)) to (O((V + E) \log V)), where (V) is the number of vertices and (E) is the number of edges.next
matrix with NumPy's vectorized operations and boolean indexing. This optimization reduces the overhead associated with Python loops and utilizes efficient low-level operations for array manipulations (this was originally a very slow part of the graph).Performance Implications
In a benchmark involving a real-world road graph with 3275 links and 1552 nodes, the execution time of
route_search_all
was reduced from approximately 19 seconds to just about 0.3 seconds. This demonstrates the significant efficiency gains achieved through these optimizations.If route search will be a bottleneck in the future again, it might be worth investigating the potential for leveraging C-optimized libraries like
graph-tool
origraph
for even more performance.If merged, this PR closes #53.