Skip to content

Commit

Permalink
Added empty and complete graph generators (#679)
Browse files Browse the repository at this point in the history
* added empty and complete generators

* cargo fmt fix

* updated `empty_graph` and added `reno`

* updated reno

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
prakharb10 and mergify[bot] authored Oct 11, 2022
1 parent bc945c9 commit c817aa1
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ Generators
rustworkx.generators.generalized_petersen_graph
rustworkx.generators.barbell_graph
rustworkx.generators.full_rary_tree
rustworkx.generators.empty_graph
rustworkx.generators.directed_empty_graph
rustworkx.generators.complete_graph
rustworkx.generators.directed_complete_graph

.. _random_generators:

Expand Down
31 changes: 31 additions & 0 deletions releasenotes/notes/empty-and-complete-09d569b42cb6b9d5.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
features:
- |
Added new generator functions, :func:`~rustworkx.generators.empty_graph`,
and :func:`~rustworkx.generators.directed_empty_graph` to the
``rustworkx.generators`` module that will generate an empty graph.
For example:
.. jupyter-execute::
import rustworkx.generators
from rustworkx.visualization import mpl_draw
graph = rustworkx.generators.empty_graph(4)
mpl_draw(graph)
- |
Added new generator functions, :func:`~rustworkx.generators.complete_graph`,
and :func:`~rustworkx.generators.directed_complete_graph` to the
``rustworkx.generators`` module that will generate a complete graph.
These functions are equivalent to calling the :func:`~rustworkx.generators.mesh_graph`
and :func:`~rustworkx.generators.directed_mesh_graph` functions.
For example:
.. jupyter-execute::
import rustworkx.generators
from rustworkx.visualization import mpl_draw
graph = rustworkx.generators.complete_graph(4)
mpl_draw(graph)
152 changes: 152 additions & 0 deletions src/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2420,6 +2420,154 @@ pub fn barbell_graph(
})
}

/// Generate an undirected empty graph with ``n`` nodes and no edges.
///
/// :param int n: The number of nodes to generate the graph with.
///
/// :returns: The generated empty graph
/// :rtype: PyGraph
///
/// .. jupyter-execute::
///
/// import rustworkx.generators
/// from rustworkx.visualization import mpl_draw
///
/// graph = rustworkx.generators.empty_graph(5)
/// mpl_draw(graph)
///
#[pyfunction(multigraph = true)]
#[pyo3(text_signature = "(/, n, multigraph=True)")]
pub fn empty_graph(py: Python, n: usize, multigraph: bool) -> PyResult<graph::PyGraph> {
let mut graph = StableUnGraph::<PyObject, PyObject>::default();
for _ in 0..n {
graph.add_node(py.None());
}
Ok(graph::PyGraph {
graph,
node_removed: false,
multigraph,
attrs: py.None(),
})
}

/// Generate a directed empty graph with ``n`` nodes and no edges.
///
/// :param int n: The number of nodes to generate the graph with.
///
/// :returns: The generated empty graph
/// :rtype: PyDiGraph
///
/// .. jupyter-execute::
///
/// import rustworkx.generators
/// from rustworkx.visualization import mpl_draw
///
/// graph = rustworkx.generators.directed_empty_graph(5)
/// mpl_draw(graph)
///
#[pyfunction(multigraph = true)]
#[pyo3(text_signature = "(/, n, multigraph=True)")]
pub fn directed_empty_graph(
py: Python,
n: usize,
multigraph: bool,
) -> PyResult<digraph::PyDiGraph> {
let mut graph = StableDiGraph::<PyObject, PyObject>::default();
for _ in 0..n {
graph.add_node(py.None());
}
Ok(digraph::PyDiGraph {
graph,
node_removed: false,
cycle_state: algo::DfsSpace::default(),
check_cycle: false,
multigraph,
attrs: py.None(),
})
}

/// Generate an undirected complete graph with ``n`` nodes.
///
/// A complete graph is a simple graph in which each pair of distinct
/// vertices is connected by a unique edge.
/// The complete graph on ``n`` nodes is the graph with the set of nodes
/// ``{0, 1, ..., n-1}`` and the set of edges ``{(i, j) : i < j, 0 <= i < n, 0 <= j < n}``.
/// The number of edges in the complete graph is ``n*(n-1)/2``.
///
/// :param int num_node: The number of nodes to generate the graph with. Node
/// weights will be None if this is specified. If both ``num_node`` and
/// ``weights`` are set this will be ignored and ``weights`` will be used.
/// :param list weights: A list of node weights. If both ``num_node`` and
/// ``weights`` are set this will be ignored and ``weights`` will be used.
/// :param bool multigraph: When set to False the output
/// :class:`~rustworkx.PyGraph` object will not be not be a multigraph and
/// won't allow parallel edges to be added. Instead
/// calls which would create a parallel edge will update the existing edge.
///
/// :returns: The generated complete graph
/// :rtype: PyGraph
/// :raises IndexError: If neither ``num_nodes`` or ``weights`` are specified
///
/// .. jupyter-execute::
///
/// import rustworkx.generators
/// from rustworkx.visualization import mpl_draw
///
/// graph = rustworkx.generators.complete_graph(5)
/// mpl_draw(graph)
///
#[pyfunction(multigraph = true)]
#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")]
pub fn complete_graph(
py: Python,
num_nodes: Option<usize>,
weights: Option<Vec<PyObject>>,
multigraph: bool,
) -> PyResult<graph::PyGraph> {
mesh_graph(py, num_nodes, weights, multigraph)
}

