-
Notifications
You must be signed in to change notification settings - Fork 4
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
Add {all_pairs,single_source}_bellman_ford_path_length
#44
Add {all_pairs,single_source}_bellman_ford_path_length
#44
Conversation
That is, add these to `nxapi`: - `all_pairs_bellman_ford_path_length` - `single_source_bellman_ford_path_length`
Codecov ReportBase: 72.48% // Head: 68.87% // Decreases project coverage by
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more Additional details and impacted files@@ Coverage Diff @@
## main #44 +/- ##
==========================================
- Coverage 72.48% 68.87% -3.62%
==========================================
Files 72 74 +2
Lines 2777 3023 +246
Branches 516 574 +58
==========================================
+ Hits 2013 2082 +69
- Misses 587 753 +166
- Partials 177 188 +11
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
# Mask is True where cur not in d or cur < d | ||
mask(cur.S, replace) << True # or: `mask << unary.one[bool](cur)` | ||
mask(binary.second) << binary.lt(cur & d) | ||
|
||
# Drop values from `cur` that didn't improve | ||
cur(mask.V, replace) << cur |
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.
FYI, a very similar pattern to this also showed up in Floyd-Warshall
graphblas-algorithms/graphblas_algorithms/algorithms/shortest_paths/dense.py
Lines 67 to 73 in 0b649b2
# Update Outer to only include off-diagonal values that will update D and P. | |
if is_directed: | |
Mask << indexunary.offdiag(Outer) | |
else: | |
Mask << indexunary.triu(Outer, 1) | |
Mask(binary.second) << binary.lt(Outer & D) | |
Outer(Mask.V, replace) << Outer |
where we need to set a mask according to a comparison and set the mask to True for new values.
Just thought this was interesting. It's neat to see common patterns.
def all_pairs_bellman_ford_path_length(G, weight="weight"): | ||
# TODO: what if weight is a function? | ||
# How should we implement and call `algorithms.all_pairs_bellman_ford_path_length`? | ||
# Should we compute in chunks to expose more parallelism? |
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.
I'm not sure what the best API for a backend implementation (i.e., to have in graphblas_algorithms.algorithms
). Returning a Matrix
seems risky.
Maybe bellman_ford_path_lengths(G, nodes=None)
, which will return a Matrix
with distances for the specified nodes (default to all nodes). Then, nxapi.all_pairs_bellman_ford_path_length
can compute in batches to get increased parallelism (assuming doing so is actually faster).
@LuisFelipeRamos, I like that we can compare these to For all-pairs shortest path, our version with batching Bellman-Ford is 2-3x faster than My benchmarks aren't very exhaustive. They're also on my laptop (4 cores, 8 threads). I would expect GraphBLAS to do even better running on a beefier system (such as DGX that has 40 cores / 80 threads). My variant of SSSP Bellman-Ford is about 3-4x faster than the "simple" GraphBLAS implementation that uses I don't know how our all-pairs shortest path with Bellman-Ford compares to Floyd-Warshall except that Bellman-ford is a generator and uses much less memory. |
] | ||
|
||
|
||
def all_pairs_bellman_ford_path_length(G, weight="weight", *, chunksize=128): |
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.
We're adding a new keyword-only argument to nxapi
. @jim22k, do you like chunksize
for this?
We have a similar extra keyword-argument nchunks
in nxapi.square_clustering
that controls how much memory is used during calculation.
Neither one, nchunks
or chunksize
, changes the result; they're only used to control memory use and performance via available parallelism.
# Use `offdiag` instead of `A`, b/c self-loops don't contribute to the result, | ||
# and negative self-loops are easy negative cycles to avoid. | ||
# We check if we hit a self-loop negative cycle at the end. | ||
A, has_negative_diagonal = G.get_properties("offdiag has_negative_diagonal") |
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.
Yet another change from the "simple" implementation: don't use diagonal values. I think "offdiag"
is a property we'll use regularly, so I think we shouldn't be afraid to use it if it's useful.
The downside is possible extra memory use and some micro-benchmarks may perform worse 🤷♂️
(Also, added new properties has_negative_diagonal
and has_negative_edges*
).
Hi Erik! For my problem, I only need distances. I tested the Floyd-Warshall implementation with my graphs but it was very slow, probably because they are connected, as you said in our meeting. But that Bellman-Ford implementation sounds great! I'll try ASAP!
…________________________________
De: Erik Welch ***@***.***>
Enviado: domingo, 12 de fevereiro de 2023 01:36
Para: python-graphblas/graphblas-algorithms ***@***.***>
Cc: Luís Felipe Ramos Ferreira ***@***.***>; Mention ***@***.***>
Assunto: Re: [python-graphblas/graphblas-algorithms] Add `{all_pairs,single_source}_bellman_ford_path_length` (PR #44)
@LuisFelipeRamos<https://github.com/LuisFelipeRamos>, all_pairs_bellman_ford_path_length might be useful to you. Do you only need distances, or do you need more such as predecessors?
I like that we can compare these to scipy.sparse.csgraph algorithms. For SSSP, our Bellman-Ford is about the same speed as (or a little faster than) scipy's Dijkstra SSSP, which I think is impressive. I don't know what's up with scipy.sparse.csgraph.bellman_ford--it's super slow, like 15000x slower.
For all-pairs shortest path, our version with batching Bellman-Ford is 2-3x faster than scipy.sparse.csgraph.dijkstra! Batching gives us more parallelism, and we can do even better with larger batches.
My benchmarks aren't very exhaustive. They're also on my laptop (4 cores, 8 threads). I would expect GraphBLAS to do even better running on a beefier system (such as DGX that has 40 cores / 80 threads).
My variant of SSSP Bellman-Ford is about 3-4x faster than the "simple" GraphBLAS implementation that uses d(min) << min_plus(d @ A) and comparison to previous value. It's interesting that we're able to find optimizations for most algorithms in graphblas-algorithms with just a little bit of experimentation.
I don't know how our all-pairs shortest path with Bellman-Ford compares to Floyd-Warshall except that Bellman-ford is a generator and uses much less memory.
—
Reply to this email directly, view it on GitHub<#44 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ANVHAVJUALXYTK2Z5BODANDWXBSDXANCNFSM6AAAAAAUYQ6KQ4>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Cool! I'm eager to see how this turns out. Let us know if you want any help or if I should improve anything in this PR. Did Floyd-Warshall finish, or was it too large? |
Also, @LuisFelipeRamos, is your graph directed or undirected, and are the edges all the same value or different values? |
They are undirected and unweighted.
…________________________________
De: Erik Welch ***@***.***>
Enviado: segunda-feira, 13 de fevereiro de 2023 17:22
Para: python-graphblas/graphblas-algorithms ***@***.***>
Cc: Luís Felipe Ramos Ferreira ***@***.***>; Mention ***@***.***>
Assunto: Re: [python-graphblas/graphblas-algorithms] Add `{all_pairs,single_source}_bellman_ford_path_length` (PR #44)
Also, @LuisFelipeRamos<https://github.com/LuisFelipeRamos>, is your graph directed or undirected, and are the edges all the same value or different values?
—
Reply to this email directly, view it on GitHub<#44 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ANVHAVOACXZLRXPLUZ5Y4KTWXKJZXANCNFSM6AAAAAAUYQ6KQ4>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Good to know! We should be able to further optimize for this case, which I think is pretty much level-BFS. |
Good news @LuisFelipeRamos--I just doubled the performance of Bellman-Ford for unweighted graphs! (and also for graph that are iso-valued) I do this by performing BFS that stores the level. That this is only twice as fast suggests to me that our Bellman-Ford implementation is probably pretty solid. |
That's great news! |
Alright, I think this is good to go in. I just updated |
This is in! 🎉 |
That is, add these to
nxapi
:all_pairs_bellman_ford_path_length
(only implemented innxapi
for now)single_source_bellman_ford_path_length
I did a slightly different implementation of Bellman-Ford. It seems to run faster in my limited testing. This has not been heavily benchmarked and tuned, so there could be room for improvement.
This algorithm could probably be optimized further when the adjacency matrix is known to be iso-valued.