From 89d37158fefab25b7445257daae6fcbde3005a89 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 5 Jan 2023 09:48:46 -0800 Subject: [PATCH 1/9] Initial complete graph --- .../src/generators/complete_graph.rs | 147 ++++++++++++++++++ rustworkx-core/src/generators/mod.rs | 34 ++++ rustworkx-core/src/generators/utils.rs | 20 +++ rustworkx-core/src/lib.rs | 1 + src/generators.rs | 39 ++++- 5 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 rustworkx-core/src/generators/complete_graph.rs create mode 100644 rustworkx-core/src/generators/mod.rs create mode 100644 rustworkx-core/src/generators/utils.rs diff --git a/rustworkx-core/src/generators/complete_graph.rs b/rustworkx-core/src/generators/complete_graph.rs new file mode 100644 index 000000000..60b19e984 --- /dev/null +++ b/rustworkx-core/src/generators/complete_graph.rs @@ -0,0 +1,147 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +//use petgraph::GraphProp; +use petgraph::data::{Build, Create}; +use petgraph::visit::{Data, GraphProp, NodeIndexable}; + +use super::utils::get_num_nodes; +use super::InvalidInputError; + +/// Generate a complete graph +/// +/// Arguments: +/// +/// * `num_nodes` - The number of nodes to create a complete graph for. Either this or +/// `weights must be specified. If both this and `weights are specified, weights +/// will take priorty and this argument will be ignored +/// * `weights` - A `Vec` of node weight objects. +/// * `default_node_weight` - A callable that will return the weight to use +/// for newly created nodes. This is ignored if `weights` is specified, +/// as the weights from that argument will be used instead. +/// * `default_edge_weight` - A callable that will return the weight object +/// to use for newly created edges. +/// +/// # Example +/// ```rust +/// use rustworkx_core::petgraph; +/// use rustworkx_core::generators::complete_graph; +/// use rustworkx_core::petgraph::visit::EdgeRef; +/// +/// let g: petgraph::graph::UnGraph<(), ()> = complete_graph( +/// Some(4), +/// None, +/// || {()}, +/// || {()}, +/// false +/// ).unwrap(); +/// assert_eq!( +/// vec![(0, 1), (1, 2), (2, 3)], +/// g.edge_references() +/// .map(|edge| (edge.source().index(), edge.target().index())) +/// .collect::>(), +/// ) +/// ``` +pub fn complete_graph( + num_nodes: Option, + weights: Option>, + mut default_node_weight: F, + mut default_edge_weight: H, +) -> Result +where + G: Build + Create + Data + NodeIndexable + GraphProp, + F: FnMut() -> T, + H: FnMut() -> M, +{ + if weights.is_none() && num_nodes.is_none() { + return Err(InvalidInputError {}); + } + let node_len = get_num_nodes(&num_nodes, &weights); + let mut graph = G::with_capacity(node_len, node_len); + if node_len == 0 { + return Ok(graph); + } + + match weights { + Some(weights) => { + for weight in weights { + graph.add_node(weight); + } + } + None => { + for _ in 0..node_len { + graph.add_node(default_node_weight()); + } + } + }; + for i in 0..node_len - 1 { + for j in i + 1..node_len { + let node_i = graph.from_index(i); + let node_j = graph.from_index(j); + graph.add_edge(node_i, node_j, default_edge_weight()); + if graph.is_directed() { + graph.add_edge(node_j, node_i, default_edge_weight()); + } + } + } + Ok(graph) +} + +#[cfg(test)] +mod tests { + use crate::generators::complete_graph; + use crate::generators::InvalidInputError; + use crate::petgraph; + use crate::petgraph::visit::EdgeRef; + + #[test] + fn test_with_weights() { + let g: petgraph::graph::UnGraph = + complete_graph(None, Some(vec![0, 1, 2, 3]), || 4, || (), false).unwrap(); + assert_eq!( + vec![(0, 1), (1, 2), (2, 3)], + g.edge_references() + .map(|edge| (edge.source().index(), edge.target().index())) + .collect::>(), + ); + assert_eq!( + vec![0, 1, 2, 3], + g.node_weights().copied().collect::>(), + ); + } + + #[test] + fn test_bidirectional() { + let g: petgraph::graph::DiGraph<(), ()> = + complete_graph(Some(4), None, || (), || (), true).unwrap(); + assert_eq!( + vec![(0, 1), (1, 0), (1, 2), (2, 1), (2, 3), (3, 2),], + g.edge_references() + .map(|edge| (edge.source().index(), edge.target().index())) + .collect::>(), + ); + } + + #[test] + fn test_error() { + match complete_graph::, (), _, _, ()>( + None, + None, + || (), + || (), + false, + ) { + Ok(_) => panic!("Returned a non-error"), + Err(e) => assert_eq!(e, InvalidInputError), + }; + } +} diff --git a/rustworkx-core/src/generators/mod.rs b/rustworkx-core/src/generators/mod.rs new file mode 100644 index 000000000..baf489eb5 --- /dev/null +++ b/rustworkx-core/src/generators/mod.rs @@ -0,0 +1,34 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +//! This module contains generator functions for building graphs + +mod complete_graph; + +mod utils; + +use std::{error::Error, fmt}; + +/// Error returned by generator functions when the input arguments are an +/// invalid combination (such as missing required options). +#[derive(Debug, PartialEq, Eq)] +pub struct InvalidInputError; + +impl Error for InvalidInputError {} + +impl fmt::Display for InvalidInputError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Invalid inputs received.") + } +} + +pub use complete_graph::complete_graph; diff --git a/rustworkx-core/src/generators/utils.rs b/rustworkx-core/src/generators/utils.rs new file mode 100644 index 000000000..b63ab7043 --- /dev/null +++ b/rustworkx-core/src/generators/utils.rs @@ -0,0 +1,20 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +#[inline] +pub fn get_num_nodes(num_nodes: &Option, weights: &Option>) -> usize { + if weights.is_some() { + weights.as_ref().unwrap().len() + } else { + num_nodes.unwrap() + } +} diff --git a/rustworkx-core/src/lib.rs b/rustworkx-core/src/lib.rs index 40d839545..f9184545d 100644 --- a/rustworkx-core/src/lib.rs +++ b/rustworkx-core/src/lib.rs @@ -71,6 +71,7 @@ pub type Result = core::result::Result; /// Module for centrality algorithms. pub mod centrality; pub mod connectivity; +pub mod generators; /// Module for maximum weight matching algorithms. pub mod max_weight_matching; pub mod planar; diff --git a/src/generators.rs b/src/generators.rs index 26406cbfc..956fca3a5 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -25,6 +25,7 @@ use pyo3::wrap_pyfunction; use pyo3::Python; use super::{digraph, graph, StablePyGraph}; +use rustworkx_core::generators::complete_graph as complete_graph_core; pub fn pairwise(right: I) -> impl Iterator, I::Item)> where @@ -2524,7 +2525,22 @@ pub fn complete_graph( weights: Option>, multigraph: bool, ) -> PyResult { - mesh_graph(py, num_nodes, weights, multigraph) + let default_fn = || py.None(); + let graph: StablePyGraph = + match complete_graph_core(num_nodes, weights, default_fn, default_fn) { + Ok(graph) => graph, + Err(_) => { + return Err(PyIndexError::new_err( + "num_nodes and weights list not specified", + )) + } + }; + Ok(graph::PyGraph { + graph, + node_removed: false, + multigraph, + attrs: py.None(), + }) } /// Generate a directed complete graph with ``n`` nodes. @@ -2557,7 +2573,7 @@ pub fn complete_graph( /// graph = rustworkx.generators.directed_complete_graph(5) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] +#[pyfunction(multigraph = "true")] #[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] pub fn directed_complete_graph( py: Python, @@ -2565,7 +2581,24 @@ pub fn directed_complete_graph( weights: Option>, multigraph: bool, ) -> PyResult { - directed_mesh_graph(py, num_nodes, weights, multigraph) + let default_fn = || py.None(); + let graph: StablePyGraph = + match complete_graph_core(num_nodes, weights, default_fn, default_fn) { + Ok(graph) => graph, + Err(_) => { + return Err(PyIndexError::new_err( + "num_nodes and weights list not specified", + )) + } + }; + Ok(digraph::PyDiGraph { + graph, + node_removed: false, + check_cycle: false, + cycle_state: algo::DfsSpace::default(), + multigraph, + attrs: py.None(), + }) } #[pymodule] From c8fa63d6dd9509458fefd98d8c2f2f85bbcf7acc Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 5 Jan 2023 12:54:17 -0800 Subject: [PATCH 2/9] Add tests --- .../src/generators/complete_graph.rs | 91 ++++++++++++++----- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/rustworkx-core/src/generators/complete_graph.rs b/rustworkx-core/src/generators/complete_graph.rs index 60b19e984..ed9789e1a 100644 --- a/rustworkx-core/src/generators/complete_graph.rs +++ b/rustworkx-core/src/generators/complete_graph.rs @@ -104,31 +104,29 @@ mod tests { use crate::petgraph::visit::EdgeRef; #[test] - fn test_with_weights() { - let g: petgraph::graph::UnGraph = - complete_graph(None, Some(vec![0, 1, 2, 3]), || 4, || (), false).unwrap(); - assert_eq!( - vec![(0, 1), (1, 2), (2, 3)], - g.edge_references() - .map(|edge| (edge.source().index(), edge.target().index())) - .collect::>(), - ); - assert_eq!( - vec![0, 1, 2, 3], - g.node_weights().copied().collect::>(), - ); + fn test_directed_complete_graph() { + let g: petgraph::graph::DiGraph<(), ()> = + complete_graph(Some(10), None, || (), || ()).unwrap(); + assert_eq!(g.node_count(), 10); + assert_eq!(g.edge_count(), 90); + let elist = vec![]; + for i in 0..10 { + for j in 0..19_i32.iter().rev() { + if i != j { + elist.push((i, j)); + } + } + assert_eq!(g.edges(i), elist); + } + // ls = [] + // for j in range(19, -1, -1): + // if i != j: + // ls.append((i, j, None)) + // self.assertEqual(graph.out_edges(i), ls) } #[test] - fn test_bidirectional() { - let g: petgraph::graph::DiGraph<(), ()> = - complete_graph(Some(4), None, || (), || (), true).unwrap(); - assert_eq!( - vec![(0, 1), (1, 0), (1, 2), (2, 1), (2, 3), (3, 2),], - g.edge_references() - .map(|edge| (edge.source().index(), edge.target().index())) - .collect::>(), - ); + fn test_directed_complete_graph_weights() { } #[test] @@ -138,10 +136,57 @@ mod tests { None, || (), || (), - false, ) { Ok(_) => panic!("Returned a non-error"), Err(e) => assert_eq!(e, InvalidInputError), }; } } + // graph = rustworkx.generators.directed_mesh_graph(20) + // self.assertEqual(len(graph), 20) + // self.assertEqual(len(graph.edges()), 380) + // for i in range(20): + // ls = [] + // for j in range(19, -1, -1): + // if i != j: + // ls.append((i, j, None)) + // self.assertEqual(graph.out_edges(i), ls) + + // def test_directed_mesh_graph_weights(self): + // graph = rustworkx.generators.directed_mesh_graph(weights=list(range(20))) + // self.assertEqual(len(graph), 20) + // self.assertEqual([x for x in range(20)], graph.nodes()) + // self.assertEqual(len(graph.edges()), 380) + // for i in range(20): + // ls = [] + // for j in range(19, -1, -1): + // if i != j: + // ls.append((i, j, None)) + // self.assertEqual(graph.out_edges(i), ls) + + // def test_mesh_directed_no_weights_or_num(self): + // with self.assertRaises(IndexError): + // rustworkx.generators.directed_mesh_graph() + + // def test_mesh_graph(self): + // graph = rustworkx.generators.mesh_graph(20) + // self.assertEqual(len(graph), 20) + // self.assertEqual(len(graph.edges()), 190) + + // def test_mesh_graph_weights(self): + // graph = rustworkx.generators.mesh_graph(weights=list(range(20))) + // self.assertEqual(len(graph), 20) + // self.assertEqual([x for x in range(20)], graph.nodes()) + // self.assertEqual(len(graph.edges()), 190) + + // def test_mesh_no_weights_or_num(self): + // with self.assertRaises(IndexError): + // rustworkx.generators.mesh_graph() + + // def test_zero_size_mesh_graph(self): + // graph = rustworkx.generators.mesh_graph(0) + // self.assertEqual(0, len(graph)) + + // def test_zero_size_directed_mesh_graph(self): + // graph = rustworkx.generators.directed_mesh_graph(0) + // self.assertEqual(0, len(graph)) From 7ad15e5087162b256332696dceabdf1461f29ee7 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 5 Jan 2023 14:45:46 -0800 Subject: [PATCH 3/9] Finish tests --- .../src/generators/complete_graph.rs | 144 +++++++++--------- 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/rustworkx-core/src/generators/complete_graph.rs b/rustworkx-core/src/generators/complete_graph.rs index ed9789e1a..6c358ede0 100644 --- a/rustworkx-core/src/generators/complete_graph.rs +++ b/rustworkx-core/src/generators/complete_graph.rs @@ -10,7 +10,6 @@ // License for the specific language governing permissions and limitations // under the License. -//use petgraph::GraphProp; use petgraph::data::{Build, Create}; use petgraph::visit::{Data, GraphProp, NodeIndexable}; @@ -42,10 +41,9 @@ use super::InvalidInputError; /// None, /// || {()}, /// || {()}, -/// false /// ).unwrap(); /// assert_eq!( -/// vec![(0, 1), (1, 2), (2, 3)], +/// vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)], /// g.edge_references() /// .map(|edge| (edge.source().index(), edge.target().index())) /// .collect::>(), @@ -100,93 +98,99 @@ where mod tests { use crate::generators::complete_graph; use crate::generators::InvalidInputError; - use crate::petgraph; - use crate::petgraph::visit::EdgeRef; + use crate::petgraph::graph::{DiGraph, NodeIndex, UnGraph}; #[test] fn test_directed_complete_graph() { - let g: petgraph::graph::DiGraph<(), ()> = - complete_graph(Some(10), None, || (), || ()).unwrap(); + let g: DiGraph<(), ()> = complete_graph(Some(10), None, || (), || ()).unwrap(); assert_eq!(g.node_count(), 10); assert_eq!(g.edge_count(), 90); - let elist = vec![]; + let mut elist = vec![]; for i in 0..10 { - for j in 0..19_i32.iter().rev() { + for j in i..10 { if i != j { - elist.push((i, j)); + elist.push(Some((i, j))); + elist.push(Some((j, i))); } } - assert_eq!(g.edges(i), elist); } - // ls = [] - // for j in range(19, -1, -1): - // if i != j: - // ls.append((i, j, None)) - // self.assertEqual(graph.out_edges(i), ls) + let mut g_edges = vec![]; + for e in g.edge_indices() { + g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); + } + assert_eq!(elist, g_edges); } #[test] fn test_directed_complete_graph_weights() { + let g: DiGraph = + complete_graph(None, Some(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), || 4, || ()).unwrap(); + assert_eq!(g.node_count(), 10); + assert_eq!(g.edge_count(), 90); + let mut elist = vec![]; + for i in 0..10 { + for j in i..10 { + if i != j { + elist.push(Some((i, j))); + elist.push(Some((j, i))); + } + } + assert_eq!(*g.node_weight(NodeIndex::new(i)).unwrap(), i); + } + let mut g_edges = vec![]; + for e in g.edge_indices() { + g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); + } + assert_eq!(elist, g_edges); } #[test] - fn test_error() { - match complete_graph::, (), _, _, ()>( - None, - None, - || (), - || (), - ) { + fn test_compete_graph_error() { + match complete_graph::, (), _, _, ()>(None, None, || (), || ()) { Ok(_) => panic!("Returned a non-error"), Err(e) => assert_eq!(e, InvalidInputError), }; } -} - // graph = rustworkx.generators.directed_mesh_graph(20) - // self.assertEqual(len(graph), 20) - // self.assertEqual(len(graph.edges()), 380) - // for i in range(20): - // ls = [] - // for j in range(19, -1, -1): - // if i != j: - // ls.append((i, j, None)) - // self.assertEqual(graph.out_edges(i), ls) - - // def test_directed_mesh_graph_weights(self): - // graph = rustworkx.generators.directed_mesh_graph(weights=list(range(20))) - // self.assertEqual(len(graph), 20) - // self.assertEqual([x for x in range(20)], graph.nodes()) - // self.assertEqual(len(graph.edges()), 380) - // for i in range(20): - // ls = [] - // for j in range(19, -1, -1): - // if i != j: - // ls.append((i, j, None)) - // self.assertEqual(graph.out_edges(i), ls) - - // def test_mesh_directed_no_weights_or_num(self): - // with self.assertRaises(IndexError): - // rustworkx.generators.directed_mesh_graph() - - // def test_mesh_graph(self): - // graph = rustworkx.generators.mesh_graph(20) - // self.assertEqual(len(graph), 20) - // self.assertEqual(len(graph.edges()), 190) - // def test_mesh_graph_weights(self): - // graph = rustworkx.generators.mesh_graph(weights=list(range(20))) - // self.assertEqual(len(graph), 20) - // self.assertEqual([x for x in range(20)], graph.nodes()) - // self.assertEqual(len(graph.edges()), 190) - - // def test_mesh_no_weights_or_num(self): - // with self.assertRaises(IndexError): - // rustworkx.generators.mesh_graph() - - // def test_zero_size_mesh_graph(self): - // graph = rustworkx.generators.mesh_graph(0) - // self.assertEqual(0, len(graph)) + #[test] + fn test_complete_graph() { + let g: UnGraph<(), ()> = complete_graph(Some(10), None, || (), || ()).unwrap(); + assert_eq!(g.node_count(), 10); + assert_eq!(g.edge_count(), 45); + let mut elist = vec![]; + for i in 0..10 { + for j in i..10 { + if i != j { + elist.push(Some((i, j))); + } + } + } + let mut g_edges = vec![]; + for e in g.edge_indices() { + g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); + } + assert_eq!(elist, g_edges); + } - // def test_zero_size_directed_mesh_graph(self): - // graph = rustworkx.generators.directed_mesh_graph(0) - // self.assertEqual(0, len(graph)) + #[test] + fn test_complete_graph_weights() { + let g: UnGraph = + complete_graph(None, Some(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), || 4, || ()).unwrap(); + assert_eq!(g.node_count(), 10); + assert_eq!(g.edge_count(), 45); + let mut elist = vec![]; + for i in 0..10 { + for j in i..10 { + if i != j { + elist.push(Some((i, j))); + } + } + assert_eq!(*g.node_weight(NodeIndex::new(i)).unwrap(), i); + } + let mut g_edges = vec![]; + for e in g.edge_indices() { + g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); + } + assert_eq!(elist, g_edges); + } +} From 2c1a5a392faaaf96ae1001ab9dcf98452b6b7291 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 5 Jan 2023 15:21:38 -0800 Subject: [PATCH 4/9] Fmt --- rustworkx-core/src/generators/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustworkx-core/src/generators/mod.rs b/rustworkx-core/src/generators/mod.rs index dc0533bfc..9dd1ed86a 100644 --- a/rustworkx-core/src/generators/mod.rs +++ b/rustworkx-core/src/generators/mod.rs @@ -12,8 +12,8 @@ //! This module contains generator functions for building graphs -mod cycle_graph; mod complete_graph; +mod cycle_graph; mod utils; @@ -32,5 +32,5 @@ impl fmt::Display for InvalidInputError { } } -pub use cycle_graph::cycle_graph; pub use complete_graph::complete_graph; +pub use cycle_graph::cycle_graph; From 0717ca68f6f99f2aa12a6328106ba9c142db3d31 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 6 Jan 2023 08:24:36 -0800 Subject: [PATCH 5/9] Mesh calls complete --- src/generators.rs | 90 ++++++++++------------------------------------- 1 file changed, 18 insertions(+), 72 deletions(-) diff --git a/src/generators.rs b/src/generators.rs index 741848503..4c9cbd88b 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -474,42 +474,16 @@ pub fn mesh_graph( weights: Option>, multigraph: bool, ) -> PyResult { - if weights.is_none() && num_nodes.is_none() { - return Err(PyIndexError::new_err( - "num_nodes and weights list not specified", - )); - } - let node_len = get_num_nodes(&num_nodes, &weights); - if node_len == 0 { - return Ok(graph::PyGraph { - graph: StablePyGraph::::default(), - node_removed: false, - multigraph, - attrs: py.None(), - }); - } - let num_edges = (node_len * (node_len - 1)) / 2; - let mut graph = StablePyGraph::::with_capacity(node_len, num_edges); - match weights { - Some(weights) => { - for weight in weights { - graph.add_node(weight); + let default_fn = || py.None(); + let graph: StablePyGraph = + match core_generators::complete_graph(num_nodes, weights, default_fn, default_fn) { + Ok(graph) => graph, + Err(_) => { + return Err(PyIndexError::new_err( + "num_nodes and weights list not specified", + )) } - } - None => { - (0..node_len).for_each(|_| { - graph.add_node(py.None()); - }); - } - }; - - for i in 0..node_len - 1 { - for j in i + 1..node_len { - let i_index = NodeIndex::new(i); - let j_index = NodeIndex::new(j); - graph.add_edge(i_index, j_index, py.None()); - } - } + }; Ok(graph::PyGraph { graph, node_removed: false, @@ -550,44 +524,16 @@ pub fn directed_mesh_graph( weights: Option>, multigraph: bool, ) -> PyResult { - if weights.is_none() && num_nodes.is_none() { - return Err(PyIndexError::new_err( - "num_nodes and weights list not specified", - )); - } - let node_len = get_num_nodes(&num_nodes, &weights); - if node_len == 0 { - return Ok(digraph::PyDiGraph { - graph: StablePyGraph::::default(), - node_removed: false, - check_cycle: false, - cycle_state: algo::DfsSpace::default(), - multigraph, - attrs: py.None(), - }); - } - let num_edges = node_len * (node_len - 1); - let mut graph = StablePyGraph::::with_capacity(node_len, num_edges); - match weights { - Some(weights) => { - for weight in weights { - graph.add_node(weight); + let default_fn = || py.None(); + let graph: StablePyGraph = + match core_generators::complete_graph(num_nodes, weights, default_fn, default_fn) { + Ok(graph) => graph, + Err(_) => { + return Err(PyIndexError::new_err( + "num_nodes and weights list not specified", + )) } - } - None => { - (0..node_len).for_each(|_| { - graph.add_node(py.None()); - }); - } - }; - for i in 0..node_len - 1 { - for j in i + 1..node_len { - let i_index = NodeIndex::new(i); - let j_index = NodeIndex::new(j); - graph.add_edge(i_index, j_index, py.None()); - graph.add_edge(j_index, i_index, py.None()); - } - } + }; Ok(digraph::PyDiGraph { graph, node_removed: false, From 90fa539281493b6522ecc608660241bb546ebbec Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 6 Jan 2023 14:50:58 -0800 Subject: [PATCH 6/9] Update tests --- .../src/generators/complete_graph.rs | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/rustworkx-core/src/generators/complete_graph.rs b/rustworkx-core/src/generators/complete_graph.rs index 6c358ede0..cb46d6d28 100644 --- a/rustworkx-core/src/generators/complete_graph.rs +++ b/rustworkx-core/src/generators/complete_graph.rs @@ -99,6 +99,7 @@ mod tests { use crate::generators::complete_graph; use crate::generators::InvalidInputError; use crate::petgraph::graph::{DiGraph, NodeIndex, UnGraph}; + use crate::petgraph::visit::EdgeRef; #[test] fn test_directed_complete_graph() { @@ -109,16 +110,15 @@ mod tests { for i in 0..10 { for j in i..10 { if i != j { - elist.push(Some((i, j))); - elist.push(Some((j, i))); + elist.push((i, j)); + elist.push((j, i)); } } } - let mut g_edges = vec![]; - for e in g.edge_indices() { - g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); - } - assert_eq!(elist, g_edges); + assert_eq!(elist, g.edge_references() + .map(|edge| (edge.source().index(), edge.target().index())) + .collect::>(), + ); } #[test] @@ -131,17 +131,16 @@ mod tests { for i in 0..10 { for j in i..10 { if i != j { - elist.push(Some((i, j))); - elist.push(Some((j, i))); + elist.push((i, j)); + elist.push((j, i)); } } assert_eq!(*g.node_weight(NodeIndex::new(i)).unwrap(), i); } - let mut g_edges = vec![]; - for e in g.edge_indices() { - g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); - } - assert_eq!(elist, g_edges); + assert_eq!(elist, g.edge_references() + .map(|edge| (edge.source().index(), edge.target().index())) + .collect::>(), + ); } #[test] @@ -161,15 +160,14 @@ mod tests { for i in 0..10 { for j in i..10 { if i != j { - elist.push(Some((i, j))); + elist.push((i, j)); } } } - let mut g_edges = vec![]; - for e in g.edge_indices() { - g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); - } - assert_eq!(elist, g_edges); + assert_eq!(elist, g.edge_references() + .map(|edge| (edge.source().index(), edge.target().index())) + .collect::>(), + ); } #[test] @@ -182,15 +180,14 @@ mod tests { for i in 0..10 { for j in i..10 { if i != j { - elist.push(Some((i, j))); + elist.push((i, j)); } } assert_eq!(*g.node_weight(NodeIndex::new(i)).unwrap(), i); } - let mut g_edges = vec![]; - for e in g.edge_indices() { - g_edges.push(g.edge_endpoints(e).map(|(s, t)| (s.index(), t.index()))); - } - assert_eq!(elist, g_edges); + assert_eq!(elist, g.edge_references() + .map(|edge| (edge.source().index(), edge.target().index())) + .collect::>(), + ); } } From 22dfc11eca20a9111e956cd3184ca9025c467176 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 6 Jan 2023 14:54:17 -0800 Subject: [PATCH 7/9] Fmt --- rustworkx-core/src/generators/complete_graph.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rustworkx-core/src/generators/complete_graph.rs b/rustworkx-core/src/generators/complete_graph.rs index cb46d6d28..0aa7753c1 100644 --- a/rustworkx-core/src/generators/complete_graph.rs +++ b/rustworkx-core/src/generators/complete_graph.rs @@ -115,7 +115,9 @@ mod tests { } } } - assert_eq!(elist, g.edge_references() + assert_eq!( + elist, + g.edge_references() .map(|edge| (edge.source().index(), edge.target().index())) .collect::>(), ); @@ -137,7 +139,9 @@ mod tests { } assert_eq!(*g.node_weight(NodeIndex::new(i)).unwrap(), i); } - assert_eq!(elist, g.edge_references() + assert_eq!( + elist, + g.edge_references() .map(|edge| (edge.source().index(), edge.target().index())) .collect::>(), ); @@ -164,7 +168,9 @@ mod tests { } } } - assert_eq!(elist, g.edge_references() + assert_eq!( + elist, + g.edge_references() .map(|edge| (edge.source().index(), edge.target().index())) .collect::>(), ); @@ -185,7 +191,9 @@ mod tests { } assert_eq!(*g.node_weight(NodeIndex::new(i)).unwrap(), i); } - assert_eq!(elist, g.edge_references() + assert_eq!( + elist, + g.edge_references() .map(|edge| (edge.source().index(), edge.target().index())) .collect::>(), ); From af756265926b98333723ab25192bcb5bfb035828 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 13 Jan 2023 15:47:40 -0800 Subject: [PATCH 8/9] Simplify mesh call --- src/generators.rs | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/src/generators.rs b/src/generators.rs index e22032c93..b6bc6a5c0 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -429,22 +429,7 @@ pub fn mesh_graph( weights: Option>, multigraph: bool, ) -> PyResult { - let default_fn = || py.None(); - let graph: StablePyGraph = - match core_generators::complete_graph(num_nodes, weights, default_fn, default_fn) { - Ok(graph) => graph, - Err(_) => { - return Err(PyIndexError::new_err( - "num_nodes and weights list not specified", - )) - } - }; - Ok(graph::PyGraph { - graph, - node_removed: false, - multigraph, - attrs: py.None(), - }) + complete_graph(py, num_nodes, weights, multigraph) } /// Generate a directed mesh graph where every node is connected to every other @@ -479,24 +464,7 @@ pub fn directed_mesh_graph( weights: Option>, multigraph: bool, ) -> PyResult { - let default_fn = || py.None(); - let graph: StablePyGraph = - match core_generators::complete_graph(num_nodes, weights, default_fn, default_fn) { - Ok(graph) => graph, - Err(_) => { - return Err(PyIndexError::new_err( - "num_nodes and weights list not specified", - )) - } - }; - Ok(digraph::PyDiGraph { - graph, - node_removed: false, - check_cycle: false, - cycle_state: algo::DfsSpace::default(), - multigraph, - attrs: py.None(), - }) + directed_complete_graph(py, num_nodes, weights, multigraph) } /// Generate an undirected grid graph. From 189bd30bcebaa4d779f2aa5c88debb04c72e3bbf Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 13 Jan 2023 15:57:34 -0800 Subject: [PATCH 9/9] Remove get_num_nodes from generators.rs --- src/generators.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/generators.rs b/src/generators.rs index 31a9b8d06..c03f536c9 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -34,15 +34,6 @@ where left.zip(right) } -#[inline] -fn get_num_nodes(num_nodes: &Option, weights: &Option>) -> usize { - if weights.is_some() { - weights.as_ref().unwrap().len() - } else { - num_nodes.unwrap() - } -} - /// Generate a cycle graph /// /// :param int num_node: The number of nodes to generate the graph with. Node