/// Generate a directed complete graph with ``n`` nodes.
///
/// A directed complete graph is a directed graph in which each pair of distinct
/// vertices is connected by a unique pair of directed edges.
/// The directed complete graph on ``n`` nodes is the graph with the set of nodes
/// ``{0, 1, ..., n-1}`` and the set of edges ``{(i, j) : 0 <= i < n, 0 <= j < n}``.
/// The number of edges in the directed complete graph is ``n*(n-1)``.
///
/// :param int num_node: The number of nodes to generate the graph with. Node
/// weights will be None if this is specified. If both ``num_node`` and
/// ``weights`` are set this will be ignored and ``weights`` will be used.
/// :param list weights: A list of node weights. If both ``num_node`` and
/// ``weights`` are set this will be ignored and ``weights`` will be used.
/// :param bool multigraph: When set to False the output
/// :class:`~rustworkx.PyDiGraph` object will not be not be a multigraph and
/// won't allow parallel edges to be added. Instead
/// calls which would create a parallel edge will update the existing edge.
///
/// :returns: The generated directed complete graph
/// :rtype: PyDiGraph
/// :raises IndexError: If neither ``num_nodes`` or ``weights`` are specified
///
/// .. jupyter-execute::
///
/// import rustworkx.generators
/// from rustworkx.visualization import mpl_draw
///
/// graph = rustworkx.generators.directed_complete_graph(5)
/// mpl_draw(graph)
///
#[pyfunction(multigraph = true)]
#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")]
pub fn directed_complete_graph(
py: Python,
num_nodes: Option<usize>,
weights: Option<Vec<PyObject>>,
multigraph: bool,
) -> PyResult<digraph::PyDiGraph> {
directed_mesh_graph(py, num_nodes, weights, multigraph)
}

#[pymodule]
pub fn generators(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(cycle_graph))?;
Expand All @@ -2444,5 +2592,9 @@ pub fn generators(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(full_rary_tree))?;
m.add_wrapped(wrap_pyfunction!(generalized_petersen_graph))?;
m.add_wrapped(wrap_pyfunction!(barbell_graph))?;
m.add_wrapped(wrap_pyfunction!(empty_graph))?;
m.add_wrapped(wrap_pyfunction!(directed_empty_graph))?;
m.add_wrapped(wrap_pyfunction!(complete_graph))?;
m.add_wrapped(wrap_pyfunction!(directed_complete_graph))?;
Ok(())
}
30 changes: 30 additions & 0 deletions tests/rustworkx_tests/generators/test_complete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 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.

import unittest

import rustworkx


class TestCompleteGraph(unittest.TestCase):
def test_complete_graph(self):
for m in [0, 1, 3, 5]:
graph = rustworkx.generators.complete_graph(m)
self.assertEqual(len(graph), m)
self.assertEqual(len(graph.edges()), m * (m - 1) / 2)

def test_complete_directed_graph(self):
for m in [0, 1, 3, 5]:
graph = rustworkx.generators.directed_complete_graph(m)
self.assertEqual(len(graph), m)
self.assertEqual(len(graph.edges()), m * (m - 1))
self.assertIsInstance(graph, rustworkx.PyDiGraph)
28 changes: 28 additions & 0 deletions tests/rustworkx_tests/generators/test_empty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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.

import unittest

import rustworkx


class TestEmptyGraph(unittest.TestCase):
def test_empty_graph(self):
graph = rustworkx.generators.empty_graph(20)
self.assertEqual(len(graph), 20)
self.assertEqual(len(graph.edges()), 0)

def test_empty_directed_graph(self):
graph = rustworkx.generators.directed_empty_graph(20)
self.assertEqual(len(graph), 20)
self.assertEqual(len(graph.edges()), 0)
self.assertIsInstance(graph, rustworkx.PyDiGraph)

0 comments on commit c817aa1

Please sign in to comment.