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

Added ladder graph generators and test_ladder #705

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Seungwook-Woo
Copy link

<Ladder graph generator for generators module in #150 >

What?

I've added a ladder graph generator for generators module. For information about ladder graph, see NetworkX's ladder graph function.

Why?

This change can offer more options for quickly creating graphs. See #150 for more information.

How?

A ladder graph of length n is planar, undirected graph with 2n vertices and 3n-2 edges.
The graph consists of two path graphs and each node in a path is connected to a corresponding node in another path.
Edges in a path graph are called rails and edges between paths are called rungs.
For a weighted ladder graph, the function checks the length of weights list which should be even number.

Testing?

I've added a test file for ladder graph generator.
I tested cases for generating 1) ladder graphs, 2) weighted ladder graphs, 3) ladder graphs with no weights or num, and 4) zero length ladder graph.
I tested it 'tox -epy -- -n rustworkx_tests/generators/test_ladder.py' and got successful result.

@CLAassistant
Copy link

CLAassistant commented Oct 20, 2022

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ Seungwook-Woo
❌ Seungwook Woo


Seungwook Woo seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

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 is a great looking start. Thanks for working on this!. I left a couple inline comments about the tests where I think some improvements are needed. Also, can you delete the .idea files we shouldn't commit local IDE files to the repo because they're for your local development environment. The branch also looks like it needs to be rebased because of a merge conflict with main..

Comment on lines +12 to +18
self.assertEqual(len(graph.edges()), 58)

def test_ladder_graph_weights(self):
graph = rustworkx.generators.ladder_graph(weights=list(range(40)))
self.assertEqual(len(graph), 40)
self.assertEqual([x for x in range(40)], graph.nodes())
self.assertEqual(len(graph.edges()), 58)
Copy link
Member

Choose a reason for hiding this comment

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

For these 2 tests it'd be good to add some assertion on the structure of the edges too. For example, if I built a circuit like:

from rustworkx import rx
graph = rx.PyGraph()
graph.add_nodes_from(range(40))
graph.add_edges_from_no_data([(0, 1)*50)

We should try to make the tests so they assert the structure of the created graph is correct and if it were to change by mistake on a future change to the code the test will fail if it's no longer a ladder graph.

Copy link
Collaborator

@IvanIsCoding IvanIsCoding 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 writing this. I agree with Matthew that we should write tests about the structure of the graph. A test that could be interesting is:

Take the cartesian product of P2 and Pn and checks that it is isomorphic with the graph you returned

You can see this test for the Generalized Petersen Graph for inspiration

Also, I left a suggestion to reuse the grid graph code. I don't know if it is the best idea to reuse the other code, but it does make the implementation of the ladder graph super short

Comment on lines +2603 to +2655
if weights.is_none() && num_nodes.is_none() {
return Err(PyIndexError::new_err(
"num_nodes and weights list not specified",
));
} else if num_nodes.is_none() && weights.as_ref().unwrap().len() % 2 == 1 {
return Err(PyIndexError::new_err(
"length of weights must be even numbers",
));
}
let node_len = if weights.is_none() {
num_nodes.unwrap()
} else {
weights.as_ref().unwrap().len() / 2
};

if node_len == 0 {
return Ok(graph::PyGraph {
graph: StablePyGraph::<Undirected>::default(),
node_removed: false,
multigraph,
attrs: py.None(),
});
}
let num_edges = 3 * node_len - 2;
let mut graph = StablePyGraph::<Undirected>::with_capacity(node_len * 2, num_edges);
match weights {
Some(weights) => {
for weight in weights {
graph.add_node(weight);
}
}
None => {
(0..(node_len * 2)).for_each(|_| {
graph.add_node(py.None());
});
}
};

for rail_a in 0..node_len - 1 {
graph.add_edge(NodeIndex::new(rail_a), NodeIndex::new(rail_a+1), py.None());
let rail_b = rail_a + node_len;
graph.add_edge(NodeIndex::new(rail_b), NodeIndex::new(rail_b+1), py.None());
}
for rung_a in 0..node_len {
graph.add_edge(NodeIndex::new(rung_a), NodeIndex::new(rung_a+node_len), py.None());
}

Ok(graph::PyGraph {
graph,
node_removed: false,
multigraph,
attrs: py.None(),
})
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
if weights.is_none() && num_nodes.is_none() {
return Err(PyIndexError::new_err(
"num_nodes and weights list not specified",
));
} else if num_nodes.is_none() && weights.as_ref().unwrap().len() % 2 == 1 {
return Err(PyIndexError::new_err(
"length of weights must be even numbers",
));
}
let node_len = if weights.is_none() {
num_nodes.unwrap()
} else {
weights.as_ref().unwrap().len() / 2
};
if node_len == 0 {
return Ok(graph::PyGraph {
graph: StablePyGraph::<Undirected>::default(),
node_removed: false,
multigraph,
attrs: py.None(),
});
}
let num_edges = 3 * node_len - 2;
let mut graph = StablePyGraph::<Undirected>::with_capacity(node_len * 2, num_edges);
match weights {
Some(weights) => {
for weight in weights {
graph.add_node(weight);
}
}
None => {
(0..(node_len * 2)).for_each(|_| {
graph.add_node(py.None());
});
}
};
for rail_a in 0..node_len - 1 {
graph.add_edge(NodeIndex::new(rail_a), NodeIndex::new(rail_a+1), py.None());
let rail_b = rail_a + node_len;
graph.add_edge(NodeIndex::new(rail_b), NodeIndex::new(rail_b+1), py.None());
}
for rung_a in 0..node_len {
graph.add_edge(NodeIndex::new(rung_a), NodeIndex::new(rung_a+node_len), py.None());
}
Ok(graph::PyGraph {
graph,
node_removed: false,
multigraph,
attrs: py.None(),
})
grid_graph(py, num_nodes, 2, weights, multigraph)

The syntax might not be correct, but the ladder graph is equivalent to a n x 2 grid graph hence we probably want to reuse most of the other code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants