Skip to content

Add option for biadjacency_matrix to be returned as a dense NumPy array#7973

Merged
dschult merged 5 commits intonetworkx:mainfrom
michaelweinold:main
Apr 17, 2025
Merged

Add option for biadjacency_matrix to be returned as a dense NumPy array#7973
dschult merged 5 commits intonetworkx:mainfrom
michaelweinold:main

Conversation

@michaelweinold
Copy link
Copy Markdown
Contributor

...sometimes my biadjacency matrices are not sparse. I therefore believe that it would be helpful to have an option of getting the matrix directly as a dense array, rather than just a SciPy sparse array.

I have added a format option "dense" - otherwise, the function remains the same.

Do let me know if this warrants a separate test case somewhere in networkx/algorithms/bipartite/tests/test_basic.py.

This would be my first NetworkX contribution 😇

@eriknw
Copy link
Copy Markdown
Contributor

eriknw commented Apr 14, 2025

This seems like a good idea to me! Note that "dense" and "array" are already valid values for format= even though they're not documented: A.asformat("dense") returns a numpy array.

@michaelweinold I'm curious--what's the performance difference between your code for creating a numpy array vs using the original code with format="dense"? If the latter is not noticeably worse, then the code could remain the same and the only thing that would need updated is the docstring.

to_scipy_sparse_array is another function that returns a scipy sparse array and has the format= argument, so it also currently supports "dense" format (but this isn't documented).

The other functions I found that return scipy sparse arrays but don't have a way to specify the format are adjacency_matrix, attr_sparse_matrix, bethe_hessian_matrix, incidence_matrix, laplacian_matrix, normalized_laplacian_matrix, and tournament_matrix. I don't recommend adding format= to these functions in this PR, but if anybody thinks doing so is a good idea then please make a new issue or PR to continue exploring this option.

@michaelweinold
Copy link
Copy Markdown
Contributor Author

Hmm... that's odd - I could have sworn that I tried to pass "dense" to the function, even though it was not listed among the options. In any case, I tested my implementation quickly, using two different size graphs:

#edges perf. old implementation perf. new implementation
1'231'833 461 ms ± 3.91 ms per loop 413 ms ± 2.96 ms per loop
30 46.2 μs ± 1.12 μs per loop 26.5 μs ± 68.6 ns per loop

I believe the speedup is negligible - I can roll back the changes to the function itself and simply leave the updated docstring with the "dense" option.

I would very much like to adapt the from_biadjacency_matrix function though - there, the input really does need to be a sparse array at the moment.

@rossbar
Copy link
Copy Markdown
Contributor

rossbar commented Apr 15, 2025

then the code could remain the same and the only thing that would need updated is the docstring.

Thanks for pointing this out @eriknw - I really like this idea! AIUI it's basically just taking advantage of a (new-ish?) feature in scipy to provide users with dense arrays with zero code change!

@dschult
Copy link
Copy Markdown
Member

dschult commented Apr 15, 2025

Depending on your needs, you could try from_numpy_array. It will create a bipartite graph if the input represents a bipartitie graph. The nodes sets are not indicated automatically, but you can find them with top_nodes, bottom_nodes = nx.bipartitie.sets() and set node attributes using G.add_nodes_from(top_nodes, bipartite=0), etc.

I think to update from_bipartitie_matrix to handle numpy arrays you only need to update convert_matrix._generate_weighted_edges using some form of ((int(u), int(v), A[u,v]) for u,v in zip(*A.nonzero())

@michaelweinold
Copy link
Copy Markdown
Contributor Author

...I removed the condition (negligible speedup, as mentioned above). The only change now is the 'dense' option mentioned in the function docstring. Ready for review 😎

Copy link
Copy Markdown
Contributor

@rossbar rossbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thanks @michaelweinold

We could also consider adding a test, but presumably the "dense" option is sufficiently covered in scipy's test suite so it's not absolutely critical.

Copy link
Copy Markdown
Member

@dschult dschult left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approve this as well. I've also opened an issue #7980 to add support for "dense" in the other functions. We can/should add tests, but we can do that as part of a separate PR for that issue.

@dschult dschult merged commit 6612c41 into networkx:main Apr 17, 2025
39 checks passed
@jarrodmillman jarrodmillman added this to the 3.5 milestone May 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

5 participants