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 connected components to retworkx-core #595

Merged
merged 26 commits into from
May 23, 2022

Conversation

enavarro51
Copy link
Contributor

This PR adds the connected_components and number_connected_components functions to retworkx-core. Needs a release note and maybe further tests and docs.

Copy link
Member

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

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

This is a good start, thanks for doing this. I know this is still in progress, but I left a few inline comments all 3 functions need the same changes I think. Also it'd be good if we deleted the retworkx crate's version of these functions and just updated the python interface to call the retworkx-core version you're adding here.

retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
@coveralls
Copy link

coveralls commented Apr 26, 2022

Pull Request Test Coverage Report for Build 2360696828

  • 67 of 67 (100.0%) changed or added relevant lines in 2 files are covered.
  • 3 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.01%) to 97.086%

Files with Coverage Reduction New Missed Lines %
retworkx-core/src/min_scored.rs 1 59.09%
src/shortest_path/all_pairs_dijkstra.rs 2 98.54%
Totals Coverage Status
Change from base Build 2333052804: 0.01%
Covered Lines: 12196
Relevant Lines: 12562

💛 - Coveralls

@enavarro51
Copy link
Contributor Author

@mtreinish Remaining is,

  • Add tests to docs
  • Release note
  • Remove retworkx's crate version of these functions and update python interface to point to retworkx-core version.

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.

With current trait restrictions we can't really remove retworkx's crate version of these functions since they also work for directed StableGraphs.

retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
Comment on lines 99 to 104
///
/// :param Graph graph: The input graph to find the number of connected
/// components for.
///
/// :return: The number of connected components.
/// :rtype: usize
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
///
/// :param Graph graph: The input graph to find the number of connected
/// components for.
///
/// :return: The number of connected components.
/// :rtype: usize

retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/conn_components.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/mod.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/test_connectivity.rs Outdated Show resolved Hide resolved
retworkx-core/src/connectivity/test_connectivity.rs Outdated Show resolved Hide resolved
@enavarro51
Copy link
Contributor Author

With current trait restrictions we can't really remove retworkx's crate version of these functions since they also work for directed StableGraphs.

Can you elaborate on this for me? What are the trait restrictions? Thanks.

@georgios-ts
Copy link
Collaborator

Can you elaborate on this for me? What are the trait restrictions? Thanks.

@enavarro51
The input graph in retworkx-core must implement G: GraphProp<EdgeType = Undirected> but in retworkx we're calling connected_components https://github.com/Qiskit/retworkx/blob/main/src/connectivity/mod.rs#L329-L331
with a directed StableGraph as input which does not implement the above trait.

and remove retworkx/src/connectivity/conn_components.rs
and modify retworkx/src/connectivity/mod.rs to point
to retworkx/retworkx-core/src/connectivity/conn_components.rs
@enavarro51
Copy link
Contributor Author

This latest version should resolve all the open review issues here. The following changes have been made,

  • Remove the retworkx/src/connectivity/conn_components.rs file and change the mod.rs file in that directory to point to retworkx/retworkx-core/src/connectivity/conn_components.rs.
  • Change the 3 functions in retworkx-core/src/connectivity/conn_components.rs to work with either directed or undirected graphs.
  • Set up 3 layers of testing for the retworkx-core rust code. The first is doc-string tests. The second is tests within the module where a function is defined. The last is a new retworkx-core/tests directory, where more complex integration tests can be placed. Running cargo test within the retworkx-core directory will run all 3 types of tests.

stack.push_front(start);

while let Some(node) = stack.pop_front() {
for succ in graph.neighbors(node) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not as simple as dropping GraphProp<EdgeType = Undirected> restriction. It will give wrong output for directed graphs since the algorithm that finds the weakly connected components of a directed graph must visit the neighbors of a node in both directions (incoming and outgoing).

For example the following fails (ideally our retworkx tests should have caught this):

import retworkx

graph = retworkx.PyDiGraph()
graph.add_nodes_from(range(4))
graph.add_edges_from_no_data([
    (3, 2), (2, 1), (1, 0)
])

comps = retworkx.weakly_connected_components(graph)
# Graph is weakly connected, so it should have just one component
assert len(comps) == 1

There are some ways to fix this:

  1. We can keep the old retworkx version and restrict GraphProp<EdgeType = Undirected> in order to accept only undirected graphs in retworkx-core, or
  2. We can restrict G: IntoNeighborsDirected and:
Suggested change
for succ in graph.neighbors(node) {
for succ in graph
.neighbors_directed(node, Outgoing)
.chain(graph.neighbors_directed(node, Incoming))
{

@enavarro51 enavarro51 changed the title [WIP] Add connected components to retworkx-core Add connected components to retworkx-core May 16, 2022
Copy link
Member

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

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

Overall this LGTM now, thanks for sticking with it and making the updates. I just have a few small nits inline but once those are fixed I think we're good to go on this. @georgios-ts might want to take another look too before we merge though

///
/// * `graph` - The graph object to run the algorithm on
/// * `node` - The node index to find the connected nodes for
/// * `graph.visit_map()` - The visit map for the graph
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// * `graph.visit_map()` - The visit map for the graph
/// * `discovered` - The visit map for the graph

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in d5e5def.

use petgraph::{Incoming, Outgoing};

/// Given an graph, a node in the graph, and a visit_map,
/// return the set of nodes connected to the given node.
Copy link
Member

Choose a reason for hiding this comment

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

I'd probably also mention here that this is in breadth first order and treating all edges as undirected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in d5e5def.

Comment on lines 246 to 250
let return_value: Vec<HashSet<usize>> = connectivity::connected_components(&graph.graph)
.into_iter()
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
.collect();
return_value
Copy link
Member

Choose a reason for hiding this comment

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

It'll probably be optimized away by the compiler but we don't need the return_value variable:

Suggested change
let return_value: Vec<HashSet<usize>> = connectivity::connected_components(&graph.graph)
.into_iter()
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
.collect();
return_value
connectivity::connected_components(&graph.graph)
.into_iter()
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
.collect()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in d5e5def.

Comment on lines 273 to 278
let return_value: HashSet<usize> =
connectivity::bfs_undirected(&graph.graph, node, &mut graph.graph.visit_map())
.into_iter()
.map(|x| x.index())
.collect();
Ok(return_value)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let return_value: HashSet<usize> =
connectivity::bfs_undirected(&graph.graph, node, &mut graph.graph.visit_map())
.into_iter()
.map(|x| x.index())
.collect();
Ok(return_value)
Ok(connectivity::bfs_undirected(&graph.graph, node, &mut graph.graph.visit_map())
.into_iter()
.map(|x| x.index())
.collect())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in d5e5def.

Comment on lines 334 to 338
let return_value: Vec<HashSet<usize>> = connectivity::connected_components(&graph.graph)
.into_iter()
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
.collect();
return_value
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let return_value: Vec<HashSet<usize>> = connectivity::connected_components(&graph.graph)
.into_iter()
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
.collect();
return_value
connectivity::connected_components(&graph.graph)
.into_iter()
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
.collect()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in d5e5def.

@georgios-ts georgios-ts added the automerge Queue a approved PR for merging label May 23, 2022
@mergify mergify bot merged commit 0c253be into Qiskit:main May 23, 2022
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.

4 participants