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 binomial tree graph generator #299

Merged
merged 40 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
127f685
Merge pull request #2 from Qiskit/master
nahumsa Apr 1, 2021
75bc722
Add binomial tree graph
nahumsa Apr 1, 2021
5ff3f47
update documentation
nahumsa Apr 1, 2021
aff705d
add release notes
nahumsa Apr 1, 2021
0a6749c
lint
nahumsa Apr 1, 2021
4b5241f
lint
nahumsa Apr 1, 2021
af129b1
lint
nahumsa Apr 1, 2021
5eb6b56
fix docs
nahumsa Apr 1, 2021
c7a6891
remove option for order
nahumsa Apr 1, 2021
3a52c15
change order to u32
nahumsa Apr 8, 2021
d9e9bb8
clippy
nahumsa Apr 8, 2021
56e6beb
Merge branch 'master' into binomial-tree-graph
mtreinish Apr 9, 2021
2741051
add directed binomial tree graph
nahumsa Apr 26, 2021
e2c9a4d
Merge branch 'binomial-tree-graph' of https://github.com/nahumsa/retw…
nahumsa Apr 26, 2021
199ee00
lint
nahumsa Apr 26, 2021
1a2e8fd
fix positional argument
nahumsa May 4, 2021
764f487
updated test
nahumsa May 4, 2021
590e824
updated tests
nahumsa May 4, 2021
4fa210f
add case mismatch weights
nahumsa May 4, 2021
9639284
Merge branch 'binomial-tree-graph' of https://github.com/nahumsa/retw…
nahumsa May 4, 2021
769b04b
add edgelist assertion
nahumsa May 4, 2021
7f8f78a
lint
nahumsa May 4, 2021
d336599
add find_edge before adding edge
nahumsa May 7, 2021
7449f7c
add bidirectional tests
nahumsa May 7, 2021
43158ee
clippy
nahumsa May 7, 2021
ee8017e
lint
nahumsa May 8, 2021
d598afd
lint
nahumsa May 8, 2021
ed271f4
Merge branch 'main' into binomial-tree-graph
nahumsa May 8, 2021
23e4e5e
run black
nahumsa May 8, 2021
e37eda2
Merge remote-tracking branch 'upstream/main' into binomial-tree-graph
nahumsa May 18, 2021
7aa3d3c
fix merge leftover
nahumsa May 18, 2021
f977eaf
fix lint
nahumsa May 18, 2021
0fef932
add newline release notes
nahumsa May 18, 2021
c33983f
Merge branch 'main' into binomial-tree-graph
nahumsa May 20, 2021
7b3238a
add `.is_none()` assertion
nahumsa May 21, 2021
534d49a
`order` required arg
nahumsa May 21, 2021
ad0d838
`order` required arg
nahumsa May 21, 2021
c5fe7d2
Use `.is_none()` instead of `== None` everywhere
mtreinish May 21, 2021
fb2c810
Merge branch 'main' into binomial-tree-graph
mtreinish May 21, 2021
fd1707a
Run cargo fmt
mtreinish May 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Generators
retworkx.generators.directed_mesh_graph
retworkx.generators.grid_graph
retworkx.generators.directed_grid_graph
retworkx.generators.binomial_tree_graph

Random Circuit Functions
------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features:
- |
Added a new generator for constructing a binomial tree graph (:func:`retworkx.generators.binomial_tree_graph`).
98 changes: 98 additions & 0 deletions src/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
// License for the specific language governing permissions and limitations
// under the License.

use std::convert::TryInto;
use std::iter;

use petgraph::algo;
use petgraph::graph::NodeIndex;
use petgraph::stable_graph::{StableDiGraph, StableUnGraph};
use petgraph::visit::{EdgeRef, IntoEdgeReferences};

use pyo3::exceptions::PyIndexError;
use pyo3::prelude::*;
Expand Down Expand Up @@ -985,6 +987,101 @@ pub fn directed_grid_graph(
})
}

/// Generate an undirected binomial tree of order n recursively.
///
/// :param int order: Order of the binomial tree.
/// :param list weights: A list of node weights. It must have 2**order values.
/// :param bool multigraph: When set to False the output
/// :class:`~retworkx.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: A binomail tree with 2^n vertices and 2^n - 1 edges.
/// :rtype: PyGraph
/// :raises IndexError: If neither ``order`` or ``weights`` are specified
///
/// .. jupyter-execute::
///
/// import os
/// import tempfile
///
/// import pydot
/// from PIL import Image
///
/// import retworkx.generators
///
/// graph = retworkx.generators.binomial_tree_graph(4)
/// dot_str = graph.to_dot(
/// lambda node: dict(
/// color='black', fillcolor='lightblue', style='filled'))
/// dot = pydot.graph_from_dot_data(dot_str)[0]
///
/// with tempfile.TemporaryDirectory() as tmpdirname:
/// tmp_path = os.path.join(tmpdirname, 'dag.png')
/// dot.write_png(tmp_path)
/// image = Image.open(tmp_path)
/// os.remove(tmp_path)
/// image
///
#[pyfunction(multigraph = true)]
#[text_signature = "(/, order=None, weights=None, multigraph=True)"]
nahumsa marked this conversation as resolved.
Show resolved Hide resolved
pub fn binomial_tree_graph(
py: Python,
order: usize,
weights: Option<Vec<PyObject>>,
multigraph: bool,
) -> PyResult<graph::PyGraph> {
let mut graph = StableUnGraph::<PyObject, PyObject>::default();

// try_into is used to convert from usize to u32
let num_nodes = usize::pow(2, order.try_into().unwrap());
nahumsa marked this conversation as resolved.
Show resolved Hide resolved

let nodes: Vec<NodeIndex> = match weights {
Some(weights) => {
let mut node_list: Vec<NodeIndex> = Vec::new();

for weight in weights {
mtreinish marked this conversation as resolved.
Show resolved Hide resolved
let index = graph.add_node(weight);
node_list.push(index);
}

node_list
}

None => (0..num_nodes).map(|_| graph.add_node(py.None())).collect(),
};

let mut n = 1;

for _ in 0..order {
let edges: Vec<(NodeIndex, NodeIndex)> = graph
.edge_references()
.map(|e| (e.source(), e.target()))
.collect();

for (source, target) in edges {
let source_index = source.index();
let target_index = target.index();

graph.add_edge(
nodes[source_index + n],
nodes[target_index + n],
py.None(),
);
}

graph.add_edge(nodes[0], nodes[n], py.None());

n *= 2;
}

Ok(graph::PyGraph {
graph,
node_removed: false,
multigraph,
})
}

#[pymodule]
pub fn generators(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(cycle_graph))?;
Expand All @@ -997,5 +1094,6 @@ pub fn generators(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(directed_mesh_graph))?;
m.add_wrapped(wrap_pyfunction!(grid_graph))?;
m.add_wrapped(wrap_pyfunction!(directed_grid_graph))?;
m.add_wrapped(wrap_pyfunction!(binomial_tree_graph))?;
Ok(())
}
35 changes: 35 additions & 0 deletions tests/generators/test_binomial_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 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 retworkx


class TestBinomailTreeGraph(unittest.TestCase):

def test_binomial_tree_graph(self):
for n in range(10):
graph = retworkx.generators.binomial_tree_graph(n)
self.assertEqual(len(graph), 2**n)
self.assertEqual(len(graph.edges()), 2**n - 1)
Copy link
Member

Choose a reason for hiding this comment

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

Can we add some assertions here on the edge list. It would be good to assert that the output graph is actually a binomial tree instead of just a graph with 2**n nodes and 2**n - 1 edges

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added assertions to check if the edges match what is expected for a binomial tree graph

nahumsa marked this conversation as resolved.
Show resolved Hide resolved

def test_binomial_tree_graph_weights(self):
mtreinish marked this conversation as resolved.
Show resolved Hide resolved
graph = retworkx.generators.binomial_tree_graph(
2, weights=list(range(4)))
self.assertEqual(len(graph), 4)
self.assertEqual([x for x in range(4)], graph.nodes())
self.assertEqual(len(graph.edges()), 3)

def test_binomial_tree_no_order(self):
with self.assertRaises(TypeError):
retworkx.generators.binomial_tree_graph(weights=list(range(4)))