Skip to content
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 eigenvector centrality function #621

Merged
merged 12 commits into from
Jun 11, 2022

Conversation

mtreinish
Copy link
Member

This commit adds a new function eigenvector_centrality() to compute the
eigenvector centrality of a graph. It uses the same power function
approach that the NetworkX function eigenvector_centrality() [1]
function uses. This is for two reasons, the first is that a more
traditional eigenvector linear algebra/BLAS function would either
require us to link against BLAS at build time (which is a big change
in the build system and a large requirement) or to call out to numpy
via python both of which seemed less than ideal. The second reason was
to make handling holes in node indices bit easier. Using this approach
also enabled us to put the implementation in retworkx-core so it can be
reused with any petgraph graph.

Part of #441

This commit adds a new function eigenvector_centrality() to compute the
eigenvector centrality of a graph. It uses the same power function
approach that the NetworkX function eigenvector_centrality() [1]
function uses. This is for two reasons, the first is that a more
traditional eigenvector linear algebra/BLAS function would either
require us to link against BLAS at build time (which is a big change
in the build system and a large requirement) or to call out to numpy
via python both of which seemed less than ideal. The second reason was
to make handling holes in node indices bit easier. Using this approach
also enabled us to put the implementation in retworkx-core so it can be
reused with any petgraph graph.

Part of Qiskit#441
@coveralls
Copy link

coveralls commented Jun 4, 2022

Pull Request Test Coverage Report for Build 2477501415

  • 109 of 120 (90.83%) changed or added relevant lines in 3 files are covered.
  • 2 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.1%) to 97.254%

Changes Missing Coverage Covered Lines Changed/Added Lines %
retworkx-core/src/centrality.rs 37 38 97.37%
src/centrality.rs 68 78 87.18%
Files with Coverage Reduction New Missed Lines %
src/shortest_path/all_pairs_bellman_ford.rs 2 98.88%
Totals Coverage Status
Change from base Build 2428334538: 0.1%
Covered Lines: 12394
Relevant Lines: 12744

💛 - Coveralls

retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
src/centrality.rs Outdated Show resolved Hide resolved
let cost_fn = CostFn::try_from((weight_fn, default_weight))?;
let ev_centrality = centrality::eigenvector_centrality(
&graph.graph,
|e| cost_fn.call(py, e.weight()),
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might be beneficial to precompute and store all edge weights like we do in all_pairs_dijkstra_path_lengths so we avoid calling Python overhead each iteration.

Copy link
Member Author

@mtreinish mtreinish Jun 9, 2022

Choose a reason for hiding this comment

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

Let me benchmark this to see if it makes a difference (we only did the precomputation in the all pairs functions because it operates in parallel and we didn't want to be gil bound in parallel threads)

Copy link
Member Author

@mtreinish mtreinish Jun 9, 2022

Choose a reason for hiding this comment

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

I benchmarked this and it's basically the same but marginally faster in a couple of cases:

eigv_centrality_times_py_callback

not really a noticeable difference. But I think I'll make the change anyway, mostly because it does open up potential parallelization. I think I can make the inner loop execute in parallel and will test that in bit. (I played with this a bit and I don't think it's actually feasible without locking which would defeat the purpose of doing it in parallel)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, actually ignore that graph I forgot to set a weight callback function in the benchmark so that's improvement is just the time for using default weight. Which still seems worthwhile to me

Copy link
Collaborator

Choose a reason for hiding this comment

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

We might want to benchmark against a more "difficult" graph since a path graph will converge after 12 iterations (I think) so the performance difference will be really minor.

Copy link
Member Author

@mtreinish mtreinish Jun 9, 2022

Choose a reason for hiding this comment

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

I pushed this up in: 3204e09 I'm still waiting on the data collection for the run with a python callback. It's been running the sweep for ~60min and the precomputed weights sweep took ~15min. So there is no doubt this is faster. I'll generate the graph when it eventually finishes just for posterity.

Copy link
Member Author

@mtreinish mtreinish Jun 9, 2022

Choose a reason for hiding this comment

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

This is the graph with a callback set (I just used float).

eigv_centrality_times_py_callback

src/centrality.rs Outdated Show resolved Hide resolved
src/centrality.rs Outdated Show resolved Hide resolved
retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
mtreinish and others added 8 commits June 8, 2022 16:04
Co-authored-by: georgios-ts <[email protected]>
This commit fixes an issue where we were overcounting parallel edges in
the graph. There was a bug in the logic that was calculating the
combined weight of parallel edges incorrectly.

Co-authored-by: georgios-ts <[email protected]>
This commit changes the callback from the retworkx functions for
determining edge weight to precompute them to avoid requiring a python
context in the callback. This make a minor improvement in runtime since
we only callback to python once at the very beginning instead of in the
middle of the loop.
@mtreinish mtreinish requested a review from georgios-ts June 10, 2022 14:10
Copy link
Collaborator

@georgios-ts georgios-ts left a comment

Choose a reason for hiding this comment

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

Thanks for all the updates. Some minor comments but it's good to go.

retworkx-core/src/centrality.rs Outdated Show resolved Hide resolved
src/centrality.rs Outdated Show resolved Hide resolved
src/centrality.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@georgios-ts georgios-ts left a comment

Choose a reason for hiding this comment

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

Oh, we'll need to update the docs before we merge.

@georgios-ts georgios-ts added the automerge Queue a approved PR for merging label Jun 11, 2022
@mergify mergify bot merged commit a9c5648 into Qiskit:main Jun 11, 2022
@mtreinish mtreinish deleted the eigenvector-centrality branch June 11, 2022 14:14
@IvanIsCoding IvanIsCoding mentioned this pull request May 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge Queue a approved PR for merging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants