From 5ab599f8ded2f04e111bb7349d3fbcf760a04f21 Mon Sep 17 00:00:00 2001 From: Ivan Carvalho <8753214+IvanIsCoding@users.noreply.github.com> Date: Tue, 3 Oct 2023 18:19:50 -0400 Subject: [PATCH 01/12] Bump `indexmap` to 2.0.2, `hashbrown` to 0.14.1 & more (#989) * Bump indexmap and hashmap * Bump indexmap again * Update even more dependencies --- Cargo.lock | 94 +++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36b79a054..fcb89c141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,9 +128,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ "ahash", "allocator-api2", @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "indexmap" @@ -155,12 +155,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", "rayon", ] @@ -196,9 +196,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libm" @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" dependencies = [ "autocfg", "rawpointer", @@ -228,9 +228,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" @@ -390,7 +390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.0", + "indexmap 2.0.2", ] [[package]] @@ -411,9 +411,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -425,8 +425,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" dependencies = [ "cfg-if", - "hashbrown 0.14.0", - "indexmap 2.0.0", + "hashbrown 0.14.1", + "indexmap 2.0.2", "indoc", "libc", "memoffset", @@ -493,9 +493,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -597,8 +597,8 @@ version = "0.14.0" dependencies = [ "ahash", "fixedbitset", - "hashbrown 0.14.0", - "indexmap 2.0.0", + "hashbrown 0.14.1", + "indexmap 2.0.2", "ndarray", "ndarray-stats", "num-bigint", @@ -623,8 +623,8 @@ version = "0.14.0" dependencies = [ "ahash", "fixedbitset", - "hashbrown 0.14.0", - "indexmap 2.0.0", + "hashbrown 0.14.1", + "indexmap 2.0.2", "num-traits", "petgraph", "priority-queue", @@ -663,7 +663,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.37", ] [[package]] @@ -679,9 +679,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "sprs" @@ -711,9 +711,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -728,9 +728,9 @@ checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unindent" @@ -752,9 +752,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -767,42 +767,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" From 651409f403cfd458ab6c92aae0e2a3e6df4b9484 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 5 Oct 2023 18:32:00 -0400 Subject: [PATCH 02/12] Fix build errors with Rust 1.73.0 (#996) The recent Rust 1.73.0 release introduced some changes to clippy's behavior that are causing failures in CI (and correctly calling out issues in our code). This commit updates the rustworkx source to correct these failures. --- rustworkx-core/src/centrality.rs | 2 +- src/dag_algo/mod.rs | 1 - src/matching/mod.rs | 2 +- src/score.rs | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rustworkx-core/src/centrality.rs b/rustworkx-core/src/centrality.rs index c099c6304..2d856244f 100644 --- a/rustworkx-core/src/centrality.rs +++ b/rustworkx-core/src/centrality.rs @@ -738,7 +738,7 @@ where { let alpha: f64 = alpha.unwrap_or(0.1); - let mut beta: HashMap = beta_map.unwrap_or_else(HashMap::new); + let mut beta: HashMap = beta_map.unwrap_or_default(); if beta.is_empty() { // beta_map was none diff --git a/src/dag_algo/mod.rs b/src/dag_algo/mod.rs index 489cf2344..04068342d 100644 --- a/src/dag_algo/mod.rs +++ b/src/dag_algo/mod.rs @@ -628,7 +628,6 @@ pub fn collect_bicolor_runs( } } else { for color in colors { - let color = color; ensure_vector_has_index!(pending_list, block_id, color); if let Some(color_block_id) = block_id[color] { block_list[color_block_id].append(&mut pending_list[color]); diff --git a/src/matching/mod.rs b/src/matching/mod.rs index fac47e973..af9740ad9 100644 --- a/src/matching/mod.rs +++ b/src/matching/mod.rs @@ -92,7 +92,7 @@ fn _inner_is_matching(graph: &graph::PyGraph, matching: &HashSet<(usize, usize)> .contains_edge(NodeIndex::new(e.0), NodeIndex::new(e.1)) }; - if !matching.iter().all(|e| has_edge(e)) { + if !matching.iter().all(has_edge) { return false; } let mut found: HashSet = HashSet::with_capacity(2 * matching.len()); diff --git a/src/score.rs b/src/score.rs index 4dc888c5b..95e0d5bea 100644 --- a/src/score.rs +++ b/src/score.rs @@ -10,6 +10,7 @@ // License for the specific language governing permissions and limitations // under the License. #![allow(clippy::derive_partial_eq_without_eq)] +#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)] use std::cmp::Ordering; use std::ops::{Add, AddAssign}; From c5b41fc51b7d47001010b933a8e0a6979af9c4bd Mon Sep 17 00:00:00 2001 From: Arjun Bhamra <33864884+abhamra@users.noreply.github.com> Date: Thu, 5 Oct 2023 23:21:28 -0400 Subject: [PATCH 03/12] Added clear, clear_edges functions to PyGraph and PyDiGraph objects (#993) * First pass at testing infrastructure + graph.rs file changes * Fixed clear, clear_edges for graph.rs and digraph.rs, added tests, added documentation * fix for docstring for clear_edges in digraph * docstring fix for graph.rs * Minor fixes for codestyle for python lint * Added new tests to show reuse after using clear, clear_edges, updated docs * Adding fix for build error with prev commit * fixes from black codestyle format * fixed flake8 F841 - variable assigned to but never used errors * retry at fix for F841 error, used noqa * fixes for black * fixes for CICD, F841 local variable unused error * flake8 fixes --- ...ear_edges-for-graphs-041b166aa541639c.yaml | 10 +++ src/digraph.rs | 14 ++++ src/graph.rs | 13 ++++ tests/rustworkx_tests/digraph/test_clear.py | 66 ++++++++++++++++ tests/rustworkx_tests/graph/test_clear.py | 76 +++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml create mode 100644 tests/rustworkx_tests/digraph/test_clear.py create mode 100644 tests/rustworkx_tests/graph/test_clear.py diff --git a/releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml b/releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml new file mode 100644 index 000000000..ef6931f54 --- /dev/null +++ b/releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Added a new function, :func:`clear` that clears all nodes and edges + from a :class:`rustworkx.PyGraph` or :class:`rustworkx.PyDiGraph` + + - | + Added a new function, :func:`clear_edges` that clears all edges for + :class:`rustworkx.PyGraph` or :class:`rustworkx.PyDiGraph` without + modifying nodes diff --git a/src/digraph.rs b/src/digraph.rs index 0fe27c4c3..bf5395084 100644 --- a/src/digraph.rs +++ b/src/digraph.rs @@ -492,6 +492,20 @@ impl PyDiGraph { } false } + + /// Clear all nodes and edges + #[pyo3(text_signature = "(self)")] + pub fn clear(&mut self) { + self.graph.clear(); + self.node_removed = true; + } + + /// Clears all edges, leaves nodes intact + #[pyo3(text_signature = "(self)")] + pub fn clear_edges(&mut self) { + self.graph.clear_edges(); + } + /// Return the number of nodes in the graph #[pyo3(text_signature = "(self)")] pub fn num_nodes(&self) -> usize { diff --git a/src/graph.rs b/src/graph.rs index 1d97404c5..58d463813 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -368,6 +368,19 @@ impl PyGraph { false } + /// Clears all nodes and edges + #[pyo3(text_signature = "(self)")] + pub fn clear(&mut self) { + self.graph.clear(); + self.node_removed = true; + } + + /// Clears all edges, leaves nodes intact + #[pyo3(text_signature = "(self)")] + pub fn clear_edges(&mut self) { + self.graph.clear_edges(); + } + /// Return the number of nodes in the graph #[pyo3(text_signature = "(self)")] pub fn num_nodes(&self) -> usize { diff --git a/tests/rustworkx_tests/digraph/test_clear.py b/tests/rustworkx_tests/digraph/test_clear.py new file mode 100644 index 000000000..043ae43e6 --- /dev/null +++ b/tests/rustworkx_tests/digraph/test_clear.py @@ -0,0 +1,66 @@ +# 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 TestClear(unittest.TestCase): + def test_clear(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + dag.clear() + self.assertEqual(dag.num_nodes(), 0) + self.assertEqual(dag.num_edges(), 0) + self.assertEqual(dag.nodes(), []) + self.assertEqual(dag.edges(), []) + + def test_clear_reuse(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + dag.clear() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + self.assertEqual(dag.num_nodes(), 3) + self.assertEqual(dag.num_edges(), 2) + self.assertEqual(dag.nodes(), ["a", "b", "c"]) + self.assertEqual(dag.edges(), [{"a": 1}, {"a": 2}]) + + def test_clear_edges(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + dag.clear_edges() + self.assertEqual(dag.num_nodes(), 3) + self.assertEqual(dag.num_edges(), 0) + self.assertEqual(dag.nodes(), ["a", "b", "c"]) + self.assertEqual(dag.edges(), []) + + def test_clear_edges_reuse(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + node_b = dag.add_child(node_a, "b", {"a": 1}) + node_c = dag.add_child(node_a, "c", {"a": 2}) + dag.clear_edges() + dag.add_edge(node_a, node_b, {"a": 1}) + dag.add_edge(node_a, node_c, {"a": 2}) + self.assertEqual(dag.num_nodes(), 3) + self.assertEqual(dag.num_edges(), 2) + self.assertEqual(dag.nodes(), ["a", "b", "c"]) + self.assertEqual(dag.edges(), [{"a": 1}, {"a": 2}]) diff --git a/tests/rustworkx_tests/graph/test_clear.py b/tests/rustworkx_tests/graph/test_clear.py new file mode 100644 index 000000000..3672564fb --- /dev/null +++ b/tests/rustworkx_tests/graph/test_clear.py @@ -0,0 +1,76 @@ +# Licensed under the Apache License, Version 3.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 TestClear(unittest.TestCase): + def test_clear(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"a": 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"a": 2}) + graph.clear() + self.assertEqual(graph.num_nodes(), 0) + self.assertEqual(graph.num_edges(), 0) + self.assertEqual(graph.nodes(), []) + self.assertEqual(graph.edges(), []) + + def test_clear_reuse(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"a": 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"a": 2}) + graph.clear() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"a": 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"a": 2}) + self.assertEqual(graph.num_nodes(), 3) + self.assertEqual(graph.num_edges(), 2) + self.assertEqual(graph.nodes(), ["a", "b", "c"]) + self.assertEqual(graph.edges(), [{"a": 1}, {"a": 2}]) + + def test_clear_edges(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"e1", 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"e2", 2}) + graph.clear_edges() + self.assertEqual(graph.num_edges(), 0) + self.assertEqual(graph.edges(), []) + self.assertEqual(graph.num_nodes(), 3) + self.assertEqual(graph.nodes(), ["a", "b", "c"]) + + def test_clear_edges_reuse(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"e1", 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"e2", 2}) + graph.clear_edges() + graph.add_edge(node_a, node_b, {"e1", 1}) + graph.add_edge(node_a, node_c, {"e2", 2}) + self.assertEqual(graph.num_nodes(), 3) + self.assertEqual(graph.num_edges(), 2) + self.assertEqual(graph.nodes(), ["a", "b", "c"]) + self.assertEqual(graph.edges(), [{"e1", 1}, {"e2", 2}]) From 2d5694edb547d024e8831fb9789a47df920533b3 Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Fri, 6 Oct 2023 16:25:23 +0300 Subject: [PATCH 04/12] mapping is not possible when a node has no neighbors (#995) * mapping is not possible when a node has no neighbors * suggested improvement --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- rustworkx-core/src/token_swapper.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rustworkx-core/src/token_swapper.rs b/rustworkx-core/src/token_swapper.rs index c60e31425..8e30e9a76 100644 --- a/rustworkx-core/src/token_swapper.rs +++ b/rustworkx-core/src/token_swapper.rs @@ -205,6 +205,11 @@ where } let id_node = self.rev_node_map[&node]; let id_token = self.rev_node_map[&tokens[&node]]; + + if self.graph.neighbors(id_node).next().is_none() { + return Err(MapNotPossible {}); + } + for id_neighbor in self.graph.neighbors(id_node) { let neighbor = self.node_map[&id_neighbor]; let dist_neighbor: DictMap = dijkstra( @@ -705,4 +710,19 @@ mod test_token_swapper { Err(_) => (), }; } + + #[test] + fn test_edgeless_graph_fails() { + let mut g = petgraph::graph::UnGraph::<(), ()>::new_undirected(); + let a = g.add_node(()); + let b = g.add_node(()); + let c = g.add_node(()); + let d = g.add_node(()); + g.add_edge(c, d, ()); + let mapping = HashMap::from([(a, b), (b, a)]); + match token_swapper(&g, mapping, Some(10), Some(4), Some(50)) { + Ok(_) => panic!("This should error"), + Err(_) => (), + }; + } } From 632aa9a5dd157c1511b876596d9488945814d6d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:57:20 +0000 Subject: [PATCH 05/12] Bump num-traits from 0.2.16 to 0.2.17 (#999) Bumps [num-traits](https://github.com/rust-num/num-traits) from 0.2.16 to 0.2.17. - [Changelog](https://github.com/rust-num/num-traits/blob/master/RELEASES.md) - [Commits](https://github.com/rust-num/num-traits/compare/num-traits-0.2.16...num-traits-0.2.17) --- updated-dependencies: - dependency-name: num-traits dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcb89c141..be7bc5f32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,9 +321,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", From 2062a1c2101e0dbb0cdb6120b04b676b7d008787 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 10 Oct 2023 08:36:12 -0400 Subject: [PATCH 06/12] Add support for Python 3.12 and musllinux to main (#997) * Add support for Python 3.12 and musllinux to main As part of the 0.13.2 release we added support for Python 3.12 and musllinux to rustworkx. However, these changes did not happen on main yet. This commit applies the necessary changes to the main branch for the 0.14.0 and future releases. Also to simplify the configuration of the cibuildwheel jobs this combines #753 into this PR so that the configuration is centralized in the pyproject.toml. * DNM: Test wheel build configuration * Remove testtools usage from test suite * Don't require blas on numpy install * Fix docs typo * Drop musl on aarch64 * Try installing openblas to fix numpy build * Fix toml syntax * Adjust override to use allowed fields only * Fix toml syntax again * Switch back to pip command * Downgrade pp64le to tier 4 and skip tests * Fix apk command copy paste error * Raise minimum supported macOS version to 10.12 In Rust 1.74 the Rust programming language is raising their minimum support macOS version to 10.12, so rustworkx is raising it's supported version of macOS to match this. * Tweak test skip regex * Split arm into 2 jobs * Revert "DNM: Test wheel build configuration" This reverts commit 57dd451087e285044d53ccd28194c78215775b57. --- .github/workflows/main.yml | 15 +-- .github/workflows/wheels.yml | 110 +++++++----------- docs/source/install.rst | 6 +- pyproject.toml | 26 ++++- .../platform-updates-e9b296144e633c95.yaml | 26 +++++ setup.py | 1 + .../graph/test_max_weight_matching.py | 12 +- .../graph/test_max_weight_matching.py | 12 +- 8 files changed, 104 insertions(+), 104 deletions(-) create mode 100644 releasenotes/notes/platform-updates-e9b296144e633c95.yaml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f9d0b1c76..b03b7a8e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: strategy: matrix: rust: [stable] - python-version: [3.8, 3.9, "3.10", "3.11"] + python-version: [3.8, 3.9, "3.10", "3.11", "3.12"] platform: [ { os: "macOS-latest", python-architecture: "x64", rust-target: "x86_64-apple-darwin" }, { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" }, @@ -76,19 +76,6 @@ jobs: with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.platform.python-architecture }} - if: runner.os != 'Windows' - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: 3.7 - architecture: ${{ matrix.platform.python-architecture }} - if: ${{ runner.os == 'Windows' && matrix.python-version == '3.7.16' }} - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.platform.python-architecture }} - if: ${{ runner.os == 'Windows' && matrix.python-version != '3.7.16' }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4312f16de..c942df586 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -55,20 +55,10 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse - env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -97,21 +87,43 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine + - name: Build wheels + run: | + python -m cibuildwheel --output-dir wheelhouse + env: + CIBW_ARCHS_LINUX: aarch64 + CIBW_SKIP: cp36-* cp37-* cp311-* cp312-* pp* *musl* + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + build_wheels_aarch64_part_2: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: '3.8' + - uses: dtolnay/rust-toolchain@stable + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: all + - name: Install cibuildwheel + run: | + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx scipy testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests CIBW_ARCHS_LINUX: aarch64 + CIBW_SKIP: cp36-* cp37-* cp38-* cp39-* cp310-* pp* *musl* - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -140,20 +152,12 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* cp39-* cp310-* cp311-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests + CIBW_SKIP: cp36-* cp37-* cp39-* cp310-* cp311-* pp* *win32 CIBW_ARCHS_LINUX: ppc64le - uses: actions/upload-artifact@v3 with: @@ -183,20 +187,12 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* cp38-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests + CIBW_SKIP: cp36-* cp37-* cp38-* cp312-* pp* *win32 *musl* CIBW_ARCHS_LINUX: ppc64le - uses: actions/upload-artifact@v3 with: @@ -226,22 +222,13 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest CIBW_SKIP: cp36-* cp37-* cp39-* cp310-* cp311-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests CIBW_ARCHS_LINUX: s390x - CIBW_TEST_SKIP: "*-*linux_s390x" - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -270,22 +257,13 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* cp38-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests + CIBW_SKIP: cp36-* cp37-* cp38-* cp312-* pp* *win32 *musl* CIBW_ARCHS_LINUX: s390x - CIBW_TEST_SKIP: "*-*linux_s390x" - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -300,7 +278,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build wheels - uses: joerick/cibuildwheel@v2.10.1 + uses: joerick/cibuildwheel@v2.16.2 env: CIBW_BEFORE_ALL: rustup target add aarch64-apple-darwin CIBW_ARCHS_MACOS: arm64 universal2 @@ -338,16 +316,12 @@ jobs: run: rustup default stable-i686-pc-windows-msvc - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 CIBW_SKIP: cp36-* cp37-* pp* *amd64 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl diff --git a/docs/source/install.rst b/docs/source/install.rst index 0b44823f7..61c854f94 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -89,7 +89,11 @@ source. - s390x - :ref:`tier-4` - Distributions compatible with the `manylinux 2014`_ packaging specification - * - macOS (10.9 or newer) + * - Linux (musl) + - x86_64 + - :ref:`tier-3` + - + * - macOS (10.12 or newer) - x86_64 - :ref:`tier-1` - diff --git a/pyproject.toml b/pyproject.toml index c348b0338..4aee0fecb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,4 +4,28 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 100 -target-version = ['py37', 'py38', 'py39', 'py310'] +target-version = ['py38', 'py39', 'py310', 'py311'] + +[tool.cibuildwheel] +manylinux-x86_64-image = "manylinux2014" +manylinux-i686-image = "manylinux2014" +skip = "pp* cp36-* cp37-* *win32 *musllinux*i686" +test-requires = "networkx" +test-command = "python -m unittest discover {project}/tests/rustworkx_tests" +before-build = "pip install -U setuptools-rust" +test-skip = "cp38-*musllinux* *linux_s390x *ppc64le" + +[tool.cibuildwheel.linux] +before-all = "yum install -y wget && {package}/tools/install_rust.sh" +environment = 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' + +[[tool.cibuildwheel.overrides]] +select = "*-musllinux*" +before-all = "apk add --no-cache curl gcc && curl https://sh.rustup.rs -sSf | sh -s -- -y && source $HOME/.cargo/env && rustup install stable && rustup default stable" + +[[tool.cibuildwheel.overrides]] +select = "*i686" +before-test = 'python -m pip install numpy --config-settings=setup-args="-Dallow-noblas=true"' + +[tool.cibuildwheel.macos] +environment = "MACOSX_DEPLOYMENT_TARGET=10.12" diff --git a/releasenotes/notes/platform-updates-e9b296144e633c95.yaml b/releasenotes/notes/platform-updates-e9b296144e633c95.yaml new file mode 100644 index 000000000..876fabbc8 --- /dev/null +++ b/releasenotes/notes/platform-updates-e9b296144e633c95.yaml @@ -0,0 +1,26 @@ +--- +features: + - | + Added support for musl Linux platforms on x86_64 and aarch64 at :ref:`tier-3`. +upgrade: + - | + Support for the Linux ppc64le pllatform has changed from tier 3 to tier 4 + (as documented in :ref:`platform-suppport`). This is a result of no longer + being able to run tests during the pre-compiled wheel publishing jobs due + to constraints in the available CI infrastructure. There hopefully + shouldn't be any meaningful impact resulting from this change, but as there + are no longer tests being run to validate the binaries prior to publishing + them there are no longer guarantees that the wheels for ppc64le are fully + functional (although the likelihood they are is still high as it works on + other platforms). If any issues are encountered with ppc64le Linux please + open an issue. + - | + For macOS the minimum version of macOS is now 10.12. Previously, the + precompiled binary wheel packages for macOS x86_64 were published with + support for >=10.9. However, because of changes in the + `support policy `__ + for the Rust programming language the minimum version needed to raised + to macOS 10.12. If you're using Qiskit on macOS 10.9 you can probably + build Qiskit from source while the rustworkx MSRV (minimum supported Rust + version) is < 1.74, but the precompiled binaries published to PyPI will + only be compatible with macOS >= 10.12. diff --git a/setup.py b/setup.py index 815f17538..e734d8be1 100644 --- a/setup.py +++ b/setup.py @@ -68,6 +68,7 @@ def readme(): "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", diff --git a/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py b/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py index 79e4d7041..091626da3 100644 --- a/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py +++ b/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py @@ -14,10 +14,9 @@ # https://github.com/networkx/networkx/blob/3351206a3ce5b3a39bb2fc451e93ef545b96c95b/networkx/algorithms/tests/test_matching.py import random +import unittest -import fixtures import networkx -import testtools import retworkx @@ -26,14 +25,7 @@ def match_dict_to_set(match): return {(u, v) for (u, v) in set(map(frozenset, match.items()))} -class TestMaxWeightMatching(testtools.TestCase): - def setUp(self): - super().setUp() - stdout = self.useFixture(fixtures.StringStream("stdout")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout)) - stderr = self.useFixture(fixtures.StringStream("stderr")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) - +class TestMaxWeightMatching(unittest.TestCase): def compare_match_sets(self, rx_match, expected_match): for (u, v) in rx_match: if (u, v) not in expected_match and (v, u) not in expected_match: diff --git a/tests/rustworkx_tests/graph/test_max_weight_matching.py b/tests/rustworkx_tests/graph/test_max_weight_matching.py index 89bc468f0..29e5a3382 100644 --- a/tests/rustworkx_tests/graph/test_max_weight_matching.py +++ b/tests/rustworkx_tests/graph/test_max_weight_matching.py @@ -14,10 +14,9 @@ # https://github.com/networkx/networkx/blob/3351206a3ce5b3a39bb2fc451e93ef545b96c95b/networkx/algorithms/tests/test_matching.py import random +import unittest -import fixtures import networkx -import testtools import rustworkx @@ -26,14 +25,7 @@ def match_dict_to_set(match): return {(u, v) for (u, v) in set(map(frozenset, match.items()))} -class TestMaxWeightMatching(testtools.TestCase): - def setUp(self): - super().setUp() - stdout = self.useFixture(fixtures.StringStream("stdout")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout)) - stderr = self.useFixture(fixtures.StringStream("stderr")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) - +class TestMaxWeightMatching(unittest.TestCase): def compare_match_sets(self, rx_match, expected_match): for (u, v) in rx_match: if (u, v) not in expected_match and (v, u) not in expected_match: From 274b0041908edf2c80d38c2b780ba5b005f57454 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 11 Oct 2023 21:55:40 -0400 Subject: [PATCH 07/12] Add isolates() function to rustworkx (#998) * Add isolates() function to rustworkx This commit adds a new function, isolates(), which is used to find all the isolates in a graph. * Move implementation to rustworkx-core * Add missing isolates module * Update rustworkx-core/src/connectivity/isolates.rs --------- Co-authored-by: Edwin Navarro --- .../notes/add-isolates-edc5da3a3d8fb4fd.yaml | 8 + rustworkx-core/src/connectivity/isolates.rs | 144 ++++++++++++++++++ rustworkx-core/src/connectivity/mod.rs | 2 + rustworkx/__init__.py | 17 +++ src/connectivity/mod.rs | 35 +++++ src/lib.rs | 2 + .../rustworkx_tests/digraph/test_isolates.py | 47 ++++++ tests/rustworkx_tests/graph/test_isolates.py | 37 +++++ 8 files changed, 292 insertions(+) create mode 100644 releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml create mode 100644 rustworkx-core/src/connectivity/isolates.rs create mode 100644 tests/rustworkx_tests/digraph/test_isolates.py create mode 100644 tests/rustworkx_tests/graph/test_isolates.py diff --git a/releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml b/releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml new file mode 100644 index 000000000..d1bf9272b --- /dev/null +++ b/releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Added a new function, :func:`~.isolates`, which is used to find the isolates + (nodes with a degree of 0) in a :class:`~.PyDiGraph` or :class:`~.PyGraph`. + - | + Added a new function, ``isolates()`` to the rustworkx-core ``rustworkx_core::connectivity`` + module which is used to find the isolates (nodes with a degree of 0). diff --git a/rustworkx-core/src/connectivity/isolates.rs b/rustworkx-core/src/connectivity/isolates.rs new file mode 100644 index 000000000..df1a5b7c2 --- /dev/null +++ b/rustworkx-core/src/connectivity/isolates.rs @@ -0,0 +1,144 @@ +// 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::visit::{IntoNeighborsDirected, IntoNodeIdentifiers, NodeIndexable}; +use petgraph::Direction::{Incoming, Outgoing}; + +/// Return the isolates in a graph object +/// +/// An isolate is a node without any neighbors meaning it has a degree of 0. For +/// directed graphs this means the in-degree and out-degree are both 0. +/// +/// Arguments: +/// +/// * `graph` - The graph in which to find the isolates. +/// +/// # Example +/// ```rust +/// use petgraph::prelude::*; +/// use rustworkx_core::connectivity::isolates; +/// +/// let edge_list = vec![ +/// (0, 1), +/// (3, 0), +/// (0, 5), +/// (8, 0), +/// (1, 2), +/// (1, 6), +/// (2, 3), +/// (3, 4), +/// (4, 5), +/// (6, 7), +/// (7, 8), +/// (8, 9), +/// ]; +/// let mut graph = DiGraph::::from_edges(&edge_list); +/// graph.add_node(10); +/// graph.add_node(11); +/// let res: Vec = isolates(&graph).into_iter().map(|x| x.index()).collect(); +/// assert_eq!(res, [10, 11]) +/// ``` +pub fn isolates(graph: G) -> Vec +where + G: NodeIndexable + IntoNodeIdentifiers + IntoNeighborsDirected, +{ + graph + .node_identifiers() + .filter(|x| { + graph + .neighbors_directed(*x, Incoming) + .chain(graph.neighbors_directed(*x, Outgoing)) + .next() + .is_none() + }) + .collect() +} + +#[cfg(test)] +mod tests { + use crate::connectivity::isolates; + use petgraph::prelude::*; + + #[test] + fn test_isolates_directed_empty() { + let graph = DiGraph::::new(); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_undirected_empty() { + let graph = UnGraph::::default(); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_directed_no_isolates() { + let graph = DiGraph::::from_edges([(0, 1), (1, 2)]); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_undirected_no_isolates() { + let graph = UnGraph::::from_edges([(0, 1), (1, 2)]); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_directed() { + let edge_list = vec![ + (0, 1), + (3, 0), + (0, 5), + (8, 0), + (1, 2), + (1, 6), + (2, 3), + (3, 4), + (4, 5), + (6, 7), + (7, 8), + (8, 9), + ]; + let mut graph = DiGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let res: Vec = isolates(&graph).into_iter().map(|x| x.index()).collect(); + assert_eq!(res, [10, 11]) + } + + #[test] + fn test_isolates_undirected() { + let edge_list = vec![ + (0, 1), + (3, 0), + (0, 5), + (8, 0), + (1, 2), + (1, 6), + (2, 3), + (3, 4), + (4, 5), + (6, 7), + (7, 8), + (8, 9), + ]; + let mut graph = UnGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let res: Vec = isolates(&graph).into_iter().map(|x| x.index()).collect(); + assert_eq!(res, [10, 11]) + } +} diff --git a/rustworkx-core/src/connectivity/mod.rs b/rustworkx-core/src/connectivity/mod.rs index b66405c55..bc5851324 100644 --- a/rustworkx-core/src/connectivity/mod.rs +++ b/rustworkx-core/src/connectivity/mod.rs @@ -19,6 +19,7 @@ mod conn_components; mod core_number; mod cycle_basis; mod find_cycle; +mod isolates; mod min_cut; pub use all_simple_paths::{ @@ -32,4 +33,5 @@ pub use conn_components::number_connected_components; pub use core_number::core_number; pub use cycle_basis::cycle_basis; pub use find_cycle::find_cycle; +pub use isolates::isolates; pub use min_cut::stoer_wagner_min_cut; diff --git a/rustworkx/__init__.py b/rustworkx/__init__.py index 48f65fde0..b97eada4f 100644 --- a/rustworkx/__init__.py +++ b/rustworkx/__init__.py @@ -2054,3 +2054,20 @@ def longest_simple_path(graph): longest_simple_path.register(PyDiGraph, digraph_longest_simple_path) longest_simple_path.register(PyGraph, graph_longest_simple_path) + + +@functools.singledispatch +def isolates(graph): + """Return a list of isolates in a graph object + + An isolate is a node without any neighbors meaning it has a degree of 0. For + directed graphs this means the in-degree and out-degree are both 0. + + :param graph: The input graph to find isolates in + :returns: A list of node indices for isolates in the graph + :rtype: NodeIndices + """ + + +isolates.register(PyDiGraph, digraph_isolates) +isolates.register(PyGraph, graph_isolates) diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 7d38b3cf9..8274538c7 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -1000,3 +1000,38 @@ pub fn chain_decomposition(graph: graph::PyGraph, source: Option) -> Chai .collect(), } } + +/// Return a list of isolates in a :class:`~.PyGraph` object +/// +/// An isolate is a node without any neighbors meaning it has a degree of 0. +/// +/// :param PyGraph graph: The input graph to find isolates in +/// :returns: A list of node indices for isolates in the graph +/// :rtype: NodeIndices +#[pyfunction] +pub fn graph_isolates(graph: graph::PyGraph) -> NodeIndices { + NodeIndices { + nodes: connectivity::isolates(&graph.graph) + .into_iter() + .map(|x| x.index()) + .collect(), + } +} + +/// Return a list of isolates in a :class:`~.PyGraph` object +/// +/// An isolate is a node without any neighbors meaning it has an in-degree +/// and out-degree of 0. +/// +/// :param PyGraph graph: The input graph to find isolates in +/// :returns: A list of node indices for isolates in the graph +/// :rtype: NodeIndices +#[pyfunction] +pub fn digraph_isolates(graph: digraph::PyDiGraph) -> NodeIndices { + NodeIndices { + nodes: connectivity::isolates(&graph.graph) + .into_iter() + .map(|x| x.index()) + .collect(), + } +} diff --git a/src/lib.rs b/src/lib.rs index d34e31f10..6f889be85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -498,6 +498,8 @@ fn rustworkx(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(articulation_points))?; m.add_wrapped(wrap_pyfunction!(biconnected_components))?; m.add_wrapped(wrap_pyfunction!(chain_decomposition))?; + m.add_wrapped(wrap_pyfunction!(graph_isolates))?; + m.add_wrapped(wrap_pyfunction!(digraph_isolates))?; m.add_wrapped(wrap_pyfunction!(is_planar))?; m.add_wrapped(wrap_pyfunction!(read_graphml))?; m.add_wrapped(wrap_pyfunction!(digraph_node_link_json))?; diff --git a/tests/rustworkx_tests/digraph/test_isolates.py b/tests/rustworkx_tests/digraph/test_isolates.py new file mode 100644 index 000000000..bb1993bb8 --- /dev/null +++ b/tests/rustworkx_tests/digraph/test_isolates.py @@ -0,0 +1,47 @@ +# 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 TestIsolates(unittest.TestCase): + def test_isolates(self): + graph = rustworkx.PyDiGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + res = rustworkx.isolates(graph) + self.assertEqual(res, [2, 3]) + + def test_isolates_with_holes(self): + graph = rustworkx.PyDiGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + graph.remove_node(2) + res = rustworkx.isolates(graph) + self.assertEqual(res, [3]) + + def test_isolates_empty_graph(self): + graph = rustworkx.PyDiGraph() + res = rustworkx.isolates(graph) + self.assertEqual(res, []) + + def test_isolates_outgoing_star(self): + graph = rustworkx.generators.directed_star_graph(5) + res = rustworkx.isolates(graph) + self.assertEqual(res, []) + + def test_isolates_incoming_star(self): + graph = rustworkx.generators.directed_star_graph(5, inward=True) + res = rustworkx.isolates(graph) + self.assertEqual(res, []) diff --git a/tests/rustworkx_tests/graph/test_isolates.py b/tests/rustworkx_tests/graph/test_isolates.py new file mode 100644 index 000000000..fc21911cc --- /dev/null +++ b/tests/rustworkx_tests/graph/test_isolates.py @@ -0,0 +1,37 @@ +# 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 TestIsolates(unittest.TestCase): + def test_isolates(self): + graph = rustworkx.PyGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + res = rustworkx.isolates(graph) + self.assertEqual(res, [2, 3]) + + def test_isolates_with_holes(self): + graph = rustworkx.PyGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + graph.remove_node(2) + res = rustworkx.isolates(graph) + self.assertEqual(res, [3]) + + def test_isolates_empty_graph(self): + graph = rustworkx.PyGraph() + res = rustworkx.isolates(graph) + self.assertEqual(res, []) From c216efaa22b66214348c1faf9a5baab8b803dcfc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:35:49 -0400 Subject: [PATCH 08/12] Bump serde from 1.0.188 to 1.0.189 (#1003) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.188 to 1.0.189. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.188...v1.0.189) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be7bc5f32..05ccca190 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -648,18 +648,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", From 674044fda8bf509c00855d7f57221796d72c55cc Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Sun, 15 Oct 2023 13:22:45 -0400 Subject: [PATCH 09/12] Ramp up deprecation of retworkx package and remove tests (#1004) Since it's been > 1 year since we renamed retworkx to rustworkx, this commit starts actively emitting `DeprecationWarning`s for importing retworkx. Previously we had only documented the name as being deprecated, however we still ~54k downloads per month. The warning should hopefully encourage more people to move to the new name. While we prepare to drop support for the retworkx name in the lead up to rustworkx 1.0 eventually (see #1000) this commit also prepares us to stop publishing updates in the future. Besides removing the warning it decreases the prominence of the rename warning from the rustworkx package documentation. This commit also remove the retworkx legacy tests from the test suite as we've been running them for > 1 year now and have not enountered any issues with the import redirect. The benefits of keeping around a duplicated test suite for validating the redirects has outlived it's usefulness, and is just wasted CPU resources (both locally and more importantly in CI). As for the final step of the retworkx name, to eventually drop support for the legacy name, a comment is added to the setup.py about how we make that migration. For the final 0.X release of rustworkx we should change the `rustworkx==` pin in retworkx's setup.py to `rustworkx<1`. We do have the option to do this at anytime because the retworkx package source code is basically frozen and just redirecting imports from retworkx to rustworkx. However, if the retworkx package wasn't pinned to a fixed version then current users would potentially get a different experience when installing the same version of the retworkx package (i.e. if a user installed retworkx 0.14.0 tomorrow and then again 6 months later they could be using different rustworkx versions and encounter different API bugs or deprecation warnings). --- .github/workflows/main.yml | 41 - README.md | 8 +- docs/source/index.rst | 12 +- docs/source/install.rst | 2 +- ...retworkx-deprecation-848bc6b41f2368cf.yaml | 7 + retworkx/__init__.py | 7 + setup.py | 1 + tests/retworkx_backwards_compat/__init__.py | 0 .../digraph/__init__.py | 0 .../digraph/test_adj.py | 102 -- .../digraph/test_adjacency_matrix.py | 264 --- .../digraph/test_all_simple_paths.py | 307 ---- .../digraph/test_ancestors_descendants.py | 64 - .../digraph/test_astar.py | 114 -- .../digraph/test_avg_shortest_path.py | 169 -- .../digraph/test_bellman_ford.py | 438 ----- .../digraph/test_bfs_search.py | 162 -- .../digraph/test_cartesian_product.py | 60 - .../digraph/test_centrality.py | 162 -- .../digraph/test_collect_bicolor_runs.py | 350 ---- .../digraph/test_collect_runs.py | 138 -- .../digraph/test_complement.py | 68 - .../digraph/test_compose.py | 95 - .../digraph/test_contract_nodes.py | 265 --- .../digraph/test_copy.py | 55 - .../digraph/test_core_number.py | 96 - .../digraph/test_deepcopy.py | 48 - .../digraph/test_depth.py | 297 ---- .../digraph/test_dfs_edges.py | 31 - .../digraph/test_dfs_search.py | 106 -- .../digraph/test_dijkstra.py | 313 ---- .../digraph/test_dijkstra_search.py | 189 -- .../digraph/test_dist_matrix.py | 140 -- .../digraph/test_dot.py | 73 - .../digraph/test_edgelist.py | 213 --- .../digraph/test_edges.py | 938 ---------- .../digraph/test_find_cycle.py | 72 - .../digraph/test_floyd_warshall.py | 294 ---- .../digraph/test_graph_attrs.py | 31 - .../digraph/test_isomorphic.py | 350 ---- .../digraph/test_k_shortest_path.py | 96 - .../digraph/test_layers.py | 65 - .../digraph/test_layout.py | 477 ----- .../digraph/test_neighbors.py | 59 - .../digraph/test_nodes.py | 403 ----- .../digraph/test_num_shortest_path.py | 140 -- .../digraph/test_pred_succ.py | 385 ---- .../digraph/test_spring_layout.py | 73 - .../digraph/test_strongly_connected.py | 67 - .../digraph/test_subgraph.py | 150 -- .../digraph/test_subgraph_isomorphic.py | 266 --- .../test_substitute_node_with_subgraph.py | 163 -- .../digraph/test_symmetric.py | 39 - .../digraph/test_tensor_product.py | 110 -- .../digraph/test_to_undirected.py | 66 - .../digraph/test_toposort.py | 84 - .../digraph/test_transitivity.py | 43 - .../digraph/test_union.py | 105 -- .../digraph/test_weakly_connected.py | 81 - .../generators/__init__.py | 0 .../generators/test_barbell.py | 57 - .../generators/test_binomial_tree.py | 195 -- .../generators/test_cycle.py | 71 - .../generators/test_full_rary_tree.py | 89 - .../generators/test_grid.py | 131 -- .../generators/test_heavy_hex.py | 424 ----- .../generators/test_heavy_square.py | 503 ------ .../generators/test_hexagonal.py | 417 ----- .../generators/test_lollipop.py | 79 - .../generators/test_mesh.py | 67 - .../generators/test_path.py | 71 - .../generators/test_petersen.py | 56 - .../generators/test_star.py | 108 -- .../graph/__init__.py | 0 .../graph/test_adj.py | 32 - .../graph/test_adjencency_matrix.py | 262 --- .../graph/test_all_simple_paths.py | 245 --- .../graph/test_astar.py | 114 -- .../graph/test_avg_shortest_path.py | 89 - .../graph/test_bellman_ford.py | 308 ---- .../graph/test_bfs_search.py | 162 -- .../graph/test_biconnected.py | 138 -- .../graph/test_cartesian_product.py | 60 - .../graph/test_centrality.py | 133 -- .../graph/test_chain_decomposition.py | 89 - .../graph/test_coloring.py | 46 - .../graph/test_complement.py | 83 - .../graph/test_compose.py | 97 - .../graph/test_connected_components.py | 88 - .../graph/test_contract_nodes.py | 242 --- .../graph/test_copy.py | 55 - .../graph/test_core_number.py | 96 - .../graph/test_cycle_basis.py | 69 - .../graph/test_deepcopy.py | 50 - .../graph/test_dfs_edges.py | 31 - .../graph/test_dfs_search.py | 106 -- .../graph/test_dijkstra.py | 238 --- .../graph/test_dijkstra_search.py | 189 -- .../graph/test_dist_matrix.py | 102 -- .../graph/test_dot.py | 130 -- .../graph/test_edgelist.py | 209 --- .../graph/test_edges.py | 819 --------- .../graph/test_floyd_warshall.py | 201 --- .../graph/test_graph_attrs.py | 31 - .../graph/test_isomorphic.py | 313 ---- .../graph/test_k_shortest_path.py | 75 - .../graph/test_layout.py | 477 ----- .../graph/test_matching.py | 56 - .../graph/test_max_weight_matching.py | 569 ------ .../graph/test_mst.py | 122 -- .../graph/test_neighbors.py | 43 - .../graph/test_nodes.py | 181 -- .../graph/test_num_shortest_path.py | 138 -- .../graph/test_spring_layout.py | 73 - .../graph/test_steiner_tree.py | 188 -- .../graph/test_subgraph.py | 150 -- .../graph/test_subgraph_isomorphic.py | 296 ---- .../graph/test_tensor_product.py | 112 -- .../graph/test_to_directed.py | 79 - .../graph/test_transitivity.py | 49 - .../graph/test_union.py | 74 - .../test_converters.py | 117 -- .../test_custom_return_types.py | 1561 ----------------- .../test_dispatch.py | 111 -- .../retworkx_backwards_compat/test_graphml.py | 512 ------ .../retworkx_backwards_compat/test_random.py | 222 --- .../visualization/__init__.py | 0 .../visualization/test_graphviz.py | 152 -- .../visualization/test_mpl.py | 194 -- 129 files changed, 24 insertions(+), 21576 deletions(-) create mode 100644 releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml delete mode 100644 tests/retworkx_backwards_compat/__init__.py delete mode 100644 tests/retworkx_backwards_compat/digraph/__init__.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_adj.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_astar.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_bellman_ford.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_bfs_search.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_cartesian_product.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_centrality.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_collect_runs.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_complement.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_compose.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_contract_nodes.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_copy.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_core_number.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_deepcopy.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_depth.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_dfs_edges.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_dfs_search.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_dijkstra.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_dist_matrix.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_dot.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_edgelist.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_edges.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_find_cycle.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_graph_attrs.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_isomorphic.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_layers.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_layout.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_neighbors.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_nodes.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_pred_succ.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_spring_layout.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_strongly_connected.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_subgraph.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_symmetric.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_tensor_product.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_to_undirected.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_toposort.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_transitivity.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_union.py delete mode 100644 tests/retworkx_backwards_compat/digraph/test_weakly_connected.py delete mode 100644 tests/retworkx_backwards_compat/generators/__init__.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_barbell.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_binomial_tree.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_cycle.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_full_rary_tree.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_grid.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_heavy_hex.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_heavy_square.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_hexagonal.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_lollipop.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_mesh.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_path.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_petersen.py delete mode 100644 tests/retworkx_backwards_compat/generators/test_star.py delete mode 100644 tests/retworkx_backwards_compat/graph/__init__.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_adj.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_all_simple_paths.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_astar.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_bellman_ford.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_bfs_search.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_biconnected.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_cartesian_product.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_centrality.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_chain_decomposition.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_coloring.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_complement.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_compose.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_connected_components.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_contract_nodes.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_copy.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_core_number.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_cycle_basis.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_deepcopy.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_dfs_edges.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_dfs_search.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_dijkstra.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_dijkstra_search.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_dist_matrix.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_dot.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_edgelist.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_edges.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_floyd_warshall.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_graph_attrs.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_isomorphic.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_k_shortest_path.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_layout.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_matching.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_max_weight_matching.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_mst.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_neighbors.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_nodes.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_num_shortest_path.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_spring_layout.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_steiner_tree.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_subgraph.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_tensor_product.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_to_directed.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_transitivity.py delete mode 100644 tests/retworkx_backwards_compat/graph/test_union.py delete mode 100644 tests/retworkx_backwards_compat/test_converters.py delete mode 100644 tests/retworkx_backwards_compat/test_custom_return_types.py delete mode 100644 tests/retworkx_backwards_compat/test_dispatch.py delete mode 100644 tests/retworkx_backwards_compat/test_graphml.py delete mode 100644 tests/retworkx_backwards_compat/test_random.py delete mode 100644 tests/retworkx_backwards_compat/visualization/__init__.py delete mode 100644 tests/retworkx_backwards_compat/visualization/test_graphviz.py delete mode 100644 tests/retworkx_backwards_compat/visualization/test_mpl.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b03b7a8e7..b55878ce4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -110,47 +110,6 @@ jobs: run: python -m pip install --upgrade tox - name: 'Run rustworkx stub tests' run: tox -estubs - tests_retworkx_compat: - if: github.repository_owner == 'Qiskit' - needs: [build_lint] - name: python${{ matrix.python-version }}-${{ matrix.platform.python-architecture }} ${{ matrix.platform.os }} ${{ matrix.msrv }} - runs-on: ${{ matrix.platform.os }} - strategy: - matrix: - rust: [stable] - python-version: ["3.10"] - platform: [ - { os: "macOS-latest", python-architecture: "x64", rust-target: "x86_64-apple-darwin" }, - { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" }, - { os: "windows-latest", python-architecture: "x64", rust-target: "x86_64-pc-windows-msvc" }, - ] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.platform.python-architecture }} - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust }} - targets: ${{ matrix.platform.rust-target }} - - name: 'Install binary dependencies' - run: sudo apt-get install -y graphviz - if: runner.os == 'Linux' - - name: 'Build rustworkx and test dependencies' - run: | - pip install -c constraints.txt -U '.[mpl,graphviz]' fixtures testtools>=2.5.0 networkx>=2.5 stestr>=4.1 - - name: 'Build retworkx' - env: - RUSTWORKX_PKG_NAME: "retworkx" - run: | - pip install -c constraints.txt -U . - - name: 'Run retworkx tests' - run: | - cd tests - stestr run -t ./retworkx_backwards_compat coverage: if: github.repository_owner == 'Qiskit' needs: [tests] diff --git a/README.md b/README.md index 417e4ff29..5542b86af 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,7 @@ [![Zenodo](https://img.shields.io/badge/Zenodo-10.5281%2Fzenodo.5879859-blue)](https://doi.org/10.5281/zenodo.5879859) - You can see the full rendered docs at: - - -|:warning:| The retworkx project has been renamed to **rustworkx**. The use of the -retworkx package will still work for the time being but starting in the 1.0.0 -release retworkx will no longer be supported + rustworkx is a general purpose graph library for Python written in Rust to take advantage of the performance and safety that Rust provides. It is @@ -27,7 +23,7 @@ any Python application. Rustworkx was originally called retworkx and was created initially to be a replacement for [qiskit](https://qiskit.org/)'s previous (and current) -networkx usage (hence the original name). The project was originally started +NetworkX usage (hence the original name). The project was originally started to build a faster directed graph to use as the underlying data structure for the DAG at the center of [qiskit-terra](https://github.com/Qiskit/qiskit-terra/)'s transpiler. However, diff --git a/docs/source/index.rst b/docs/source/index.rst index 26ec65d00..6e5ac96ac 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,12 +2,6 @@ rustworkx Documentation ####################### -.. note:: - - The project has been renamed to **rustworkx**. You can still use the legacy - retworkx name for now but starting in the 1.0.0 release the retworkx name - will no longer be supported. - rustworkx is a Python package for working with graphs and complex networks. It enables the creation, interaction with, and study of graphs and networks. @@ -57,6 +51,12 @@ https://docs.rs/rustworkx-core/0.13.0/rustworkx_core/ Project history --------------- +.. note:: + + The project has been renamed to **rustworkx**. You can still use the legacy + retworkx name for now but starting in the 1.0.0 release the retworkx name + will no longer be supported. + rustworkx was originally called retworkx and was created to be a high performance replacement for the Qiskit project's internal usage of the `NetworkX `__ library (which is where the name came diff --git a/docs/source/install.rst b/docs/source/install.rst index 61c854f94..f55bcb711 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -59,7 +59,7 @@ limitations in available testing resources and platform availability, not all platforms can be supported. Platform support for rustworkx is broken into 4 tiers with different levels of support for each tier. For platforms outside these, rustworkx is probably still installable, but it’s not tested and you will -need a Rust compiler and have to build retworkx (and likely Numpy too) from +need a Rust compiler and have to build rustworkx (and likely Numpy too) from source. .. list-table:: Platform Support diff --git a/releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml b/releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml new file mode 100644 index 000000000..87d97569a --- /dev/null +++ b/releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml @@ -0,0 +1,7 @@ +--- +deprecations: + - | + The legacy ``retworkx`` package that operates as a backwards compatibility + alias for ``rustworkx`` has been marked as deprecated. If you're using + the ``retworkx`` package it will now emit a ``DeprecationWarning`` on + import. diff --git a/retworkx/__init__.py b/retworkx/__init__.py index 8113d7616..3cb4bca86 100644 --- a/retworkx/__init__.py +++ b/retworkx/__init__.py @@ -10,11 +10,18 @@ import sys +import warnings from rustworkx import * # noqa from . import namespace +warnings.warn( + "The retworkx package is deprecated and has been renamed to rustworkx. Rustworkx is a " + "drop-in replacement and can be used by replacing `import retworkx` with import `rustworkx`. ", + DeprecationWarning, + stacklevel=2, +) sys.modules["retworkx.generators"] = generators # noqa new_meta_path_finder = namespace.RetworkxImport("retworkx", "rustworkx") diff --git a/setup.py b/setup.py index e734d8be1..f9ba66454 100644 --- a/setup.py +++ b/setup.py @@ -46,6 +46,7 @@ def readme(): if PKG_NAME == "retworkx": README = retworkx_readme_compat + README PKG_PACKAGES = ["retworkx"] + # TODO: For final retworkx release change this to < 1. PKG_INSTALL_REQUIRES.append(f"rustworkx=={PKG_VERSION}") RUST_EXTENSIONS = [] diff --git a/tests/retworkx_backwards_compat/__init__.py b/tests/retworkx_backwards_compat/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/digraph/__init__.py b/tests/retworkx_backwards_compat/digraph/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/digraph/test_adj.py b/tests/retworkx_backwards_compat/digraph/test_adj.py deleted file mode 100644 index e09a00872..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_adj.py +++ /dev/null @@ -1,102 +0,0 @@ -# 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 TestAdj(unittest.TestCase): - def test_single_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.adj(node_a) - self.assertEqual({node_b: {"a": 1}, node_c: {"a": 2}}, res) - - def test_in_and_out_adj_neighbor(self): - dag = retworkx.PyDAG() - dag.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b")]) - res = dag.adj(1) - self.assertEqual({0: "a", 2: "b"}, res) - - def test_single_neighbor_dir(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.adj_direction(node_a, False) - self.assertEqual({node_b: {"a": 1}, node_c: {"a": 2}}, res) - res = dag.adj_direction(node_a, True) - self.assertEqual({}, res) - - def test_neighbor_dir_surrounded(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = dag.adj_direction(node_b, False) - self.assertEqual({node_c: {"a": 2}}, res) - res = dag.adj_direction(node_b, True) - self.assertEqual({node_a: {"a": 1}}, res) - - def test_single_neighbor_dir_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.out_edges(node_a) - self.assertEqual([(node_a, node_c, {"a": 2}), (node_a, node_b, {"a": 1})], res) - - def test_neighbor_dir_surrounded_in_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = dag.out_edges(node_b) - self.assertEqual([(node_b, node_c, {"a": 2})], res) - res = dag.in_edges(node_b) - self.assertEqual([(node_a, node_b, {"a": 1})], res) - - def test_no_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - self.assertEqual({}, dag.adj(node_a)) - - def test_in_direction(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_parent(node_a, i, None) - self.assertEqual(5, dag.in_degree(node_a)) - - def test_in_direction_none(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - self.assertEqual(0, dag.in_degree(node_a)) - - def test_out_direction(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_parent(node_a, i, None) - self.assertEqual(0, dag.out_degree(node_a)) - - def test_out_direction_none(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - self.assertEqual(5, dag.out_degree(node_a)) diff --git a/tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py b/tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py deleted file mode 100644 index e62535f56..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py +++ /dev/null @@ -1,264 +0,0 @@ -# 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 -import numpy as np - - -class TestDAGAdjacencyMatrix(unittest.TestCase): - def test_single_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_a, "c", {"a": 2}) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_no_weight_fn(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_a, "c", {"a": 2}) - res = retworkx.digraph_adjacency_matrix(dag) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_default_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_a, "c", {"a": 2}) - res = retworkx.digraph_adjacency_matrix(dag, default_weight=4) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 4.0, 4.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_float_cast_weight_func(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", 7.0) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.0], [0.0, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 7.0) - dag.add_edge(node_a, node_b, 0.5) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.5], [0.0, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func_non_zero_null(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - graph.add_edge(node_a, node_b, 0.5) - res = retworkx.adjacency_matrix(graph, lambda x: float(x), null_value=np.inf) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[np.inf, 7.5], [np.inf, np.inf]]), res)) - - def test_graph_to_digraph_adjacency_matrix(self): - graph = retworkx.PyGraph() - self.assertRaises(TypeError, retworkx.digraph_adjacency_matrix, graph) - - def test_no_edge_digraph_adjacency_matrix(self): - dag = retworkx.PyDAG() - for i in range(50): - dag.add_node(i) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: 1) - self.assertTrue(np.array_equal(np.zeros([50, 50]), res)) - - def test_digraph_with_index_holes(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - dag.add_child(node_a, "c", 1) - dag.remove_node(node_b) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0, 1], [0, 0]]), res)) - - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.float64, - ) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_array) - out_array = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(input_array, out_array)) - - def test_random_graph_full_path(self): - graph = retworkx.directed_gnp_random_graph(100, 0.95, seed=42) - adjacency_matrix = retworkx.digraph_adjacency_matrix(graph) - new_graph = retworkx.PyDiGraph.from_adjacency_matrix(adjacency_matrix) - new_adjacency_matrix = retworkx.digraph_adjacency_matrix(new_graph) - self.assertTrue(np.array_equal(adjacency_matrix, new_adjacency_matrix)) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyDiGraph.from_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyDiGraph.from_adjacency_matrix( - input_matrix.astype(np.float64, copy=False) - ) - adj_matrix = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_random_graph_float_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=float) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.float64, - ) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix, null_value=np.Inf) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array( - [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - dtype=np.float64, - ) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - def test_negative_weight(self): - input_matrix = np.array([[0, 1, 0], [-1, 0, -1], [0, 1, 0]], dtype=float) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - self.assertEqual( - [(0, 1, 1), (1, 0, -1), (1, 2, -1), (2, 1, 1)], - graph.weighted_edge_list(), - ) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.float64, - ) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix, null_value=np.nan) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.float64) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - -class TestFromComplexAdjacencyMatrix(unittest.TestCase): - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.complex128, - ) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_array) - expected = [ - (0, 1, 4 + 0j), - (1, 0, 4 + 0j), - (1, 2, 4 + 0j), - (2, 1, 4 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix( - input_matrix.astype(np.complex128, copy=False) - ) - expected = [ - (0, 1, 1 + 0j), - (1, 0, 1 + 0j), - (1, 2, 1 + 0j), - (2, 1, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_complex_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix) - expected = [ - (0, 1, 1 + 0j), - (1, 0, 1 + 0j), - (1, 2, 1 + 0j), - (2, 1, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.complex128, - ) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.Inf) - expected = [ - (0, 1, 1 + 0j), - (1, 0, 1 + 0j), - (1, 2, 1 + 0j), - (2, 1, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_negative_weight(self): - input_matrix = np.array([[0, 1, 0], [-1, 0, -1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix) - self.assertEqual( - [(0, 1, 1), (1, 0, -1), (1, 2, -1), (2, 1, 1)], - graph.weighted_edge_list(), - ) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.complex128, - ) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.nan) - edge_list = graph.weighted_edge_list() - self.assertEqual( - edge_list, - [(0, 1, 1 + 0j), (1, 0, 1 + 0j), (1, 2, 1 + 0j), (2, 1, 1 + 0j)], - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py b/tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py deleted file mode 100644 index 8d2b8e2aa..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py +++ /dev/null @@ -1,307 +0,0 @@ -# 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 TestDAGAllSimplePaths(unittest.TestCase): - def setUp(self): - super().setUp() - self.edges = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 2), - (3, 4), - (4, 2), - (4, 5), - (5, 2), - (5, 3), - ] - - def test_all_simple_paths(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5) - expected = [ - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 4, 5], - [0, 2, 3, 4, 5], - [0, 2, 4, 5], - [0, 3, 2, 4, 5], - [0, 3, 4, 5], - ] - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_min_depth(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5, min_depth=6) - expected = [ - [0, 1, 2, 3, 4, 5], - [0, 1, 3, 2, 4, 5], - ] - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5, cutoff=4) - expected = [[0, 2, 4, 5], [0, 3, 4, 5]] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5, min_depth=5, cutoff=5) - expected = [ - [0, 3, 2, 4, 5], - [0, 2, 3, 4, 5], - [0, 1, 3, 4, 5], - [0, 1, 2, 4, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_path_no_path(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - self.assertEqual([], retworkx.digraph_all_simple_paths(dag, 0, 1)) - - def test_all_simple_path_invalid_node_index(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - with self.assertRaises(retworkx.InvalidNode): - retworkx.digraph_all_simple_paths(dag, 0, 5) - - def test_graph_digraph_all_simple_paths(self): - dag = retworkx.PyGraph() - dag.add_node(0) - dag.add_node(1) - self.assertRaises(TypeError, retworkx.digraph_all_simple_paths, (dag, 0, 1)) - - -class TestDiGraphAllSimplePathsAllPairs(unittest.TestCase): - def setUp(self): - super().setUp() - self.edges = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 2), - (3, 4), - (4, 2), - (4, 5), - (5, 2), - (5, 3), - ] - - def test_all_simple_paths(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag) - expected = { - 0: { - 1: [[0, 1]], - 2: [ - [0, 3, 4, 5, 2], - [0, 3, 4, 2], - [0, 3, 2], - [0, 2], - [0, 1, 3, 4, 5, 2], - [0, 1, 3, 4, 2], - [0, 1, 3, 2], - [0, 1, 2], - ], - 3: [ - [0, 3], - [0, 2, 4, 5, 3], - [0, 2, 3], - [0, 1, 3], - [0, 1, 2, 4, 5, 3], - [0, 1, 2, 3], - ], - 4: [ - [0, 3, 4], - [0, 3, 2, 4], - [0, 2, 4], - [0, 2, 3, 4], - [0, 1, 3, 4], - [0, 1, 3, 2, 4], - [0, 1, 2, 4], - [0, 1, 2, 3, 4], - ], - 5: [ - [0, 3, 4, 5], - [0, 3, 2, 4, 5], - [0, 2, 4, 5], - [0, 2, 3, 4, 5], - [0, 1, 3, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 2, 4, 5], - [0, 1, 2, 3, 4, 5], - ], - }, - 1: { - 2: [[1, 3, 4, 5, 2], [1, 3, 4, 2], [1, 3, 2], [1, 2]], - 3: [[1, 3], [1, 2, 4, 5, 3], [1, 2, 3]], - 4: [[1, 3, 4], [1, 3, 2, 4], [1, 2, 4], [1, 2, 3, 4]], - 5: [[1, 3, 4, 5], [1, 3, 2, 4, 5], [1, 2, 4, 5], [1, 2, 3, 4, 5]], - }, - 2: { - 3: [[2, 4, 5, 3], [2, 3]], - 4: [[2, 4], [2, 3, 4]], - 5: [[2, 4, 5], [2, 3, 4, 5]], - }, - 3: { - 2: [[3, 4, 5, 2], [3, 4, 2], [3, 2]], - 4: [[3, 4], [3, 2, 4]], - 5: [[3, 4, 5], [3, 2, 4, 5]], - }, - 4: { - 2: [[4, 5, 3, 2], [4, 5, 2], [4, 2]], - 3: [[4, 5, 3], [4, 5, 2, 3], [4, 2, 3]], - 5: [[4, 5]], - }, - 5: { - 2: [[5, 3, 4, 2], [5, 3, 2], [5, 2]], - 3: [[5, 3], [5, 2, 3]], - 4: [[5, 3, 4], [5, 3, 2, 4], [5, 2, 4], [5, 2, 3, 4]], - }, - } - self.assertEqual(expected, paths) - - def test_all_simple_paths_min_depth(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag, min_depth=6) - expected = { - 0: { - 2: [[0, 1, 3, 4, 5, 2]], - 3: [[0, 1, 2, 4, 5, 3]], - 5: [[0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 4, 5]], - }, - 1: {}, - 2: {}, - 3: {}, - 4: {}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_all_simple_paths_with_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag, cutoff=4) - expected = { - 0: { - 1: [[0, 1]], - 2: [[0, 3, 4, 2], [0, 3, 2], [0, 2], [0, 1, 3, 2], [0, 1, 2]], - 3: [[0, 3], [0, 2, 3], [0, 1, 3], [0, 1, 2, 3]], - 4: [[0, 3, 4], [0, 3, 2, 4], [0, 2, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4]], - 5: [[0, 3, 4, 5], [0, 2, 4, 5]], - }, - 1: { - 2: [[1, 3, 4, 2], [1, 3, 2], [1, 2]], - 3: [[1, 3], [1, 2, 3]], - 4: [[1, 3, 4], [1, 3, 2, 4], [1, 2, 4], [1, 2, 3, 4]], - 5: [[1, 3, 4, 5], [1, 2, 4, 5]], - }, - 2: { - 3: [[2, 4, 5, 3], [2, 3]], - 4: [[2, 4], [2, 3, 4]], - 5: [[2, 4, 5], [2, 3, 4, 5]], - }, - 3: { - 2: [[3, 4, 5, 2], [3, 4, 2], [3, 2]], - 4: [[3, 4], [3, 2, 4]], - 5: [[3, 4, 5], [3, 2, 4, 5]], - }, - 4: { - 2: [[4, 5, 3, 2], [4, 5, 2], [4, 2]], - 3: [[4, 5, 3], [4, 5, 2, 3], [4, 2, 3]], - 5: [[4, 5]], - }, - 5: { - 2: [[5, 3, 4, 2], [5, 3, 2], [5, 2]], - 3: [[5, 3], [5, 2, 3]], - 4: [[5, 3, 4], [5, 3, 2, 4], [5, 2, 4], [5, 2, 3, 4]], - }, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag, min_depth=5, cutoff=5) - expected = { - 0: { - 2: [[0, 3, 4, 5, 2], [0, 1, 3, 4, 2]], - 5: [[0, 3, 2, 4, 5], [0, 2, 3, 4, 5], [0, 1, 3, 4, 5], [0, 1, 2, 4, 5]], - 3: [[0, 2, 4, 5, 3]], - 4: [[0, 1, 3, 2, 4], [0, 1, 2, 3, 4]], - }, - 1: { - 2: [[1, 3, 4, 5, 2]], - 5: [[1, 3, 2, 4, 5], [1, 2, 3, 4, 5]], - 3: [[1, 2, 4, 5, 3]], - }, - 2: {}, - 3: {}, - 4: {}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_all_simple_path_no_path(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - self.assertEqual({0: {}, 1: {}}, retworkx.all_pairs_all_simple_paths(dag)) - - def test_all_simple_paths_empty(self): - self.assertEqual({}, retworkx.all_pairs_all_simple_paths(retworkx.PyDiGraph())) diff --git a/tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py b/tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py deleted file mode 100644 index 0db8d72ac..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py +++ /dev/null @@ -1,64 +0,0 @@ -# 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 TestAncestors(unittest.TestCase): - def test_ancestors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = retworkx.ancestors(dag, node_c) - self.assertEqual({node_a, node_b}, res) - - def test_no_ancestors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - res = retworkx.ancestors(dag, node_a) - self.assertEqual(set(), res) - - def test_ancestors_no_descendants(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_b, "c", {"b": 1}) - res = retworkx.ancestors(dag, node_b) - self.assertEqual({node_a}, res) - - -class TestDescendants(unittest.TestCase): - def test_descendants(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = retworkx.descendants(dag, node_a) - self.assertEqual({node_b, node_c}, res) - - def test_no_descendants(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - res = retworkx.descendants(dag, node_a) - self.assertEqual(set(), res) - - def test_descendants_no_ancestors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"b": 1}) - res = retworkx.descendants(dag, node_b) - self.assertEqual({node_c}, res) diff --git a/tests/retworkx_backwards_compat/digraph/test_astar.py b/tests/retworkx_backwards_compat/digraph/test_astar.py deleted file mode 100644 index 7c03ea119..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_astar.py +++ /dev/null @@ -1,114 +0,0 @@ -# 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 TestAstarDigraph(unittest.TestCase): - def test_astar_null_heuristic(self): - g = retworkx.PyDAG() - a = g.add_node("A") - b = g.add_node("B") - c = g.add_node("C") - d = g.add_node("D") - e = g.add_node("E") - f = g.add_node("F") - g.add_edge(a, b, 7) - g.add_edge(c, a, 9) - g.add_edge(a, d, 14) - g.add_edge(b, c, 10) - g.add_edge(d, c, 2) - g.add_edge(d, e, 9) - g.add_edge(b, f, 15) - g.add_edge(c, f, 11) - g.add_edge(e, f, 6) - path = retworkx.digraph_astar_shortest_path( - g, a, lambda goal: goal == "E", lambda x: float(x), lambda y: 0 - ) - expected = [a, d, e] - self.assertEqual(expected, path) - - def test_astar_manhattan_heuristic(self): - g = retworkx.PyDAG() - a = g.add_node((0.0, 0.0)) - b = g.add_node((2.0, 0.0)) - c = g.add_node((1.0, 1.0)) - d = g.add_node((0.0, 2.0)) - e = g.add_node((3.0, 3.0)) - f = g.add_node((4.0, 2.0)) - no_path = g.add_node((5.0, 5.0)) # no path to node - g.add_edge(a, b, 2.0) - g.add_edge(a, d, 4.0) - g.add_edge(b, c, 1.0) - g.add_edge(b, f, 7.0) - g.add_edge(c, e, 5.0) - g.add_edge(e, f, 1.0) - g.add_edge(d, e, 1.0) - - def heuristic_func(f): - x1, x2 = f - return abs(x2 - x1) - - def finish_func(node, x): - return x == g.get_node_data(node) - - expected = [ - [0], - [0, 1], - [0, 1, 2], - [0, 3], - [0, 3, 4], - [0, 3, 4, 5], - ] - - for index, end in enumerate([a, b, c, d, e, f]): - path = retworkx.digraph_astar_shortest_path( - g, - a, - lambda finish: finish_func(end, finish), - lambda x: float(x), - heuristic_func, - ) - self.assertEqual(expected[index], path) - - with self.assertRaises(retworkx.NoPathFound): - retworkx.digraph_astar_shortest_path( - g, - a, - lambda finish: finish_func(no_path, finish), - lambda x: float(x), - heuristic_func, - ) - - def test_astar_digraph_with_graph_input(self): - g = retworkx.PyGraph() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.digraph_astar_shortest_path(g, 0, lambda x: x, lambda y: 1, lambda z: 0) - - def test_astar_with_invalid_weights(self): - g = retworkx.PyDAG() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 7) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_astar_shortest_path( - g, - a, - goal_fn=lambda goal: goal == "B", - edge_cost_fn=lambda _: invalid_weight, - estimate_cost_fn=lambda _: 0, - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py b/tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py deleted file mode 100644 index a5f04c999..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py +++ /dev/null @@ -1,169 +0,0 @@ -# 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 math -import unittest - -import retworkx - - -class TestAvgShortestPath(unittest.TestCase): - def test_simple_example(self): - # Graph is not strongly connected. - edge_list = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (3, 6), (6, 7)] - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list(edge_list) - res = retworkx.digraph_unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - def test_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(7) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(3.5, res, delta=1e-7) - - def test_path_graph(self): - # Graph is not strongly connected. - graph = retworkx.generators.directed_path_graph(5) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - def test_parallel_grid(self): - # Graph is not strongly connected. - graph = retworkx.generators.directed_grid_graph(30, 11) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - def test_empty(self): - graph = retworkx.PyDiGraph() - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node_self_edge(self): - graph = retworkx.PyDiGraph() - node = graph.add_node(0) - graph.add_edge(node, node, 0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_disconnected_graph(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_partially_connected_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - s = 15872 - den = 992 # n*(n-1), n=32 (only connected pairs considered) - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - def test_connected_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - res = retworkx.unweighted_average_shortest_path_length(graph) - s = 15872 - den = 992 # n*(n-1) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - -class TestAvgShortestPathAsUndirected(unittest.TestCase): - def test_simple_example(self): - edge_list = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (3, 6), (6, 7)] - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list(edge_list) - res = retworkx.digraph_unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(2.5714285714285716, res, delta=1e-7) - - def test_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(7) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_path_graph(self): - graph = retworkx.generators.directed_path_graph(5) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_parallel_grid(self): - graph = retworkx.generators.directed_grid_graph(30, 11) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(13.666666666666666, res, delta=1e-7) - - def test_empty(self): - graph = retworkx.PyDiGraph() - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node_self_edge(self): - graph = retworkx.PyDiGraph() - node = graph.add_node(0) - graph.add_edge(node, node, 0) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_disconnected_graph(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - res = retworkx.unweighted_average_shortest_path_length( - graph, as_undirected=True, disconnected=True - ) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_partially_connected_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - s = 8192 - den = 992 # n*(n-1), n=32 (only connected pairs considered) - res = retworkx.unweighted_average_shortest_path_length( - graph, as_undirected=True, disconnected=True - ) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - def test_connected_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - s = 8192 - den = 992 # n*(n-1) - self.assertAlmostEqual(s / den, res, delta=1e-7) diff --git a/tests/retworkx_backwards_compat/digraph/test_bellman_ford.py b/tests/retworkx_backwards_compat/digraph/test_bellman_ford.py deleted file mode 100644 index 3d5a9ef24..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_bellman_ford.py +++ /dev/null @@ -1,438 +0,0 @@ -# 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 TestBellmanFordDiGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - edge_list = [ - (self.a, self.b, 7), - (self.c, self.a, 9), - (self.a, self.d, 14), - (self.b, self.c, 10), - (self.d, self.c, 2), - (self.d, self.e, 9), - (self.b, self.f, 15), - (self.c, self.f, 11), - (self.e, self.f, 6), - ] - self.graph.add_edges_from(edge_list) - - def test_bellman_ford(self): - path = retworkx.digraph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x) - ) - expected = {1: 7.0, 2: 16.0, 3: 14.0, 4: 23.0, 5: 22.0} - self.assertEqual(expected, path) - - def test_bellman_ford_length_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path_lenghts = retworkx.digraph_bellman_ford_shortest_path_lengths(g, a, edge_cost_fn=float) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_path(self): - paths = retworkx.digraph_bellman_ford_shortest_paths(self.graph, self.a) - expected = { - # a -> b - 1: [0, 1], - # a -> c: a, d, c - 2: [0, 3, 2], - # a -> d - 3: [0, 3], - # a -> e: a, d, e - 4: [0, 3, 4], - # a -> f: a, b, f - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_path_with_weight_fn(self): - paths = retworkx.digraph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: x - ) - expected = { - 1: [0, 1], - 2: [0, 3, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_path_undirected(self): - paths = retworkx.digraph_bellman_ford_shortest_paths(self.graph, self.a, as_undirected=True) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_path_undirected_with_weight_fn(self): - paths = retworkx.digraph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: x, as_undirected=True - ) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_with_no_goal_set(self): - path = retworkx.digraph_bellman_ford_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = {1: 1.0, 2: 2.0, 3: 1.0, 4: 2.0, 5: 2.0} - self.assertEqual(expected, path) - - def test_bellman_path(self): - path = retworkx.digraph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - expected = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_path_lengths(self): - path = retworkx.digraph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - expected = retworkx.digraph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_ford_length_with_no_path_and_goal(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.digraph_bellman_ford_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = retworkx.digraph_dijkstra_shortest_path_lengths(g, a, edge_cost_fn=float, goal=b) - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_bellman_ford_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_path_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_bellman_ford_shortest_paths(g, a) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_with_disconnected_nodes(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_child(a, "B", 1.2) - g.add_node("C") - g.add_parent(b, "D", 2.4) - path = retworkx.digraph_bellman_ford_shortest_path_lengths(g, a, lambda x: x) - expected = {1: 1.2} - self.assertEqual(expected, path) - - def test_bellman_ford_with_graph_input(self): - g = retworkx.PyGraph() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.digraph_bellman_ford_shortest_path_lengths(g, 0, lambda x: x) - - def bellman_ford_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - - for as_undirected in [False, True]: - with self.subTest(as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.digraph_bellman_ford_shortest_paths( - graph, - source=0, - weight_fn=lambda _: float("nan"), - as_undirected=as_undirected, - ) - - def bellman_ford_lengths_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - - with self.assertRaises(ValueError): - retworkx.digraph_bellman_ford_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: float("nan") - ) - - def test_raises_negative_cycle_bellman_ford_paths(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_paths(graph, 0, weight_fn=float) - - def test_raises_negative_cycle_bellman_ford_path_lenghts(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_path_lengths(graph, 0, edge_cost_fn=float) - - def test_negative_edges_but_no_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, 1), - ] - ) - - result = retworkx.bellman_ford_shortest_path_lengths(graph, 0, edge_cost_fn=float) - - expected = {k: v for k, v in retworkx.floyd_warshall(graph, float)[0].items() if k != 0} - - self.assertEqual(result, expected) - - def test_negative_edge_cycle_true_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - self.assertTrue(retworkx.negative_edge_cycle(graph, float)) - - def test_negative_edge_cycle_no_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, 1), - ] - ) - - self.assertFalse(retworkx.negative_edge_cycle(graph, float)) - - def test_find_negative_cycle_true_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - cycle = retworkx.find_negative_cycle(graph, edge_cost_fn=float) - cycle_weight = 0 - - for i in range(len(cycle) - 1): - cycle_weight += graph.get_edge_data(cycle[i], cycle[i + 1]) - - self.assertTrue(cycle_weight < 0) - - def test_find_negative_cycle_self_loop_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from([(0, 1, 1), (1, 0, 1), (0, 0, -1)]) - - cycle = retworkx.find_negative_cycle(graph, edge_cost_fn=float) - cycle_weight = 0 - - for i in range(len(cycle) - 1): - cycle_weight += graph.get_edge_data(cycle[i], cycle[i + 1]) - - self.assertTrue(cycle_weight < 0) - - def test_find_negative_cycle_no_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, 1), - ] - ) - - with self.assertRaises(ValueError): - retworkx.find_negative_cycle(graph, edge_cost_fn=float) - - def test_bellman_ford_all_pair_path_lengths(self): - lengths = retworkx.digraph_all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 16.0, 3: 14.0, 4: 23.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 3: 33.0, 4: 42.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 3: 23.0, 4: 32.0, 5: 11.0}, - 3: {0: 11.0, 1: 18.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths(self): - paths = retworkx.digraph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 3, 2], 3: [0, 3], 4: [0, 3, 4], 5: [0, 1, 5]}, - 1: { - 0: [1, 2, 0], - 2: [1, 2], - 3: [1, 2, 0, 3], - 4: [1, 2, 0, 3, 4], - 5: [1, 5], - }, - 2: { - 0: [2, 0], - 1: [2, 0, 1], - 3: [2, 0, 3], - 4: [2, 0, 3, 4], - 5: [2, 5], - }, - 3: { - 0: [3, 2, 0], - 1: [3, 2, 0, 1], - 2: [3, 2], - 4: [3, 4], - 5: [3, 2, 5], - }, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_bellman_ford_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 17.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 5: 11.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 1, 2], 5: [0, 1, 5]}, - 1: {0: [1, 2, 0], 2: [1, 2], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 0, 1], 5: [2, 5]}, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_bellman_ford_path_lengths(graph, float)) - - def test_bellman_ford_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_bellman_ford_shortest_paths(graph, float)) - - def test_bellman_ford_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_bellman_ford_path_lengths(graph, float), - ) - - def test_bellman_ford_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_bellman_ford_shortest_paths(graph, float), - ) - - def test_raises_negative_cycle_all_pairs_bellman_ford_paths(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_shortest_paths(graph, float) - - def test_raises_negative_cycle_all_pairs_bellman_ford_path_lenghts(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_path_lengths(graph, float) diff --git a/tests/retworkx_backwards_compat/digraph/test_bfs_search.py b/tests/retworkx_backwards_compat/digraph/test_bfs_search.py deleted file mode 100644 index 999f8422d..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_bfs_search.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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 TestBfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_digraph_bfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3)]) - - def test_digraph_bfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_bfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3), (4, 7)]) - - def test_digraph_bfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.BFSVisitor): - - prohibited = [(0, 2), (1, 2)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.digraph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 1), (1, 3)]) - - def test_digraph_bfs_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.digraph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_digraph_bfs_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise StopIfGoalFound - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.digraph_bfs_search(self.graph, [0], vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_graph_prune_non_tree_edge(self): - class PruneNonTreeEdge(retworkx.visit.BFSVisitor): - def non_tree_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneNonTreeEdge() - retworkx.digraph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_black_target_edge(self): - class PruneBlackTargetEdge(retworkx.visit.BFSVisitor): - def black_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneBlackTargetEdge() - retworkx.digraph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_gray_target_edge(self): - class PruneGrayTargetEdge(retworkx.visit.BFSVisitor): - def gray_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneGrayTargetEdge() - retworkx.digraph_bfs_search(self.graph, [0], vis) diff --git a/tests/retworkx_backwards_compat/digraph/test_cartesian_product.py b/tests/retworkx_backwards_compat/digraph/test_cartesian_product.py deleted file mode 100644 index 9117abf6e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_cartesian_product.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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 TestCartesianProduct(unittest.TestCase): - def test_null_cartesian_null(self): - graph_1 = retworkx.PyDiGraph() - graph_2 = retworkx.PyDiGraph() - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(len(graph_product.nodes()), 0) - self.assertEqual(len(graph_product.edge_list()), 0) - - def test_directed_path_2_cartesian_path_2(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(len(graph_product.nodes()), 4) - self.assertEqual(len(graph_product.edge_list()), 4) - - def test_directed_path_2_cartesian_path_3(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(3) - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(len(graph_product.nodes()), 6) - self.assertEqual(len(graph_product.edge_list()), 7) - - def test_directed_node_weights_cartesian(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_directed_edge_weights_cartesian(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(["w_1", "w_1", "w_2", "w_2"], graph_product.edges()) diff --git a/tests/retworkx_backwards_compat/digraph/test_centrality.py b/tests/retworkx_backwards_compat/digraph/test_centrality.py deleted file mode 100644 index eadb47614..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_centrality.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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 math -import unittest - -import retworkx - - -class TestCentralityDiGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - - def test_betweenness_centrality(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.3333333333333333, - 2: 0.3333333333333333, - 3: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.25, - 1: 0.41666666666666663, - 2: 0.41666666666666663, - 3: 0.25, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 3: 0.0} - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_parallel(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph, parallel_threshold=1) - expected = { - 0: 0.0, - 1: 0.3333333333333333, - 2: 0.3333333333333333, - 3: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints_parallel(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=True, parallel_threshold=1 - ) - expected = { - 0: 0.25, - 1: 0.41666666666666663, - 2: 0.41666666666666663, - 3: 0.25, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized_parallel(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=False, normalized=False, parallel_threshold=1 - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 3: 0.0} - self.assertEqual(expected, betweenness) - - def test_closeness_centrality(self): - closeness = retworkx.digraph_closeness_centrality(self.graph) - expected = {0: 0.0, 1: 1.0 / 3.0, 2: 4.0 / 9.0, 3: 0.5} - self.assertEqual(expected, closeness) - - def test_closeness_centrality_wf_improved(self): - closeness = retworkx.digraph_closeness_centrality(self.graph, wf_improved=False) - expected = {0: 0.0, 1: 1.0, 2: 2.0 / 3.0, 3: 0.5} - self.assertEqual(expected, closeness) - - -class TestCentralityDiGraphDeletedNode(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - c0 = self.graph.add_node("C0") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - self.graph.remove_node(c0) - - def test_betweenness_centrality(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.3333333333333333, - 2: 0.3333333333333333, - 4: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.25, - 1: 0.41666666666666663, - 2: 0.41666666666666663, - 4: 0.25, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 4: 0.0} - self.assertEqual(expected, betweenness) - - -class TestEigenvectorCentrality(unittest.TestCase): - def test_complete_graph(self): - graph = retworkx.generators.directed_mesh_graph(5) - centrality = retworkx.eigenvector_centrality(graph) - expected_value = math.sqrt(1.0 / 5.0) - for value in centrality.values(): - self.assertAlmostEqual(value, expected_value) - - def test_path_graph(self): - graph = retworkx.generators.directed_path_graph(3, bidirectional=True) - centrality = retworkx.eigenvector_centrality(graph) - expected = [0.5, 0.7071, 0.5] - for k, v in centrality.items(): - self.assertAlmostEqual(v, expected[k], 4) - - def test_no_convergence(self): - graph = retworkx.PyDiGraph() - with self.assertRaises(retworkx.FailedToConverge): - retworkx.eigenvector_centrality(graph, max_iter=0) diff --git a/tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py b/tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py deleted file mode 100644 index f0f6de149..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py +++ /dev/null @@ -1,350 +0,0 @@ -# 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 TestCollectBicolorRuns(unittest.TestCase): - def test_cycle(self): - dag = retworkx.PyDiGraph() - dag.extend_from_edge_list([(0, 1), (1, 2), (2, 0)]) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.collect_bicolor_runs(dag, lambda _: True, lambda _: None) - - def test_filter_function_inner_exception(self): - dag = retworkx.PyDiGraph() - dag.add_node("a") - dag.add_child(0, "b", None) - dag.add_child(1, "c", None) - - def fail_function(node): - raise IndexError("Things fail from time to time") - - with self.assertRaises(IndexError): - retworkx.collect_bicolor_runs(dag, fail_function, lambda _: None) - - with self.assertRaises(IndexError): - retworkx.collect_bicolor_runs(dag, lambda _: True, fail_function) - - def test_empty(self): - dag = retworkx.PyDAG() - self.assertEqual( - [], - retworkx.collect_bicolor_runs(dag, lambda _: True, lambda _: None), - ) - - def test_two_colors(self): - """ - Input: - ┌─────────────┐ ┌─────────────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └───┬─────────┘ └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ q1 - │ │ │ │ - └─────────►│ cx │◄────────┘ - ┌──────────┤ ├─────────┐ - │ │ │ │ - q0 │ └─────────────┘ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ cz │◄────────┘ - ┌─────────┤ ├─────────┐ - │ └─────────────┘ │ - q0 │ │ q1 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └─────────────┘ └─────────────┘ - - Expected: [[cx, cz]] - """ - dag = retworkx.PyDAG() - q0_list = [] - q1_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - q1_list.append(dag.add_node("q1")) - - cx_gate = dag.add_node("cx") - cz_gate = dag.add_node("cz") - - dag.add_edge(q0_list[0], cx_gate, "q0") - dag.add_edge(q1_list[0], cx_gate, "q1") - dag.add_edge(cx_gate, cz_gate, "q0") - dag.add_edge(cx_gate, cz_gate, "q1") - dag.add_edge(cz_gate, q0_list[1], "q0") - dag.add_edge(cz_gate, q1_list[1], "q1") - - def filter_function(node): - if node in ["cx", "cz"]: - return True - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [["cx", "cz"]], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) - - def test_two_colors_with_pending(self): - """ - Input: - ┌─────────────┐ - │ │ - │ q0 │ - │ │ - └───┬─────────┘ - | q0 - │ - ┌───▼─────────┐ - │ │ - │ h │ - │ │ - └───┬─────────┘ - | q0 - │ ┌─────────────┐ - │ │ │ - │ │ q1 │ - │ │ │ - | └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ q1 - │ │ │ │ - └─────────►│ cx │◄────────┘ - ┌──────────┤ ├─────────┐ - │ │ │ │ - q0 │ └─────────────┘ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ cz │◄────────┘ - ┌─────────┤ ├─────────┐ - │ └─────────────┘ │ - q0 │ │ q1 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ y │ - │ │ │ │ - └─────────────┘ └─────────────┘ - | q1 - │ - ┌───▼─────────┐ - │ │ - │ q1 │ - │ │ - └─────────────┘ - - Expected: [[h, cx, cz, y]] - """ - dag = retworkx.PyDAG() - q0_list = [] - q1_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - q1_list.append(dag.add_node("q1")) - - h_gate = dag.add_node("h") - cx_gate = dag.add_node("cx") - cz_gate = dag.add_node("cz") - y_gate = dag.add_node("y") - - dag.add_edge(q0_list[0], h_gate, "q0") - dag.add_edge(h_gate, cx_gate, "q0") - dag.add_edge(q1_list[0], cx_gate, "q1") - dag.add_edge(cx_gate, cz_gate, "q0") - dag.add_edge(cx_gate, cz_gate, "q1") - dag.add_edge(cz_gate, q0_list[1], "q0") - dag.add_edge(cz_gate, y_gate, "q1") - dag.add_edge(y_gate, q1_list[1], "q1") - - def filter_function(node): - if node in ["cx", "cz", "h", "y"]: - return True - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [["h", "cx", "cz", "y"]], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) - - def test_two_colors_with_barrier(self): - """ - Input: - ┌─────────────┐ ┌─────────────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └───┬─────────┘ └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ q1 - └─────────►│ cx │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ barrier │◄────────┘ - ┌─────────┤ ├─────────┐ - │ └─────────────┘ │ - q0 │ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └────────►│ cz │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ q1 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └─────────────┘ └─────────────┘ - - Expected: [[cx], [cz]] - """ - dag = retworkx.PyDAG() - q0_list = [] - q1_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - q1_list.append(dag.add_node("q1")) - - cx_gate = dag.add_node("cx") - barrier = dag.add_node("barrier") - cz_gate = dag.add_node("cz") - - # CX - dag.add_edge(q0_list[0], cx_gate, "q0") - dag.add_edge(q1_list[0], cx_gate, "q1") - # Barrier - dag.add_edge(cx_gate, barrier, "q0") - dag.add_edge(cx_gate, barrier, "q1") - # CZ - dag.add_edge(barrier, cz_gate, "q0") - dag.add_edge(barrier, cz_gate, "q1") - dag.add_edge(cz_gate, q0_list[1], "q0") - dag.add_edge(cz_gate, q1_list[1], "q1") - - def filter_function(node): - if node in ["cx", "cz"]: - return True - elif node == "barrier": - return False - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [["cx"], ["cz"]], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) - - def test_color_with_ignored_edge(self): - """ - Input: - ┌─────────────┐ ┌─────────────┐ - │ │ │ │ - │ q0 │ │ c0 │ - │ │ │ │ - └───┬─────────┘ └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ c0 - └─────────►│ rx │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ c0 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ barrier │ │ - ┌─────────┤ │ │ - │ └─────────────┘ │ - q0 │ │ c0 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └────────►│ rz │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ c0 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ c0 │ - │ │ │ │ - └─────────────┘ └─────────────┘ - - Expected: [] - """ - dag = retworkx.PyDAG() - q0_list = [] - c0_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - c0_list.append(dag.add_node("c0")) - - rx_gate = dag.add_node("rx") - barrier = dag.add_node("barrier") - rz_gate = dag.add_node("rz") - - # RX - dag.add_edge(q0_list[0], rx_gate, "q0") - dag.add_edge(c0_list[0], rx_gate, "c0") - # Barrier - dag.add_edge(rx_gate, barrier, "q0") - # RZ - dag.add_edge(barrier, rz_gate, "q0") - dag.add_edge(rx_gate, rz_gate, "c0") - dag.add_edge(rz_gate, q0_list[1], "q0") - dag.add_edge(rz_gate, c0_list[1], "c0") - - def filter_function(node): - if node == "barrier": - return False - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_collect_runs.py b/tests/retworkx_backwards_compat/digraph/test_collect_runs.py deleted file mode 100644 index 2e8ea2006..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_collect_runs.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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 TestCollectRuns(unittest.TestCase): - def test_dagcircuit_basic(self): - dag = retworkx.PyDAG() - qr_0_in = dag.add_node("qr[0]") - qr_0_out = dag.add_node("qr[0]") - qr_1_in = dag.add_node("qr[1]") - qr_1_out = dag.add_node("qr[1]") - cr_0_in = dag.add_node("cr[0]") - cr_0_out = dag.add_node("cr[0]") - cr_1_in = dag.add_node("cr[1]") - cr_1_out = dag.add_node("cr[1]") - - h_gate = dag.add_child(qr_0_in, "h", "qr[0]") - x_gate = dag.add_child(h_gate, "x", "qr[0]") - cx_gate = dag.add_child(x_gate, "cx", "qr[0]") - dag.add_edge(qr_1_in, cx_gate, "qr[1]") - - measure_qr_1 = dag.add_child(cx_gate, "measure", "qr[1]") - dag.add_edge(cr_1_in, measure_qr_1, "cr[1]") - x_gate = dag.add_child(measure_qr_1, "x", "qr[1]") - dag.add_edge(measure_qr_1, x_gate, "cr[1]") - dag.add_edge(cr_0_in, x_gate, "cr[0]") - - measure_qr_0 = dag.add_child(cx_gate, "measure", "qr[0]") - dag.add_edge(measure_qr_0, qr_0_out, "qr[0]") - dag.add_edge(measure_qr_0, cr_0_out, "cr[0]") - dag.add_edge(x_gate, measure_qr_0, "cr[0]") - - measure_qr_1_out = dag.add_child(x_gate, "measure", "cr[1]") - dag.add_edge(x_gate, measure_qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, cr_1_out, "cr[1]") - - def filter_function(node): - return node in ["h", "x"] - - res = retworkx.collect_runs(dag, filter_function) - expected = [["h", "x"], ["x"]] - self.assertEqual(expected, res) - - def test_multiple_successor_edges(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - cx_1 = dag.add_child(q0, "cx", "q0") - dag.add_edge(q1, cx_1, "q1") - cx_2 = dag.add_child(cx_1, "cx", "q0") - dag.add_edge(q1, cx_2, "q1") - cx_3 = dag.add_child(cx_2, "cx", "q0") - dag.add_edge(q1, cx_3, "q1") - - def filter_function(node): - return node == "cx" - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["cx", "cx", "cx"]], res) - - def test_cycle(self): - dag = retworkx.PyDiGraph() - dag.extend_from_edge_list([(0, 1), (1, 2), (2, 0)]) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.collect_runs(dag, lambda _: True) - - def test_filter_function_inner_exception(self): - dag = retworkx.PyDiGraph() - dag.add_node("a") - dag.add_child(0, "b", None) - - def filter_function(node): - raise IndexError("Things fail from time to time") - - with self.assertRaises(IndexError): - retworkx.collect_runs(dag, filter_function) - - def test_empty(self): - dag = retworkx.PyDAG() - self.assertEqual([], retworkx.collect_runs(dag, lambda _: True)) - - def test_h_h_cx(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - h_1 = dag.add_child(q0, "h", "q0") - h_2 = dag.add_child(q1, "h", "q1") - cx_2 = dag.add_child(h_1, "cx", "q0") - dag.add_edge(h_2, cx_2, "q1") - - def filter_function(node): - return node in ["cx", "h"] - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["h", "cx"], ["h"]], res) - - def test_cx_h_h_cx(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - cx_1 = dag.add_child(q0, "cx", "q0") - dag.add_edge(q1, cx_1, "q1") - h_1 = dag.add_child(cx_1, "h", "q0") - h_2 = dag.add_child(cx_1, "h", "q1") - cx_2 = dag.add_child(h_1, "cx", "q0") - dag.add_edge(h_2, cx_2, "q1") - - def filter_function(node): - return node in ["cx", "h"] - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["cx"], ["h", "cx"], ["h"]], res) - - def test_cx_h_cx(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - cx_1 = dag.add_child(q0, "cx", "q0") - dag.add_edge(q1, cx_1, "q1") - h_1 = dag.add_child(cx_1, "h", "q0") - cx_2 = dag.add_child(h_1, "cx", "q0") - dag.add_edge(cx_1, cx_2, "q1") - - def filter_function(node): - return node in ["cx", "h"] - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["cx"], ["h", "cx"]], res) diff --git a/tests/retworkx_backwards_compat/digraph/test_complement.py b/tests/retworkx_backwards_compat/digraph/test_complement.py deleted file mode 100644 index ef5eccc82..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_complement.py +++ /dev/null @@ -1,68 +0,0 @@ -# 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 TestComplement(unittest.TestCase): - def test_null_graph(self): - graph = retworkx.PyDiGraph() - complement_graph = retworkx.complement(graph) - self.assertEqual(0, len(complement_graph.nodes())) - self.assertEqual(0, len(complement_graph.edges())) - - def test_clique_directed(self): - N = 5 - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i != j]) - - complement_graph = retworkx.complement(graph) - self.assertEqual(graph.nodes(), complement_graph.nodes()) - self.assertEqual(0, len(complement_graph.edges())) - - def test_empty_directed(self): - N = 5 - graph = retworkx.PyDiGraph() - graph.add_nodes_from([i for i in range(N)]) - - expected_graph = retworkx.PyDiGraph() - expected_graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i != j]) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) - - def test_complement_directed(self): - N = 8 - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [(i, j) for i in range(N) for j in range(N) if i != j and (i + j) % 3 == 0] - ) - - expected_graph = retworkx.PyDiGraph() - expected_graph.extend_from_edge_list( - [(i, j) for i in range(N) for j in range(N) if i != j and (i + j) % 3 != 0] - ) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_compose.py b/tests/retworkx_backwards_compat/digraph/test_compose.py deleted file mode 100644 index 86268dda7..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_compose.py +++ /dev/null @@ -1,95 +0,0 @@ -# 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 TestCompose(unittest.TestCase): - def test_simple_dag_composition(self): - dag = retworkx.PyDAG() - dag.check_cycle = True - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag_other = retworkx.PyDAG() - node_d = dag_other.add_node("d") - dag_other.add_child(node_d, "e", {"a": 3}) - res = dag.compose(dag_other, {node_c: (node_d, {"b": 1})}) - self.assertEqual({0: 3, 1: 4}, res) - self.assertEqual([0, 1, 2, 3, 4], retworkx.topological_sort(dag)) - - def test_compose_graph_onto_digraph_error(self): - digraph = retworkx.PyDiGraph() - graph = retworkx.PyGraph() - with self.assertRaises(TypeError): - digraph.compose(graph, {}) - - def test_edge_map_and_node_map_funcs_digraph_compose(self): - digraph = retworkx.PyDiGraph() - original_input_nodes = digraph.add_nodes_from(["qr[0]", "qr[1]"]) - original_op_nodes = digraph.add_nodes_from(["h"]) - output_nodes = digraph.add_nodes_from(["qr[0]", "qr[1]"]) - digraph.add_edge(original_input_nodes[0], original_op_nodes[0], "qr[0]") - digraph.add_edge(original_op_nodes[0], output_nodes[0], "qr[0]") - # Setup other graph - other_digraph = retworkx.PyDiGraph() - input_nodes = other_digraph.add_nodes_from(["qr[2]", "qr[3]"]) - op_nodes = other_digraph.add_nodes_from(["cx"]) - other_output_nodes = other_digraph.add_nodes_from(["qr[2]", "qr[3]"]) - other_digraph.add_edges_from( - [ - (input_nodes[0], op_nodes[0], "qr[2]"), - (input_nodes[1], op_nodes[0], "qr[3]"), - ] - ) - other_digraph.add_edges_from( - [ - (op_nodes[0], other_output_nodes[0], "qr[2]"), - (op_nodes[0], other_output_nodes[1], "qr[3]"), - ] - ) - - def map_fn(weight): - if weight == "qr[2]": - return "qr[0]" - elif weight == "qr[3]": - return "qr[1]" - else: - return weight - - digraph.remove_nodes_from(output_nodes) - other_digraph.remove_nodes_from(input_nodes) - node_map = { - original_op_nodes[0]: (op_nodes[0], "qr[0]"), - original_input_nodes[1]: (op_nodes[0], "qr[1]"), - } - res = digraph.compose(other_digraph, node_map, node_map_func=map_fn, edge_map_func=map_fn) - self.assertEqual({2: 4, 3: 3, 4: 5}, res) - self.assertEqual(digraph[res[other_output_nodes[0]]], "qr[0]") - self.assertEqual(digraph[res[other_output_nodes[1]]], "qr[1]") - # qr[0] -> h - self.assertTrue(digraph.has_edge(0, 2)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[0]"]) - # qr[1] -> cx - self.assertTrue(digraph.has_edge(1, 4)) - self.assertTrue(digraph.get_all_edge_data(1, 4), ["qr[1]"]) - # h -> cx - self.assertTrue(digraph.has_edge(2, 4)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[2] - self.assertTrue(digraph.has_edge(4, 3)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[3] - self.assertTrue(digraph.has_edge(4, 5)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[1]"]) diff --git a/tests/retworkx_backwards_compat/digraph/test_contract_nodes.py b/tests/retworkx_backwards_compat/digraph/test_contract_nodes.py deleted file mode 100644 index 8caf5580b..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_contract_nodes.py +++ /dev/null @@ -1,265 +0,0 @@ -# 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 TestContractNodesCheckCycleSwitch(unittest.TestCase): - def setUp(self): - super().setUp() - self.dag = retworkx.PyDAG() - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_child(self.node_a, "b", "b") - self.node_c = self.dag.add_child(self.node_b, "c", "c") - - self.new_weight = "m" - - def contract(self, **kwargs): - """ - ┌─┐ ┌─┐ - ┌─┤a│ ┌─────────┤m│ - │ └─┘ │ └▲┘ - ┌▼┐ ┌▼┐ │ - │b│ ───► │b├─────────┘ - └┬┘ └─┘ - │ ┌─┐ - └─►┤c│ - └─┘ - """ - self.dag.contract_nodes([self.node_a, self.node_c], self.new_weight, **kwargs) - - def test_cycle_check_enable_local(self): - # Disable at class level. - self.dag.check_cycle = False - - # Check removal is not allowed with explicit check_cycle=True. - self.assertRaises(retworkx.DAGWouldCycle, self.contract, check_cycle=True) - - def test_cycle_check_disable_local(self): - # Enable at class level. - self.dag.check_cycle = True - - # Check removal is allowed for check_cycle=False - self.contract(check_cycle=False) - self.assertEqual(set(self.dag.nodes()), {"b", "m"}) - - def test_cycle_check_inherit_class_enable(self): - # Enable at class level. - self.dag.check_cycle = True - - # Check removal is not allowed. - self.assertRaises(retworkx.DAGWouldCycle, self.contract) - - def test_cycle_check_inherit_class_disable(self): - # Disable at class level. - self.dag.check_cycle = False - - # Check removal is allowed. - self.contract() - self.assertEqual(set(self.dag.nodes()), {"b", "m"}) - - -class TestContractNodes(unittest.TestCase): - def test_empty_nodes(self): - """Replacing empty nodes is functionally equivalent to add_node.""" - dag = retworkx.PyDAG() - dag.contract_nodes([], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_unknown_nodes(self): - """ - Replacing all unknown nodes is functionally equivalent to add_node, - since unknown nodes should be ignored. - """ - dag = retworkx.PyDAG() - dag.contract_nodes([0, 1, 2], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_cycle_path_len_gt_1(self): - """ - ┌─┐ ┌─┐ - ┌4─┤a├─1┐ │m├──1───┐ - │ └─┘ │ └▲┘ │ - ┌▼┐ ┌▼┐ │ ┌▼┐ - │d│ │b│ ───► │ │b│ - └▲┘ └┬┘ │ └┬┘ - │ ┌─┐ 2 │ ┌─┐ 2 - └3─┤c│◄─┘ └3─┤c│◄─┘ - └─┘ └─┘ - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 2) - node_d = dag.add_child(node_c, "c", 3) - dag.add_edge(node_a, node_d, 4) - - with self.assertRaises(retworkx.DAGWouldCycle): - dag.contract_nodes([node_a, node_d], "m", check_cycle=True) - - # Proceed, ignoring cycles. - node_m = dag.contract_nodes([node_a, node_d], "m") - - self.assertEqual([node_b, node_c, node_m], dag.node_indexes()) - self.assertEqual( - {(node_b, node_c), (node_c, node_m), (node_m, node_b)}, - set(dag.edge_list()), - ) - - def test_multiple_paths_would_cycle(self): - """ - ┌─┐ ┌─┐ ┌─┐ ┌─┐ - ┌3─┤c│ │e├─5┐ ┌──┤c│ │e├──┐ - │ └▲┘ └▲┘ │ │ └▲┘ └▲┘ │ - ┌▼┐ 2 ┌─┐ 4 ┌▼┐ │ 2 ┌─┐ 4 │ - │d│ └──┤b├──┘ │f│ ───► │ └──┤b├──┘ │ - └─┘ └▲┘ └─┘ 3 └▲┘ 5 - 1 │ 1 │ - ┌┴┐ │ ┌┴┐ │ - │a│ └─────►│m│◄─────┘ - └─┘ └─┘ - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 2) - node_d = dag.add_child(node_c, "d", 3) - node_e = dag.add_child(node_b, "e", 4) - node_f = dag.add_child(node_e, "f", 5) - - with self.assertRaises(retworkx.DAGWouldCycle): - dag.contract_nodes([node_a, node_d, node_f], "m", check_cycle=True) - - # Proceed, ignoring cycles. - node_m = dag.contract_nodes([node_a, node_d, node_f], "m") - - self.assertEqual([node_b, node_c, node_e, node_m], dag.node_indexes()) - self.assertEqual( - { - (node_b, node_c), - (node_c, node_m), - (node_e, node_m), - (node_b, node_e), - (node_m, node_b), - }, - set(dag.edge_list()), - ) - - def test_replace_node_no_neighbors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_m = dag.contract_nodes([node_a], "m", check_cycle=True) - self.assertEqual([node_m], dag.node_indexes()) - self.assertEqual(set(), set(dag.edge_list())) - - def test_keep_edges_multigraph(self): - """ - ┌─┐ ┌─┐ - ┌─┤a│◄┐ ┌─┤a│◄┐ - │ └─┘ │ │ └─┘ │ - 1 2 ──► 1 2 - ┌▼┐ ┌┴┐ │ ┌─┐ │ - │b│ │c│ └►│m├─┘ - └─┘ └─┘ └─┘ - """ - dag = retworkx.PyDiGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_c, node_a, 2) - - with self.assertRaises(retworkx.DAGWouldCycle): - dag.contract_nodes([node_b, node_c], "m", check_cycle=True) - - # Proceed, ignoring cycles. - node_m = dag.contract_nodes([node_b, node_c], "m") - self.assertEqual([node_a, node_m], dag.node_indexes()) - self.assertEqual( - {(node_a, node_m, 1), (node_m, node_a, 2)}, - set(dag.weighted_edge_list()), - ) - - -class TestContractNodesSimpleGraph(unittest.TestCase): - def setUp(self): - super().setUp() - self.dag = retworkx.PyDAG(multigraph=False) - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_child(self.node_a, "b", 1) - self.node_c = self.dag.add_child(self.node_a, "c", 2) - self.node_d = self.dag.add_child(self.node_a, "d", 3) - self.node_e = self.dag.add_node("e") - self.dag.add_edge(self.node_b, self.node_e, 4) - self.dag.add_edge(self.node_c, self.node_e, 5) - self.dag.add_edge(self.node_d, self.node_e, 6) - - def test_collapse_parallel_edges_no_combo_fn(self): - """ - Parallel edges are collapsed arbitrarily when weight_combo_fn is None. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 1 or 2 or 3 - ┌▼┐ ┌▼┐ ┌▼┐ ┌▼┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 4 or 5 or 6 - └──►▼◄──┘ ┌▼┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes([self.node_b, self.node_c, self.node_d], "m") - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertTrue(any(e in self.dag.edges() for e in {1, 2, 3})) - self.assertTrue(any(e in self.dag.edges() for e in {4, 5, 6})) - - def test_collapse_parallel_edges(self): - """ - Parallel edges are collapsed using weight_combo_fn. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 6 - ┌▼┐ ┌▼┐ ┌▼┐ ┌▼┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 15 - └──►▼◄──┘ ┌▼┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes( - [self.node_b, self.node_c, self.node_d], - "m", - weight_combo_fn=lambda w1, w2: w1 + w2, - ) - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertEqual(set(self.dag.edges()), {6, 15}) - - def test_replace_all_nodes(self): - self.dag.contract_nodes(self.dag.node_indexes(), "m") - self.assertEqual(set(self.dag.nodes()), {"m"}) - self.assertFalse(self.dag.edges()) diff --git a/tests/retworkx_backwards_compat/digraph/test_copy.py b/tests/retworkx_backwards_compat/digraph/test_copy.py deleted file mode 100644 index 18e12b203..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_copy.py +++ /dev/null @@ -1,55 +0,0 @@ -# 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 TestCopy(unittest.TestCase): - def test_copy_returns_graph(self): - graph_a = retworkx.PyDiGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyDiGraph) - - def test_copy_with_holes_returns_graph(self): - graph_a = retworkx.PyDiGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_a.remove_node(node_b) - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyDiGraph) - self.assertEqual([node_a, node_c], graph_b.node_indexes()) - - def test_copy_empty(self): - graph = retworkx.PyDiGraph() - empty_copy = graph.copy() - self.assertEqual(len(empty_copy), 0) - - def test_copy_shared_ref(self): - graph_a = retworkx.PyDiGraph() - node_a = graph_a.add_node({"a": 1}) - node_b = graph_a.add_node({"b": 2}) - graph_a.add_edge(node_a, node_b, {"edge": 1}) - graph_b = graph_a.copy() - graph_a[0]["a"] = 42 - graph_b.get_edge_data(0, 1)["edge"] = 162 - self.assertEqual(graph_b[0]["a"], 42) - self.assertEqual(graph_a.get_edge_data(0, 1), {"edge": 162}) diff --git a/tests/retworkx_backwards_compat/digraph/test_core_number.py b/tests/retworkx_backwards_compat/digraph/test_core_number.py deleted file mode 100644 index b13a9a35b..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_core_number.py +++ /dev/null @@ -1,96 +0,0 @@ -# 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 TestCoreNumber(unittest.TestCase): - def setUp(self): - # This is the example graph in Figure 1 from Batagelj and - # Zaversnik's paper titled An O(m) Algorithm for Cores - # Decomposition of Networks, 2003, - # http://arXiv.org/abs/cs/0310049. With nodes labeled as - # shown, the 3-core is given by nodes 0-7, the 2-core by nodes - # 8-15, the 1-core by nodes 16-19 and node 20 is in the - # 0-core. - self.example_edges = [ - (0, 2), - (0, 3), - (0, 5), - (1, 4), - (1, 6), - (1, 7), - (2, 3), - (3, 5), - (2, 5), - (5, 6), - (4, 6), - (4, 7), - (6, 7), - (5, 8), - (6, 8), - (6, 9), - (8, 9), - (0, 10), - (1, 10), - (1, 11), - (10, 11), - (12, 13), - (13, 15), - (14, 15), - (12, 14), - (8, 19), - (11, 16), - (11, 17), - (12, 18), - ] - - example_core = {} - for i in range(8): - example_core[i] = 3 - for i in range(8, 16): - example_core[i] = 2 - for i in range(16, 20): - example_core[i] = 1 - example_core[20] = 0 - self.example_core = example_core - - def test_directed_empty(self): - digraph = retworkx.PyDiGraph() - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {}) - - def test_directed_all_0(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from(list(range(4))) - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 0, 1: 0, 2: 0, 3: 0}) - - def test_directed_all_3(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from(list(range(4))) - digraph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 3, 1: 3, 2: 3, 3: 3}) - - def test_directed_paper_example(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from(list(range(21))) - digraph.add_edges_from_no_data(self.example_edges) - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, self.example_core) diff --git a/tests/retworkx_backwards_compat/digraph/test_deepcopy.py b/tests/retworkx_backwards_compat/digraph/test_deepcopy.py deleted file mode 100644 index cdd41b14a..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_deepcopy.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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 copy -import unittest - -import retworkx - - -class TestDeepcopy(unittest.TestCase): - def test_isomorphic_compare_nodes_identical(self): - dag_a = retworkx.PyDAG() - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - dag_b = copy.deepcopy(dag_a) - self.assertTrue(retworkx.is_isomorphic_node_match(dag_a, dag_b, lambda x, y: x == y)) - - def test_deepcopy_with_holes(self): - dag_a = retworkx.PyDAG() - node_a = dag_a.add_node("a_1") - node_b = dag_a.add_node("a_2") - dag_a.add_edge(node_a, node_b, "edge_1") - node_c = dag_a.add_node("a_3") - dag_a.add_edge(node_b, node_c, "edge_2") - dag_a.remove_node(node_b) - dag_b = copy.deepcopy(dag_a) - self.assertIsInstance(dag_b, retworkx.PyDAG) - self.assertEqual([node_a, node_c], dag_b.node_indexes()) - - def test_deepcopy_empty(self): - dag = retworkx.PyDAG() - empty_copy = copy.deepcopy(dag) - self.assertEqual(len(empty_copy), 0) - - def test_deepcopy_attrs(self): - graph = retworkx.PyDiGraph(attrs="abc") - graph_copy = copy.deepcopy(graph) - self.assertEqual(graph.attrs, graph_copy.attrs) diff --git a/tests/retworkx_backwards_compat/digraph/test_depth.py b/tests/retworkx_backwards_compat/digraph/test_depth.py deleted file mode 100644 index 601bd5102..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_depth.py +++ /dev/null @@ -1,297 +0,0 @@ -# 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 TestLongestPath(unittest.TestCase): - def test_linear(self): - """Longest depth for a simple dag. - - a - | - b - |\ - c d - |\ - e | - | | - f g - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - dag.add_child(node_b, "d", {}) - node_e = dag.add_child(node_c, "e", {}) - node_f = dag.add_child(node_e, "f", {}) - dag.add_child(node_c, "g", {}) - self.assertEqual(4, retworkx.dag_longest_path_length(dag)) - self.assertEqual( - [node_a, node_b, node_c, node_e, node_f], - retworkx.dag_longest_path(dag), - ) - - def test_less_linear(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - node_d = dag.add_child(node_c, "d", {}) - node_e = dag.add_child(node_d, "e", {}) - dag.add_edge(node_a, node_c, {}) - dag.add_edge(node_a, node_e, {}) - dag.add_edge(node_c, node_e, {}) - self.assertEqual(4, retworkx.dag_longest_path_length(dag)) - self.assertEqual( - [node_a, node_b, node_c, node_d, node_e], - retworkx.dag_longest_path(dag), - ) - - def test_degenerate_graph(self): - dag = retworkx.PyDAG() - dag.add_node(0) - self.assertEqual(0, retworkx.dag_longest_path_length(dag)) - self.assertEqual([0], retworkx.dag_longest_path(dag)) - - def test_empty_graph(self): - dag = retworkx.PyDAG() - self.assertEqual(0, retworkx.dag_longest_path_length(dag)) - self.assertEqual([], retworkx.dag_longest_path(dag)) - - def test_parallel_edges(self): - dag = retworkx.PyDiGraph() - dag.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 3, 1), - (3, 4, 1), - (4, 5, 1), - (1, 2, 1), - (0, 1, 3), - ] - ) - self.assertEqual( - [0, 3, 4, 5], - retworkx.dag_longest_path(dag), - ) - - def test_linear_with_weight(self): - """Longest depth for a simple dag. - - a - | - b - |\ - c d - |\ - e | - | | - f g - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 4) - node_c = dag.add_child(node_b, "c", 4) - dag.add_child(node_b, "d", 5) - node_e = dag.add_child(node_c, "e", 2) - dag.add_child(node_e, "f", 2) - node_g = dag.add_child(node_c, "g", 15) - self.assertEqual( - [node_a, node_b, node_c, node_g], - retworkx.dag_longest_path(dag, lambda _, __, weight: weight), - ) - self.assertEqual( - 23, - retworkx.dag_longest_path_length(dag, lambda _, __, weight: weight), - ) - - def test_parallel_edges_with_weights(self): - dag = retworkx.PyDiGraph() - dag.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 3, 1), - (3, 4, 1), - (4, 5, 1), - (1, 2, 1), - (0, 1, 3), - ] - ) - self.assertEqual( - [0, 1, 2], - retworkx.dag_longest_path(dag, lambda _, __, weight: weight), - ) - self.assertEqual( - 4, - retworkx.dag_longest_path_length(dag, weight_fn=lambda _, __, weight: weight), - ) - - def test_less_linear_with_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 1) - node_d = dag.add_child(node_c, "d", 1) - node_e = dag.add_child(node_d, "e", 1) - dag.add_edge(node_a, node_c, 3) - dag.add_edge(node_a, node_e, 3) - dag.add_edge(node_c, node_e, 3) - self.assertEqual( - 6, - retworkx.dag_longest_path_length(dag, weight_fn=lambda _, __, weight: weight), - ) - self.assertEqual( - [node_a, node_c, node_e], - retworkx.dag_longest_path(dag, weight_fn=lambda _, __, weight: weight), - ) - - def test_degenerate_graph_with_weight(self): - dag = retworkx.PyDAG() - dag.add_node(0) - self.assertEqual([0], retworkx.dag_longest_path(dag, weight_fn=weight_fn)) - self.assertEqual(0, retworkx.dag_longest_path_length(dag, weight_fn=weight_fn)) - - def test_empty_graph_with_weights(self): - dag = retworkx.PyDAG() - self.assertEqual([], retworkx.dag_longest_path(dag, weight_fn=weight_fn)) - self.assertEqual(0, retworkx.dag_longest_path_length(dag, weight_fn=weight_fn)) - - def test_cycle(self): - not_a_dag = retworkx.generators.directed_cycle_graph(250) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_longest_path_length(not_a_dag, lambda *_: 1.0) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_longest_path(not_a_dag, lambda *_: 1.0) - - -def weight_fn(_, __, weight): - return int(weight) - - -class TestWeightedLongestPath(unittest.TestCase): - def test_linear_with_weight(self): - """Longest depth for a simple dag. - - a - | - b - |\ - c d - |\ - e | - | | - f g - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 4) - node_c = dag.add_child(node_b, "c", 4) - dag.add_child(node_b, "d", 5) - node_e = dag.add_child(node_c, "e", 2) - dag.add_child(node_e, "f", 2) - node_g = dag.add_child(node_c, "g", 15) - self.assertEqual( - 23.0, - retworkx.dag_weighted_longest_path_length(dag, lambda _, __, weight: float(weight)), - ) - self.assertEqual( - [node_a, node_b, node_c, node_g], - retworkx.dag_weighted_longest_path(dag, lambda _, __, weight: float(weight)), - ) - - def test_parallel_edges_with_weights(self): - dag = retworkx.PyDiGraph() - dag.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 3, 1), - (3, 4, 1), - (4, 5, 1), - (1, 2, 1), - (0, 1, 3), - ] - ) - self.assertEqual( - 4.0, - retworkx.dag_weighted_longest_path_length( - dag, weight_fn=lambda _, __, weight: float(weight) - ), - ) - self.assertEqual( - [0, 1, 2], - retworkx.dag_weighted_longest_path(dag, lambda _, __, weight: float(weight)), - ) - - def test_less_linear_with_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 1) - node_d = dag.add_child(node_c, "d", 1) - node_e = dag.add_child(node_d, "e", 1) - dag.add_edge(node_a, node_c, 3) - dag.add_edge(node_a, node_e, 3) - dag.add_edge(node_c, node_e, 3) - self.assertEqual( - 6.0, - retworkx.dag_weighted_longest_path_length( - dag, weight_fn=lambda _, __, weight: float(weight) - ), - ) - self.assertEqual( - [node_a, node_c, node_e], - retworkx.dag_weighted_longest_path(dag, weight_fn=lambda _, __, weight: float(weight)), - ) - - def test_degenerate_graph_with_weight(self): - dag = retworkx.PyDAG() - dag.add_node(0) - self.assertEqual( - 0.0, - retworkx.dag_weighted_longest_path_length(dag, lambda x: float(weight_fn(x))), - ) - self.assertEqual( - [0], - retworkx.dag_weighted_longest_path(dag, lambda x: float(weight_fn(x))), - ) - - def test_empty_graph_with_weights(self): - dag = retworkx.PyDAG() - self.assertEqual( - 0.0, - retworkx.dag_weighted_longest_path_length(dag, lambda x: float(weight_fn(x))), - ) - self.assertEqual( - [], - retworkx.dag_weighted_longest_path(dag, lambda x: float(weight_fn(x))), - ) - - def test_nan_not_valid_weight(self): - dag = retworkx.generators.directed_path_graph(526) - - def weight_fn(*_): - return float("nan") - - with self.assertRaises(ValueError): - retworkx.dag_weighted_longest_path_length(dag, weight_fn) - with self.assertRaises(ValueError): - retworkx.dag_weighted_longest_path(dag, weight_fn) - - def test_cycle(self): - not_a_dag = retworkx.generators.directed_cycle_graph(250) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_weighted_longest_path_length(not_a_dag, lambda *_: 1.0) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_weighted_longest_path(not_a_dag, lambda *_: 1.0) diff --git a/tests/retworkx_backwards_compat/digraph/test_dfs_edges.py b/tests/retworkx_backwards_compat/digraph/test_dfs_edges.py deleted file mode 100644 index 054e170ec..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dfs_edges.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 TestDfsEdges(unittest.TestCase): - def test_digraph_disconnected_dfs_edges(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list([(0, 1), (2, 3)]) - edges = retworkx.digraph_dfs_edges(graph) - expected = [(0, 1), (2, 3)] - self.assertEqual(expected, edges) - - def test_digraph_dfs_edges(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - edges = retworkx.digraph_dfs_edges(graph, 0) - expected = [(0, 1), (1, 2), (2, 4), (1, 3)] - self.assertEqual(expected, edges) diff --git a/tests/retworkx_backwards_compat/digraph/test_dfs_search.py b/tests/retworkx_backwards_compat/digraph/test_dfs_search.py deleted file mode 100644 index 8c099ae2e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dfs_search.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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 TestDfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_digraph_dfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (2, 1)]) - - def test_digraph_dfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_dfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (2, 1), (4, 7)]) - - def test_digraph_dfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.DFSVisitor): - - prohibited = [(0, 1), (5, 3)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.digraph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (2, 1), (1, 3)]) - - def test_digraph_dfs_goal_search(self): - class GoalSearch(retworkx.visit.DFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.digraph_dfs_search(self.graph, [0], vis) - except retworkx.visit.StopSearch: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) diff --git a/tests/retworkx_backwards_compat/digraph/test_dijkstra.py b/tests/retworkx_backwards_compat/digraph/test_dijkstra.py deleted file mode 100644 index 0d7c6d47a..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dijkstra.py +++ /dev/null @@ -1,313 +0,0 @@ -# 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 TestDijkstraDiGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - edge_list = [ - (self.a, self.b, 7), - (self.c, self.a, 9), - (self.a, self.d, 14), - (self.b, self.c, 10), - (self.d, self.c, 2), - (self.d, self.e, 9), - (self.b, self.f, 15), - (self.c, self.f, 11), - (self.e, self.f, 6), - ] - self.graph.add_edges_from(edge_list) - - def test_dijkstra(self): - path = retworkx.digraph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), self.e - ) - expected = {4: 23.0} - self.assertEqual(expected, path) - - def test_dijkstra_length_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.digraph_dijkstra_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_dijkstra_path(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a) - expected = { - # a -> b - 1: [0, 1], - # a -> c: a, d, c - 2: [0, 3, 2], - # a -> d - 3: [0, 3], - # a -> e: a, d, e - 4: [0, 3, 4], - # a -> f: a, b, f - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_with_weight_fn(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a, weight_fn=lambda x: x) - expected = { - 1: [0, 1], - 2: [0, 3, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_with_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a, target=self.e) - expected = { - 4: [0, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_with_weight_fn_and_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, target=self.e, weight_fn=lambda x: x - ) - expected = { - 4: [0, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a, as_undirected=True) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected_with_weight_fn(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: x, as_undirected=True - ) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected_with_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, target=self.e, as_undirected=True - ) - expected = { - 4: [0, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected_with_weight_fn_and_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, - self.a, - target=self.e, - weight_fn=lambda x: x, - as_undirected=True, - ) - expected = { - 4: [0, 2, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_with_no_goal_set(self): - path = retworkx.digraph_dijkstra_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = {1: 1.0, 2: 2.0, 3: 1.0, 4: 2.0, 5: 2.0} - self.assertEqual(expected, path) - - def test_dijkstra_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_dijkstra_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_path_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_dijkstra_shortest_paths(g, a) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_with_disconnected_nodes(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_child(a, "B", 1.2) - g.add_node("C") - g.add_parent(b, "D", 2.4) - path = retworkx.digraph_dijkstra_shortest_path_lengths(g, a, lambda x: x) - expected = {1: 1.2} - self.assertEqual(expected, path) - - def test_dijkstra_with_graph_input(self): - g = retworkx.PyGraph() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.digraph_dijkstra_shortest_path_lengths(g, 0, lambda x: x) - - def test_dijkstra_all_pair_path_lengths(self): - lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 16.0, 3: 14.0, 4: 23.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 3: 33.0, 4: 42.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 3: 23.0, 4: 32.0, 5: 11.0}, - 3: {0: 11.0, 1: 18.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths(self): - paths = retworkx.digraph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 3, 2], 3: [0, 3], 4: [0, 3, 4], 5: [0, 1, 5]}, - 1: { - 0: [1, 2, 0], - 2: [1, 2], - 3: [1, 2, 0, 3], - 4: [1, 2, 0, 3, 4], - 5: [1, 5], - }, - 2: { - 0: [2, 0], - 1: [2, 0, 1], - 3: [2, 0, 3], - 4: [2, 0, 3, 4], - 5: [2, 5], - }, - 3: { - 0: [3, 2, 0], - 1: [3, 2, 0, 1], - 2: [3, 2], - 4: [3, 4], - 5: [3, 2, 5], - }, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_dijkstra_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 17.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 5: 11.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 1, 2], 5: [0, 1, 5]}, - 1: {0: [1, 2, 0], 2: [1, 2], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 0, 1], 5: [2, 5]}, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float)) - - def test_dijkstra_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_dijkstra_shortest_paths(graph, float)) - - def test_dijkstra_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float), - ) - - def test_dijkstra_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_dijkstra_shortest_paths(graph, float), - ) - - def dijkstra_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - for as_undirected in [False, True]: - with self.subTest(invalid_weight=invalid_weight, as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.digraph_dijkstra_shortest_paths( - graph, - source=0, - weight_fn=lambda _: invalid_weight, - as_undirected=as_undirected, - ) - - def dijkstra_lengths_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_dijkstra_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_all_pairs_dijkstra_shortest_paths( - graph, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_lenghts_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_all_pairs_dijkstra_path_lengths( - graph, edge_cost_fn=lambda _: invalid_weight - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py b/tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py deleted file mode 100644 index 9cd8e6d0e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py +++ /dev/null @@ -1,189 +0,0 @@ -# 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 TestDijkstraSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 2, 2), - (1, 3, 10), - (2, 1, 1), - (2, 5, 1), - (2, 6, 1), - (5, 3, 1), - (4, 7, 1), - ] - ) - - def test_digraph_dijkstra_tree_edges(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3)]) - - def test_digraph_dijkstra_tree_edges_no_starting_point(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.digraph_dijkstra_search(self.graph, None, float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3), (4, 7)]) - - def test_digraph_dijkstra_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_digraph_dijkstra_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise StopIfGoalFound - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_digraph_dijkstra_goal_search_with_prohibited_edges(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - prohibited = [(5, 3)] - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def examine_edge(self, edge): - u, v, _ = edge - if (u, v) in self.prohibited: - raise retworkx.visit.PruneSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - self.assertEqual(vis.opt_goal_cost, 11.0) - - def test_digraph_prune_edge_not_relaxed(self): - class PruneEdgeNotRelaxed(retworkx.visit.DijkstraVisitor): - def edge_not_relaxed(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneEdgeNotRelaxed() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) diff --git a/tests/retworkx_backwards_compat/digraph/test_dist_matrix.py b/tests/retworkx_backwards_compat/digraph/test_dist_matrix.py deleted file mode 100644 index 05459c4f2..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dist_matrix.py +++ /dev/null @@ -1,140 +0,0 @@ -# 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 numpy as np - -import retworkx - - -class TestDistanceMatrix(unittest.TestCase): - def test_digraph_distance_matrix(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1.0], - [0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0], - [0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0], - [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_parallel(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph, parallel_threshold=5) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1.0], - [0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0], - [0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0], - [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph, as_undirected=True) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_parallel_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph, parallel_threshold=5, as_undirected=True) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_non_zero_null(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.distance_matrix(graph, as_undirected=True, null_value=np.nan) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_digraph_distance_matrix_parallel_non_zero_null(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.distance_matrix( - graph, as_undirected=True, parallel_threshold=5, null_value=np.nan - ) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_digraph_distance_matrix_node_hole(self): - graph = retworkx.generators.directed_path_graph(4) - graph.remove_node(0) - dist = retworkx.digraph_distance_matrix(graph) - expected = np.array([[0.0, 1.0, 2.0], [0.0, 0.0, 1.0], [0.0, 0.0, 0.0]]) - self.assertTrue(np.array_equal(dist, expected)) diff --git a/tests/retworkx_backwards_compat/digraph/test_dot.py b/tests/retworkx_backwards_compat/digraph/test_dot.py deleted file mode 100644 index fb2211c43..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dot.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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 os -import tempfile -import unittest - -import retworkx - - -class TestDot(unittest.TestCase): - def setUp(self): - fd, self.path = tempfile.mkstemp() - os.close(fd) - os.remove(self.path) - - def test_digraph_to_dot_to_file(self): - graph = retworkx.PyDiGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'digraph {\n0 [color=black, fillcolor=green, label="a", ' - 'style=filled];\n1 [color=black, fillcolor=red, label="a", ' - 'style=filled];\n0 -> 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) - self.addCleanup(os.remove, self.path) - self.assertIsNone(res) - with open(self.path, "r") as fd: - res = fd.read() - self.assertEqual(expected, res) - - def test_digraph_empty_dicts(self): - graph = retworkx.directed_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}) - self.assertEqual("digraph {\n0 ;\n1 ;\n2 ;\n0 -> 1 ;\n0 -> 2 ;\n}\n", dot_str) - - def test_digraph_graph_attrs(self): - graph = retworkx.directed_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}, {"bgcolor": "red"}) - self.assertEqual( - "digraph {\nbgcolor=red ;\n0 ;\n1 ;\n2 ;\n0 -> 1 ;\n" "0 -> 2 ;\n}\n", - dot_str, - ) - - def test_digraph_no_args(self): - graph = retworkx.directed_gnp_random_graph(3, 0.95, seed=24) - dot_str = graph.to_dot() - self.assertEqual("digraph {\n0 ;\n1 ;\n2 ;\n0 -> 1 ;\n0 -> 2 ;\n}\n", dot_str) diff --git a/tests/retworkx_backwards_compat/digraph/test_edgelist.py b/tests/retworkx_backwards_compat/digraph/test_edgelist.py deleted file mode 100644 index 45ae47091..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_edgelist.py +++ /dev/null @@ -1,213 +0,0 @@ -# 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 os -import tempfile -import unittest - -import retworkx - - -class TestEdgeList(unittest.TestCase): - def test_empty_edge_list_digraph(self): - with tempfile.NamedTemporaryFile() as fd: - graph = retworkx.PyDiGraph.read_edge_list(fd.name) - self.assertEqual(graph.nodes(), []) - - def test_invalid_path_digraph(self): - path = os.path.join(tempfile.gettempdir(), "fake_file_name.txt") - with self.assertRaises(FileNotFoundError): - retworkx.PyDiGraph.read_edge_list(path) - - def test_simple_example_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_blank_line_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 // test a comment\n") - fd.write("1 2\n") - fd.write("//2 3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_leading_space_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 // test a comment\n") - fd.write("1 2\n") - fd.write(" //2 3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_weight_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 0// test a comment\n") - fd.write("1 2 1\n") - fd.write("//2 3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_delim_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0|1|0// test a comment\n") - fd.write("1|2|1\n") - fd.write("//2|3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//", deliminator="|") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("//c|d\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_digraph_target_existing(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("a|c\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertTrue(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1", None]) - - def test_write_edge_list_empty_digraph(self): - path = os.path.join(tempfile.gettempdir(), "empty.txt") - graph = retworkx.PyDiGraph() - graph.write_edge_list(path) - self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: - self.assertEqual("", edge_file.read()) - - def test_write_edge_list_round_trip(self): - path = os.path.join(tempfile.gettempdir(), "round_trip.txt") - graph = retworkx.generators.directed_star_graph(5) - count = iter(range(5)) - - def weight_fn(edge): - return str(next(count)) - - graph.write_edge_list(path, weight_fn=weight_fn) - self.addCleanup(os.remove, path) - new_graph = retworkx.PyDiGraph.read_edge_list(path) - expected = [ - (0, 1, "0"), - (0, 2, "1"), - (0, 3, "2"), - (0, 4, "3"), - ] - self.assertEqual(expected, new_graph.weighted_edge_list()) - - def test_custom_delim(self): - path = os.path.join(tempfile.gettempdir(), "custom_delim.txt") - graph = retworkx.generators.directed_path_graph(5) - graph.write_edge_list(path, deliminator=",") - self.addCleanup(os.remove, path) - expected = """0,1 -1,2 -2,3 -3,4 -""" - with open(path, "rt") as edge_file: - self.assertEqual(edge_file.read(), expected) - - def test_invalid_return_type_weight_fn(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.directed_gnm_random_graph(5, 4) - self.addCleanup(cleanup_file, path) - with self.assertRaises(TypeError): - graph.write_edge_list(path, weight_fn=lambda _: 4.5) - - def test_weight_fn_raises(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.directed_gnm_random_graph(5, 4) - - def weight_fn(edge): - raise KeyError - - self.addCleanup(cleanup_file, path) - with self.assertRaises(KeyError): - graph.write_edge_list(path, weight_fn=weight_fn) - - -def cleanup_file(path): - try: - os.remove(path) - except Exception: - pass diff --git a/tests/retworkx_backwards_compat/digraph/test_edges.py b/tests/retworkx_backwards_compat/digraph/test_edges.py deleted file mode 100644 index 1552b3d50..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_edges.py +++ /dev/null @@ -1,938 +0,0 @@ -# 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 TestEdges(unittest.TestCase): - def test_get_edge_data(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - res = dag.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_a, node_b, "b") - res = dag.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertIn("Edgy", res) - - def test_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, dag.get_edge_data, node_a, node_b) - - def test_num_edges(self): - graph = retworkx.PyDiGraph() - graph.add_node(1) - graph.add_node(42) - graph.add_node(146) - graph.add_edges_from_no_data([(0, 1), (1, 2)]) - self.assertEqual(2, graph.num_edges()) - - def test_num_edges_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_node(1) - graph.add_node(42) - self.assertEqual(0, graph.num_edges()) - - def test_update_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "not edgy") - dag.update_edge(node_a, node_b, "Edgy") - self.assertEqual([(0, 1, "Edgy")], dag.weighted_edge_list()) - - def test_update_edge_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, dag.update_edge, node_a, node_b, None) - - def test_update_edge_by_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "not edgy") - dag.update_edge_by_index(0, "Edgy") - self.assertEqual([(0, 1, "Edgy")], dag.weighted_edge_list()) - - def test_update_edge_invalid_index(self): - dag = retworkx.PyDAG() - dag.add_node("a") - dag.add_node("b") - self.assertRaises(IndexError, dag.update_edge_by_index, 0, None) - - def test_update_edge_parallel_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "not edgy") - edge_index = graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge_by_index(edge_index, "Edgy") - self.assertEqual( - [(0, 1, "not edgy"), (0, 1, "Edgy")], - list(graph.weighted_edge_list()), - ) - - def test_has_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - self.assertTrue(dag.has_edge(node_a, node_b)) - - def test_has_edge_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertFalse(dag.has_edge(node_a, node_b)) - - def test_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], dag.edges()) - - def test_edges_empty(self): - dag = retworkx.PyDAG() - dag.add_node("a") - self.assertEqual([], dag.edges()) - - def test_edge_indices(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Super edgy") - self.assertEqual([0, 1], dag.edge_indices()) - - def test_edge_indices_empty(self): - dag = retworkx.PyDAG() - dag.add_node("a") - self.assertEqual([], dag.edge_indices()) - - def test_add_duplicates(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "a", "a") - dag.add_edge(node_a, node_b, "b") - self.assertEqual(["a", "b"], dag.edges()) - - def test_remove_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, dag.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "edgy") - dag.remove_edge(node_a, node_b) - self.assertEqual([], dag.edges()) - - def test_remove_multiple(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "edgy") - dag.add_edge(node_a, node_b, "super_edgy") - dag.remove_edge_from_index(0) - self.assertEqual(["super_edgy"], dag.edges()) - - def test_remove_edges_from(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - graph.remove_edges_from([(node_a, node_b), (node_a, node_c)]) - self.assertEqual([], graph.edges()) - - def test_remove_edges_from_invalid(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - with self.assertRaises(retworkx.NoEdgeBetweenNodes): - graph.remove_edges_from([(node_b, node_c), (node_a, node_c)]) - - def test_remove_edge_from_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "edgy") - dag.remove_edge_from_index(0) - self.assertEqual([], dag.edges()) - - def test_remove_edge_no_edge(self): - dag = retworkx.PyDAG() - dag.add_node("a") - dag.remove_edge_from_index(0) - self.assertEqual([], dag.edges()) - - def test_add_cycle(self): - dag = retworkx.PyDAG() - dag.check_cycle = True - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - self.assertRaises(retworkx.DAGWouldCycle, dag.add_edge, node_b, node_a, {}) - - def test_add_edge_with_cycle_check_enabled(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_c = dag.add_node("c") - node_b = dag.add_child(node_a, "b", {}) - dag.add_edge(node_c, node_b, {}) - self.assertTrue(dag.has_edge(node_c, node_b)) - - def test_enable_cycle_checking_after_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - dag.add_edge(node_b, node_a, {}) - with self.assertRaises(retworkx.DAGHasCycle): - dag.check_cycle = True - - def test_cycle_checking_at_init(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.add_edge(node_b, node_a, {}) - - def test_find_adjacent_node_by_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"weights": [1, 2]}) - dag.add_child(node_a, "c", {"weights": [3, 4]}) - - def compare_edges(edge): - return 4 in edge["weights"] - - res = dag.find_adjacent_node_by_edge(node_a, compare_edges) - self.assertEqual("c", res) - - def test_find_adjacent_node_by_edge_no_match(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"weights": [1, 2]}) - dag.add_child(node_a, "c", {"weights": [3, 4]}) - - def compare_edges(edge): - return 5 in edge["weights"] - - with self.assertRaises(retworkx.NoSuitableNeighbors): - dag.find_adjacent_node_by_edge(node_a, compare_edges) - - def test_add_edge_from(self): - dag = retworkx.PyDAG() - nodes = list(range(4)) - dag.add_nodes_from(nodes) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - res = dag.add_edges_from(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual(["a", "b", "c", "d", "e"], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_add_edge_from_empty(self): - dag = retworkx.PyDAG() - res = dag.add_edges_from([]) - self.assertEqual([], res) - - def test_cycle_checking_at_init_nodes_from(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.add_edges_from([(node_a, node_c, {}), (node_c, node_b, {})]) - - def test_is_directed_acyclic_graph(self): - dag = retworkx.generators.directed_path_graph(1000) - res = retworkx.is_directed_acyclic_graph(dag) - self.assertTrue(res) - - def test_is_directed_acyclic_graph_false(self): - digraph = retworkx.generators.directed_cycle_graph(1000) - self.assertFalse(retworkx.is_directed_acyclic_graph(digraph)) - - def test_add_edge_from_no_data(self): - dag = retworkx.PyDAG() - nodes = list(range(4)) - dag.add_nodes_from(nodes) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - res = dag.add_edges_from_no_data(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual([None, None, None, None, None], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_add_edge_from_empty_no_data(self): - dag = retworkx.PyDAG() - res = dag.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_cycle_checking_at_init_nodes_from_no_data(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.add_edges_from_no_data([(node_a, node_c), (node_c, node_b)]) - - def test_edge_list(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.add_edges_from(edge_list) - self.assertEqual([(x[0], x[1]) for x in edge_list], dag.edge_list()) - - def test_edge_list_empty(self): - dag = retworkx.PyDiGraph() - self.assertEqual([], dag.edge_list()) - - def test_weighted_edge_list(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.add_edges_from(edge_list) - self.assertEqual(edge_list, dag.weighted_edge_list()) - - def test_weighted_edge_list_empty(self): - dag = retworkx.PyDiGraph() - self.assertEqual([], dag.weighted_edge_list()) - - def test_extend_from_edge_list(self): - dag = retworkx.PyDAG() - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - dag.extend_from_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual([None] * 5, dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_extend_from_edge_list_empty(self): - dag = retworkx.PyDAG() - dag.extend_from_edge_list([]) - self.assertEqual(0, len(dag)) - - def test_cycle_checking_at_init_extend_from_weighted_edge_list(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.extend_from_weighted_edge_list([(node_a, node_c, {}), (node_c, node_b, {})]) - - def test_extend_from_edge_list_nodes_exist(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - dag.extend_from_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual([None] * 5, dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_extend_from_weighted_edge_list(self): - dag = retworkx.PyDAG() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual(["a", "b", "c", "d", "e"], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_extend_from_weighted_edge_list_empty(self): - dag = retworkx.PyDAG() - dag.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(dag)) - - def test_cycle_checking_at_init_nodes_extend_from_edge_list(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.extend_from_edge_list([(node_a, node_c), (node_c, node_b)]) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual(["a", "b", "c", "d", "e"], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_insert_node_on_in_edges(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - graph.insert_node_on_in_edges(h_gate, out_node) - self.assertEqual( - [(in_node, h_gate, "qr[0]"), (h_gate, out_node, "qr[0]")], - graph.weighted_edge_list(), - ) - - def test_insert_node_on_in_edges_multiple(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - graph.insert_node_on_in_edges_multiple(cx_gate, [out_node_0, out_node_1]) - self.assertEqual( - { - (in_node_0, cx_gate, "qr[0]"), - (cx_gate, out_node_0, "qr[0]"), - (in_node_1, cx_gate, "qr[1]"), - (cx_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_in_edges_double(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - z_gate = graph.add_node("z") - graph.insert_node_on_in_edges(h_gate, out_node) - graph.insert_node_on_in_edges(z_gate, out_node) - self.assertEqual( - { - (in_node, h_gate, "qr[0]"), - (h_gate, z_gate, "qr[0]"), - (z_gate, out_node, "qr[0]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_in_edges_multiple_double(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - cz_gate = graph.add_node("cz") - graph.insert_node_on_in_edges_multiple(cx_gate, [out_node_0, out_node_1]) - graph.insert_node_on_in_edges_multiple(cz_gate, [out_node_0, out_node_1]) - self.assertEqual( - { - (in_node_0, cx_gate, "qr[0]"), - (cx_gate, cz_gate, "qr[0]"), - (in_node_1, cx_gate, "qr[1]"), - (cx_gate, cz_gate, "qr[1]"), - (cz_gate, out_node_0, "qr[0]"), - (cz_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - graph.insert_node_on_out_edges(h_gate, in_node) - self.assertEqual( - {(in_node, h_gate, "qr[0]"), (h_gate, out_node, "qr[0]")}, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges_multiple(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - graph.insert_node_on_out_edges_multiple(cx_gate, [in_node_0, in_node_1]) - self.assertEqual( - { - (in_node_0, cx_gate, "qr[0]"), - (cx_gate, out_node_0, "qr[0]"), - (in_node_1, cx_gate, "qr[1]"), - (cx_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges_double(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - z_gate = graph.add_node("z") - graph.insert_node_on_out_edges(h_gate, in_node) - graph.insert_node_on_out_edges(z_gate, in_node) - self.assertEqual( - { - (in_node, z_gate, "qr[0]"), - (z_gate, h_gate, "qr[0]"), - (h_gate, out_node, "qr[0]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges_multiple_double(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - cz_gate = graph.add_node("cz") - graph.insert_node_on_out_edges_multiple(cx_gate, [in_node_0, in_node_1]) - graph.insert_node_on_out_edges_multiple(cz_gate, [in_node_0, in_node_1]) - self.assertEqual( - { - (in_node_0, cz_gate, "qr[0]"), - (cz_gate, cx_gate, "qr[0]"), - (in_node_1, cz_gate, "qr[1]"), - (cz_gate, cx_gate, "qr[1]"), - (cx_gate, out_node_0, "qr[0]"), - (cx_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_in_edges_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_in_edges(node_b, node_a) - self.assertEqual([], graph.edge_list()) - - def test_insert_node_on_in_edges_multiple_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_in_edges_multiple(node_b, [node_a]) - self.assertEqual([], graph.edge_list()) - - def test_insert_node_on_out_edges_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_out_edges(node_b, node_a) - self.assertEqual([], graph.edge_list()) - - def test_insert_node_on_out_edges_multiple_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_out_edges_multiple(node_b, [node_a]) - self.assertEqual([], graph.edge_list()) - - def test_edge_index_map(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_child(node_a, "c", "edge a") - node_d = graph.add_parent(node_b, "d", "edge_b") - graph.add_edge(node_c, node_d, "edge c") - self.assertEqual( - { - 0: (node_a, node_c, "edge a"), - 1: (node_d, node_b, "edge_b"), - 2: (node_c, node_d, "edge c"), - }, - graph.edge_index_map(), - ) - - def test_edge_index_map_empty(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, graph.edge_index_map()) - - def test_has_parallel_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(0, 1, 0) - self.assertTrue(graph.has_parallel_edges()) - - def test_has_parallel_edges_no_parallel_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - self.assertFalse(graph.has_parallel_edges()) - - def test_has_parallel_edges_empty(self): - graph = retworkx.PyDiGraph() - self.assertFalse(graph.has_parallel_edges()) - - def test_get_edge_data_by_index(self): - graph = retworkx.PyDiGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_data_by_index(2) - self.assertEqual("c", res) - - def test_get_edge_data_by_index_invalid_index(self): - graph = retworkx.PyDiGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_data_by_index(2) - - def test_get_edge_endpoints_by_index(self): - graph = retworkx.PyDiGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_endpoints_by_index(2) - self.assertEqual((0, 2), res) - - def test_get_edge_endpoints_by_index_invalid_index(self): - graph = retworkx.PyDiGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_endpoints_by_index(2) - - def test_incident_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edges(node_d) - self.assertEqual([2], res) - - def test_incident_edges_invalid_node(self): - graph = retworkx.PyDiGraph() - res = graph.incident_edges(42) - self.assertEqual([], res) - - def test_incident_edges_all_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edges(node_d, all_edges=True) - self.assertEqual([2, 1], res) - - def test_incident_edge_index_map(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edge_index_map(node_d) - self.assertEqual({2: (3, 2, "edge c")}, res) - - def test_incident_edge_index_map_invalid_node(self): - graph = retworkx.PyDiGraph() - res = graph.incident_edge_index_map(42) - self.assertEqual([], res) - - def test_incident_edge_index_map_all_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edge_index_map(node_d, all_edges=True) - self.assertEqual({2: (3, 2, "edge c"), 1: (1, 3, "edge_b")}, res) - - -class TestEdgesMultigraphFalse(unittest.TestCase): - def test_multigraph_attr(self): - graph = retworkx.PyDiGraph(multigraph=False) - self.assertFalse(graph.multigraph) - - def test_has_parallel_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(0, 1, 0) - self.assertFalse(graph.has_parallel_edges()) - - def test_get_edge_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - res = graph.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph.add_edge(node_a, node_b, "b") - res = graph.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertNotIn("Edgy", res) - - def test_no_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_edge_data, node_a, node_b) - - def test_no_edge_get_all_edge_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_all_edge_data, node_a, node_b) - - def test_has_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {}) - self.assertTrue(graph.has_edge(node_a, node_b)) - - def test_has_edge_no_edge(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertFalse(graph.has_edge(node_a, node_b)) - - def test_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], graph.edges()) - - def test_edges_empty(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_node("a") - self.assertEqual([], graph.edges()) - - def test_add_duplicates(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "a") - graph.add_edge(node_a, node_b, "b") - self.assertEqual(["b"], graph.edges()) - - def test_remove_no_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge(node_a, node_b) - self.assertEqual([], graph.edges()) - - def test_remove_multiple(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_b, "super_edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_from_index(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_no_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_node("a") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_add_edge_from_empty(self): - graph = retworkx.PyDiGraph(multigraph=False) - res = graph.add_edges_from([]) - self.assertEqual([], res) - - def test_add_edge_from_empty_no_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - res = graph.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_add_edges_from_parallel_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from([(0, 1, False), (0, 1, True)]) - self.assertEqual([0, 0], res) - self.assertEqual([True], graph.edges()) - - def test_add_edges_from_no_data_parallel_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from_no_data([(0, 1), (0, 1)]) - self.assertEqual([0, 0], res) - self.assertEqual([None], graph.edges()) - - def test_extend_from_weighted_edge_list_empty(self): - graph = retworkx.PyDiGraph() - graph.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_weighted_edge_list_edges_exist(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - (0, 1, "not_a"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["not_a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_edge_list(self): - graph = retworkx.PyDiGraph(multigraph=False) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_edge_list_empty(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.extend_from_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_edge_list_existing_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3), (0, 1)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_weighted_edge_list(self): - graph = retworkx.PyDiGraph(multigraph=False) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) diff --git a/tests/retworkx_backwards_compat/digraph/test_find_cycle.py b/tests/retworkx_backwards_compat/digraph/test_find_cycle.py deleted file mode 100644 index 6ecdf77e3..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_find_cycle.py +++ /dev/null @@ -1,72 +0,0 @@ -# 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 TestFindCycle(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.add_nodes_from(list(range(10))) - self.graph.add_edges_from_no_data( - [ - (0, 1), - (3, 0), - (0, 5), - (8, 0), - (1, 2), - (1, 6), - (2, 3), - (3, 4), - (4, 5), - (6, 7), - (7, 8), - (8, 9), - ] - ) - - def test_find_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(6))) - graph.add_edges_from_no_data( - [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5), (4, 0)] - ) - res = retworkx.digraph_find_cycle(graph, 0) - self.assertEqual([(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)], res) - - def test_find_cycle_multiple_roots_same_cycles(self): - res = retworkx.digraph_find_cycle(self.graph, 0) - self.assertEqual(res, [(0, 1), (1, 2), (2, 3), (3, 0)]) - res = retworkx.digraph_find_cycle(self.graph, 1) - self.assertEqual(res, [(1, 2), (2, 3), (3, 0), (0, 1)]) - res = retworkx.digraph_find_cycle(self.graph, 5) - self.assertEqual(res, []) - - def test_find_cycle_disconnected_graphs(self): - self.graph.add_nodes_from(["A", "B", "C"]) - self.graph.add_edges_from_no_data([(10, 11), (12, 10), (11, 12)]) - res = retworkx.digraph_find_cycle(self.graph, 0) - self.assertEqual(res, [(0, 1), (1, 2), (2, 3), (3, 0)]) - res = retworkx.digraph_find_cycle(self.graph, 10) - self.assertEqual(res, [(10, 11), (11, 12), (12, 10)]) - - def test_invalid_types(self): - graph = retworkx.PyGraph() - with self.assertRaises(TypeError): - retworkx.digraph_find_cycle(graph) - - def test_self_loop(self): - self.graph.add_edge(1, 1, None) - res = retworkx.digraph_find_cycle(self.graph, 0) - self.assertEqual([(1, 1)], res) diff --git a/tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py b/tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py deleted file mode 100644 index 1643eb5dc..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py +++ /dev/null @@ -1,294 +0,0 @@ -# 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 numpy - -import retworkx - - -class TestFloydWarshall(unittest.TestCase): - parallel_threshold = 300 - - def test_floyd_warshall(self): - """Test the algorithm on a 5q x 4 depth circuit.""" - dag = retworkx.PyDAG() - # inputs - qr_0 = dag.add_node("qr[0]") - qr_1 = dag.add_node("qr[1]") - qr_2 = dag.add_node("qr[2]") - cr_0 = dag.add_node("cr[0]") - cr_1 = dag.add_node("cr[1]") - # wires - cx_1 = dag.add_node("cx_1") - dag.add_edge(qr_0, cx_1, "qr[0]") - dag.add_edge(qr_1, cx_1, "qr[1]") - h_1 = dag.add_node("h_1") - dag.add_edge(cx_1, h_1, "qr[0]") - cx_2 = dag.add_node("cx_2") - dag.add_edge(cx_1, cx_2, "qr[1]") - dag.add_edge(qr_2, cx_2, "qr[2]") - cx_3 = dag.add_node("cx_3") - dag.add_edge(h_1, cx_3, "qr[0]") - dag.add_edge(cx_2, cx_3, "qr[2]") - h_2 = dag.add_node("h_2") - dag.add_edge(cx_3, h_2, "qr[2]") - # # outputs - qr_0_out = dag.add_node("qr[0]_out") - dag.add_edge(cx_3, qr_0_out, "qr[0]") - qr_1_out = dag.add_node("qr[1]_out") - dag.add_edge(cx_2, qr_1_out, "qr[1]") - qr_2_out = dag.add_node("qr[2]_out") - dag.add_edge(h_2, qr_2_out, "qr[2]") - cr_0_out = dag.add_node("cr[0]_out") - dag.add_edge(cr_0, cr_0_out, "qr[2]") - cr_1_out = dag.add_node("cr[1]_out") - dag.add_edge(cr_1, cr_1_out, "cr[1]") - - result = retworkx.floyd_warshall(dag) - expected = { - 0: {0: 0, 5: 1, 6: 2, 7: 2, 8: 3, 9: 4, 10: 4, 11: 3, 12: 5}, - 1: {1: 0, 5: 1, 6: 2, 7: 2, 8: 3, 9: 4, 10: 4, 11: 3, 12: 5}, - 2: {2: 0, 7: 1, 8: 2, 9: 3, 10: 3, 11: 2, 12: 4}, - 3: {3: 0, 13: 1}, - 4: {4: 0, 14: 1}, - 5: {5: 0, 6: 1, 7: 1, 8: 2, 9: 3, 10: 3, 11: 2, 12: 4}, - 6: {6: 0, 8: 1, 9: 2, 10: 2, 12: 3}, - 7: {7: 0, 8: 1, 9: 2, 10: 2, 11: 1, 12: 3}, - 8: {8: 0, 9: 1, 10: 1, 12: 2}, - 9: {9: 0, 12: 1}, - 10: {10: 0}, - 11: {11: 0}, - 12: {12: 0}, - 13: {13: 0}, - 14: {14: 0}, - } - - self.assertEqual(result, expected) - - def test_vs_dijkstra_all_pairs(self): - graph = retworkx.PyDiGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - - dijkstra_lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.digraph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_vs_dijkstra_all_pairs_with_node_removal(self): - graph = retworkx.PyDiGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - graph.remove_node(d) - - dijkstra_lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.digraph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_floyd_warshall_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_floyd_warshall(graph, float)) - - def test_floyd_warshall_graph_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_floyd_warshall(graph, float), - ) - - def test_directed_floyd_warshall_cycle_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_floyd_warshall( - graph, - lambda _: 1, - as_undirected=True, - parallel_threshold=self.parallel_threshold, - ) - expected = { - 0: {0: 0.0, 1: 1.0, 2: 2.0, 3: 3.0, 4: 3.0, 5: 2.0, 6: 1.0}, - 1: {0: 1.0, 1: 0.0, 2: 1.0, 3: 2.0, 4: 3.0, 5: 3.0, 6: 2.0}, - 2: {0: 2.0, 1: 1.0, 2: 0.0, 3: 1.0, 4: 2.0, 5: 3.0, 6: 3.0}, - 3: {0: 3.0, 1: 2.0, 2: 1.0, 3: 0.0, 4: 1.0, 5: 2.0, 6: 3.0}, - 4: {0: 3.0, 1: 3.0, 2: 2.0, 3: 1.0, 4: 0.0, 5: 1.0, 6: 2.0}, - 5: {0: 2.0, 1: 3.0, 2: 3.0, 3: 2.0, 4: 1.0, 5: 0.0, 6: 1.0}, - 6: {0: 1.0, 1: 2.0, 2: 3.0, 3: 3.0, 4: 2.0, 5: 1.0, 6: 0.0}, - } - self.assertEqual(dist, expected) - - def test_directed_floyd_warshall_numpy_cycle_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_floyd_warshall_numpy(graph, lambda x: 1, as_undirected=True) - expected = numpy.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(numpy.array_equal(dist, expected)) - - def test_floyd_warshall_numpy_digraph_three_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(6))) - weights = [2, 12, 1, 5, 1] - graph.add_edges_from([(i, i + 1, weights[i]) for i in range(5)]) - graph.add_edge(5, 0, 10) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 15) - self.assertEqual(dist[3, 0], 16) - - def test_weighted_numpy_digraph_two_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from( - [ - (0, 1, 2), - (1, 2, 2), - (2, 3, 1), - (3, 4, 1), - (4, 5, 1), - (5, 6, 1), - (6, 7, 1), - (7, 0, 1), - ] - ) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 2], 4) - self.assertEqual(dist[2, 0], 6) - - def test_floyd_warshall_numpy_digraph_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 4) - - def test_weighted_numpy_directed_negative_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - dist = retworkx.digraph_floyd_warshall_numpy(graph, lambda x: x) - self.assertTrue(numpy.all(numpy.diag(dist) < 0)) - - def test_numpy_directed_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - expected = numpy.full((4, 4), numpy.inf) - numpy.fill_diagonal(expected, 0) - self.assertTrue(numpy.array_equal(dist, expected)) - - def test_floyd_warshall_numpy_digraph_cycle_with_removals(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 4) - - def test_floyd_warshall_numpy_digraph_cycle_no_weight_fn(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.digraph_floyd_warshall_numpy(graph) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 4) - - def test_floyd_warshall_numpy_digraph_cycle_default_weight(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, default_weight=2, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 6) - self.assertEqual(dist[0, 4], 8) - - -class TestParallelFloydWarshall(TestFloydWarshall): - parallel_threshold = 0 diff --git a/tests/retworkx_backwards_compat/digraph/test_graph_attrs.py b/tests/retworkx_backwards_compat/digraph/test_graph_attrs.py deleted file mode 100644 index 348ef3e88..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_graph_attrs.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 TestAttributes(unittest.TestCase): - def test_no_attrs(self): - graph = retworkx.PyDiGraph() - self.assertIsNone(graph.attrs) - - def test_attrs_set_at_init(self): - graph = retworkx.PyDiGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - - def test_attrs_set_at_init_override(self): - graph = retworkx.PyDiGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - graph.attrs = "ABC" - self.assertEqual("ABC", graph.attrs) diff --git a/tests/retworkx_backwards_compat/digraph/test_isomorphic.py b/tests/retworkx_backwards_compat/digraph/test_isomorphic.py deleted file mode 100644 index ce1e06785..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_isomorphic.py +++ /dev/null @@ -1,350 +0,0 @@ -# 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 copy -import unittest - -import retworkx - - -class TestIsomorphic(unittest.TestCase): - def test_empty_isomorphic(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_b, id_order=id_order)) - - def test_empty_isomorphic_compare_nodes(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_identical(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "a_1") - dag_b.add_child(node_b, "a_3", "a_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_b, id_order=id_order)) - - def test_isomorphic_mismatch_node_data(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("b_1") - dag_b.add_child(node_b, "b_2", "b_1") - dag_b.add_child(node_b, "b_3", "b_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_b, id_order=id_order)) - - def test_isomorphic_compare_nodes_mismatch_node_data(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("b_1") - dag_b.add_child(node_b, "b_2", "b_1") - dag_b.add_child(node_b, "b_3", "b_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_is_isomorphic_nodes_compare_raises(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("b_1") - dag_b.add_child(node_b, "b_2", "b_1") - dag_b.add_child(node_b, "b_3", "b_2") - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises(TypeError, retworkx.is_isomorphic, (dag_a, dag_b, compare_nodes)) - - def test_isomorphic_compare_nodes_identical(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "a_1") - dag_b.add_child(node_b, "a_3", "a_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_compare_edges_identical(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "a_1") - dag_b.add_child(node_b, "a_3", "a_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic( - dag_a, - dag_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_isomorphic_compare_nodes_with_removals(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - qr_0_in = dag_a.add_node("qr[0]") - qr_1_in = dag_a.add_node("qr[1]") - cr_0_in = dag_a.add_node("cr[0]") - qr_0_out = dag_a.add_node("qr[0]") - qr_1_out = dag_a.add_node("qr[1]") - cr_0_out = dag_a.add_node("qr[0]") - cu1 = dag_a.add_child(qr_0_in, "cu1", "qr[0]") - dag_a.add_edge(qr_1_in, cu1, "qr[1]") - measure_0 = dag_a.add_child(cr_0_in, "measure", "cr[0]") - dag_a.add_edge(cu1, measure_0, "qr[0]") - measure_1 = dag_a.add_child(cu1, "measure", "qr[1]") - dag_a.add_edge(measure_0, measure_1, "cr[0]") - dag_a.add_edge(measure_1, qr_1_out, "qr[1]") - dag_a.add_edge(measure_1, cr_0_out, "cr[0]") - dag_a.add_edge(measure_0, qr_0_out, "qr[0]") - dag_a.remove_node(cu1) - dag_a.add_edge(qr_0_in, measure_0, "qr[0]") - dag_a.add_edge(qr_1_in, measure_1, "qr[1]") - - qr_0_in = dag_b.add_node("qr[0]") - qr_1_in = dag_b.add_node("qr[1]") - cr_0_in = dag_b.add_node("cr[0]") - qr_0_out = dag_b.add_node("qr[0]") - qr_1_out = dag_b.add_node("qr[1]") - cr_0_out = dag_b.add_node("qr[0]") - measure_0 = dag_b.add_child(cr_0_in, "measure", "cr[0]") - dag_b.add_edge(qr_0_in, measure_0, "qr[0]") - measure_1 = dag_b.add_child(qr_1_in, "measure", "qr[1]") - dag_b.add_edge(measure_1, qr_1_out, "qr[1]") - dag_b.add_edge(measure_1, cr_0_out, "cr[0]") - dag_b.add_edge(measure_0, measure_1, "cr[0]") - dag_b.add_edge(measure_0, qr_0_out, "qr[0]") - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_compare_nodes_with_removals_deepcopy(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - qr_0_in = dag_a.add_node("qr[0]") - qr_1_in = dag_a.add_node("qr[1]") - cr_0_in = dag_a.add_node("cr[0]") - qr_0_out = dag_a.add_node("qr[0]") - qr_1_out = dag_a.add_node("qr[1]") - cr_0_out = dag_a.add_node("qr[0]") - cu1 = dag_a.add_child(qr_0_in, "cu1", "qr[0]") - dag_a.add_edge(qr_1_in, cu1, "qr[1]") - measure_0 = dag_a.add_child(cr_0_in, "measure", "cr[0]") - dag_a.add_edge(cu1, measure_0, "qr[0]") - measure_1 = dag_a.add_child(cu1, "measure", "qr[1]") - dag_a.add_edge(measure_0, measure_1, "cr[0]") - dag_a.add_edge(measure_1, qr_1_out, "qr[1]") - dag_a.add_edge(measure_1, cr_0_out, "cr[0]") - dag_a.add_edge(measure_0, qr_0_out, "qr[0]") - dag_a.remove_node(cu1) - dag_a.add_edge(qr_0_in, measure_0, "qr[0]") - dag_a.add_edge(qr_1_in, measure_1, "qr[1]") - - qr_0_in = dag_b.add_node("qr[0]") - qr_1_in = dag_b.add_node("qr[1]") - cr_0_in = dag_b.add_node("cr[0]") - qr_0_out = dag_b.add_node("qr[0]") - qr_1_out = dag_b.add_node("qr[1]") - cr_0_out = dag_b.add_node("qr[0]") - measure_0 = dag_b.add_child(cr_0_in, "measure", "cr[0]") - dag_b.add_edge(qr_0_in, measure_0, "qr[0]") - measure_1 = dag_b.add_child(qr_1_in, "measure", "qr[1]") - dag_b.add_edge(measure_1, qr_1_out, "qr[1]") - dag_b.add_edge(measure_1, cr_0_out, "cr[0]") - dag_b.add_edge(measure_0, measure_1, "cr[0]") - dag_b.add_edge(measure_0, qr_0_out, "qr[0]") - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic( - copy.deepcopy(dag_a), - copy.deepcopy(dag_b), - lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_digraph_isomorphic_parallel_edges_with_edge_matcher(self): - graph = retworkx.PyDiGraph() - graph.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "b"), (1, 2, "c")]) - self.assertTrue(retworkx.is_isomorphic(graph, graph, edge_matcher=lambda x, y: x == y)) - - def test_digraph_isomorphic_self_loop(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0]) - graph.add_edges_from([(0, 0, "a")]) - self.assertTrue(retworkx.is_isomorphic(graph, graph)) - - def test_digraph_non_isomorphic_edge_mismatch_self_loop(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0]) - graph.add_edges_from([(0, 0, "a")]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0]) - second_graph.add_edges_from([(0, 0, "b")]) - self.assertFalse( - retworkx.is_isomorphic(graph, second_graph, edge_matcher=lambda x, y: x == y) - ) - - def test_digraph_non_isomorphic_rule_out_incoming(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2, 3]) - graph.add_edges_from_no_data([(0, 1), (0, 2), (2, 1)]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0, 1, 2, 3]) - second_graph.add_edges_from_no_data([(0, 1), (0, 2), (3, 1)]) - self.assertFalse(retworkx.is_isomorphic(graph, second_graph, id_order=True)) - - def test_digraph_non_isomorphic_rule_ins_outgoing(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2, 3]) - graph.add_edges_from_no_data([(1, 0), (2, 0), (1, 2)]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0, 1, 2, 3]) - second_graph.add_edges_from_no_data([(1, 0), (2, 0), (1, 3)]) - self.assertFalse(retworkx.is_isomorphic(graph, second_graph, id_order=True)) - - def test_digraph_non_isomorphic_rule_ins_incoming(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2, 3]) - graph.add_edges_from_no_data([(1, 0), (2, 0), (2, 1)]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0, 1, 2, 3]) - second_graph.add_edges_from_no_data([(1, 0), (2, 0), (3, 1)]) - self.assertFalse(retworkx.is_isomorphic(graph, second_graph, id_order=True)) - - def test_isomorphic_parallel_edges(self): - first = retworkx.PyDiGraph() - first.extend_from_edge_list([(0, 1), (0, 1), (1, 2), (2, 3)]) - second = retworkx.PyDiGraph() - second.extend_from_edge_list([(0, 1), (1, 2), (1, 2), (2, 3)]) - self.assertFalse(retworkx.is_isomorphic(first, second)) - - def test_digraph_isomorphic_insufficient_call_limit(self): - graph = retworkx.generators.directed_path_graph(5) - self.assertFalse(retworkx.is_isomorphic(graph, graph, call_limit=2)) - - def test_digraph_vf2_mapping_identical(self): - graph = retworkx.generators.directed_grid_graph(2, 2) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_digraph_vf2_mapping_identical_removals(self): - graph = retworkx.generators.directed_path_graph(2) - second_graph = retworkx.generators.directed_path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_digraph_vf2_mapping_identical_removals_first(self): - second_graph = retworkx.generators.directed_path_graph(2) - graph = retworkx.generators.directed_path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_digraph_vf2_mapping_identical_vf2pp(self): - graph = retworkx.generators.directed_grid_graph(2, 2) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_digraph_vf2_mapping_identical_removals_vf2pp(self): - graph = retworkx.generators.directed_path_graph(2) - second_graph = retworkx.generators.directed_path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_digraph_vf2_mapping_identical_removals_first_vf2pp(self): - second_graph = retworkx.generators.directed_path_graph(2) - graph = retworkx.generators.directed_path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_digraph_vf2_number_of_valid_mappings(self): - graph = retworkx.generators.directed_mesh_graph(3) - mapping = retworkx.digraph_vf2_mapping(graph, graph, id_order=True) - total = 0 - for _ in mapping: - total += 1 - self.assertEqual(total, 6) - - def test_empty_digraph_vf2_mapping(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.digraph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=False) - self.assertEqual({}, next(mapping)) diff --git a/tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py b/tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py deleted file mode 100644 index 1a788441b..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py +++ /dev/null @@ -1,96 +0,0 @@ -# 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 TestKShortestpath(unittest.TestCase): - def test_digraph_k_shortest_path_lengths(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (4, 5), - (1, 4), - (5, 6), - (6, 7), - (7, 5), - ] - ) - res = retworkx.digraph_k_shortest_path_lengths(graph, 1, 2, lambda _: 1) - expected = { - 0: 7.0, - 1: 4.0, - 2: 5.0, - 3: 6.0, - 4: 5.0, - 5: 5.0, - 6: 6.0, - 7: 7.0, - } - self.assertEqual(res, expected) - - def test_digraph_k_shortest_path_lengths_with_goal(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (4, 5), - (1, 4), - (5, 6), - (6, 7), - (7, 5), - ] - ) - res = retworkx.digraph_k_shortest_path_lengths(graph, 1, 2, lambda _: 1, 3) - self.assertEqual(res, {3: 6}) - - def test_digraph_k_shortest_path_with_goal_node_hole(self): - graph = retworkx.generators.directed_path_graph(4) - graph.remove_node(0) - res = retworkx.digraph_k_shortest_path_lengths( - graph, start=1, k=1, edge_cost=lambda _: 1, goal=3 - ) - self.assertEqual({3: 2}, res) - - def test_digraph_k_shortest_path_with_invalid_weight(self): - graph = retworkx.generators.directed_path_graph(4) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_k_shortest_path_lengths( - graph, - start=1, - k=1, - edge_cost=lambda _: invalid_weight, - goal=3, - ) - - def test_k_shortest_path_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.digraph_k_shortest_path_lengths( - g, start=a, k=1, edge_cost=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) diff --git a/tests/retworkx_backwards_compat/digraph/test_layers.py b/tests/retworkx_backwards_compat/digraph/test_layers.py deleted file mode 100644 index 720c1f0fb..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_layers.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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 TestLayers(unittest.TestCase): - def test_dagcircuit_basic(self): - dag = retworkx.PyDAG() - qr_0_in = dag.add_node("qr[0]") - qr_0_out = dag.add_node("qr[0]") - qr_1_in = dag.add_node("qr[1]") - qr_1_out = dag.add_node("qr[1]") - cr_0_in = dag.add_node("cr[0]") - cr_0_out = dag.add_node("cr[0]") - cr_1_in = dag.add_node("cr[1]") - cr_1_out = dag.add_node("cr[1]") - input_nodes = [qr_0_in, qr_1_in, cr_0_in, cr_1_in] - - h_gate = dag.add_child(qr_0_in, "h", "qr[0]") - cx_gate = dag.add_child(h_gate, "cx", "qr[0]") - dag.add_edge(qr_1_in, cx_gate, "qr[1]") - measure_qr_1 = dag.add_child(cx_gate, "measure", "qr[1]") - dag.add_edge(cr_1_in, measure_qr_1, "cr[1]") - x_gate = dag.add_child(measure_qr_1, "x", "qr[1]") - dag.add_edge(measure_qr_1, x_gate, "cr[1]") - dag.add_edge(cr_0_in, x_gate, "cr[0]") - - measure_qr_0 = dag.add_child(cx_gate, "measure", "qr[0]") - dag.add_edge(measure_qr_0, qr_0_out, "qr[0]") - dag.add_edge(measure_qr_0, cr_0_out, "cr[0]") - dag.add_edge(x_gate, measure_qr_0, "cr[0]") - - measure_qr_1_out = dag.add_child(x_gate, "measure", "cr[1]") - dag.add_edge(x_gate, measure_qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, cr_1_out, "cr[1]") - - res = retworkx.layers(dag, input_nodes) - expected = [ - ["qr[0]", "qr[1]", "cr[0]", "cr[1]"], - ["h"], - ["cx"], - ["measure"], - ["x"], - ["measure", "measure"], - ["cr[1]", "qr[1]", "cr[0]", "qr[0]"], - ] - self.assertEqual(expected, res) - - def test_first_layer_invalid_node(self): - dag = retworkx.PyDAG() - with self.assertRaises(retworkx.InvalidNode): - retworkx.layers(dag, [42]) diff --git a/tests/retworkx_backwards_compat/digraph/test_layout.py b/tests/retworkx_backwards_compat/digraph/test_layout.py deleted file mode 100644 index 1017f4f91..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_layout.py +++ /dev/null @@ -1,477 +0,0 @@ -# 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 LayoutTest(unittest.TestCase): - thres = 1e-6 - - def assertLayoutEquiv(self, exp, res): - for k in exp: - ev = exp[k] - rv = res[k] - if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: - self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) - ) - - -class TestRandomLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_random_layout(self): - res = retworkx.digraph_random_layout(self.graph, seed=42) - expected = { - 0: (0.2265125179283135, 0.23910669031859955), - 4: (0.8025885957751138, 0.37085692752109345), - 5: (0.23635127852185123, 0.9286365888207462), - 1: (0.760833410686741, 0.5278396573581516), - 3: (0.1879083014236631, 0.524657662927804), - 2: (0.9704763177409157, 0.37546268141451944), - 6: (0.462700947802672, 0.44025745918644743), - 7: (0.3125895420208278, 0.0893209773065271), - 8: (0.5567725240957387, 0.21079648777222115), - 9: (0.7586719404939911, 0.43090704138697045), - } - self.assertEqual(expected, res) - - def test_random_layout_center(self): - res = retworkx.digraph_random_layout(self.graph, center=(0.5, 0.5), seed=42) - expected = { - 1: [1.260833410686741, 1.0278396573581516], - 5: [0.7363512785218512, 1.4286365888207462], - 7: [0.8125895420208278, 0.5893209773065271], - 4: [1.3025885957751138, 0.8708569275210934], - 8: [1.0567725240957389, 0.7107964877722212], - 9: [1.2586719404939912, 0.9309070413869704], - 0: [0.7265125179283135, 0.7391066903185995], - 2: [1.4704763177409157, 0.8754626814145194], - 6: [0.962700947802672, 0.9402574591864474], - 3: [0.6879083014236631, 1.0246576629278041], - } - self.assertEqual(expected, res) - - def test_random_layout_no_seed(self): - res = retworkx.digraph_random_layout(self.graph) - # Random output, just assert structurally correct - self.assertIsInstance(res, retworkx.Pos2DMapping) - self.assertEqual(len(res), 10) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - -class TestBipartiteLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_bipartite_layout_empty(self): - res = retworkx.bipartite_layout(retworkx.PyDiGraph(), set()) - self.assertEqual({}, res) - - def test_bipartite_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.bipartite_layout(g, set()) - expected = { - 0: (0.0, -1.0), - 2: (0.0, -0.3333333333333333), - 3: (0.0, 0.3333333333333333), - 4: (0.0, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3, 4}) - expected = { - 0: (-1.0, -0.75), - 1: (-1.0, -0.375), - 2: (-1.0, 0.0), - 3: (-1.0, 0.375), - 4: (-1.0, 0.75), - 5: (1.0, -0.75), - 6: (1.0, -0.375), - 7: (1.0, 0.0), - 8: (1.0, 0.375), - 9: (1.0, 0.75), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_horizontal(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3}, horizontal=True) - expected = { - 0: (1.0, -0.9), - 1: (0.3333333333333333, -0.9), - 2: (-0.333333333333333, -0.9), - 3: (-1.0, -0.9), - 4: (1.0, 0.6), - 5: (0.6, 0.6), - 6: (0.2, 0.6), - 7: (-0.2, 0.6), - 8: (-0.6, 0.6), - 9: (-1.0, 0.6), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_scale(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2}, scale=2) - expected = { - 0: (-2.0, -1.0714285714285714), - 1: (-2.0, 2.3790493384824785e-17), - 2: (-2.0, 1.0714285714285714), - 3: (0.8571428571428571, -1.0714285714285714), - 4: (0.8571428571428571, -0.7142857142857143), - 5: (0.8571428571428571, -0.35714285714285715), - 6: (0.8571428571428571, 2.3790493384824785e-17), - 7: (0.8571428571428571, 0.35714285714285704), - 8: (0.8571428571428571, 0.7142857142857141), - 9: (0.8571428571428571, 1.0714285714285714), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_center(self): - res = retworkx.bipartite_layout(self.graph, {4, 5, 6}, center=(0.5, 0.5)) - expected = { - 4: (-0.5, -0.0357142857142857), - 5: (-0.5, 0.5), - 6: (-0.5, 1.0357142857142856), - 0: (0.9285714285714286, -0.0357142857142857), - 1: (0.9285714285714286, 0.14285714285714285), - 2: (0.9285714285714286, 0.3214285714285714), - 3: (0.9285714285714286, 0.5), - 7: (0.9285714285714286, 0.6785714285714285), - 8: (0.9285714285714286, 0.857142857142857), - 9: (0.9285714285714286, 1.0357142857142856), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_ratio(self): - res = retworkx.bipartite_layout(self.graph, {2, 4, 8}, aspect_ratio=4) - expected = { - 8: [-1.0, 0.17857142857142858], - 2: [-1.0, -0.17857142857142858], - 4: [-1.0, 0], - 0: [0.42857142857142855, -0.17857142857142858], - 1: [0.42857142857142855, -0.11904761904761907], - 3: [0.42857142857142855, -0.05952380952380952], - 5: [0.42857142857142855, 0], - 6: [0.42857142857142855, 0.05952380952380952], - 7: [0.42857142857142855, 0.11904761904761903], - 9: [0.42857142857142855, 0.17857142857142858], - } - self.assertLayoutEquiv(expected, res) - - -class TestCircularLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_circular_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyDiGraph()) - self.assertEqual({}, res) - - def test_circular_layout_one_node(self): - res = retworkx.circular_layout(retworkx.generators.directed_path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_circular_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.circular_layout(g) - expected = { - 0: (0.999999986090933, 2.1855693665697608e-08), - 2: (-3.576476059301554e-08, 1.0), - 3: (-0.9999999701976796, -6.556708099709282e-08), - 4: (1.987150711625619e-08, -0.9999999562886126), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout(self): - res = retworkx.circular_layout(self.graph) - expected = { - 0: (1.0, 2.662367085193061e-08), - 1: (0.8090170042900712, 0.5877852653564984), - 2: (0.3090169789580973, 0.9510565581329226), - 3: (-0.3090170206813483, 0.9510564985282783), - 4: (-0.8090170460133221, 0.5877852057518542), - 5: (-0.9999999821186069, -6.079910493992474e-08), - 6: (-0.8090169268040337, -0.5877853313184453), - 7: (-0.3090170802859925, -0.9510564452809367), - 8: (0.3090171279697079, -0.9510564452809367), - 9: (0.809016944685427, -0.587785271713801), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_scale(self): - res = retworkx.circular_layout(self.graph, scale=2) - expected = { - 0: (2.0, 5.324734170386122e-08), - 1: (1.6180340085801423, 1.1755705307129969), - 2: (0.6180339579161946, 1.9021131162658451), - 3: (-0.6180340413626966, 1.9021129970565567), - 4: (-1.6180340920266443, 1.1755704115037084), - 5: (-1.9999999642372137, -1.2159820987984948e-07), - 6: (-1.6180338536080674, -1.1755706626368907), - 7: (-0.618034160571985, -1.9021128905618734), - 8: (0.6180342559394159, -1.9021128905618734), - 9: (1.618033889370854, -1.175570543427602), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_center(self): - res = retworkx.circular_layout(self.graph, center=(0.5, 0.5)) - expected = { - 0: (1.5, 0.5000000266236708), - 1: (1.3090170042900713, 1.0877852653564983), - 2: (0.8090169789580973, 1.4510565581329224), - 3: (0.1909829793186517, 1.4510564985282783), - 4: (-0.30901704601332214, 1.0877852057518542), - 5: (-0.49999998211860686, 0.4999999392008951), - 6: (-0.3090169268040337, -0.08778533131844535), - 7: (0.1909829197140075, -0.4510564452809367), - 8: (0.8090171279697079, -0.4510564452809367), - 9: (1.309016944685427, -0.08778527171380102), - } - self.assertLayoutEquiv(expected, res) - - -class TestShellLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_shell_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyDiGraph()) - self.assertEqual({}, res) - - def test_shell_layout_one_node(self): - res = retworkx.shell_layout(retworkx.generators.directed_path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_shell_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.shell_layout(g) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 2: (1.1924880638503055e-08, -1.0), - 3: (1.0, 1.7484555314695172e-07), - 4: (-3.3776623808989825e-07, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_hole_two_shells(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([2]) - res = retworkx.shell_layout(g, [[0, 1], [3, 4]]) - expected = { - 0: (-2.1855694143368964e-08, 0.5), - 1: (5.962440319251527e-09, -0.5), - 3: (-1.0, -8.742277657347586e-08), - 4: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout(self): - res = retworkx.shell_layout(self.graph) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 1: (-0.8090169429779053, -0.5877853631973267), - 2: (-0.3090170919895172, -0.9510564804077148), - 3: (0.3090171217918396, -0.9510564804077148), - 4: (0.8090172410011292, -0.5877849459648132), - 5: (1.0, 1.7484555314695172e-07), - 6: (0.80901700258255, 0.5877852439880371), - 7: (0.30901679396629333, 0.9510565996170044), - 8: (-0.30901744961738586, 0.9510563611984253), - 9: (-0.8090168833732605, 0.5877854228019714), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_nlist(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 2], [1, 3], [4, 9], [8, 7], [6, 5]]) - expected = { - 0: (0.16180340945720673, 0.11755704879760742), - 2: (-0.16180339455604553, -0.11755707114934921), - 1: (0.12360679358243942, 0.3804226219654083), - 3: (-0.123606838285923, -0.38042259216308594), - 4: (-0.18541023135185242, 0.5706338882446289), - 9: (0.185410276055336, -0.5706338882446289), - 8: (-0.6472136378288269, 0.4702281653881073), - 7: (0.6472138166427612, -0.4702279567718506), - 6: (-1.0, -8.742277657347586e-08), - 5: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_rotate(self): - res = retworkx.shell_layout( - self.graph, nlist=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]], rotate=0.5 - ) - expected = { - 0: (0.21939563751220703, 0.11985638737678528), - 1: (-0.21349650621414185, 0.13007399439811707), - 2: (-0.005899117328226566, -0.24993039667606354), - 3: (0.27015113830566406, 0.4207354784011841), - 4: (-0.4994432032108307, 0.023589985445141792), - 5: (0.229292094707489, -0.4443254768848419), - 6: (0.05305289849638939, 0.7481212615966797), - 7: (-0.6744184494018555, -0.3281154930591583), - 8: (0.6213656067848206, -0.420005738735199), - 9: (-0.416146844625473, 0.9092974066734314), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_scale(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], scale=2) - expected = { - 0: (-4.371138828673793e-08, 1.0), - 1: (-0.9510565996170044, 0.30901679396629333), - 2: (-0.5877850651741028, -0.8090171217918396), - 3: (0.5877854824066162, -0.8090168237686157), - 4: (0.9510564208030701, 0.30901727080345154), - 9: (-2.0, -1.7484555314695172e-07), - 8: (-0.6180341839790344, -1.9021129608154297), - 7: (1.6180344820022583, -1.1755698919296265), - 6: (1.6180340051651, 1.1755704879760742), - 5: (-0.6180348992347717, 1.9021127223968506), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_center(self): - res = retworkx.shell_layout( - self.graph, - nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], - center=(0.5, 0.5), - ) - expected = { - 0: (0.49999997814430586, 1.0), - 1: (0.024471700191497803, 0.6545083969831467), - 2: (0.2061074674129486, 0.0954914391040802), - 3: (0.7938927412033081, 0.09549158811569214), - 4: (0.975528210401535, 0.6545086354017258), - 9: (-0.5, 0.4999999125772234), - 8: (0.1909829080104828, -0.45105648040771484), - 7: (1.3090172410011292, -0.08778494596481323), - 6: (1.30901700258255, 1.087785243988037), - 5: (0.19098255038261414, 1.4510563611984253), - } - self.assertLayoutEquiv(expected, res) - - -class TestSpiralLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_spiral_layout_empty(self): - res = retworkx.spiral_layout(retworkx.PyDiGraph()) - self.assertEqual({}, res) - - def test_spiral_layout_one_node(self): - res = retworkx.spiral_layout(retworkx.generators.directed_path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_spiral_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.spiral_layout(g) - expected = { - 0: (-0.6415327868391166, -0.6855508729419231), - 2: (-0.03307913182988828, -0.463447951079834), - 3: (0.34927952438480797, 0.1489988240217569), - 4: (0.32533239428419697, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout(self): - res = retworkx.spiral_layout(self.graph) - expected = { - 0: (0.3083011152777303, -0.36841870322845377), - 1: (0.4448595378922136, -0.3185709877650719), - 2: (0.5306742824266687, -0.18111636841212878), - 3: (0.5252997033017661, 0.009878257518578544), - 4: (0.40713492048969163, 0.20460820654918466), - 5: (0.17874125121181098, 0.3468009691240852), - 6: (-0.1320415949011884, 0.3844997574641717), - 7: (-0.4754889029311045, 0.28057288841663486), - 8: (-0.7874803127675889, 0.021164283410983312), - 9: (-0.9999999999999999, -0.3794183030779839), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_scale(self): - res = retworkx.spiral_layout(self.graph, scale=2) - expected = { - 0: (0.6166022305554606, -0.7368374064569075), - 1: (0.8897190757844272, -0.6371419755301438), - 2: (1.0613485648533374, -0.36223273682425755), - 3: (1.0505994066035322, 0.01975651503715709), - 4: (0.8142698409793833, 0.4092164130983693), - 5: (0.35748250242362195, 0.6936019382481704), - 6: (-0.2640831898023768, 0.7689995149283434), - 7: (-0.950977805862209, 0.5611457768332697), - 8: (-1.5749606255351778, 0.042328566821966625), - 9: (-1.9999999999999998, -0.7588366061559678), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_center(self): - res = retworkx.spiral_layout(self.graph, center=(1, 1)) - expected = { - 0: (1.3083011152777302, 0.6315812967715462), - 1: (1.4448595378922136, 0.681429012234928), - 2: (1.5306742824266686, 0.8188836315878713), - 3: (1.5252997033017661, 1.0098782575185785), - 4: (1.4071349204896917, 1.2046082065491848), - 5: (1.178741251211811, 1.3468009691240852), - 6: (0.8679584050988116, 1.3844997574641718), - 7: (0.5245110970688955, 1.2805728884166347), - 8: (0.2125196872324111, 1.0211642834109833), - 9: (1.1102230246251565e-16, 0.6205816969220161), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_resolution(self): - res = retworkx.spiral_layout(self.graph, resolution=0.6) - expected = { - 0: (0.14170895375949058, 0.22421978768273812), - 1: (0.2657196183870804, 0.30906004798138936), - 2: (0.2506009612140119, 0.5043065412934762), - 3: (0.039294315670400995, 0.6631957258449066), - 4: (-0.3014789232909145, 0.6301862160709318), - 5: (-0.602046830323471, 0.3302396035952633), - 6: (-0.66674476042188, -0.17472522299849289), - 7: (-0.3739394496041176, -0.6924895145748617), - 8: (0.2468861146093996, -0.9732085843739783), - 9: (1.0, -0.8207846005213728), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_equidistant(self): - res = retworkx.spiral_layout(self.graph, equidistant=True) - expected = { - 0: (-0.13161882865656718, -0.7449342807652114), - 1: (0.7160560542246066, -0.6335352483233974), - 2: (0.6864868274284994, -0.34165899654603915), - 3: (0.5679822628330004, -0.07281296883784087), - 4: (0.375237081214659, 0.14941210155952697), - 5: (0.12730720268992277, 0.30830226777240866), - 6: (-0.15470865936858091, 0.3939608192236113), - 7: (-0.4495426197217269, 0.4027809258196645), - 8: (-0.7371993206438128, 0.33662707199446507), - 9: (-1.0, 0.2018583081028111), - } - self.assertLayoutEquiv(expected, res) diff --git a/tests/retworkx_backwards_compat/digraph/test_neighbors.py b/tests/retworkx_backwards_compat/digraph/test_neighbors.py deleted file mode 100644 index f33f49c6c..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_neighbors.py +++ /dev/null @@ -1,59 +0,0 @@ -# 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 TestAdj(unittest.TestCase): - def test_single_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_unique_neighbors_on_dags(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", ["edge a->b"]) - node_c = dag.add_child(node_a, "c", ["edge a->c"]) - dag.add_edge(node_a, node_b, ["edge a->b bis"]) - res = dag.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_single_neighbor_dir(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.successor_indices(node_a) - self.assertEqual([node_c, node_b], res) - res = dag.predecessor_indices(node_a) - self.assertEqual([], res) - - def test_neighbor_dir_surrounded(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = dag.successor_indices(node_b) - self.assertEqual([node_c], res) - res = dag.predecessor_indices(node_b) - self.assertEqual([node_a], res) - - def test_no_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - self.assertEqual([], dag.neighbors(node_a)) diff --git a/tests/retworkx_backwards_compat/digraph/test_nodes.py b/tests/retworkx_backwards_compat/digraph/test_nodes.py deleted file mode 100644 index 4d9dfcd79..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_nodes.py +++ /dev/null @@ -1,403 +0,0 @@ -# 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 TestNodes(unittest.TestCase): - def test_nodes(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - res = dag.nodes() - self.assertEqual(["a", "b"], res) - self.assertEqual([0, 1], dag.node_indexes()) - - def test_node_indices(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - graph.add_child(node_a, "b", "Edgy") - self.assertEqual([0, 1], graph.node_indices()) - - def test_no_nodes(self): - dag = retworkx.PyDAG() - self.assertEqual([], dag.nodes()) - self.assertEqual([], dag.node_indexes()) - self.assertEqual([], dag.node_indices()) - - def test_remove_node(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node(node_b) - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - - def test_remove_node_invalid_index(self): - graph = retworkx.PyDAG() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.remove_node(76) - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) - - def test_remove_nodes_from(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_nodes_from([node_b, node_c]) - res = dag.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], dag.node_indexes()) - - def test_remove_nodes_from_with_invalid_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_nodes_from([node_b, node_c, 76]) - res = dag.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], dag.node_indexes()) - - def test_remove_nodes_retain_edges_single_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertEqual(dag.get_all_edge_data(node_a, node_c), ["Edgy"]) - - def test_remove_nodes_retain_edges_single_edge_outgoing_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b, use_outgoing=True) - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertEqual(dag.get_all_edge_data(node_a, node_c), ["Edgy_mk2"]) - - def test_remove_nodes_retain_edges_multiple_in_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_d, node_b, "Multiple in edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "d", "c"], res) - self.assertEqual([0, 1, 3], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertTrue(dag.has_edge(node_d, node_c)) - - def test_remove_nodes_retain_edges_multiple_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_b, node_d, "Multiple out edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "d", "c"], res) - self.assertEqual([0, 1, 3], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertTrue(dag.has_edge(node_a, node_d)) - - def test_remove_nodes_retain_edges_multiple_in_and_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_e = dag.add_node("e") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_b, node_d, "Multiple out edgy") - dag.add_edge(node_e, node_b, "multiple in edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "d", "e", "c"], res) - self.assertEqual([0, 1, 2, 4], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertTrue(dag.has_edge(node_a, node_d)) - self.assertTrue(dag.has_edge(node_e, node_c)) - self.assertTrue(dag.has_edge(node_e, node_d)) - - def test_remove_node_retain_edges_with_condition(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_e = dag.add_node("e") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_b, node_d, "Multiple out edgy") - dag.add_edge(node_e, node_b, "multiple in edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b, condition=lambda a, b: a == "multiple in edgy") - res = dag.nodes() - self.assertEqual(["a", "d", "e", "c"], res) - self.assertEqual([0, 1, 2, 4], dag.node_indexes()) - self.assertFalse(dag.has_edge(node_a, node_c)) - self.assertFalse(dag.has_edge(node_a, node_d)) - self.assertTrue(dag.has_edge(node_e, node_c)) - self.assertTrue(dag.has_edge(node_e, node_d)) - - def test_remove_nodes_retain_edges_with_invalid_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(76) - res = dag.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], dag.node_indexes()) - - def test_topo_sort_empty(self): - dag = retworkx.PyDAG() - self.assertEqual([], retworkx.topological_sort(dag)) - - def test_topo_sort(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - dag.add_parent(3, "A parent", None) - res = retworkx.topological_sort(dag) - self.assertEqual([6, 0, 5, 4, 3, 2, 1], res) - - def test_topo_sort_with_cycle(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - dag.add_edge(node_b, node_a, {}) - self.assertRaises(retworkx.DAGHasCycle, retworkx.topological_sort, dag) - - def test_lexicographical_topo_sort(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - dag.add_parent(3, "A parent", None) - res = retworkx.lexicographical_topological_sort(dag, lambda x: str(x)) - # Node values for nodes [6, 0, 5, 4, 3, 2, 1] - expected = ["A parent", "a", 0, 1, 2, 3, 4] - self.assertEqual(expected, res) - - def test_lexicographical_topo_sort_qiskit(self): - dag = retworkx.PyDAG() - # inputs - qr_0 = dag.add_node("qr[0]") - qr_1 = dag.add_node("qr[1]") - qr_2 = dag.add_node("qr[2]") - cr_0 = dag.add_node("cr[0]") - cr_1 = dag.add_node("cr[1]") - - # wires - cx_1 = dag.add_node("cx_1") - dag.add_edge(qr_0, cx_1, "qr[0]") - dag.add_edge(qr_1, cx_1, "qr[1]") - h_1 = dag.add_node("h_1") - dag.add_edge(cx_1, h_1, "qr[0]") - cx_2 = dag.add_node("cx_2") - dag.add_edge(cx_1, cx_2, "qr[1]") - dag.add_edge(qr_2, cx_2, "qr[2]") - cx_3 = dag.add_node("cx_3") - dag.add_edge(h_1, cx_3, "qr[0]") - dag.add_edge(cx_2, cx_3, "qr[2]") - h_2 = dag.add_node("h_2") - dag.add_edge(cx_3, h_2, "qr[2]") - - # outputs - qr_0_out = dag.add_node("qr[0]_out") - dag.add_edge(cx_3, qr_0_out, "qr[0]") - qr_1_out = dag.add_node("qr[1]_out") - dag.add_edge(cx_2, qr_1_out, "qr[1]") - qr_2_out = dag.add_node("qr[2]_out") - dag.add_edge(h_2, qr_2_out, "qr[2]") - cr_0_out = dag.add_node("cr[0]_out") - dag.add_edge(cr_0, cr_0_out, "qr[2]") - cr_1_out = dag.add_node("cr[1]_out") - dag.add_edge(cr_1, cr_1_out, "cr[1]") - - res = list(retworkx.lexicographical_topological_sort(dag, lambda x: str(x))) - expected = [ - "cr[0]", - "cr[0]_out", - "cr[1]", - "cr[1]_out", - "qr[0]", - "qr[1]", - "cx_1", - "h_1", - "qr[2]", - "cx_2", - "cx_3", - "h_2", - "qr[0]_out", - "qr[1]_out", - "qr[2]_out", - ] - self.assertEqual(expected, res) - - def test_get_node_data(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - self.assertEqual("b", dag.get_node_data(node_b)) - - def test_get_node_data_bad_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - self.assertRaises(IndexError, dag.get_node_data, 42) - - def test_pydag_length(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - self.assertEqual(2, len(dag)) - - def test_pydag_length_empty(self): - dag = retworkx.PyDAG() - self.assertEqual(0, len(dag)) - - def test_pydigraph_num_nodes(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "An_edge") - self.assertEqual(2, graph.num_nodes()) - - def test_pydigraph_num_nodes_empty(self): - graph = retworkx.PyDiGraph() - self.assertEqual(0, graph.num_nodes()) - - def test_add_nodes_from(self): - dag = retworkx.PyDAG() - nodes = list(range(100)) - res = dag.add_nodes_from(nodes) - self.assertEqual(len(res), 100) - self.assertEqual(res, nodes) - - def test_add_node_from_empty(self): - dag = retworkx.PyDAG() - res = dag.add_nodes_from([]) - self.assertEqual(len(res), 0) - - def test_get_node_data_getitem(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - self.assertEqual("b", dag[node_b]) - - def test_get_node_data_getitem_bad_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - with self.assertRaises(IndexError): - dag[42] - - def test_set_node_data_setitem(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag[node_b] = "Oh so cool" - self.assertEqual("Oh so cool", dag[node_b]) - - def test_set_node_data_setitem_bad_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - with self.assertRaises(IndexError): - dag[42] = "Oh so cool" - - def test_remove_node_delitem(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Edgy_mk2") - del dag[node_b] - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - - def test_remove_node_delitem_invalid_index(self): - graph = retworkx.PyDAG() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - with self.assertRaises(IndexError): - del graph[76] - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) - - def test_find_node_by_weight(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(10))) - res = graph.find_node_by_weight(9) - self.assertEqual(res, 9) - - def test_find_node_by_weight_no_match(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(10))) - res = graph.find_node_by_weight(42) - self.assertEqual(res, None) - - def test_find_node_by_weight_multiple_matches(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "a"]) - res = graph.find_node_by_weight("a") - self.assertEqual(res, 0) - - def test_merge_nodes(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "a", "b", "c"]) - graph.add_edge(0, 2, "edge0") - graph.add_edge(3, 0, "edge1") - graph.merge_nodes(0, 1) - self.assertEqual(graph.node_indexes(), [1, 2, 3]) - self.assertEqual([(3, 1, "edge1"), (1, 2, "edge0")], graph.weighted_edge_list()) - - def test_merge_nodes_no_match(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "a", "b", "c"]) - graph.add_edge(0, 2, "edge0") - graph.add_edge(3, 0, "edge1") - graph.merge_nodes(0, 2) - self.assertEqual(graph.node_indexes(), [0, 1, 2, 3]) - self.assertEqual([(0, 2, "edge0"), (3, 0, "edge1")], graph.weighted_edge_list()) - - def test_merge_nodes_invalid_node_first_index(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "b"]) - with self.assertRaises(IndexError): - graph.merge_nodes(2, 0) - - def test_merge_nodes_invalid_node_second_index(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "b"]) - with self.assertRaises(IndexError): - graph.merge_nodes(0, 3) diff --git a/tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py b/tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py deleted file mode 100644 index 07b9d41b8..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py +++ /dev/null @@ -1,140 +0,0 @@ -# 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 TestNumShortestpath(unittest.TestCase): - def test_num_shortest_path_unweighted(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node("end") - for i in range(3): - node = graph.add_child(node_a, i, None) - graph.add_edge(node, node_b, None) - res = retworkx.digraph_num_shortest_paths_unweighted(graph, node_a) - expected = {2: 1, 4: 1, 3: 1, 1: 3} - self.assertEqual(expected, res) - - def test_parallel_paths(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (0, 4), - (4, 5), - (5, 3), - ] - ) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 2, - 4: 1, - 5: 1, - } - self.assertEqual(expected, res) - - def test_grid_graph(self): - """Test num shortest paths for a 5x5 grid graph - 0 -> 1 -> 2 -> 3 -> 4 - | | | | | - v v v v v - 5 -> 6 -> 7 -> 8 -> 9 - | | | | | - v v v v v - 10-> 11-> 12-> 13-> 14 - | | | | | - v v v v v - 15-> 16-> 17-> 18-> 19 - | | | | | - v v v v v - 20-> 21-> 22-> 23-> 24 - """ - graph = retworkx.generators.directed_grid_graph(5, 5) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 2, - 7: 3, - 8: 4, - 9: 5, - 10: 1, - 11: 3, - 12: 6, - 13: 10, - 14: 15, - 15: 1, - 16: 4, - 17: 10, - 18: 20, - 19: 35, - 20: 1, - 21: 5, - 22: 15, - 23: 35, - 24: 70, - } - self.assertEqual(expected, res) - - def test_node_with_no_path(self): - graph = retworkx.generators.directed_path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - expected = {1: 1, 2: 1, 3: 1, 4: 1} - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - res = retworkx.num_shortest_paths_unweighted(graph, 6) - expected = {7: 1, 8: 1, 9: 1, 10: 1, 11: 1} - self.assertEqual(expected, res) - - def test_node_indices_with_holes(self): - graph = retworkx.generators.directed_path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - graph.add_edge(4, 6, None) - graph.remove_node(5) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 6: 1, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - - def test_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - graph.add_node(1) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual({}, res) - - def test_invalid_source_index(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - graph.add_child(0, 1, None) - with self.assertRaises(IndexError): - retworkx.num_shortest_paths_unweighted(graph, 4) diff --git a/tests/retworkx_backwards_compat/digraph/test_pred_succ.py b/tests/retworkx_backwards_compat/digraph/test_pred_succ.py deleted file mode 100644 index 7f655044a..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_pred_succ.py +++ /dev/null @@ -1,385 +0,0 @@ -# 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 TestPredecessors(unittest.TestCase): - def test_single_predecessor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.predecessors(node_c) - self.assertEqual(["a"], res) - - def test_single_predecessor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - dag.add_edge(node_a, node_c, {"a": 3}) - res = dag.predecessors(node_c) - self.assertEqual(["a"], res) - - def test_many_parents(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_parent(node_a, {"numeral": i}, {"edge": i}) - res = dag.predecessors(node_a) - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 8}, - {"numeral": 7}, - {"numeral": 6}, - {"numeral": 5}, - {"numeral": 4}, - {"numeral": 3}, - {"numeral": 2}, - {"numeral": 1}, - {"numeral": 0}, - ], - res, - ) - - -class TestSuccessors(unittest.TestCase): - def test_single_successor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - res = dag.successors(node_b) - self.assertEqual(["c"], res) - - def test_single_successor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - dag.add_edge(node_b, node_c, {"a": 3}) - res = dag.successors(node_b) - self.assertEqual(["c"], res) - - def test_many_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_child(node_a, {"numeral": i}, {"edge": i}) - res = dag.successors(node_a) - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 8}, - {"numeral": 7}, - {"numeral": 6}, - {"numeral": 5}, - {"numeral": 4}, - {"numeral": 3}, - {"numeral": 2}, - {"numeral": 1}, - {"numeral": 0}, - ], - res, - ) - - -class TestFindPredecessorsByEdge(unittest.TestCase): - def test_single_predecessor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - - res_even = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 == 0) - - res_odd = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 != 0) - - self.assertEqual(["a"], res_even) - self.assertEqual([], res_odd) - - def test_single_predecessor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - dag.add_edge(node_a, node_c, {"a": 3}) - - res_even = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 == 0) - - res_odd = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 == 0) - - self.assertEqual(["a"], res_even) - self.assertEqual(["a"], res_odd) - - def test_many_parents(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_parent(node_a, {"numeral": i}, {"edge": i}) - - res_even = dag.find_predecessors_by_edge(node_a, lambda x: x["edge"] % 2 == 0) - - res_odd = dag.find_predecessors_by_edge(node_a, lambda x: x["edge"] % 2 != 0) - - self.assertEqual( - [ - {"numeral": 8}, - {"numeral": 6}, - {"numeral": 4}, - {"numeral": 2}, - {"numeral": 0}, - ], - res_even, - ) - - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 7}, - {"numeral": 5}, - {"numeral": 3}, - {"numeral": 1}, - ], - res_odd, - ) - - def test_no_parents(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - - res = dag.find_predecessors_by_edge(node_a, lambda _: True) - - self.assertEqual([], res) - - -class TestFindSuccessorsByEdge(unittest.TestCase): - def test_single_successor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - - res_even = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 == 0) - res_odd = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 != 0) - - self.assertEqual(["c"], res_even) - self.assertEqual([], res_odd) - - def test_single_successor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - dag.add_edge(node_b, node_c, {"a": 3}) - - res_even = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 == 0) - res_odd = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 != 0) - - self.assertEqual(["c"], res_even) - self.assertEqual(["c"], res_odd) - - def test_many_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_child(node_a, {"numeral": i}, {"edge": i}) - - res_even = dag.find_successors_by_edge(node_a, lambda x: x["edge"] % 2 == 0) - - res_odd = dag.find_successors_by_edge(node_a, lambda x: x["edge"] % 2 != 0) - - self.assertEqual( - [ - {"numeral": 8}, - {"numeral": 6}, - {"numeral": 4}, - {"numeral": 2}, - {"numeral": 0}, - ], - res_even, - ) - - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 7}, - {"numeral": 5}, - {"numeral": 3}, - {"numeral": 1}, - ], - res_odd, - ) - - def test_no_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - - res = dag.find_successors_by_edge(node_a, lambda _: True) - - self.assertEqual([], res) - - -class TestBfsSuccessors(unittest.TestCase): - def test_single_successor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - res = retworkx.bfs_successors(dag, node_b) - self.assertEqual([("b", ["c"]), ("c", ["d"])], res) - - def test_many_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_child(node_a, {"numeral": i}, {"edge": i}) - res = retworkx.bfs_successors(dag, node_a) - self.assertEqual( - [ - ( - "a", - [ - {"numeral": 9}, - {"numeral": 8}, - {"numeral": 7}, - {"numeral": 6}, - {"numeral": 5}, - {"numeral": 4}, - {"numeral": 3}, - {"numeral": 2}, - {"numeral": 1}, - {"numeral": 0}, - ], - ) - ], - res, - ) - - def test_bfs_succesors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = {n: sorted(s) for n, s in retworkx.bfs_successors(dag, node_b)} - expected = { - 1: [2], - 2: [3, 7], - 3: [4], - 4: [5], - 5: [6], - 7: [8], - 8: [9], - 9: [10], - } - self.assertEqual(expected, res) - self.assertEqual( - [(7, [8]), (8, [9]), (9, [10])], - retworkx.bfs_successors(dag, node_h), - ) - - def test_bfs_successors_sequence(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = retworkx.bfs_successors(dag, node_b) - expected = [ - (1, [2]), - (2, [7, 3]), - (7, [8]), - (3, [4]), - (8, [9]), - (4, [5]), - (9, [10]), - (5, [6]), - ] - for index, expected_value in enumerate(expected): - self.assertEqual((res[index][0], res[index][1]), expected_value) - - def test_bfs_successors_sequence_invalid_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = retworkx.bfs_successors(dag, node_b) - with self.assertRaises(IndexError): - res[8] - - def test_bfs_successors_sequence_negative_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = retworkx.bfs_successors(dag, node_b) - self.assertEqual((5, [6]), res[-1]) - self.assertEqual((4, [5]), res[-3]) - - def test_bfs_successors_sequence_stop_iterator(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = iter(retworkx.bfs_successors(dag, node_b)) - for _ in range(8): - next(res) - with self.assertRaises(StopIteration): - next(res) diff --git a/tests/retworkx_backwards_compat/digraph/test_spring_layout.py b/tests/retworkx_backwards_compat/digraph/test_spring_layout.py deleted file mode 100644 index 13d6aa0fb..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_spring_layout.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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 TestSpringLayout(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - node_a = self.graph.add_node(1) - node_b = self.graph.add_node(2) - self.graph.add_edge(node_a, node_b, 1) - node_c = self.graph.add_node(3) - self.graph.add_edge(node_a, node_c, 2) - - def test_empty_graph(self): - graph = retworkx.PyGraph() - res = retworkx.spring_layout(graph) - self.assertEqual({}, res) - - def test_simple_graph(self): - res = retworkx.spring_layout(self.graph, seed=42) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_with_edge_weights(self): - res = retworkx.spring_layout(self.graph, weight_fn=lambda e: e) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_center(self): - res = retworkx.spring_layout(self.graph, center=[0.5, 0.5]) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_fixed(self): - pos = {0: [0.1, 0.1]} - res = retworkx.spring_layout(self.graph, pos=pos, fixed={0}) - self.assertEqual(res[0], pos[0]) - - def test_simple_graph_fixed_not_pos(self): - with self.assertRaises(ValueError): - retworkx.spring_layout(self.graph, fixed={0}) - - def test_simple_graph_linear_cooling(self): - res = retworkx.spring_layout(self.graph, adaptive_cooling=False) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_graph_with_removed_nodes(self): - graph = retworkx.PyDiGraph() - nodes = graph.add_nodes_from([0, 1, 2]) - graph.remove_node(nodes[1]) - res = retworkx.spring_layout(graph) - self.assertEqual(len(res), 2) - self.assertTrue(nodes[0] in res) - self.assertTrue(nodes[2] in res) - self.assertFalse(nodes[1] in res) diff --git a/tests/retworkx_backwards_compat/digraph/test_strongly_connected.py b/tests/retworkx_backwards_compat/digraph/test_strongly_connected.py deleted file mode 100644 index 0e1679004..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_strongly_connected.py +++ /dev/null @@ -1,67 +0,0 @@ -# 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 TestStronglyConnected(unittest.TestCase): - def test_number_strongly_connected_all_strong(self): - G = retworkx.PyDiGraph() - node_a = G.add_node(1) - node_b = G.add_child(node_a, 2, {}) - node_c = G.add_child(node_b, 3, {}) - self.assertEqual( - retworkx.strongly_connected_components(G), - [[node_c], [node_b], [node_a]], - ) - - def test_number_strongly_connected(self): - G = retworkx.PyDiGraph() - node_a = G.add_node(1) - node_b = G.add_child(node_a, 2, {}) - node_c = G.add_node(3) - self.assertEqual( - retworkx.strongly_connected_components(G), - [[node_c], [node_b], [node_a]], - ) - - def test_stongly_connected_no_linear(self): - G = retworkx.PyDiGraph() - G.add_nodes_from(list(range(8))) - G.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (1, 7), - (2, 3), - (2, 6), - (3, 4), - (4, 2), - (4, 5), - (6, 3), - (6, 5), - (7, 0), - (7, 6), - ] - ) - expected = [[5], [2, 3, 4, 6], [0, 1, 7]] - components = retworkx.strongly_connected_components(G) - self.assertEqual(components, expected) - - def test_number_strongly_connected_big(self): - G = retworkx.PyDiGraph() - for i in range(100000): - node = G.add_node(i) - G.add_child(node, str(i), {}) - self.assertEqual(len(retworkx.strongly_connected_components(G)), 200000) diff --git a/tests/retworkx_backwards_compat/digraph/test_subgraph.py b/tests/retworkx_backwards_compat/digraph/test_subgraph.py deleted file mode 100644 index 2b19343f0..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_subgraph.py +++ /dev/null @@ -1,150 +0,0 @@ -# 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 TestSubgraph(unittest.TestCase): - def test_subgraph(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3]) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - - def test_subgraph_empty_list(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_invalid_entry(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([42]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_pass_by_reference(self): - graph = retworkx.PyDiGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0]["a"] = 4 - self.assertEqual(subgraph[0]["a"], 4) - - def test_subgraph_replace_weight_no_reference(self): - graph = retworkx.PyDiGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0] = 4 - self.assertEqual(subgraph[0]["a"], 0) - - def test_edge_subgraph(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.edge_subgraph([(0, 1), (1, 3)]) - self.assertEqual(["a", "b", "d"], subgraph.nodes()) - self.assertEqual([(0, 1, 1), (1, 3, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_parallel_edge(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([(0, 1), (1, 2)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_empty_list(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([]) - self.assertEqual([], subgraph.nodes()) - - def test_edge_subgraph_non_edge(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - # 1->3 isn't an edge in graph - subgraph = graph.edge_subgraph([(0, 1), (1, 2), (1, 3)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_preserve_attrs(self): - graph = retworkx.PyGraph(attrs="My attribute") - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3], preserve_attrs=True) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - self.assertEqual(graph.attrs, subgraph.attrs) diff --git a/tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py b/tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py deleted file mode 100644 index 8bcdf61e5..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py +++ /dev/null @@ -1,266 +0,0 @@ -# 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 TestSubgraphIsomorphic(unittest.TestCase): - def test_empty_subgraph_isomorphic_identical(self): - g_a = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_empty_subgraph_isomorphic(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_subgraph_isomorphic_compare_nodes(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_identical(self): - g_a = retworkx.PyDiGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_subgraph_isomorphic_mismatch_node_data(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_subgraph_isomorphic_compare_nodes_mismatch_node_data(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_compare_nodes_identical(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_is_subgraph_isomorphic_nodes_compare_raises(self): - g_a = retworkx.PyDiGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises( - TypeError, - retworkx.is_subgraph_isomorphic, - (g_a, g_a, compare_nodes), - ) - - def test_subgraph_isomorphic_compare_edges_identical(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, - g_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_subgraph_isomorphic_node_count_not_ge(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1")]) - - nodes = g_b.add_nodes_from(["a_0", "a_1", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_subgraph_isomorphic_edge_matcher(self): - first = retworkx.PyDiGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyDiGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b")]) - - self.assertTrue( - retworkx.is_subgraph_isomorphic( - first, second, induced=False, edge_matcher=lambda x, y: x == y - ) - ) - - def test_subgraph_isomorphic_mismatch_edge_data_parallel_edges(self): - first = retworkx.PyDiGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "f"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyDiGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "a"), (1, 2, "b")]) - - self.assertFalse( - retworkx.is_subgraph_isomorphic( - first, second, id_order=True, edge_matcher=lambda x, y: x == y - ) - ) - - def test_non_induced_subgraph_isomorphic(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[0], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order, induced=True): - self.assertFalse( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=True) - ) - with self.subTest(id_order=id_order, induced=False): - self.assertTrue( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=False) - ) - - def test_non_induced_grid_subgraph_isomorphic(self): - g_a = retworkx.generators.directed_grid_graph(2, 2) - g_b = retworkx.PyDiGraph() - g_b.add_nodes_from([0, 1, 2, 3]) - g_b.add_edges_from_no_data([(0, 1), (2, 3)]) - - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=True)) - - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=False)) - - def test_subgraph_vf2_mapping(self): - graph = retworkx.generators.directed_grid_graph(10, 10) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True) - self.assertEqual(next(mapping), {0: 0, 1: 1, 10: 2, 11: 3}) - - def test_subgraph_vf2_all_mappings(self): - graph = retworkx.generators.directed_path_graph(3) - second_graph = retworkx.generators.directed_path_graph(2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True, id_order=True) - self.assertEqual(next(mapping), {0: 0, 1: 1}) - self.assertEqual(next(mapping), {2: 1, 1: 0}) - - def test_subgraph_vf2_mapping_vf2pp(self): - graph = retworkx.generators.directed_grid_graph(3, 3) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {4: 0, 5: 1, 7: 2, 8: 3}) - - def test_vf2pp_remapping(self): - temp = retworkx.generators.directed_grid_graph(3, 3) - - graph = retworkx.PyDiGraph() - dummy = graph.add_node(0) - - graph.compose(temp, dict()) - graph.remove_node(dummy) - - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {5: 0, 6: 1, 8: 2, 9: 3}) - - def test_empty_digraph_subgraph_vf2_mapping(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.digraph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=True) - self.assertEqual({}, next(mapping)) diff --git a/tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py b/tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py deleted file mode 100644 index c6f7996bc..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py +++ /dev/null @@ -1,163 +0,0 @@ -# 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 TestSubstitute(unittest.TestCase): - def setUp(self): - super().setUp() - self.graph = retworkx.generators.directed_path_graph(5) - - def test_empty_replacement(self): - in_graph = retworkx.PyDiGraph() - res = self.graph.substitute_node_with_subgraph(2, in_graph, lambda _, __, ___: None) - self.assertEqual(res, {}) - self.assertEqual([(0, 1), (3, 4)], self.graph.edge_list()) - - def test_single_node(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph(2, in_graph, lambda _, __, ___: 0) - self.assertEqual([(0, 1), (3, 4), (5, 6), (1, 5), (5, 3)], self.graph.edge_list()) - self.assertEqual("edge", self.graph.get_edge_data(5, 6)) - self.assertEqual(res, {0: 5, 1: 6}) - - def test_node_filter(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph( - 2, - in_graph, - lambda _, __, ___: 0, - node_filter=lambda node: node == 0, - ) - self.assertEqual([(0, 1), (3, 4), (1, 5), (5, 3)], self.graph.edge_list()) - self.assertEqual(res, {0: 5}) - - def test_edge_weight_modifier(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph( - 2, - in_graph, - lambda _, __, ___: 0, - edge_weight_map=lambda edge: edge + "-migrated", - ) - self.assertEqual([(0, 1), (3, 4), (5, 6), (1, 5), (5, 3)], self.graph.edge_list()) - self.assertEqual("edge-migrated", self.graph.get_edge_data(5, 6)) - self.assertEqual(res, {0: 5, 1: 6}) - - def test_none_mapping(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph(2, in_graph, lambda _, __, ___: None) - self.assertEqual([(0, 1), (3, 4), (5, 6)], self.graph.edge_list()) - self.assertEqual(res, {0: 5, 1: 6}) - - def test_multiple_mapping(self): - graph = retworkx.generators.directed_star_graph(5) - in_graph = retworkx.generators.directed_star_graph(3, inward=True) - - def map_function(source, target, _weight): - if target > 2: - return 2 - return 1 - - res = graph.substitute_node_with_subgraph(0, in_graph, map_function) - self.assertEqual({0: 5, 1: 6, 2: 7}, res) - expected = [(6, 5), (7, 5), (7, 4), (7, 3), (6, 2), (6, 1)] - self.assertEqual(expected, graph.edge_list()) - - def test_multiple_mapping_full(self): - graph = retworkx.generators.directed_star_graph(5) - in_graph = retworkx.generators.directed_star_graph(weights=list(range(3)), inward=True) - in_graph.add_edge(1, 2, None) - - def map_function(source, target, _weight): - if target > 2: - return 2 - return 1 - - def filter_fn(node): - return node > 0 - - def map_weight(_): - return "migrated" - - res = graph.substitute_node_with_subgraph(0, in_graph, map_function, filter_fn, map_weight) - self.assertEqual({1: 5, 2: 6}, res) - expected = [ - (5, 6, "migrated"), - (6, 4, None), - (6, 3, None), - (5, 2, None), - (5, 1, None), - ] - self.assertEqual(expected, graph.weighted_edge_list()) - - def test_invalid_target(self): - in_graph = retworkx.generators.directed_grid_graph(5, 5) - with self.assertRaises(IndexError): - self.graph.substitute_node_with_subgraph(0, in_graph, lambda *args: 42) - - def test_invalid_target_both_directions(self): - graph = retworkx.generators.directed_star_graph(4, inward=True) - in_graph = retworkx.generators.directed_grid_graph(5, 5) - with self.assertRaises(IndexError): - graph.substitute_node_with_subgraph(0, in_graph, lambda *args: 42) - graph = retworkx.generators.directed_star_graph(4, inward=False) - with self.assertRaises(IndexError): - graph.substitute_node_with_subgraph(0, in_graph, lambda *args: 42) - - def test_invalid_node_id(self): - in_graph = retworkx.generators.directed_grid_graph(5, 5) - with self.assertRaises(IndexError): - self.graph.substitute_node_with_subgraph(16, in_graph, lambda *args: None) - - def test_bidrectional(self): - graph = retworkx.generators.directed_path_graph(5, bidirectional=True) - in_graph = retworkx.generators.directed_star_graph(5, bidirectional=True) - - def map_function(source, target, _weight): - if source != 2: - return 0 - else: - return target - - res = graph.substitute_node_with_subgraph(2, in_graph, map_function) - expected_node_map = {0: 5, 1: 6, 2: 7, 3: 8, 4: 9} - self.assertEqual(expected_node_map, res) - expected_edge_list = [ - (0, 1), # From graph - (1, 0), # From graph - (3, 4), # From graph - (4, 3), # From graph - (6, 5), # From in_graph - (5, 6), # From in_graph - (7, 5), # From in_graph - (5, 7), # From in_graph - (8, 5), # From in_graph - (5, 8), # From in_graph - (9, 5), # From in_graph - (5, 9), # From in_graph - (3, 5), # output of res[map_function(3, 2, None)] -> 5 - (1, 5), # output of res[map_function(1, 2, None)] -> 5 - (8, 3), # output of res[map_function(2, 3, None)] -> 8 - (6, 1), # output of res[map_function(2, 1, None)] -> 6 - ] - self.assertEqual(expected_edge_list, graph.edge_list()) diff --git a/tests/retworkx_backwards_compat/digraph/test_symmetric.py b/tests/retworkx_backwards_compat/digraph/test_symmetric.py deleted file mode 100644 index 4cb54708e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_symmetric.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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 TestSymmetric(unittest.TestCase): - def test_single_neighbor(self): - digraph = retworkx.PyDiGraph() - node_a = digraph.add_node("a") - digraph.add_child(node_a, "b", {"a": 1}) - digraph.add_child(node_a, "c", {"a": 2}) - self.assertFalse(digraph.is_symmetric()) - - def test_bidirectional_ring(self): - digraph = retworkx.PyDiGraph() - edge_list = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 0), - (0, 3), - ] - digraph.extend_from_edge_list(edge_list) - self.assertTrue(digraph.is_symmetric()) diff --git a/tests/retworkx_backwards_compat/digraph/test_tensor_product.py b/tests/retworkx_backwards_compat/digraph/test_tensor_product.py deleted file mode 100644 index 8e38674c6..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_tensor_product.py +++ /dev/null @@ -1,110 +0,0 @@ -# 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 TestTensorProduct(unittest.TestCase): - def test_directed_null_tensor_null(self): - graph_1 = retworkx.PyDiGraph() - graph_2 = retworkx.PyDiGraph() - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 0) - self.assertEqual(graph_product.num_edges(), 0) - - def test_directed_path_2_tensor_path_2(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, node_map = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_node_map = {(0, 0): 0, (0, 1): 1, (1, 0): 2, (1, 1): 3} - self.assertEqual(node_map, expected_node_map) - - expected_edges = [(0, 3)] - self.assertEqual(graph_product.num_nodes(), 4) - self.assertEqual(graph_product.num_edges(), 1) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_directed_path_2_tensor_path_3(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(3) - - graph_product, node_map = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_node_map = {(0, 1): 1, (1, 0): 3, (0, 0): 0, (1, 2): 5, (0, 2): 2, (1, 1): 4} - self.assertEqual(dict(node_map), expected_node_map) - - expected_edges = [(0, 4), (1, 5)] - self.assertEqual(graph_product.num_nodes(), 6) - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_directed_node_weights_tensor(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_directed_edge_weights_tensor(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_nodes_from([0, 1]) - graph_2.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - self.assertEqual([("w_1", "w_2")], graph_product.edges()) - - def test_multi_graph_1(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_1.add_edge(0, 1, None) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_2(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_1.add_edge(0, 0, None) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 1)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_3(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - graph_2.add_edge(0, 1, None) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_4(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - graph_2.add_edge(0, 0, None) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 2)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) diff --git a/tests/retworkx_backwards_compat/digraph/test_to_undirected.py b/tests/retworkx_backwards_compat/digraph/test_to_undirected.py deleted file mode 100644 index 14b135dd8..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_to_undirected.py +++ /dev/null @@ -1,66 +0,0 @@ -# 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 TestToUndirected(unittest.TestCase): - def test_to_undirected_empty_graph(self): - digraph = retworkx.PyDiGraph() - graph = digraph.to_undirected() - self.assertEqual(0, len(graph)) - - def test_single_direction_graph(self): - digraph = retworkx.generators.directed_path_graph(5) - graph = digraph.to_undirected() - self.assertEqual(digraph.weighted_edge_list(), graph.weighted_edge_list()) - - def test_bidirectional_graph(self): - digraph = retworkx.generators.directed_path_graph(5) - for i in range(0, 4): - digraph.add_edge(i + 1, i, None) - graph = digraph.to_undirected() - self.assertEqual(digraph.weighted_edge_list(), graph.weighted_edge_list()) - - def test_bidirectional_not_multigraph(self): - digraph = retworkx.generators.directed_path_graph(5) - for i in range(0, 4): - digraph.add_edge(i + 1, i, None) - graph = digraph.to_undirected(multigraph=False) - self.assertEqual(graph.edge_list(), [(0, 1), (1, 2), (2, 3), (3, 4)]) - - def test_multiple_edges_combo_weight_not_multigraph(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from([0, 1]) - digraph.add_edges_from([(0, 1, "a"), (0, 1, "b")]) - graph = digraph.to_undirected(multigraph=False, weight_combo_fn=lambda x, y: x + y) - self.assertEqual(graph.weighted_edge_list(), [(0, 1, "ab")]) - - def test_shared_ref(self): - digraph = retworkx.PyDiGraph() - node_weight = {"a": 1} - node_a = digraph.add_node(node_weight) - edge_weight = {"a": 1} - digraph.add_child(node_a, "b", edge_weight) - graph = digraph.to_undirected() - self.assertEqual(digraph[node_a], {"a": 1}) - self.assertEqual(graph[node_a], {"a": 1}) - node_weight["b"] = 2 - self.assertEqual(digraph[node_a], {"a": 1, "b": 2}) - self.assertEqual(graph[node_a], {"a": 1, "b": 2}) - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1}) - edge_weight["b"] = 2 - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1, "b": 2}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1, "b": 2}) diff --git a/tests/retworkx_backwards_compat/digraph/test_toposort.py b/tests/retworkx_backwards_compat/digraph/test_toposort.py deleted file mode 100644 index 08acd6352..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_toposort.py +++ /dev/null @@ -1,84 +0,0 @@ -# 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 TestTopologicalSorter(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_edge_list( - [ - (0, 2), - (1, 2), - (2, 3), - (2, 4), - (3, 5), - ] - ) - - def test_topo_sort(self): - sorter = retworkx.TopologicalSorter(self.graph) - nodes = sorter.get_ready() - self.assertEqual(nodes, [0, 1]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, [2]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, [4, 3]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, [5]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, []) - - def test_topo_sort_do_not_emit_if_node_has_undone_preds(self): - sorter = retworkx.TopologicalSorter(self.graph) - nodes = sorter.get_ready() - self.assertEqual(nodes, [0, 1]) - sorter.done([0]) - nodes = sorter.get_ready() - self.assertEqual(nodes, []) - - def test_topo_sort_raises_if_node_not_ready(self): - sorter = retworkx.TopologicalSorter(self.graph) - with self.assertRaises(ValueError): - sorter.done([0]) - - def test_topo_sort_raises_if_node_already_done(self): - sorter = retworkx.TopologicalSorter(self.graph) - sorter.get_ready() - sorter.done([0]) - with self.assertRaises(ValueError): - sorter.done([0]) - - def test_topo_sort_raises_if_graph_has_cycle(self): - graph = retworkx.generators.directed_cycle_graph(5) - with self.assertRaises(retworkx.DAGHasCycle): - _ = retworkx.TopologicalSorter(graph) - - def test_topo_sort_progress_if_graph_has_cycle_and_cycle_check_disabled( - self, - ): - graph = retworkx.generators.directed_cycle_graph(5) - starting_node = graph.add_node("starting node") - graph.add_edge(starting_node, 0, "starting edge") - - sorter = retworkx.TopologicalSorter(graph, check_cycle=False) - nodes = sorter.get_ready() - self.assertEqual(nodes, [starting_node]) - sorter.done(nodes) - self.assertFalse(sorter.is_active()) diff --git a/tests/retworkx_backwards_compat/digraph/test_transitivity.py b/tests/retworkx_backwards_compat/digraph/test_transitivity.py deleted file mode 100644 index 5b95efe4c..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_transitivity.py +++ /dev/null @@ -1,43 +0,0 @@ -# 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 TestTransitivity(unittest.TestCase): - def test_transitivity_directed(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(5))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 3 / 10) - - def test_transitivity_triangle_directed(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(3))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.5) - - def test_transitivity_fulltriangle_directed(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(3))) - graph.add_edges_from_no_data([(0, 1), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 1.0) - - def test_transitivity_empty_directed(self): - graph = retworkx.PyDiGraph() - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) diff --git a/tests/retworkx_backwards_compat/digraph/test_union.py b/tests/retworkx_backwards_compat/digraph/test_union.py deleted file mode 100644 index d1fcaf2e9..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_union.py +++ /dev/null @@ -1,105 +0,0 @@ -# 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 TestUnion(unittest.TestCase): - def test_union_merge_all(self): - dag_a = retworkx.PyDiGraph() - dag_b = retworkx.PyDiGraph() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "e_1") - dag_a.add_child(node_a, "a_3", "e_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "e_1") - dag_b.add_child(node_b, "a_3", "e_2") - - dag_c = retworkx.digraph_union(dag_a, dag_b, True, True) - - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_c)) - - def test_union_basic_merge_nodes_only(self): - dag_a = retworkx.PyDiGraph() - dag_b = retworkx.PyDiGraph() - - node_a = dag_a.add_node("a_1") - child_a = dag_a.add_child(node_a, "a_2", "e_1") - dag_a.add_child(node_a, "a_3", "e_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "e_1") - dag_b.add_child(node_b, "a_3", "e_2") - - dag_c = retworkx.digraph_union(dag_a, dag_b, True, False) - - self.assertTrue(len(dag_c.edge_list()) == 4) - self.assertTrue(len(dag_c.get_all_edge_data(node_a, child_a)) == 2) - self.assertTrue(len(dag_c.nodes()) == 3) - - def test_union_basic_merge_none(self): - dag_a = retworkx.PyDiGraph() - dag_b = retworkx.PyDiGraph() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "e_1") - dag_a.add_child(node_a, "a_3", "r_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "e_1") - dag_b.add_child(node_b, "a_3", "e_2") - - dag_c = retworkx.digraph_union(dag_a, dag_b, False, False) - - self.assertTrue(len(dag_c.nodes()) == 6) - self.assertTrue(len(dag_c.edge_list()) == 4) - - def test_union_mismatch_edge_weight(self): - first = retworkx.PyDiGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyDiGraph() - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.digraph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 1, "b")]) - - def test_union_node_hole(self): - first = retworkx.PyDiGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyDiGraph() - dummy = second.add_node("dummy") - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "a")]) - second.remove_node(dummy) - - final = retworkx.digraph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a")]) - - def test_union_edge_between_merged_and_unmerged_nodes(self): - first = retworkx.PyDiGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyDiGraph() - nodes = second.add_nodes_from([0, 2]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.digraph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 2, "b")]) diff --git a/tests/retworkx_backwards_compat/digraph/test_weakly_connected.py b/tests/retworkx_backwards_compat/digraph/test_weakly_connected.py deleted file mode 100644 index 93fdcbdde..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_weakly_connected.py +++ /dev/null @@ -1,81 +0,0 @@ -# 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 TestWeaklyConnected(unittest.TestCase): - def test_number_weakly_connected_all_strong(self): - G = retworkx.PyDAG() - node_a = G.add_node(1) - node_b = G.add_child(node_a, 2, {}) - G.add_child(node_b, 3, {}) - self.assertEqual(retworkx.number_weakly_connected_components(G), 1) - - def test_number_weakly_connected(self): - G = retworkx.PyDAG() - node_a = G.add_node(1) - G.add_child(node_a, 2, {}) - G.add_node(3) - self.assertEqual(retworkx.number_weakly_connected_components(G), 2) - - def test_number_weakly_connected_big(self): - G = retworkx.PyDAG() - for i in range(100000): - node = G.add_node(i) - G.add_child(node, str(i), {}) - self.assertEqual(retworkx.number_weakly_connected_components(G), 100000) - - def test_number_weakly_connected_node_holes(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2]) - graph.remove_node(1) - self.assertEqual(retworkx.number_weakly_connected_components(graph), 2) - - def test_weakly_connected_components(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - components = retworkx.weakly_connected_components(graph) - self.assertEqual([{0, 1, 2, 3}, {4, 5, 6, 7}], components) - - def test_is_weakly_connected_false(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - self.assertFalse(retworkx.is_weakly_connected(graph)) - - def test_is_weakly_connected_true(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (2, 4), - (4, 5), - (5, 6), - (6, 7), - (7, 4), - ] - ) - self.assertTrue(retworkx.is_weakly_connected(graph)) - - def test_is_weakly_connected_null_graph(self): - graph = retworkx.PyDiGraph() - with self.assertRaises(retworkx.NullGraph): - retworkx.is_weakly_connected(graph) diff --git a/tests/retworkx_backwards_compat/generators/__init__.py b/tests/retworkx_backwards_compat/generators/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/generators/test_barbell.py b/tests/retworkx_backwards_compat/generators/test_barbell.py deleted file mode 100644 index 596ca95ad..000000000 --- a/tests/retworkx_backwards_compat/generators/test_barbell.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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 TestBarbellGraph(unittest.TestCase): - def test_barbell_graph_count(self): - graph = retworkx.generators.barbell_graph(17, 3) - self.assertEqual(len(graph), 37) - self.assertEqual(len(graph.edges()), 276) - - def test_barbell_graph_edge(self): - graph = retworkx.generators.barbell_graph(4, 3) - edge_list = graph.edge_list() - expected_edge_list = set( - [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (6, 7), - (7, 8), - (7, 9), - (7, 10), - (8, 9), - (8, 10), - (9, 10), - ] - ) - self.assertEqual(set(edge_list), set(expected_edge_list)) - - def test_barbell_graph_no_path_num(self): - graph = retworkx.generators.barbell_graph(4) - mesh = retworkx.generators.mesh_graph(4) - mesh.compose(mesh.copy(), {3: (0, None)}) - self.assertEqual(set(graph.edge_list()), set(mesh.edge_list())) - - def test_barbell_graph_no_mesh_num(self): - with self.assertRaises(IndexError): - retworkx.generators.barbell_graph() diff --git a/tests/retworkx_backwards_compat/generators/test_binomial_tree.py b/tests/retworkx_backwards_compat/generators/test_binomial_tree.py deleted file mode 100644 index f055bbbc0..000000000 --- a/tests/retworkx_backwards_compat/generators/test_binomial_tree.py +++ /dev/null @@ -1,195 +0,0 @@ -# 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 TestBinomialTreeGraph(unittest.TestCase): - def test_binomial_tree_graph(self): - expected_edges = { - 0: [], - 1: [(0, 1)], - 2: [(0, 1), (2, 3), (0, 2)], - 3: [(0, 1), (2, 3), (0, 2), (4, 5), (6, 7), (4, 6), (0, 4)], - 4: [ - (0, 1), - (2, 3), - (0, 2), - (4, 5), - (6, 7), - (4, 6), - (0, 4), - (8, 9), - (10, 11), - (8, 10), - (12, 13), - (14, 15), - (12, 14), - (8, 12), - (0, 8), - ], - } - for n in range(5): - with self.subTest(n=n): - graph = retworkx.generators.binomial_tree_graph(n) - self.assertEqual(len(graph), 2**n) - self.assertEqual(len(graph.edges()), 2**n - 1) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_binomial_tree_graph_weights(self): - graph = retworkx.generators.binomial_tree_graph(2, weights=list(range(4))) - expected_edges = [(0, 1), (2, 3), (0, 2)] - self.assertEqual(len(graph), 4) - self.assertEqual([x for x in range(4)], graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_binomial_tree_graph_weight_less_nodes(self): - graph = retworkx.generators.binomial_tree_graph(2, weights=list(range(2))) - self.assertEqual(len(graph), 4) - expected_weights = [x for x in range(2)] - expected_weights.extend([None, None]) - self.assertEqual(expected_weights, graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - - def test_binomial_tree_graph_weights_greater_nodes(self): - with self.assertRaises(IndexError): - retworkx.generators.binomial_tree_graph(2, weights=list(range(7))) - - def test_binomial_tree_no_order(self): - with self.assertRaises(TypeError): - retworkx.generators.binomial_tree_graph(weights=list(range(4))) - - def test_directed_binomial_tree_graph(self): - expected_edges = { - 0: [], - 1: [(0, 1)], - 2: [(0, 1), (2, 3), (0, 2)], - 3: [(0, 1), (2, 3), (0, 2), (4, 5), (6, 7), (4, 6), (0, 4)], - 4: [ - (0, 1), - (2, 3), - (0, 2), - (4, 5), - (6, 7), - (4, 6), - (0, 4), - (8, 9), - (10, 11), - (8, 10), - (12, 13), - (14, 15), - (12, 14), - (8, 12), - (0, 8), - ], - } - - for n in range(5): - with self.subTest(n=n): - graph = retworkx.generators.directed_binomial_tree_graph(n) - self.assertEqual(len(graph), 2**n) - self.assertEqual(len(graph.edges()), 2**n - 1) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_directed_binomial_tree_graph_weights(self): - graph = retworkx.generators.directed_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_directed_binomial_tree_graph_weight_less_nodes(self): - graph = retworkx.generators.directed_binomial_tree_graph(2, weights=list(range(2))) - self.assertEqual(len(graph), 4) - expected_weights = [x for x in range(2)] - expected_weights.extend([None, None]) - self.assertEqual(expected_weights, graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - - def test_directed_binomial_tree_graph_weights_greater_nodes(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_binomial_tree_graph(2, weights=list(range(7))) - - def test_directed_binomial_tree_no_order(self): - with self.assertRaises(TypeError): - retworkx.generators.directed_binomial_tree_graph(weights=list(range(4))) - - def test_directed_binomial_tree_graph_bidirectional(self): - expected_edges = { - 0: [], - 1: [(0, 1), (1, 0)], - 2: [(0, 1), (1, 0), (2, 3), (3, 2), (0, 2), (2, 0)], - 3: [ - (0, 1), - (1, 0), - (2, 3), - (3, 2), - (0, 2), - (2, 0), - (4, 5), - (5, 4), - (6, 7), - (7, 6), - (4, 6), - (6, 4), - (0, 4), - (4, 0), - ], - 4: [ - (0, 1), - (1, 0), - (2, 3), - (3, 2), - (0, 2), - (2, 0), - (4, 5), - (5, 4), - (6, 7), - (7, 6), - (4, 6), - (6, 4), - (0, 4), - (4, 0), - (8, 9), - (9, 8), - (10, 11), - (11, 10), - (8, 10), - (10, 8), - (12, 13), - (13, 12), - (14, 15), - (15, 14), - (12, 14), - (14, 12), - (8, 12), - (12, 8), - (0, 8), - (8, 0), - ], - } - for n in range(5): - with self.subTest(n=n): - graph = retworkx.generators.directed_binomial_tree_graph(n, bidirectional=True) - self.assertEqual(len(graph), 2**n) - self.assertEqual(len(graph.edges()), 2 * (2**n - 1)) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_overflow_binomial_tree(self): - with self.assertRaises(OverflowError): - retworkx.generators.binomial_tree_graph(75) - - def test_overflow_directed_binomial_tree(self): - with self.assertRaises(OverflowError): - retworkx.generators.directed_binomial_tree_graph(75) diff --git a/tests/retworkx_backwards_compat/generators/test_cycle.py b/tests/retworkx_backwards_compat/generators/test_cycle.py deleted file mode 100644 index 72199776e..000000000 --- a/tests/retworkx_backwards_compat/generators/test_cycle.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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 TestCycleGraph(unittest.TestCase): - def test_directed_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), [(19, 0, None)]) - - def test_directed_cycle_graph_weights(self): - graph = retworkx.generators.directed_cycle_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()), 20) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), [(19, 0, None)]) - - def test_directed_cycle_graph_bidirectional(self): - graph = retworkx.generators.directed_cycle_graph(20, bidirectional=True) - self.assertEqual(graph.out_edges(0), [(0, 19, None), (0, 1, None)]) - self.assertEqual(graph.in_edges(0), [(19, 0, None), (1, 0, None)]) - for i in range(1, 19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None), (i, i - 1, None)]) - self.assertEqual(graph.in_edges(i), [(i + 1, i, None), (i - 1, i, None)]) - self.assertEqual(graph.out_edges(19), [(19, 0, None), (19, 18, None)]) - self.assertEqual(graph.in_edges(19), [(0, 19, None), (18, 19, None)]) - - def test_cycle_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_cycle_graph() - - def test_cycle_graph(self): - graph = retworkx.generators.cycle_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20) - - def test_cycle_graph_weights(self): - graph = retworkx.generators.cycle_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()), 20) - - def test_cycle_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.cycle_graph() - - def test_zero_length_cycle_graph(self): - graph = retworkx.generators.cycle_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_length_directed_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/generators/test_full_rary_tree.py b/tests/retworkx_backwards_compat/generators/test_full_rary_tree.py deleted file mode 100644 index 93195a99a..000000000 --- a/tests/retworkx_backwards_compat/generators/test_full_rary_tree.py +++ /dev/null @@ -1,89 +0,0 @@ -# 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 TestFullRaryTreeTreeGraph(unittest.TestCase): - def test_full_rary_tree_graph(self): - b_factors = { - 0: 0, - 1: 2, - 2: 2, - 3: 5, - } - num_nodes = { - 0: 0, - 1: 4, - 2: 10, - 3: 15, - } - expected_edges = { - 0: [], - 1: [(0, 1), (0, 2), (1, 3)], - 2: [ - (0, 1), - (0, 2), - (1, 3), - (1, 4), - (2, 5), - (2, 6), - (3, 7), - (3, 8), - (4, 9), - ], - 3: [ - (0, 1), - (0, 2), - (0, 3), - (0, 4), - (0, 5), - (1, 6), - (1, 7), - (1, 8), - (1, 9), - (1, 10), - (2, 11), - (2, 12), - (2, 13), - (2, 14), - ], - } - for n in range(4): - with self.subTest(n=n): - graph = retworkx.generators.full_rary_tree(b_factors[n], num_nodes[n]) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_full_rary_tree_graph_weights(self): - graph = retworkx.generators.full_rary_tree(2, 4, weights=list(range(4))) - expected_edges = [(0, 1), (0, 2), (1, 3)] - self.assertEqual(len(graph), 4) - self.assertEqual([x for x in range(4)], graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_full_rary_tree_graph_weight_less_nodes(self): - graph = retworkx.generators.full_rary_tree(2, 6, weights=list(range(4))) - self.assertEqual(len(graph), 6) - expected_weights = [x for x in range(4)] - expected_weights.extend([None, None]) - self.assertEqual(expected_weights, graph.nodes()) - self.assertEqual(len(graph.edges()), 5) - - def test_full_rary_tree_graph_weights_greater_nodes(self): - with self.assertRaises(IndexError): - retworkx.generators.full_rary_tree(2, 4, weights=list(range(7))) - - def test_full_rary_tree_no_order(self): - with self.assertRaises(TypeError): - retworkx.generators.full_rary_tree(weights=list(range(4))) diff --git a/tests/retworkx_backwards_compat/generators/test_grid.py b/tests/retworkx_backwards_compat/generators/test_grid.py deleted file mode 100644 index a50c4653d..000000000 --- a/tests/retworkx_backwards_compat/generators/test_grid.py +++ /dev/null @@ -1,131 +0,0 @@ -# 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 TestGridGraph(unittest.TestCase): - def test_directed_grid_graph_dimensions(self): - graph = retworkx.generators.directed_grid_graph(4, 5) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_directed_grid_graph_weights(self): - graph = retworkx.generators.directed_grid_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()), 19) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), []) - for i in range(1, 20): - self.assertEqual(graph.in_edges(i), [(i - 1, i, None)]) - self.assertEqual(graph.in_edges(0), []) - - def test_directed_grid_graph_dimensions_weights(self): - graph = retworkx.generators.directed_grid_graph(4, 5, weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_directed_grid_graph_more_dimensions_weights(self): - graph = retworkx.generators.directed_grid_graph(4, 5, weights=list(range(16))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(16)] + [None] * 4, graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_directed_grid_graph_less_dimensions_weights(self): - graph = retworkx.generators.directed_grid_graph(4, 5, weights=list(range(24))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_grid_directed_no_weights_or_dim(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_grid_graph() - retworkx.generators.directed_grid_graph(rows=5, weights=[1] * 5) - retworkx.generators.directed_grid_graph(cols=5, weights=[1] * 5) - - def test_grid_graph_dimensions(self): - graph = retworkx.generators.grid_graph(4, 5) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 31) - - def test_grid_graph_weights(self): - graph = retworkx.generators.grid_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()), 19) - - def test_grid_graph_dimensions_weights(self): - graph = retworkx.generators.grid_graph(4, 5, weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - - graph = retworkx.generators.grid_graph(4, 5, weights=list(range(16))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(16)] + [None] * 4, graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - - graph = retworkx.generators.grid_graph(4, 5, weights=list(range(24))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - - def test_grid_no_weights_or_dim(self): - with self.assertRaises(IndexError): - retworkx.generators.grid_graph() - retworkx.generators.grid_graph(rows=5, weights=[1] * 5) - retworkx.generators.grid_graph(cols=5, weights=[1] * 5) diff --git a/tests/retworkx_backwards_compat/generators/test_heavy_hex.py b/tests/retworkx_backwards_compat/generators/test_heavy_hex.py deleted file mode 100644 index 09e5093fc..000000000 --- a/tests/retworkx_backwards_compat/generators/test_heavy_hex.py +++ /dev/null @@ -1,424 +0,0 @@ -# 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 TestHeavyHexGraph(unittest.TestCase): - def test_directed_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.directed_heavy_hex_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.heavy_hex_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_directed_heavy_hex_graph_3(self): - d = 3 - graph = retworkx.generators.directed_heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 13), - (1, 13), - (1, 14), - (2, 14), - (3, 15), - (4, 15), - (4, 16), - (5, 16), - (6, 17), - (7, 17), - (7, 18), - (8, 18), - (0, 9), - (3, 9), - (5, 12), - (8, 12), - (10, 14), - (10, 16), - (11, 15), - (11, 17), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_hex_graph_3_bidirectional(self): - d = 3 - graph = retworkx.generators.directed_heavy_hex_graph(d, bidirectional=True) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + (d + 1) * (d - 1))) - expected_edges = [ - (0, 13), - (1, 13), - (13, 0), - (13, 1), - (1, 14), - (2, 14), - (14, 1), - (14, 2), - (3, 15), - (4, 15), - (15, 3), - (15, 4), - (4, 16), - (5, 16), - (16, 4), - (16, 5), - (6, 17), - (7, 17), - (17, 6), - (17, 7), - (7, 18), - (8, 18), - (18, 7), - (18, 8), - (0, 9), - (3, 9), - (9, 0), - (9, 3), - (5, 12), - (8, 12), - (12, 5), - (12, 8), - (10, 14), - (10, 16), - (14, 10), - (16, 10), - (11, 15), - (11, 17), - (15, 11), - (17, 11), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_hex_graph_3(self): - d = 3 - graph = retworkx.generators.heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 13), - (1, 13), - (1, 14), - (2, 14), - (3, 15), - (4, 15), - (4, 16), - (5, 16), - (6, 17), - (7, 17), - (7, 18), - (8, 18), - (0, 9), - (3, 9), - (5, 12), - (8, 12), - (10, 14), - (10, 16), - (11, 15), - (11, 17), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_hex_graph_5(self): - d = 5 - graph = retworkx.generators.directed_heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 37), - (1, 37), - (1, 38), - (2, 38), - (2, 39), - (3, 39), - (3, 40), - (4, 40), - (5, 41), - (6, 41), - (6, 42), - (7, 42), - (7, 43), - (8, 43), - (8, 44), - (9, 44), - (10, 45), - (11, 45), - (11, 46), - (12, 46), - (12, 47), - (13, 47), - (13, 48), - (14, 48), - (15, 49), - (16, 49), - (16, 50), - (17, 50), - (17, 51), - (18, 51), - (18, 52), - (19, 52), - (20, 53), - (21, 53), - (21, 54), - (22, 54), - (22, 55), - (23, 55), - (23, 56), - (24, 56), - (0, 25), - (5, 25), - (9, 30), - (14, 30), - (10, 31), - (15, 31), - (19, 36), - (24, 36), - (26, 38), - (26, 42), - (27, 40), - (27, 44), - (28, 41), - (28, 45), - (29, 43), - (29, 47), - (32, 46), - (32, 50), - (33, 48), - (33, 52), - (34, 49), - (34, 53), - (35, 51), - (35, 55), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_hex_graph_5_bidirectional(self): - d = 5 - graph = retworkx.generators.directed_heavy_hex_graph(d, bidirectional=True) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + (d + 1) * (d - 1))) - expected_edges = [ - (0, 37), - (1, 37), - (37, 0), - (37, 1), - (1, 38), - (2, 38), - (38, 1), - (38, 2), - (2, 39), - (3, 39), - (39, 2), - (39, 3), - (3, 40), - (4, 40), - (40, 3), - (40, 4), - (5, 41), - (6, 41), - (41, 5), - (41, 6), - (6, 42), - (7, 42), - (42, 6), - (42, 7), - (7, 43), - (8, 43), - (43, 7), - (43, 8), - (8, 44), - (9, 44), - (44, 8), - (44, 9), - (10, 45), - (11, 45), - (45, 10), - (45, 11), - (11, 46), - (12, 46), - (46, 11), - (46, 12), - (12, 47), - (13, 47), - (47, 12), - (47, 13), - (13, 48), - (14, 48), - (48, 13), - (48, 14), - (15, 49), - (16, 49), - (49, 15), - (49, 16), - (16, 50), - (17, 50), - (50, 16), - (50, 17), - (17, 51), - (18, 51), - (51, 17), - (51, 18), - (18, 52), - (19, 52), - (52, 18), - (52, 19), - (20, 53), - (21, 53), - (53, 20), - (53, 21), - (21, 54), - (22, 54), - (54, 21), - (54, 22), - (22, 55), - (23, 55), - (55, 22), - (55, 23), - (23, 56), - (24, 56), - (56, 23), - (56, 24), - (0, 25), - (5, 25), - (25, 0), - (25, 5), - (9, 30), - (14, 30), - (30, 9), - (30, 14), - (10, 31), - (15, 31), - (31, 10), - (31, 15), - (19, 36), - (24, 36), - (36, 19), - (36, 24), - (26, 38), - (26, 42), - (38, 26), - (42, 26), - (27, 40), - (27, 44), - (40, 27), - (44, 27), - (28, 41), - (28, 45), - (41, 28), - (45, 28), - (29, 43), - (29, 47), - (43, 29), - (47, 29), - (32, 46), - (32, 50), - (46, 32), - (50, 32), - (33, 48), - (33, 52), - (48, 33), - (52, 33), - (34, 49), - (34, 53), - (49, 34), - (53, 34), - (35, 51), - (35, 55), - (51, 35), - (55, 35), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_hex_graph_5(self): - d = 5 - graph = retworkx.generators.heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 37), - (1, 37), - (1, 38), - (2, 38), - (2, 39), - (3, 39), - (3, 40), - (4, 40), - (5, 41), - (6, 41), - (6, 42), - (7, 42), - (7, 43), - (8, 43), - (8, 44), - (9, 44), - (10, 45), - (11, 45), - (11, 46), - (12, 46), - (12, 47), - (13, 47), - (13, 48), - (14, 48), - (15, 49), - (16, 49), - (16, 50), - (17, 50), - (17, 51), - (18, 51), - (18, 52), - (19, 52), - (20, 53), - (21, 53), - (21, 54), - (22, 54), - (22, 55), - (23, 55), - (23, 56), - (24, 56), - (0, 25), - (5, 25), - (9, 30), - (14, 30), - (10, 31), - (15, 31), - (19, 36), - (24, 36), - (26, 38), - (26, 42), - (27, 40), - (27, 44), - (28, 41), - (28, 45), - (29, 43), - (29, 47), - (32, 46), - (32, 50), - (33, 48), - (33, 52), - (34, 49), - (34, 53), - (35, 51), - (35, 55), - ] - - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_hex_graph_even_d(self): - with self.assertRaises(IndexError): - retworkx.generators.heavy_hex_graph(2) diff --git a/tests/retworkx_backwards_compat/generators/test_heavy_square.py b/tests/retworkx_backwards_compat/generators/test_heavy_square.py deleted file mode 100644 index c47e7d9e7..000000000 --- a/tests/retworkx_backwards_compat/generators/test_heavy_square.py +++ /dev/null @@ -1,503 +0,0 @@ -# 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 TestHeavyHexGraph(unittest.TestCase): - def test_directed_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.directed_heavy_square_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.heavy_square_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_directed_heavy_square_graph_5(self): - d = 5 - graph = retworkx.generators.directed_heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 45), - (45, 1), - (1, 46), - (46, 2), - (2, 47), - (47, 3), - (3, 48), - (48, 4), - (5, 49), - (49, 6), - (6, 50), - (50, 7), - (7, 51), - (51, 8), - (8, 52), - (52, 9), - (10, 53), - (53, 11), - (11, 54), - (54, 12), - (12, 55), - (55, 13), - (13, 56), - (56, 14), - (15, 57), - (57, 16), - (16, 58), - (58, 17), - (17, 59), - (59, 18), - (18, 60), - (60, 19), - (20, 61), - (61, 21), - (21, 62), - (62, 22), - (22, 63), - (63, 23), - (23, 64), - (64, 24), - (4, 29), - (9, 29), - (5, 30), - (10, 30), - (14, 39), - (19, 39), - (15, 40), - (20, 40), - (25, 45), - (25, 49), - (26, 46), - (26, 50), - (27, 47), - (27, 51), - (28, 48), - (28, 52), - (31, 49), - (31, 53), - (32, 50), - (32, 54), - (33, 51), - (33, 55), - (34, 52), - (34, 56), - (35, 53), - (35, 57), - (36, 54), - (36, 58), - (37, 55), - (37, 59), - (38, 56), - (38, 60), - (41, 57), - (41, 61), - (42, 58), - (42, 62), - (43, 59), - (43, 63), - (44, 60), - (44, 64), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_square_graph_5_bidirectional(self): - d = 5 - graph = retworkx.generators.directed_heavy_square_graph(d, bidirectional=True) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + 2 * d * (d - 1))) - expected_edges = [ - (0, 45), - (45, 1), - (45, 0), - (1, 45), - (1, 46), - (46, 2), - (46, 1), - (2, 46), - (2, 47), - (47, 3), - (47, 2), - (3, 47), - (3, 48), - (48, 4), - (48, 3), - (4, 48), - (5, 49), - (49, 6), - (49, 5), - (6, 49), - (6, 50), - (50, 7), - (50, 6), - (7, 50), - (7, 51), - (51, 8), - (51, 7), - (8, 51), - (8, 52), - (52, 9), - (52, 8), - (9, 52), - (10, 53), - (53, 11), - (53, 10), - (11, 53), - (11, 54), - (54, 12), - (54, 11), - (12, 54), - (12, 55), - (55, 13), - (55, 12), - (13, 55), - (13, 56), - (56, 14), - (56, 13), - (14, 56), - (15, 57), - (57, 16), - (57, 15), - (16, 57), - (16, 58), - (58, 17), - (58, 16), - (17, 58), - (17, 59), - (59, 18), - (59, 17), - (18, 59), - (18, 60), - (60, 19), - (60, 18), - (19, 60), - (20, 61), - (61, 21), - (61, 20), - (21, 61), - (21, 62), - (62, 22), - (62, 21), - (22, 62), - (22, 63), - (63, 23), - (63, 22), - (23, 63), - (23, 64), - (64, 24), - (64, 23), - (24, 64), - (4, 29), - (9, 29), - (29, 4), - (29, 9), - (5, 30), - (10, 30), - (30, 5), - (30, 10), - (14, 39), - (19, 39), - (39, 14), - (39, 19), - (15, 40), - (20, 40), - (40, 15), - (40, 20), - (25, 45), - (25, 49), - (45, 25), - (49, 25), - (26, 46), - (26, 50), - (46, 26), - (50, 26), - (27, 47), - (27, 51), - (47, 27), - (51, 27), - (28, 48), - (28, 52), - (48, 28), - (52, 28), - (31, 49), - (31, 53), - (49, 31), - (53, 31), - (32, 50), - (32, 54), - (50, 32), - (54, 32), - (33, 51), - (33, 55), - (51, 33), - (55, 33), - (34, 52), - (34, 56), - (52, 34), - (56, 34), - (35, 53), - (35, 57), - (53, 35), - (57, 35), - (36, 54), - (36, 58), - (54, 36), - (58, 36), - (37, 55), - (37, 59), - (55, 37), - (59, 37), - (38, 56), - (38, 60), - (56, 38), - (60, 38), - (41, 57), - (41, 61), - (57, 41), - (61, 41), - (42, 58), - (42, 62), - (58, 42), - (62, 42), - (43, 59), - (43, 63), - (59, 43), - (63, 43), - (44, 60), - (44, 64), - (60, 44), - (64, 44), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_square_graph_5(self): - d = 5 - graph = retworkx.generators.heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 45), - (45, 1), - (1, 46), - (46, 2), - (2, 47), - (47, 3), - (3, 48), - (48, 4), - (5, 49), - (49, 6), - (6, 50), - (50, 7), - (7, 51), - (51, 8), - (8, 52), - (52, 9), - (10, 53), - (53, 11), - (11, 54), - (54, 12), - (12, 55), - (55, 13), - (13, 56), - (56, 14), - (15, 57), - (57, 16), - (16, 58), - (58, 17), - (17, 59), - (59, 18), - (18, 60), - (60, 19), - (20, 61), - (61, 21), - (21, 62), - (62, 22), - (22, 63), - (63, 23), - (23, 64), - (64, 24), - (4, 29), - (9, 29), - (5, 30), - (10, 30), - (14, 39), - (19, 39), - (15, 40), - (20, 40), - (25, 45), - (25, 49), - (26, 46), - (26, 50), - (27, 47), - (27, 51), - (28, 48), - (28, 52), - (31, 49), - (31, 53), - (32, 50), - (32, 54), - (33, 51), - (33, 55), - (34, 52), - (34, 56), - (35, 53), - (35, 57), - (36, 54), - (36, 58), - (37, 55), - (37, 59), - (38, 56), - (38, 60), - (41, 57), - (41, 61), - (42, 58), - (42, 62), - (43, 59), - (43, 63), - (44, 60), - (44, 64), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_square_graph_3(self): - d = 3 - graph = retworkx.generators.directed_heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 15), - (15, 1), - (1, 16), - (16, 2), - (3, 17), - (17, 4), - (4, 18), - (18, 5), - (6, 19), - (19, 7), - (7, 20), - (20, 8), - (2, 11), - (5, 11), - (3, 12), - (6, 12), - (9, 15), - (9, 17), - (10, 16), - (10, 18), - (13, 17), - (13, 19), - (14, 18), - (14, 20), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_square_graph_3_bidirectional(self): - d = 3 - graph = retworkx.generators.directed_heavy_square_graph(d, bidirectional=True) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + 2 * d * (d - 1))) - expected_edges = [ - (0, 15), - (15, 1), - (15, 0), - (1, 15), - (1, 16), - (16, 2), - (16, 1), - (2, 16), - (3, 17), - (17, 4), - (17, 3), - (4, 17), - (4, 18), - (18, 5), - (18, 4), - (5, 18), - (6, 19), - (19, 7), - (19, 6), - (7, 19), - (7, 20), - (20, 8), - (20, 7), - (8, 20), - (2, 11), - (5, 11), - (11, 2), - (11, 5), - (3, 12), - (6, 12), - (12, 3), - (12, 6), - (9, 15), - (9, 17), - (15, 9), - (17, 9), - (10, 16), - (10, 18), - (16, 10), - (18, 10), - (13, 17), - (13, 19), - (17, 13), - (19, 13), - (14, 18), - (14, 20), - (18, 14), - (20, 14), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_square_graph_3(self): - d = 3 - graph = retworkx.generators.heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 15), - (15, 1), - (1, 16), - (16, 2), - (3, 17), - (17, 4), - (4, 18), - (18, 5), - (6, 19), - (19, 7), - (7, 20), - (20, 8), - (2, 11), - (5, 11), - (3, 12), - (6, 12), - (9, 15), - (9, 17), - (10, 16), - (10, 18), - (13, 17), - (13, 19), - (14, 18), - (14, 20), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_square_graph_no_d(self): - with self.assertRaises(TypeError): - retworkx.generators.heavy_square_graph() diff --git a/tests/retworkx_backwards_compat/generators/test_hexagonal.py b/tests/retworkx_backwards_compat/generators/test_hexagonal.py deleted file mode 100644 index 88fa25ca3..000000000 --- a/tests/retworkx_backwards_compat/generators/test_hexagonal.py +++ /dev/null @@ -1,417 +0,0 @@ -# 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 TestHexagonalLatticeGraph(unittest.TestCase): - def test_directed_hexagonal_graph_2_2(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (0, 5), - (2, 7), - (4, 9), - (6, 11), - (8, 13), - (10, 15), - ] - self.assertEqual(len(graph), 16) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_3_2(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(3, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (7, 8), - (8, 9), - (9, 10), - (10, 11), - (11, 12), - (12, 13), - (13, 14), - (15, 16), - (16, 17), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (0, 7), - (2, 9), - (4, 11), - (6, 13), - (8, 15), - (10, 17), - (12, 19), - (14, 21), - ] - self.assertEqual(len(graph), 22) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_2_4(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 4) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (15, 16), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (21, 22), - (23, 24), - (24, 25), - (25, 26), - (26, 27), - (0, 5), - (2, 7), - (4, 9), - (6, 12), - (8, 14), - (10, 16), - (11, 17), - (13, 19), - (15, 21), - (18, 23), - (20, 25), - (22, 27), - ] - self.assertEqual(len(graph), 28) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_2_2_bidirectional(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 2, bidirectional=True) - expected_edges = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 4), - (4, 3), - (5, 6), - (6, 5), - (6, 7), - (7, 6), - (7, 8), - (8, 7), - (8, 9), - (9, 8), - (9, 10), - (10, 9), - (11, 12), - (12, 11), - (12, 13), - (13, 12), - (13, 14), - (14, 13), - (14, 15), - (15, 14), - (0, 5), - (5, 0), - (2, 7), - (7, 2), - (4, 9), - (9, 4), - (6, 11), - (11, 6), - (8, 13), - (13, 8), - (10, 15), - (15, 10), - ] - self.assertEqual(len(graph), 16) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_3_2_bidirectional(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(3, 2, bidirectional=True) - expected_edges = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 4), - (4, 3), - (4, 5), - (5, 4), - (5, 6), - (6, 5), - (7, 8), - (8, 7), - (8, 9), - (9, 8), - (9, 10), - (10, 9), - (10, 11), - (11, 10), - (11, 12), - (12, 11), - (12, 13), - (13, 12), - (13, 14), - (14, 13), - (15, 16), - (16, 15), - (16, 17), - (17, 16), - (17, 18), - (18, 17), - (18, 19), - (19, 18), - (19, 20), - (20, 19), - (20, 21), - (21, 20), - (0, 7), - (7, 0), - (2, 9), - (9, 2), - (4, 11), - (11, 4), - (6, 13), - (13, 6), - (8, 15), - (15, 8), - (10, 17), - (17, 10), - (12, 19), - (19, 12), - (14, 21), - (21, 14), - ] - self.assertEqual(len(graph), 22) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_2_4_bidirectional(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 4, bidirectional=True) - expected_edges = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 4), - (4, 3), - (5, 6), - (6, 5), - (6, 7), - (7, 6), - (7, 8), - (8, 7), - (8, 9), - (9, 8), - (9, 10), - (10, 9), - (11, 12), - (12, 11), - (12, 13), - (13, 12), - (13, 14), - (14, 13), - (14, 15), - (15, 14), - (15, 16), - (16, 15), - (17, 18), - (18, 17), - (18, 19), - (19, 18), - (19, 20), - (20, 19), - (20, 21), - (21, 20), - (21, 22), - (22, 21), - (23, 24), - (24, 23), - (24, 25), - (25, 24), - (25, 26), - (26, 25), - (26, 27), - (27, 26), - (0, 5), - (5, 0), - (2, 7), - (7, 2), - (4, 9), - (9, 4), - (6, 12), - (12, 6), - (8, 14), - (14, 8), - (10, 16), - (16, 10), - (11, 17), - (17, 11), - (13, 19), - (19, 13), - (15, 21), - (21, 15), - (18, 23), - (23, 18), - (20, 25), - (25, 20), - (22, 27), - (27, 22), - ] - self.assertEqual(len(graph), 28) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_2_2(self): - graph = retworkx.generators.hexagonal_lattice_graph(2, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (0, 5), - (2, 7), - (4, 9), - (6, 11), - (8, 13), - (10, 15), - ] - self.assertEqual(len(graph), 16) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_3_2(self): - graph = retworkx.generators.hexagonal_lattice_graph(3, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (7, 8), - (8, 9), - (9, 10), - (10, 11), - (11, 12), - (12, 13), - (13, 14), - (15, 16), - (16, 17), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (0, 7), - (2, 9), - (4, 11), - (6, 13), - (8, 15), - (10, 17), - (12, 19), - (14, 21), - ] - self.assertEqual(len(graph), 22) - self.assertEqual(len(graph.edges()), 27) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_2_4(self): - graph = retworkx.generators.hexagonal_lattice_graph(2, 4) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (15, 16), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (21, 22), - (23, 24), - (24, 25), - (25, 26), - (26, 27), - (0, 5), - (2, 7), - (4, 9), - (6, 12), - (8, 14), - (10, 16), - (11, 17), - (13, 19), - (15, 21), - (18, 23), - (20, 25), - (22, 27), - ] - self.assertEqual(len(graph), 28) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_0_0(self): - graph = retworkx.generators.hexagonal_lattice_graph(0, 0) - self.assertEqual(len(graph), 0) - self.assertEqual(len(graph.edges()), 0) diff --git a/tests/retworkx_backwards_compat/generators/test_lollipop.py b/tests/retworkx_backwards_compat/generators/test_lollipop.py deleted file mode 100644 index 47f66c3e2..000000000 --- a/tests/retworkx_backwards_compat/generators/test_lollipop.py +++ /dev/null @@ -1,79 +0,0 @@ -# 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 TestLollipopGraph(unittest.TestCase): - def test_lollipop_graph_count(self): - graph = retworkx.generators.lollipop_graph(17, 3) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 139) - - def test_lollipop_graph_weights_count(self): - graph = retworkx.generators.lollipop_graph( - mesh_weights=list(range(17)), path_weights=list(range(17, 20)) - ) - self.assertEqual(len(graph), 20) - self.assertEqual(list(range(20)), graph.nodes()) - self.assertEqual(len(graph.edges()), 139) - - def test_lollipop_graph_edge(self): - graph = retworkx.generators.lollipop_graph(4, 3) - edge_list = graph.edge_list() - expected_edge_list = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - ] - self.assertEqual(edge_list, expected_edge_list) - - def test_lollipop_graph_weights_edge(self): - graph = retworkx.generators.lollipop_graph( - mesh_weights=list(range(4)), path_weights=list(range(3)) - ) - weighted_edge_list = graph.weighted_edge_list() - expected_weighted_edge_list = [ - (0, 1, None), - (0, 2, None), - (0, 3, None), - (1, 2, None), - (1, 3, None), - (2, 3, None), - (3, 4, None), - (4, 5, None), - (5, 6, None), - ] - self.assertEqual(weighted_edge_list, expected_weighted_edge_list) - self.assertEqual(graph.nodes(), [0, 1, 2, 3, 0, 1, 2]) - - def test_lollipop_graph_no_path_weights_or_num(self): - graph = retworkx.generators.lollipop_graph(mesh_weights=list(range(4))) - mesh = retworkx.generators.mesh_graph(weights=list(range(4))) - self.assertEqual(graph.nodes(), mesh.nodes()) - self.assertEqual(graph.weighted_edge_list(), mesh.weighted_edge_list()) - self.assertEqual( - retworkx.generators.lollipop_graph(4).edge_list(), - retworkx.generators.mesh_graph(4).edge_list(), - ) - - def test_lollipop_graph_no_mesh_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.lollipop_graph() diff --git a/tests/retworkx_backwards_compat/generators/test_mesh.py b/tests/retworkx_backwards_compat/generators/test_mesh.py deleted file mode 100644 index 02e154857..000000000 --- a/tests/retworkx_backwards_compat/generators/test_mesh.py +++ /dev/null @@ -1,67 +0,0 @@ -# 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 TestMeshGraph(unittest.TestCase): - def test_directed_mesh_graph(self): - graph = retworkx.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 = retworkx.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): - retworkx.generators.directed_mesh_graph() - - def test_mesh_graph(self): - graph = retworkx.generators.mesh_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 190) - - def test_mesh_graph_weights(self): - graph = retworkx.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): - retworkx.generators.mesh_graph() - - def test_zero_size_mesh_graph(self): - graph = retworkx.generators.mesh_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_size_directed_mesh_graph(self): - graph = retworkx.generators.directed_mesh_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/generators/test_path.py b/tests/retworkx_backwards_compat/generators/test_path.py deleted file mode 100644 index 958851bb2..000000000 --- a/tests/retworkx_backwards_compat/generators/test_path.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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 TestPathGraph(unittest.TestCase): - def test_directed_path_graph(self): - graph = retworkx.generators.directed_path_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), []) - - def test_directed_path_graph_weights(self): - graph = retworkx.generators.directed_path_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()), 19) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), []) - - def test_directed_path_graph_bidirectional(self): - graph = retworkx.generators.directed_path_graph(20, bidirectional=True) - self.assertEqual(graph.out_edges(0), [(0, 1, None)]) - self.assertEqual(graph.in_edges(0), [(1, 0, None)]) - for i in range(1, 19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None), (i, i - 1, None)]) - self.assertEqual(graph.in_edges(i), [(i + 1, i, None), (i - 1, i, None)]) - self.assertEqual(graph.out_edges(19), [(19, 18, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None)]) - - def test_path_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_path_graph() - - def test_path_graph(self): - graph = retworkx.generators.path_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - - def test_path_graph_weights(self): - graph = retworkx.generators.path_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()), 19) - - def test_path_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.path_graph() - - def test_zero_length_path_graph(self): - graph = retworkx.generators.path_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_length_directed_path_graph(self): - graph = retworkx.generators.directed_path_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/generators/test_petersen.py b/tests/retworkx_backwards_compat/generators/test_petersen.py deleted file mode 100644 index 907f52834..000000000 --- a/tests/retworkx_backwards_compat/generators/test_petersen.py +++ /dev/null @@ -1,56 +0,0 @@ -# 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 TestPetersenGraph(unittest.TestCase): - def test_petersen_graph_count(self): - n = 99 - k = 23 - graph = retworkx.generators.generalized_petersen_graph(n, k) - self.assertEqual(len(graph), 2 * n) - self.assertEqual(len(graph.edges()), 3 * n) - - def test_petersen_graph_edge(self): - graph = retworkx.generators.generalized_petersen_graph(5, 2) - edge_list = graph.edge_list() - expected_edge_list = [ - (0, 2), - (1, 3), - (2, 4), - (3, 0), - (4, 1), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 5), - (5, 0), - (6, 1), - (7, 2), - (8, 3), - (9, 4), - ] - self.assertEqual(edge_list, expected_edge_list) - - def test_petersen_invalid_n_k(self): - with self.assertRaises(IndexError): - retworkx.generators.generalized_petersen_graph(2, 1) - - with self.assertRaises(IndexError): - retworkx.generators.generalized_petersen_graph(5, 0) - - with self.assertRaises(IndexError): - retworkx.generators.generalized_petersen_graph(5, 4) diff --git a/tests/retworkx_backwards_compat/generators/test_star.py b/tests/retworkx_backwards_compat/generators/test_star.py deleted file mode 100644 index 698d5368d..000000000 --- a/tests/retworkx_backwards_compat/generators/test_star.py +++ /dev/null @@ -1,108 +0,0 @@ -# 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 TestStarGraph(unittest.TestCase): - def test_directed_star_graph(self): - graph = retworkx.generators.directed_star_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - expected_edges = [(0, i, None) for i in range(1, 20)] - self.assertEqual(sorted(graph.out_edges(0)), sorted(expected_edges)) - - def test_star_directed_graph_inward(self): - graph = retworkx.generators.directed_star_graph(20, inward=True) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - expected_edges = [(i, 0, None) for i in range(1, 20)] - self.assertEqual(sorted(graph.in_edges(0)), sorted(expected_edges)) - - def test_directed_star_graph_weights(self): - graph = retworkx.generators.directed_star_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()), 19) - expected_edges = sorted([(0, i, None) for i in range(1, 20)]) - self.assertEqual(sorted(graph.out_edges(0)), expected_edges) - - def test_directed_star_graph_bidirectional(self): - graph = retworkx.generators.directed_star_graph(20, bidirectional=True) - outw = [] - inw = [] - for i in range(1, 20): - outw.append((0, i, None)) - inw.append((i, 0, None)) - self.assertEqual(graph.out_edges(i), [(i, 0, None)]) - self.assertEqual(graph.in_edges(i), [(0, i, None)]) - self.assertEqual(graph.out_edges(0), outw[::-1]) - self.assertEqual(graph.in_edges(0), inw[::-1]) - - def test_directed_star_graph_bidirectional_inward(self): - graph = retworkx.generators.directed_star_graph(20, bidirectional=True, inward=True) - outw = [] - inw = [] - for i in range(1, 20): - outw.append((0, i, None)) - inw.append((i, 0, None)) - self.assertEqual(graph.out_edges(i), [(i, 0, None)]) - self.assertEqual(graph.in_edges(i), [(0, i, None)]) - self.assertEqual(graph.out_edges(0), outw[::-1]) - self.assertEqual(graph.in_edges(0), inw[::-1]) - graph = retworkx.generators.directed_star_graph(20, bidirectional=True, inward=False) - outw = [] - inw = [] - for i in range(1, 20): - outw.append((0, i, None)) - inw.append((i, 0, None)) - self.assertEqual(graph.out_edges(i), [(i, 0, None)]) - self.assertEqual(graph.in_edges(i), [(0, i, None)]) - self.assertEqual(graph.out_edges(0), outw[::-1]) - self.assertEqual(graph.in_edges(0), inw[::-1]) - - def test_star_directed_graph_weights_inward(self): - graph = retworkx.generators.directed_star_graph(weights=list(range(20)), inward=True) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - expected_edges = [(i, 0, None) for i in range(1, 20)] - self.assertEqual(sorted(graph.in_edges(0)), sorted(expected_edges)) - - def test_star_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_star_graph() - - def test_star_graph(self): - graph = retworkx.generators.star_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - - def test_star_graph_weights(self): - graph = retworkx.generators.star_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()), 19) - - def test_star_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.star_graph() - - def test_zero_length_star_graph(self): - graph = retworkx.generators.star_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_length_directed_star_graph(self): - graph = retworkx.generators.directed_star_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/graph/__init__.py b/tests/retworkx_backwards_compat/graph/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/graph/test_adj.py b/tests/retworkx_backwards_compat/graph/test_adj.py deleted file mode 100644 index 43b4a6d9f..000000000 --- a/tests/retworkx_backwards_compat/graph/test_adj.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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 TestAdj(unittest.TestCase): - def test_single_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {"a": 1}) - node_c = graph.add_node("c") - graph.add_edge(node_a, node_c, {"a": 2}) - res = graph.adj(node_a) - self.assertEqual({node_b: {"a": 1}, node_c: {"a": 2}}, res) - - def test_no_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - self.assertEqual({}, graph.adj(node_a)) diff --git a/tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py b/tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py deleted file mode 100644 index 32c3df44d..000000000 --- a/tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py +++ /dev/null @@ -1,262 +0,0 @@ -# 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 -import numpy as np - - -class TestGraphAdjacencyMatrix(unittest.TestCase): - def test_single_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edge_a") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "edge_b") - res = retworkx.graph_adjacency_matrix(graph, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_no_weight_fn(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edge_a") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "edge_b") - res = retworkx.graph_adjacency_matrix(graph) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_default_weight(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edge_a") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "edge_b") - res = retworkx.graph_adjacency_matrix(graph, default_weight=4) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_float_cast_weight_func(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - res = retworkx.graph_adjacency_matrix(graph, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.0], [7.0, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - graph.add_edge(node_a, node_b, 0.5) - res = retworkx.graph_adjacency_matrix(graph, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.5], [7.5, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func_non_zero_null(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - graph.add_edge(node_a, node_b, 0.5) - res = retworkx.graph_adjacency_matrix(graph, lambda x: float(x), null_value=np.inf) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[np.inf, 7.5], [7.5, np.inf]]), res)) - - def test_dag_to_graph_adjacency_matrix(self): - dag = retworkx.PyDAG() - self.assertRaises(TypeError, retworkx.graph_adjacency_matrix, dag) - - def test_no_edge_graph_adjacency_matrix(self): - graph = retworkx.PyGraph() - for i in range(50): - graph.add_node(i) - res = retworkx.graph_adjacency_matrix(graph, lambda x: 1) - self.assertTrue(np.array_equal(np.zeros([50, 50]), res)) - - def test_graph_with_index_holes(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 1) - node_c = graph.add_node("c") - graph.add_edge(node_a, node_c, 1) - graph.remove_node(node_b) - res = retworkx.graph_adjacency_matrix(graph, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0, 1], [1, 0]]), res)) - - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.float64, - ) - graph = retworkx.PyGraph.from_adjacency_matrix(input_array) - out_array = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(input_array, out_array)) - - def test_random_graph_full_path(self): - graph = retworkx.undirected_gnp_random_graph(100, 0.95, seed=42) - adjacency_matrix = retworkx.graph_adjacency_matrix(graph) - new_graph = retworkx.PyGraph.from_adjacency_matrix(adjacency_matrix) - new_adjacency_matrix = retworkx.graph_adjacency_matrix(new_graph) - self.assertTrue(np.array_equal(adjacency_matrix, new_adjacency_matrix)) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyGraph.from_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix.astype(np.float64, copy=False)) - adj_matrix = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_random_graph_float_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=float) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_graph_to_digraph_adjacency_matrix(self): - graph = retworkx.PyGraph() - self.assertRaises(TypeError, retworkx.digraph_adjacency_matrix, graph) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.float64, - ) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix, null_value=np.Inf) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.float64) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - def test_negative_weight(self): - input_matrix = np.array([[0, -1, 0], [-1, 0, -1], [0, -1, 0]], dtype=float) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - self.assertEqual([(0, 1, -1), (1, 2, -1)], graph.weighted_edge_list()) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.float64, - ) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix, null_value=np.nan) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.float64) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - -class TestFromComplexAdjacencyMatrix(unittest.TestCase): - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.complex128, - ) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_array) - expected = [ - (0, 1, 4 + 0j), - (1, 2, 4 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyGraph.from_complex_adjacency_matrix( - input_matrix.astype(np.complex128, copy=False) - ) - expected = [ - (0, 1, 1 + 0j), - (1, 2, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_complex_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix) - expected = [ - (0, 1, 1 + 0j), - (1, 2, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.complex128, - ) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.Inf) - expected = [ - (0, 1, 1 + 0j), - (1, 2, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_negative_weight(self): - input_matrix = np.array([[0, 1, 0], [-1, 0, -1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix) - self.assertEqual( - [(0, 1, 1), (1, 2, -1)], - graph.weighted_edge_list(), - ) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.complex128, - ) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.nan) - edge_list = graph.weighted_edge_list() - self.assertEqual( - edge_list, - [(0, 1, 1 + 0j), (1, 2, 1 + 0j)], - ) diff --git a/tests/retworkx_backwards_compat/graph/test_all_simple_paths.py b/tests/retworkx_backwards_compat/graph/test_all_simple_paths.py deleted file mode 100644 index 7e8d76f00..000000000 --- a/tests/retworkx_backwards_compat/graph/test_all_simple_paths.py +++ /dev/null @@ -1,245 +0,0 @@ -# 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 TestGraphAllSimplePaths(unittest.TestCase): - def setUp(self): - super().setUp() - self.edges = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 2), - (3, 4), - (4, 2), - (4, 5), - (5, 2), - (5, 3), - ] - - def test_all_simple_paths(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5) - expected = [ - [0, 3, 4, 5], - [0, 3, 4, 2, 5], - [0, 3, 4, 2, 5], - [0, 3, 2, 4, 5], - [0, 3, 2, 5], - [0, 3, 2, 4, 5], - [0, 3, 5], - [0, 3, 2, 4, 5], - [0, 3, 2, 5], - [0, 3, 2, 4, 5], - [0, 3, 1, 2, 4, 5], - [0, 3, 1, 2, 5], - [0, 3, 1, 2, 4, 5], - [0, 2, 4, 5], - [0, 2, 4, 3, 5], - [0, 2, 3, 4, 5], - [0, 2, 3, 5], - [0, 2, 5], - [0, 2, 4, 5], - [0, 2, 4, 3, 5], - [0, 2, 3, 4, 5], - [0, 2, 3, 5], - [0, 2, 1, 3, 4, 5], - [0, 2, 1, 3, 5], - [0, 1, 3, 4, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 2, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 3, 5], - [0, 1, 2, 5], - [0, 1, 2, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 3, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_min_depth(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5, min_depth=6) - expected = [ - [0, 3, 1, 2, 4, 5], - [0, 3, 1, 2, 4, 5], - [0, 2, 1, 3, 4, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_cutoff(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5, cutoff=4) - expected = [ - [0, 3, 4, 5], - [0, 3, 2, 5], - [0, 3, 5], - [0, 3, 2, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 2, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 1, 3, 5], - [0, 1, 2, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5, min_depth=4, cutoff=4) - expected = [ - [0, 3, 4, 5], - [0, 3, 2, 5], - [0, 3, 2, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 1, 3, 5], - [0, 1, 2, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_path_no_path(self): - dag = retworkx.PyGraph() - dag.add_node(0) - dag.add_node(1) - self.assertEqual([], retworkx.graph_all_simple_paths(dag, 0, 1)) - - def test_all_simple_path_invalid_node_index(self): - dag = retworkx.PyGraph() - dag.add_node(0) - dag.add_node(1) - with self.assertRaises(retworkx.InvalidNode): - retworkx.graph_all_simple_paths(dag, 0, 5) - - def test_digraph_graph_all_simple_paths(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - self.assertRaises(TypeError, retworkx.graph_all_simple_paths, (dag, 0, 1)) - - -class TestGraphAllSimplePathsAllPairs(unittest.TestCase): - def setUp(self): - super().setUp() - self.graph = retworkx.generators.cycle_graph(4) - - def test_all_simple_paths(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph) - expected = { - 0: {1: [[0, 1], [0, 3, 2, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 1, 2, 3], [0, 3]]}, - 1: {2: [[1, 2], [1, 0, 3, 2]], 3: [[1, 2, 3], [1, 0, 3]], 0: [[1, 2, 3, 0], [1, 0]]}, - 2: { - 3: [[2, 3], [2, 1, 0, 3]], - 0: [[2, 3, 0], [2, 1, 0]], - 1: [[2, 3, 0, 1], [2, 1]], - }, - 3: {0: [[3, 0], [3, 2, 1, 0]], 1: [[3, 0, 1], [3, 2, 1]], 2: [[3, 0, 1, 2], [3, 2]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_min_depth(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph, min_depth=3) - expected = { - 0: {1: [[0, 3, 2, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 1, 2, 3]]}, - 1: {2: [[1, 0, 3, 2]], 3: [[1, 2, 3], [1, 0, 3]], 0: [[1, 2, 3, 0]]}, - 2: { - 3: [[2, 1, 0, 3]], - 0: [[2, 3, 0], [2, 1, 0]], - 1: [[2, 3, 0, 1]], - }, - 3: {0: [[3, 2, 1, 0]], 1: [[3, 0, 1], [3, 2, 1]], 2: [[3, 0, 1, 2]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_with_cutoff(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph, cutoff=3) - expected = { - 0: {1: [[0, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 3]]}, - 1: {2: [[1, 2]], 3: [[1, 2, 3], [1, 0, 3]], 0: [[1, 0]]}, - 2: { - 3: [[2, 3]], - 0: [[2, 3, 0], [2, 1, 0]], - 1: [[2, 1]], - }, - 3: {0: [[3, 0]], 1: [[3, 0, 1], [3, 2, 1]], 2: [[3, 2]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph, min_depth=3, cutoff=3) - expected = { - 0: {2: [[0, 1, 2], [0, 3, 2]]}, - 1: {3: [[1, 2, 3], [1, 0, 3]]}, - 2: {0: [[2, 3, 0], [2, 1, 0]]}, - 3: {1: [[3, 0, 1], [3, 2, 1]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_path_no_path(self): - graph = retworkx.PyGraph() - graph.add_node(0) - graph.add_node(1) - self.assertEqual({0: {}, 1: {}}, retworkx.all_pairs_all_simple_paths(graph)) - - def test_all_simple_paths_empty(self): - self.assertEqual({}, retworkx.all_pairs_all_simple_paths(retworkx.PyGraph())) diff --git a/tests/retworkx_backwards_compat/graph/test_astar.py b/tests/retworkx_backwards_compat/graph/test_astar.py deleted file mode 100644 index 6f1525e23..000000000 --- a/tests/retworkx_backwards_compat/graph/test_astar.py +++ /dev/null @@ -1,114 +0,0 @@ -# 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 TestAstarGraph(unittest.TestCase): - def test_astar_null_heuristic(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - c = g.add_node("C") - d = g.add_node("D") - e = g.add_node("E") - f = g.add_node("F") - g.add_edge(a, b, 7) - g.add_edge(c, a, 9) - g.add_edge(a, d, 14) - g.add_edge(b, c, 10) - g.add_edge(d, c, 2) - g.add_edge(d, e, 9) - g.add_edge(b, f, 15) - g.add_edge(c, f, 11) - g.add_edge(e, f, 6) - path = retworkx.graph_astar_shortest_path( - g, a, lambda goal: goal == "E", lambda x: float(x), lambda y: 0 - ) - expected = [a, c, d, e] - self.assertEqual(expected, path) - - def test_astar_manhattan_heuristic(self): - g = retworkx.PyGraph() - a = g.add_node((0.0, 0.0)) - b = g.add_node((2.0, 0.0)) - c = g.add_node((1.0, 1.0)) - d = g.add_node((0.0, 2.0)) - e = g.add_node((3.0, 3.0)) - f = g.add_node((4.0, 2.0)) - no_path = g.add_node((5.0, 5.0)) # no path to node - g.add_edge(a, b, 2.0) - g.add_edge(a, d, 4.0) - g.add_edge(b, c, 1.0) - g.add_edge(b, f, 7.0) - g.add_edge(c, e, 5.0) - g.add_edge(e, f, 1.0) - g.add_edge(d, e, 1.0) - - def heuristic_func(f): - x1, x2 = f - return abs(x2 - x1) - - def finish_func(node, x): - return x == g.get_node_data(node) - - expected = [ - [0], - [0, 1], - [0, 1, 2], - [0, 3], - [0, 3, 4], - [0, 3, 4, 5], - ] - - for index, end in enumerate([a, b, c, d, e, f]): - path = retworkx.graph_astar_shortest_path( - g, - a, - lambda finish: finish_func(end, finish), - lambda x: float(x), - heuristic_func, - ) - self.assertEqual(expected[index], path) - - with self.assertRaises(retworkx.NoPathFound): - retworkx.graph_astar_shortest_path( - g, - a, - lambda finish: finish_func(no_path, finish), - lambda x: float(x), - heuristic_func, - ) - - def test_astar_graph_with_digraph_input(self): - g = retworkx.PyDAG() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.graph_astar_shortest_path(g, 0, lambda x: x, lambda y: 1, lambda z: 0) - - def test_astar_with_invalid_weights(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 7) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_astar_shortest_path( - g, - a, - goal_fn=lambda goal: goal == "B", - edge_cost_fn=lambda _: invalid_weight, - estimate_cost_fn=lambda _: 0, - ) diff --git a/tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py b/tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py deleted file mode 100644 index 18ff98ab0..000000000 --- a/tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py +++ /dev/null @@ -1,89 +0,0 @@ -# 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 math -import unittest - -import retworkx - - -class TestUnweightedAvgShortestPath(unittest.TestCase): - def test_simple_example(self): - edge_list = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (3, 6), (6, 7)] - graph = retworkx.PyGraph() - graph.extend_from_edge_list(edge_list) - res = retworkx.graph_unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(2.5714285714285716, res, delta=1e-7) - - def test_cycle_graph(self): - graph = retworkx.generators.cycle_graph(7) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_path_graph(self): - graph = retworkx.generators.path_graph(5) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_parallel_grid(self): - graph = retworkx.generators.grid_graph(30, 11) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(13.666666666666666, res, delta=1e-7) - - def test_empty(self): - graph = retworkx.PyGraph() - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node(self): - graph = retworkx.PyGraph() - graph.add_node(0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node_self_edge(self): - graph = retworkx.PyGraph() - node = graph.add_node(0) - graph.add_edge(node, node, 0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_disconnected_graph(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_partially_connected_graph(self): - graph = retworkx.generators.cycle_graph(32) - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - s = 8192 - den = 992 # n*(n-1), n=32 (only connected pairs considered) - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - def test_connected_cycle_graph(self): - graph = retworkx.generators.cycle_graph(32) - res = retworkx.unweighted_average_shortest_path_length(graph) - s = 8192 - den = 992 # n*(n-1) - self.assertAlmostEqual(s / den, res, delta=1e-7) diff --git a/tests/retworkx_backwards_compat/graph/test_bellman_ford.py b/tests/retworkx_backwards_compat/graph/test_bellman_ford.py deleted file mode 100644 index 6511e3ea3..000000000 --- a/tests/retworkx_backwards_compat/graph/test_bellman_ford.py +++ /dev/null @@ -1,308 +0,0 @@ -# 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 TestBellmanFordGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - self.graph.add_edge(self.a, self.b, 7) - self.graph.add_edge(self.c, self.a, 9) - self.graph.add_edge(self.a, self.d, 14) - self.graph.add_edge(self.b, self.c, 10) - self.graph.add_edge(self.d, self.c, 2) - self.graph.add_edge(self.d, self.e, 9) - self.graph.add_edge(self.b, self.f, 15) - self.graph.add_edge(self.c, self.f, 11) - self.graph.add_edge(self.e, self.f, 6) - - def test_bellman_ford(self): - path = retworkx.graph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x) - ) - path_dijkstra = retworkx.graph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x) - ) - self.assertEqual(path_dijkstra, path) - - def test_bellman_ford_path(self): - path = retworkx.graph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x) - ) - # a -> d -> e = 23 - # a -> c -> d -> e = 20 - expected = retworkx.graph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x) - ) - self.assertEqual(expected, path) - - def test_bellman_ford_with_no_goal_set(self): - path = retworkx.graph_bellman_ford_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = retworkx.graph_dijkstra_shortest_path_lengths(self.graph, self.a, lambda x: 1) - self.assertEqual(expected, path) - - def test_bellman_path(self): - path = retworkx.graph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - expected = retworkx.graph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_path_lengths(self): - path = retworkx.graph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - expected = retworkx.graph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_ford_length_with_no_path_and_goal(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.graph_bellman_ford_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = retworkx.graph_dijkstra_shortest_path_lengths(g, a, edge_cost_fn=float, goal=b) - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_length_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path_lenghts = retworkx.graph_bellman_ford_shortest_path_lengths(g, a, edge_cost_fn=float) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_path_with_no_goal_set(self): - path = retworkx.graph_bellman_ford_shortest_paths(self.graph, self.a) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, path) - - def test_bellman_ford_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_bellman_ford_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_path_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_bellman_ford_shortest_paths(g, a, weight_fn=lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_with_disconnected_nodes(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 1.2) - g.add_node("C") - d = g.add_node("D") - g.add_edge(b, d, 2.4) - path = retworkx.graph_bellman_ford_shortest_path_lengths(g, a, lambda x: round(x, 1)) - # Computers never work: - expected = {1: 1.2, 3: 3.5999999999999996} - self.assertEqual(expected, path) - - def test_bellman_ford_graph_with_digraph_input(self): - g = retworkx.PyDAG() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.graph_bellman_ford_shortest_path_lengths(g, 0, lambda x: x) - - def bellman_ford_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for as_undirected in [False, True]: - with self.subTest(as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.graph_bellman_ford_shortest_paths( - graph, - source=0, - weight_fn=lambda _: float("nan"), - as_undirected=as_undirected, - ) - - def bellman_ford_lengths_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - with self.assertRaises(ValueError): - retworkx.graph_bellman_ford_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: float("nan") - ) - - def test_raises_negative_cycle_bellman_ford_paths(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_paths(graph, 0, weight_fn=float) - - def test_raises_negative_cycle_bellman_ford_path_lenghts(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_path_lengths(graph, 0, edge_cost_fn=float) - - def test_bellman_all_pair_path_lengths(self): - lengths = retworkx.all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 3: 11.0, 4: 20.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 3: 12.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 3: 2.0, 4: 11.0, 5: 11.0}, - 3: {0: 11.0, 1: 12.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {0: 20.0, 1: 21.0, 2: 11.0, 3: 9.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 3: 13.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths(self): - paths = retworkx.graph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - }, - 1: {0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 5, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 3: [2, 3], 4: [2, 3, 4], 5: [2, 5]}, - 3: {0: [3, 2, 0], 1: [3, 2, 1], 2: [3, 2], 4: [3, 4], 5: [3, 2, 5]}, - 4: { - 0: [4, 3, 2, 0], - 1: [4, 5, 1], - 2: [4, 3, 2], - 3: [4, 3], - 5: [4, 5], - }, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 3: [5, 2, 3], 4: [5, 4]}, - } - - self.assertEqual(expected, paths) - - def test_bellman_ford_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.graph_all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 4: 26.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 4: 17.0, 5: 11.0}, - 4: {0: 26.0, 1: 21.0, 2: 17.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - paths = retworkx.graph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 2], 4: [0, 2, 5, 4], 5: [0, 2, 5]}, - 1: {0: [1, 0], 2: [1, 2], 4: [1, 5, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 4: [2, 5, 4], 5: [2, 5]}, - 4: {0: [4, 5, 2, 0], 1: [4, 5, 1], 2: [4, 5, 2], 5: [4, 5]}, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 4: [5, 4]}, - } - self.assertEqual(expected, paths) - - def test_bellman_ford_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_bellman_ford_path_lengths(graph, float)) - - def test_bellman_ford_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_bellman_ford_shortest_paths(graph, float)) - - def test_bellman_ford_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_bellman_ford_path_lengths(graph, float), - ) - - def test_bellman_ford_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_bellman_ford_shortest_paths(graph, float), - ) - - def test_raises_negative_cycle_all_pairs_bellman_ford_paths(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_shortest_paths(graph, float) - - def test_raises_negative_cycle_all_pairs_bellman_ford_path_lenghts(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_path_lengths(graph, float) diff --git a/tests/retworkx_backwards_compat/graph/test_bfs_search.py b/tests/retworkx_backwards_compat/graph/test_bfs_search.py deleted file mode 100644 index 055987301..000000000 --- a/tests/retworkx_backwards_compat/graph/test_bfs_search.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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 TestBfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_graph_bfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3)]) - - def test_graph_bfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_bfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3), (4, 7)]) - - def test_graph_bfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.BFSVisitor): - - prohibited = [(0, 2), (1, 2)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.graph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 1), (1, 3), (3, 5), (5, 2), (2, 6)]) - - def test_graph_bfs_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.graph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_graph_bfs_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise StopIfGoalFound - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.graph_bfs_search(self.graph, [0], vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_graph_prune_non_tree_edge(self): - class PruneNonTreeEdge(retworkx.visit.BFSVisitor): - def non_tree_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneNonTreeEdge() - retworkx.graph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_black_target_edge(self): - class PruneBlackTargetEdge(retworkx.visit.BFSVisitor): - def black_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneBlackTargetEdge() - retworkx.graph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_gray_target_edge(self): - class PruneGrayTargetEdge(retworkx.visit.BFSVisitor): - def gray_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneGrayTargetEdge() - retworkx.graph_bfs_search(self.graph, [0], vis) diff --git a/tests/retworkx_backwards_compat/graph/test_biconnected.py b/tests/retworkx_backwards_compat/graph/test_biconnected.py deleted file mode 100644 index 1ab99ae56..000000000 --- a/tests/retworkx_backwards_compat/graph/test_biconnected.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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 TestBiconnected(unittest.TestCase): - def setUp(self): - super().setUp() - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - # back edges - (0, 2), - (0, 3), - (1, 4), - (4, 9), - (5, 7), - # tree edges - (0, 1), - (1, 2), - (2, 3), - (2, 4), - (4, 5), - (4, 8), - (5, 6), - (6, 7), - (8, 9), - ] - ) - - self.barbell_graph = retworkx.PyGraph() - self.barbell_graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 2), - (3, 4), - (3, 5), - (4, 5), - (2, 3), - ] - ) - - def test_null_graph(self): - graph = retworkx.PyGraph() - self.assertEqual(retworkx.articulation_points(graph), set()) - self.assertEqual(retworkx.biconnected_components(graph), {}) - - def test_graph(self): - components = { - (4, 8): 0, - (8, 9): 0, - (9, 4): 0, - (5, 6): 1, - (6, 7): 1, - (7, 5): 1, - (4, 5): 2, - (0, 1): 3, - (1, 2): 3, - (2, 3): 3, - (2, 4): 3, - (2, 0): 3, - (3, 0): 3, - (4, 1): 3, - } - self.assertEqual(retworkx.biconnected_components(self.graph), components) - self.assertEqual(retworkx.articulation_points(self.graph), {4, 5}) - - def test_barbell_graph(self): - components = { - (0, 2): 2, - (2, 1): 2, - (1, 0): 2, - (3, 5): 0, - (5, 4): 0, - (4, 3): 0, - (2, 3): 1, - } - self.assertEqual(retworkx.biconnected_components(self.barbell_graph), components) - self.assertEqual(retworkx.articulation_points(self.barbell_graph), {2, 3}) - - def test_disconnected_graph(self): - graph = retworkx.union(self.barbell_graph, self.barbell_graph) - components = { - # first copy - (0, 2): 2, - (2, 1): 2, - (1, 0): 2, - (3, 5): 0, - (5, 4): 0, - (4, 3): 0, - (2, 3): 1, - # second copy - (6, 8): 5, - (8, 7): 5, - (7, 6): 5, - (9, 11): 3, - (11, 10): 3, - (10, 9): 3, - (8, 9): 4, - } - self.assertEqual(retworkx.biconnected_components(graph), components) - self.assertEqual(retworkx.articulation_points(graph), {2, 3, 8, 9}) - - def test_biconnected_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (0, 5), - (1, 5), - (2, 3), - (2, 4), - (3, 4), - (3, 5), - (3, 6), - (4, 5), - (4, 6), - ] - ) - num_edges = graph.num_edges() - self.assertEqual(retworkx.articulation_points(graph), set()) - bicomp = retworkx.biconnected_components(graph) - self.assertEqual(len(bicomp), num_edges) - self.assertEqual(list(bicomp.values()), [0] * num_edges) diff --git a/tests/retworkx_backwards_compat/graph/test_cartesian_product.py b/tests/retworkx_backwards_compat/graph/test_cartesian_product.py deleted file mode 100644 index 5acd0f35c..000000000 --- a/tests/retworkx_backwards_compat/graph/test_cartesian_product.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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 TestCartesianProduct(unittest.TestCase): - def test_null_cartesian_null(self): - graph_1 = retworkx.PyGraph() - graph_2 = retworkx.PyGraph() - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 0) - self.assertEqual(graph_product.num_edges(), 0) - - def test_path_2_cartesian_path_2(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 4) - self.assertEqual(graph_product.num_edges(), 4) - - def test_path_2_cartesian_path_3(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(3) - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 6) - self.assertEqual(graph_product.num_edges(), 7) - - def test_node_weights_cartesian(self): - graph_1 = retworkx.PyGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_edge_weights_cartesian(self): - graph_1 = retworkx.PyGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - graph_2 = retworkx.PyGraph() - graph_2.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(["w_1", "w_1", "w_2", "w_2"], graph_product.edges()) diff --git a/tests/retworkx_backwards_compat/graph/test_centrality.py b/tests/retworkx_backwards_compat/graph/test_centrality.py deleted file mode 100644 index 2c0dabee8..000000000 --- a/tests/retworkx_backwards_compat/graph/test_centrality.py +++ /dev/null @@ -1,133 +0,0 @@ -# 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 math -import unittest - -import retworkx - - -class TestCentralityGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - - def test_betweenness_centrality(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.6666666666666666, - 2: 0.6666666666666666, - 3: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.5, - 1: 0.8333333333333333, - 2: 0.8333333333333333, - 3: 0.5, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.graph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 3: 0.0} - self.assertEqual(expected, betweenness) - - def test_closeness_centrality(self): - closeness = retworkx.graph_closeness_centrality(self.graph) - expected = {0: 0.5, 1: 0.75, 2: 0.75, 3: 0.5} - self.assertEqual(expected, closeness) - - def test_closeness_centrality_wf_improved(self): - closeness = retworkx.graph_closeness_centrality(self.graph, wf_improved=False) - expected = {0: 0.5, 1: 0.75, 2: 0.75, 3: 0.5} - self.assertEqual(expected, closeness) - - -class TestCentralityGraphDeletedNode(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - c0 = self.graph.add_node("C0") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - self.graph.remove_node(c0) - - def test_betweenness_centrality(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.6666666666666666, - 2: 0.6666666666666666, - 4: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.5, - 1: 0.8333333333333333, - 2: 0.8333333333333333, - 4: 0.5, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.graph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 4: 0.0} - self.assertEqual(expected, betweenness) - - -class TestEigenvectorCentrality(unittest.TestCase): - def test_complete_graph(self): - graph = retworkx.generators.mesh_graph(5) - centrality = retworkx.eigenvector_centrality(graph) - expected_value = math.sqrt(1.0 / 5.0) - for value in centrality.values(): - self.assertAlmostEqual(value, expected_value) - - def test_path_graph(self): - graph = retworkx.generators.path_graph(3) - centrality = retworkx.eigenvector_centrality(graph) - expected = [0.5, 0.7071, 0.5] - for k, v in centrality.items(): - self.assertAlmostEqual(v, expected[k], 4) - - def test_no_convergence(self): - graph = retworkx.PyGraph() - with self.assertRaises(retworkx.FailedToConverge): - retworkx.eigenvector_centrality(graph, max_iter=0) diff --git a/tests/retworkx_backwards_compat/graph/test_chain_decomposition.py b/tests/retworkx_backwards_compat/graph/test_chain_decomposition.py deleted file mode 100644 index f08916364..000000000 --- a/tests/retworkx_backwards_compat/graph/test_chain_decomposition.py +++ /dev/null @@ -1,89 +0,0 @@ -# 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 TestChainDecomposition(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 2), - (3, 4), - (3, 5), - (4, 5), - (2, 3), - ] - ) - return super().setUp() - - def test_graph(self): - edges = [ - # back edges - (0, 2), - (0, 3), - (1, 4), - (4, 9), - (5, 7), - # tree edges - (0, 1), - (1, 2), - (2, 3), - (2, 4), - (4, 5), - (4, 8), - (5, 6), - (6, 7), - (8, 9), - ] - - graph = retworkx.PyGraph() - graph.extend_from_edge_list(edges) - chains = retworkx.chain_decomposition(graph, source=0) - expected = [ - [(0, 3), (3, 2), (2, 1), (1, 0)], - [(0, 2)], - [(1, 4), (4, 2)], - [(4, 9), (9, 8), (8, 4)], - [(5, 7), (7, 6), (6, 5)], - ] - self.assertEqual(expected, chains) - - def test_barbell_graph(self): - chains = retworkx.chain_decomposition(self.graph, source=0) - expected = [[(0, 1), (1, 2), (2, 0)], [(3, 4), (4, 5), (5, 3)]] - self.assertEqual(expected, chains) - - def test_disconnected_graph(self): - graph = retworkx.union(self.graph, self.graph) - chains = retworkx.chain_decomposition(graph) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - [(6, 7), (7, 8), (8, 6)], - [(9, 10), (10, 11), (11, 9)], - ] - self.assertEqual(expected, chains) - - def test_disconnected_graph_root_node(self): - graph = retworkx.union(self.graph, self.graph) - chains = retworkx.chain_decomposition(graph, source=0) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - ] - self.assertEqual(expected, chains) diff --git a/tests/retworkx_backwards_compat/graph/test_coloring.py b/tests/retworkx_backwards_compat/graph/test_coloring.py deleted file mode 100644 index acc431f04..000000000 --- a/tests/retworkx_backwards_compat/graph/test_coloring.py +++ /dev/null @@ -1,46 +0,0 @@ -# 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 TestGraphColoring(unittest.TestCase): - def test_empty_graph(self): - graph = retworkx.PyGraph() - res = retworkx.graph_greedy_color(graph) - self.assertEqual({}, res) - - def test_simple_graph(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(1) - node_b = graph.add_node(2) - graph.add_edge(node_a, node_b, 1) - node_c = graph.add_node(3) - graph.add_edge(node_a, node_c, 1) - res = retworkx.graph_greedy_color(graph) - self.assertEqual({0: 0, 1: 1, 2: 1}, res) - - def test_simple_graph_large_degree(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(1) - node_b = graph.add_node(2) - graph.add_edge(node_a, node_b, 1) - node_c = graph.add_node(3) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - res = retworkx.graph_greedy_color(graph) - self.assertEqual({0: 0, 1: 1, 2: 1}, res) diff --git a/tests/retworkx_backwards_compat/graph/test_complement.py b/tests/retworkx_backwards_compat/graph/test_complement.py deleted file mode 100644 index 6ae796228..000000000 --- a/tests/retworkx_backwards_compat/graph/test_complement.py +++ /dev/null @@ -1,83 +0,0 @@ -# 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 TestComplement(unittest.TestCase): - def test_clique(self): - N = 5 - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j]) - - complement_graph = retworkx.complement(graph) - self.assertEqual(graph.nodes(), complement_graph.nodes()) - self.assertEqual(0, len(complement_graph.edges())) - - def test_empty(self): - N = 5 - graph = retworkx.PyGraph() - graph.add_nodes_from([i for i in range(N)]) - - expected_graph = retworkx.PyGraph() - expected_graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j]) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) - - def test_null_graph(self): - graph = retworkx.PyGraph() - complement_graph = retworkx.complement(graph) - self.assertEqual(0, len(complement_graph.nodes())) - self.assertEqual(0, len(complement_graph.edges())) - - def test_complement(self): - N = 8 - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(j, i) for i in range(N) for j in range(N) if i < j and (i + j) % 3 == 0] - ) - - expected_graph = retworkx.PyGraph() - expected_graph.extend_from_edge_list( - [(i, j) for i in range(N) for j in range(N) if i < j and (i + j) % 3 != 0] - ) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) - - def test_multigraph(self): - graph = retworkx.PyGraph(multigraph=True) - graph.extend_from_edge_list([(0, 0), (0, 1), (1, 1), (2, 2), (1, 0)]) - - expected_graph = retworkx.PyGraph(multigraph=True) - expected_graph.extend_from_edge_list([(0, 2), (1, 2)]) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) diff --git a/tests/retworkx_backwards_compat/graph/test_compose.py b/tests/retworkx_backwards_compat/graph/test_compose.py deleted file mode 100644 index 751309f24..000000000 --- a/tests/retworkx_backwards_compat/graph/test_compose.py +++ /dev/null @@ -1,97 +0,0 @@ -# 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 TestCompose(unittest.TestCase): - def test_simple_graph_composition(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {"a": 1}) - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, {"a": 2}) - graph_other = retworkx.PyGraph() - node_d = graph_other.add_node("d") - node_e = graph_other.add_node("e") - graph_other.add_edge(node_d, node_e, {"a": 3}) - res = graph.compose(graph_other, {node_c: (node_d, {"b": 1})}) - self.assertEqual({0: 3, 1: 4}, res) - self.assertEqual([0, 1, 2, 3, 4], graph.node_indexes()) - - def test_edge_map_and_node_map_funcs_graph_compose(self): - graph = retworkx.PyGraph() - original_input_nodes = graph.add_nodes_from(["qr[0]", "qr[1]"]) - original_op_nodes = graph.add_nodes_from(["h"]) - output_nodes = graph.add_nodes_from(["qr[0]", "qr[1]"]) - graph.add_edge(original_input_nodes[0], original_op_nodes[0], "qr[0]") - graph.add_edge(original_op_nodes[0], output_nodes[0], "qr[0]") - # Setup other graph - other_graph = retworkx.PyGraph() - input_nodes = other_graph.add_nodes_from(["qr[2]", "qr[3]"]) - op_nodes = other_graph.add_nodes_from(["cx"]) - other_output_nodes = other_graph.add_nodes_from(["qr[2]", "qr[3]"]) - other_graph.add_edges_from( - [ - (input_nodes[0], op_nodes[0], "qr[2]"), - (input_nodes[1], op_nodes[0], "qr[3]"), - ] - ) - other_graph.add_edges_from( - [ - (op_nodes[0], other_output_nodes[0], "qr[2]"), - (op_nodes[0], other_output_nodes[1], "qr[3]"), - ] - ) - - def map_fn(weight): - if weight == "qr[2]": - return "qr[0]" - elif weight == "qr[3]": - return "qr[1]" - else: - return weight - - graph.remove_nodes_from(output_nodes) - other_graph.remove_nodes_from(input_nodes) - node_map = { - original_op_nodes[0]: (op_nodes[0], "qr[0]"), - original_input_nodes[1]: (op_nodes[0], "qr[1]"), - } - res = graph.compose(other_graph, node_map, node_map_func=map_fn, edge_map_func=map_fn) - self.assertEqual({2: 4, 3: 3, 4: 5}, res) - self.assertEqual(graph[res[other_output_nodes[0]]], "qr[0]") - self.assertEqual(graph[res[other_output_nodes[1]]], "qr[1]") - # qr[0] -> h - self.assertTrue(graph.has_edge(0, 2)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[0]"]) - # qr[1] -> cx - self.assertTrue(graph.has_edge(1, 4)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[1]"]) - # h -> cx - self.assertTrue(graph.has_edge(2, 4)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[0] - self.assertTrue(graph.has_edge(4, 3)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[1] - self.assertTrue(graph.has_edge(4, 5)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[1]"]) - - def test_compose_digraph_onto_graph_error(self): - digraph = retworkx.PyDiGraph() - graph = retworkx.PyGraph() - with self.assertRaises(TypeError): - graph.compose(digraph, {}) diff --git a/tests/retworkx_backwards_compat/graph/test_connected_components.py b/tests/retworkx_backwards_compat/graph/test_connected_components.py deleted file mode 100644 index ecd7929be..000000000 --- a/tests/retworkx_backwards_compat/graph/test_connected_components.py +++ /dev/null @@ -1,88 +0,0 @@ -# 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 TestConnectedComponents(unittest.TestCase): - def test_number_connected(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(range(3)) - graph.add_edge(0, 1, None) - self.assertEqual(retworkx.number_connected_components(graph), 2) - - def test_number_connected_direct(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(range(4)) - graph.add_edges_from_no_data([(3, 2), (2, 1), (1, 0)]) - self.assertEqual(len(retworkx.weakly_connected_components(graph)), 1) - - def test_number_connected_node_holes(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(range(3)) - graph.remove_node(1) - self.assertEqual(retworkx.number_connected_components(graph), 2) - - def test_connected_components(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - components = retworkx.connected_components(graph) - self.assertEqual([{0, 1, 2, 3}, {4, 5, 6, 7}], components) - - def test_node_connected_component(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - component = retworkx.node_connected_component(graph, 0) - self.assertEqual({0, 1, 2, 3}, component) - - def test_node_connected_component_invalid_node(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - with self.assertRaises(retworkx.InvalidNode): - retworkx.node_connected_component(graph, 10) - - def test_is_connected_false(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - self.assertFalse(retworkx.is_connected(graph)) - - def test_is_connected_true(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (2, 4), - (4, 5), - (5, 6), - (6, 7), - (7, 4), - ] - ) - self.assertTrue(retworkx.is_connected(graph)) - - def test_is_connected_null_graph(self): - graph = retworkx.PyGraph() - with self.assertRaises(retworkx.NullGraph): - retworkx.is_connected(graph) diff --git a/tests/retworkx_backwards_compat/graph/test_contract_nodes.py b/tests/retworkx_backwards_compat/graph/test_contract_nodes.py deleted file mode 100644 index b43fe19c5..000000000 --- a/tests/retworkx_backwards_compat/graph/test_contract_nodes.py +++ /dev/null @@ -1,242 +0,0 @@ -# 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 UndirectedEdge(tuple): - """An edge tuple wrapper for comparing expected edges with actual graph - edges where endpoint order doesn't matter (undirected). Supports both - edges and weighted edges. - - For example, the following become true: - ``UndirectedEdge((2, 3)) == UndirectedEdge((3, 2))`` - ``UndirectedEdge((4, 5, "a")) == UndirectedEdge((5, 4, "a"))`` - - """ - - def __eq__(self, o: object) -> bool: - return (frozenset(self[:2]), tuple(self[2:])) == ( - frozenset(o[:2]), - tuple(o[2:]), - ) - - def __hash__(self) -> int: - return hash((frozenset(self[:2]), tuple(self[2:]))) - - -class TestContractNodes(unittest.TestCase): - def test_empty_nodes(self): - """Replacing empty nodes is functionally equivalent to add_node.""" - dag = retworkx.PyGraph() - dag.contract_nodes([], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_unknown_nodes(self): - """ - Replacing all unknown nodes is functionally equivalent to add_node, - since unknown nodes should be ignored. - """ - dag = retworkx.PyGraph() - dag.contract_nodes([0, 1, 2], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_cycle_path_len_gt_1(self): - """ - ┌─┐ ┌─┐ - ┌4─┤a├─1┐ │m├──1───┐ - │ └─┘ │ └┬┘ │ - ┌┴┐ ┌┴┐ │ ┌┴┐ - │d│ │b│ ───► │ │b│ - └┬┘ └┬┘ │ └┬┘ - │ ┌─┐ 2 │ ┌─┐ 2 - └3─┤c├──┘ └3─┤c├──┘ - └─┘ └─┘ - """ - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - node_d = dag.add_node("d") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_b, node_c, 2) - dag.add_edge(node_c, node_d, 3) - dag.add_edge(node_a, node_d, 4) - - node_m = dag.contract_nodes([node_a, node_d], "m") - - self.assertEqual([node_b, node_c, node_m], dag.node_indexes()) - self.assertEqual( - { - UndirectedEdge((node_b, node_c)), - UndirectedEdge((node_c, node_m)), - UndirectedEdge((node_b, node_m)), - }, - set(UndirectedEdge(e) for e in dag.edge_list()), - ) - - def test_multiple_paths_would_cycle(self): - """ - ┌─┐ ┌─┐ ┌─┐ ┌─┐ - ┌3─┤c│ │e├─5┐ ┌──┤c│ │e├──┐ - │ └┬┘ └┬┘ │ │ └┬┘ └┬┘ │ - ┌┴┐ 2 ┌─┐ 4 ┌┴┐ │ 2 ┌─┐ 4 │ - │d│ └──┤b├──┘ │f│ ───► │ └──┤b├──┘ │ - └─┘ └┬┘ └─┘ 3 └┬┘ 5 - 1 │ 1 │ - ┌┴┐ │ ┌┴┐ │ - │a│ └──────┤m├──────┘ - └─┘ └─┘ - """ - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - node_d = dag.add_node("d") - node_e = dag.add_node("e") - node_f = dag.add_node("f") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_b, node_c, 2) - dag.add_edge(node_c, node_d, 3) - dag.add_edge(node_b, node_e, 4) - dag.add_edge(node_e, node_f, 5) - - node_m = dag.contract_nodes([node_a, node_d, node_f], "m") - - self.assertEqual([node_b, node_c, node_e, node_m], list(dag.node_indexes())) - self.assertEqual( - { - UndirectedEdge((node_b, node_c)), - UndirectedEdge((node_c, node_m)), - UndirectedEdge((node_e, node_m)), - UndirectedEdge((node_b, node_e)), - UndirectedEdge((node_b, node_m)), - }, - set(UndirectedEdge(e) for e in dag.edge_list()), - ) - - def test_replace_node_no_neighbors(self): - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_m = dag.contract_nodes([node_a], "m") - self.assertEqual([node_m], dag.node_indexes()) - self.assertEqual(set(), set(dag.edge_list())) - - def test_keep_edges_multigraph(self): - """ - ┌─┐ ┌─┐ - ┌─┤a├─┐ ┌─┤a├─┐ - │ └─┘ │ │ └─┘ │ - 1 2 ──► 1 2 - ┌┴┐ ┌┴┐ │ ┌─┐ │ - │b│ │c│ └─┤m├─┘ - └─┘ └─┘ └─┘ - """ - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_c, node_a, 2) - - node_m = dag.contract_nodes([node_b, node_c], "m") - self.assertEqual([node_a, node_m], dag.node_indexes()) - - # Note that target is *always* the new node (m). - self.assertEqual( - { - UndirectedEdge((node_a, node_m, 1)), - UndirectedEdge((node_a, node_m, 2)), - }, - set(UndirectedEdge(e) for e in dag.weighted_edge_list()), - ) - - -class TestContractNodesSimpleGraph(unittest.TestCase): - def setUp(self): - super().setUp() - self.dag = retworkx.PyGraph(multigraph=False) - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_node("b") - self.node_c = self.dag.add_node("c") - self.node_d = self.dag.add_node("d") - self.node_e = self.dag.add_node("e") - - self.dag.add_edge(self.node_a, self.node_b, 1) - self.dag.add_edge(self.node_a, self.node_c, 2) - self.dag.add_edge(self.node_a, self.node_d, 3) - self.dag.add_edge(self.node_b, self.node_e, 4) - self.dag.add_edge(self.node_c, self.node_e, 5) - self.dag.add_edge(self.node_d, self.node_e, 6) - - def test_collapse_parallel_edges_no_combo_fn(self): - """ - Parallel edges are collapsed arbitrarily when weight_combo_fn is None. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 1 or 2 or 3 - ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 4 or 5 or 6 - └──┬┴┬──┘ ┌┴┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes([self.node_b, self.node_c, self.node_d], "m") - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertTrue(any(e in self.dag.edges() for e in {1, 2, 3})) - self.assertTrue(any(e in self.dag.edges() for e in {4, 5, 6})) - - def test_collapse_parallel_edges(self): - """ - Parallel edges are collapsed using weight_combo_fn. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 6 - ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 15 - └──┬┴┬──┘ ┌┴┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes( - [self.node_b, self.node_c, self.node_d], - "m", - weight_combo_fn=lambda w1, w2: w1 + w2, - ) - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertEqual(set(self.dag.edges()), {6, 15}) - - def test_replace_all_nodes(self): - self.dag.contract_nodes(self.dag.node_indexes(), "m") - self.assertEqual(set(self.dag.nodes()), {"m"}) - self.assertFalse(self.dag.edges()) diff --git a/tests/retworkx_backwards_compat/graph/test_copy.py b/tests/retworkx_backwards_compat/graph/test_copy.py deleted file mode 100644 index 1a9aa9741..000000000 --- a/tests/retworkx_backwards_compat/graph/test_copy.py +++ /dev/null @@ -1,55 +0,0 @@ -# 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 TestCopy(unittest.TestCase): - def test_copy_returns_graph(self): - graph_a = retworkx.PyGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyGraph) - - def test_copy_with_holes_returns_graph(self): - graph_a = retworkx.PyGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_a.remove_node(node_b) - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyGraph) - self.assertEqual([node_a, node_c], graph_b.node_indexes()) - - def test_copy_empty(self): - graph = retworkx.PyGraph() - empty_copy = graph.copy() - self.assertEqual(len(empty_copy), 0) - - def test_copy_shared_ref(self): - graph_a = retworkx.PyGraph() - node_a = graph_a.add_node({"a": 1}) - node_b = graph_a.add_node({"b": 2}) - graph_a.add_edge(node_a, node_b, {"edge": 1}) - graph_b = graph_a.copy() - graph_a[0]["a"] = 42 - graph_b.get_edge_data(0, 1)["edge"] = 162 - self.assertEqual(graph_b[0]["a"], 42) - self.assertEqual(graph_a.get_edge_data(0, 1), {"edge": 162}) diff --git a/tests/retworkx_backwards_compat/graph/test_core_number.py b/tests/retworkx_backwards_compat/graph/test_core_number.py deleted file mode 100644 index 0ed4907b0..000000000 --- a/tests/retworkx_backwards_compat/graph/test_core_number.py +++ /dev/null @@ -1,96 +0,0 @@ -# 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 TestCoreNumber(unittest.TestCase): - def setUp(self): - # This is the example graph in Figure 1 from Batagelj and - # Zaversnik's paper titled An O(m) Algorithm for Cores - # Decomposition of Networks, 2003, - # http://arXiv.org/abs/cs/0310049. With nodes labeled as - # shown, the 3-core is given by nodes 0-7, the 2-core by nodes - # 8-15, the 1-core by nodes 16-19 and node 20 is in the - # 0-core. - self.example_edges = [ - (0, 2), - (0, 3), - (0, 5), - (1, 4), - (1, 6), - (1, 7), - (2, 3), - (3, 5), - (2, 5), - (5, 6), - (4, 6), - (4, 7), - (6, 7), - (5, 8), - (6, 8), - (6, 9), - (8, 9), - (0, 10), - (1, 10), - (1, 11), - (10, 11), - (12, 13), - (13, 15), - (14, 15), - (12, 14), - (8, 19), - (11, 16), - (11, 17), - (12, 18), - ] - - example_core = {} - for i in range(8): - example_core[i] = 3 - for i in range(8, 16): - example_core[i] = 2 - for i in range(16, 20): - example_core[i] = 1 - example_core[20] = 0 - self.example_core = example_core - - def test_undirected_empty(self): - graph = retworkx.PyGraph() - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {}) - - def test_undirected_all_0(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 0, 1: 0, 2: 0, 3: 0}) - - def test_undirected_all_3(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 3, 1: 3, 2: 3, 3: 3}) - - def test_undirected_paper_example(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(21))) - graph.add_edges_from_no_data(self.example_edges) - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, self.example_core) diff --git a/tests/retworkx_backwards_compat/graph/test_cycle_basis.py b/tests/retworkx_backwards_compat/graph/test_cycle_basis.py deleted file mode 100644 index 13719bb2f..000000000 --- a/tests/retworkx_backwards_compat/graph/test_cycle_basis.py +++ /dev/null @@ -1,69 +0,0 @@ -# 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 TestCycleBasis(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.add_nodes_from(list(range(10))) - self.graph.add_edges_from_no_data( - [ - (0, 1), - (0, 3), - (0, 5), - (0, 8), - (1, 2), - (1, 6), - (2, 3), - (3, 4), - (4, 5), - (6, 7), - (7, 8), - (8, 9), - ] - ) - - def test_cycle_basis(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(6))) - graph.add_edges_from_no_data([(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)]) - res = sorted(sorted(c) for c in retworkx.cycle_basis(graph, 0)) - self.assertEqual([[0, 1, 2, 3], [0, 3, 4, 5]], res) - - def test_cycle_basis_multiple_roots_same_cycles(self): - res = sorted(sorted(x) for x in retworkx.cycle_basis(self.graph, 0)) - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]]) - res = sorted(sorted(x) for x in retworkx.cycle_basis(self.graph, 1)) - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]]) - res = sorted(sorted(x) for x in retworkx.cycle_basis(self.graph, 9)) - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]]) - - def test_cycle_basis_disconnected_graphs(self): - self.graph.add_nodes_from(["A", "B", "C"]) - self.graph.add_edges_from_no_data([(10, 11), (10, 12), (11, 12)]) - cycles = retworkx.cycle_basis(self.graph, 9) - res = sorted(sorted(x) for x in cycles[:-1]) + [sorted(cycles[-1])] - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5], [10, 11, 12]]) - - def test_invalid_types(self): - digraph = retworkx.PyDiGraph() - with self.assertRaises(TypeError): - retworkx.cycle_basis(digraph) - - def test_self_loop(self): - self.graph.add_edge(1, 1, None) - res = sorted(sorted(c) for c in retworkx.cycle_basis(self.graph, 0)) - self.assertEqual([[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5], [1]], res) diff --git a/tests/retworkx_backwards_compat/graph/test_deepcopy.py b/tests/retworkx_backwards_compat/graph/test_deepcopy.py deleted file mode 100644 index fcd87b1c6..000000000 --- a/tests/retworkx_backwards_compat/graph/test_deepcopy.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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 copy -import unittest - -import retworkx - - -class TestDeepcopy(unittest.TestCase): - def test_deepcopy_returns_graph(self): - dag_a = retworkx.PyGraph() - node_a = dag_a.add_node("a_1") - node_b = dag_a.add_node("a_2") - dag_a.add_edge(node_a, node_b, "edge_1") - node_c = dag_a.add_node("a_3") - dag_a.add_edge(node_b, node_c, "edge_2") - dag_b = copy.deepcopy(dag_a) - self.assertIsInstance(dag_b, retworkx.PyGraph) - - def test_deepcopy_with_holes_returns_graph(self): - dag_a = retworkx.PyGraph() - node_a = dag_a.add_node("a_1") - node_b = dag_a.add_node("a_2") - dag_a.add_edge(node_a, node_b, "edge_1") - node_c = dag_a.add_node("a_3") - dag_a.add_edge(node_b, node_c, "edge_2") - dag_a.remove_node(node_b) - dag_b = copy.deepcopy(dag_a) - self.assertIsInstance(dag_b, retworkx.PyGraph) - self.assertEqual([node_a, node_c], dag_b.node_indexes()) - - def test_deepcopy_empty(self): - dag = retworkx.PyGraph() - empty_copy = copy.deepcopy(dag) - self.assertEqual(len(empty_copy), 0) - - def test_deepcopy_attrs(self): - graph = retworkx.PyGraph(attrs="abc") - graph_copy = copy.deepcopy(graph) - self.assertEqual(graph.attrs, graph_copy.attrs) diff --git a/tests/retworkx_backwards_compat/graph/test_dfs_edges.py b/tests/retworkx_backwards_compat/graph/test_dfs_edges.py deleted file mode 100644 index 3903e45ee..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dfs_edges.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 TestDfsEdges(unittest.TestCase): - def test_graph_dfs_edges(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - edges = retworkx.graph_dfs_edges(graph, 0) - expected = [(0, 1), (1, 2), (2, 4), (4, 3)] - self.assertEqual(expected, edges) - - def test_graph_disconnected_dfs_edges(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 1), (2, 3)]) - edges = retworkx.graph_dfs_edges(graph) - expected = [(0, 1), (2, 3)] - self.assertEqual(expected, edges) diff --git a/tests/retworkx_backwards_compat/graph/test_dfs_search.py b/tests/retworkx_backwards_compat/graph/test_dfs_search.py deleted file mode 100644 index 0b03349a5..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dfs_search.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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 TestDfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_graph_dfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (3, 1)]) - - def test_graph_dfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_dfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (3, 1), (4, 7)]) - - def test_graph_dfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.DFSVisitor): - - prohibited = [(0, 2), (1, 2)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.graph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 1), (1, 3), (3, 5), (5, 2), (2, 6)]) - - def test_graph_dfs_goal_search(self): - class GoalSearch(retworkx.visit.DFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.graph_dfs_search(self.graph, [0], vis) - except retworkx.visit.StopSearch: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) diff --git a/tests/retworkx_backwards_compat/graph/test_dijkstra.py b/tests/retworkx_backwards_compat/graph/test_dijkstra.py deleted file mode 100644 index 68b9f98ee..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dijkstra.py +++ /dev/null @@ -1,238 +0,0 @@ -# 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 TestDijkstraGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - self.graph.add_edge(self.a, self.b, 7) - self.graph.add_edge(self.c, self.a, 9) - self.graph.add_edge(self.a, self.d, 14) - self.graph.add_edge(self.b, self.c, 10) - self.graph.add_edge(self.d, self.c, 2) - self.graph.add_edge(self.d, self.e, 9) - self.graph.add_edge(self.b, self.f, 15) - self.graph.add_edge(self.c, self.f, 11) - self.graph.add_edge(self.e, self.f, 6) - - def test_dijkstra(self): - path = retworkx.graph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), self.e - ) - expected = {4: 20.0} - self.assertEqual(expected, path) - - def test_dijkstra_path(self): - path = retworkx.graph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - # a -> d -> e = 23 - # a -> c -> d -> e = 20 - expected = {4: [self.a, self.c, self.d, self.e]} - self.assertEqual(expected, path) - - def test_dijkstra_with_no_goal_set(self): - path = retworkx.graph_dijkstra_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = {1: 1.0, 2: 1.0, 3: 1.0, 4: 2.0, 5: 2.0} - self.assertEqual(expected, path) - - def test_dijkstra_length_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.graph_dijkstra_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_dijkstra_path_with_no_goal_set(self): - path = retworkx.graph_dijkstra_shortest_paths(self.graph, self.a) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, path) - - def test_dijkstra_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_dijkstra_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_path_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_dijkstra_shortest_paths(g, a, weight_fn=lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_with_disconnected_nodes(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 1.2) - g.add_node("C") - d = g.add_node("D") - g.add_edge(b, d, 2.4) - path = retworkx.graph_dijkstra_shortest_path_lengths(g, a, lambda x: round(x, 1)) - # Computers never work: - expected = {1: 1.2, 3: 3.5999999999999996} - self.assertEqual(expected, path) - - def test_dijkstra_graph_with_digraph_input(self): - g = retworkx.PyDAG() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.graph_dijkstra_shortest_path_lengths(g, 0, lambda x: x) - - def test_dijkstra_all_pair_path_lengths(self): - lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 3: 11.0, 4: 20.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 3: 12.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 3: 2.0, 4: 11.0, 5: 11.0}, - 3: {0: 11.0, 1: 12.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {0: 20.0, 1: 21.0, 2: 11.0, 3: 9.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 3: 13.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths(self): - paths = retworkx.graph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - }, - 1: {0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 2, 3, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 3: [2, 3], 4: [2, 3, 4], 5: [2, 5]}, - 3: {0: [3, 2, 0], 1: [3, 2, 1], 2: [3, 2], 4: [3, 4], 5: [3, 2, 5]}, - 4: { - 0: [4, 3, 2, 0], - 1: [4, 5, 1], - 2: [4, 3, 2], - 3: [4, 3], - 5: [4, 5], - }, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 3: [5, 2, 3], 4: [5, 4]}, - } - self.assertEqual(expected, paths) - - def test_dijkstra_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 4: 26.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 4: 17.0, 5: 11.0}, - 4: {0: 26.0, 1: 21.0, 2: 17.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - paths = retworkx.graph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 2], 4: [0, 2, 5, 4], 5: [0, 2, 5]}, - 1: {0: [1, 0], 2: [1, 2], 4: [1, 5, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 4: [2, 5, 4], 5: [2, 5]}, - 4: {0: [4, 5, 2, 0], 1: [4, 5, 1], 2: [4, 5, 2], 5: [4, 5]}, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 4: [5, 4]}, - } - self.assertEqual(expected, paths) - - def test_dijkstra_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float)) - - def test_dijkstra_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_dijkstra_shortest_paths(graph, float)) - - def test_dijkstra_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float), - ) - - def test_dijkstra_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_dijkstra_shortest_paths(graph, float), - ) - - def dijkstra_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - for as_undirected in [False, True]: - with self.subTest(invalid_weight=invalid_weight, as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.graph_dijkstra_shortest_paths( - graph, - source=0, - weight_fn=lambda _: invalid_weight, - as_undirected=as_undirected, - ) - - def dijkstra_lengths_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_dijkstra_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_all_pairs_dijkstra_shortest_paths( - graph, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_lenghts_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_all_pairs_dijkstra_path_lengths( - graph, edge_cost_fn=lambda _: invalid_weight - ) diff --git a/tests/retworkx_backwards_compat/graph/test_dijkstra_search.py b/tests/retworkx_backwards_compat/graph/test_dijkstra_search.py deleted file mode 100644 index aea0dc6d7..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dijkstra_search.py +++ /dev/null @@ -1,189 +0,0 @@ -# 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 TestDijkstraSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 2, 2), - (1, 3, 10), - (2, 1, 1), - (2, 5, 1), - (2, 6, 1), - (5, 3, 1), - (4, 7, 1), - ] - ) - - def test_graph_dijkstra_tree_edges(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3)]) - - def test_graph_dijkstra_tree_edges_no_starting_point(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.graph_dijkstra_search(self.graph, None, float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3), (4, 7)]) - - def test_graph_dijkstra_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_graph_dijkstra_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise StopIfGoalFound - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_graph_dijkstra_goal_search_with_prohibited_edges(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - prohibited = [(5, 3)] - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def examine_edge(self, edge): - u, v, _ = edge - if (u, v) in self.prohibited: - raise retworkx.visit.PruneSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - self.assertEqual(vis.opt_goal_cost, 11.0) - - def test_graph_prune_edge_not_relaxed(self): - class PruneEdgeNotRelaxed(retworkx.visit.DijkstraVisitor): - def edge_not_relaxed(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneEdgeNotRelaxed() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) diff --git a/tests/retworkx_backwards_compat/graph/test_dist_matrix.py b/tests/retworkx_backwards_compat/graph/test_dist_matrix.py deleted file mode 100644 index 166312575..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dist_matrix.py +++ /dev/null @@ -1,102 +0,0 @@ -# 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 numpy as np - -import retworkx - - -class TestDistanceMatrix(unittest.TestCase): - def test_graph_distance_matrix(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.graph_distance_matrix(graph) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_graph_distance_matrix_parallel(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.graph_distance_matrix(graph, parallel_threshold=5) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_graph_distance_matrix_non_zero_null(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.graph_distance_matrix(graph, null_value=np.nan) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_graph_distance_matrix_parallel_non_zero_null(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.graph_distance_matrix(graph, parallel_threshold=5, null_value=np.nan) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ], - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_graph_distance_matrix_node_hole(self): - graph = retworkx.generators.path_graph(4) - graph.remove_node(0) - dist = retworkx.graph_distance_matrix(graph) - expected = np.array([[0.0, 1.0, 2.0], [1.0, 0.0, 1.0], [2.0, 1.0, 0.0]]) - self.assertTrue(np.array_equal(dist, expected)) diff --git a/tests/retworkx_backwards_compat/graph/test_dot.py b/tests/retworkx_backwards_compat/graph/test_dot.py deleted file mode 100644 index fafbbcd87..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dot.py +++ /dev/null @@ -1,130 +0,0 @@ -# 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 os -import tempfile -import unittest - -import retworkx - - -class TestDot(unittest.TestCase): - def setUp(self): - fd, self.path = tempfile.mkstemp() - os.close(fd) - os.remove(self.path) - - def test_graph_to_dot(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'graph {\n0 [color=black, fillcolor=green, label="a", style=filled' - '];\n1 [color=black, fillcolor=red, label="a", style=filled];' - '\n0 -- 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge) - self.assertEqual(expected, res) - - def test_digraph_to_dot(self): - graph = retworkx.PyDiGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'digraph {\n0 [color=black, fillcolor=green, label="a", ' - 'style=filled];\n1 [color=black, fillcolor=red, label="a", ' - 'style=filled];\n0 -> 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge) - self.assertEqual(expected, res) - - def test_graph_to_dot_to_file(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'graph {\n0 [color=black, fillcolor=green, label="a", ' - 'style=filled];\n1 [color=black, fillcolor=red, label="a", ' - 'style=filled];\n0 -- 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) - self.addCleanup(os.remove, self.path) - self.assertIsNone(res) - with open(self.path, "r") as fd: - res = fd.read() - self.assertEqual(expected, res) - - def test_graph_empty_dicts(self): - graph = retworkx.undirected_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}) - self.assertEqual( - "graph {\n0 ;\n1 ;\n2 ;\n1 -- 0 ;\n2 -- 0 ;\n" "2 -- 1 ;\n}\n", - dot_str, - ) - - def test_graph_graph_attrs(self): - graph = retworkx.undirected_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}, {"bgcolor": "red"}) - self.assertEqual( - "graph {\nbgcolor=red ;\n0 ;\n1 ;\n2 ;\n1 -- 0 ;\n" "2 -- 0 ;\n2 -- 1 ;\n}\n", - dot_str, - ) - - def test_graph_no_args(self): - graph = retworkx.undirected_gnp_random_graph(3, 0.95, seed=24) - dot_str = graph.to_dot() - self.assertEqual("graph {\n0 ;\n1 ;\n2 ;\n2 -- 0 ;\n2 -- 1 ;\n}\n", dot_str) diff --git a/tests/retworkx_backwards_compat/graph/test_edgelist.py b/tests/retworkx_backwards_compat/graph/test_edgelist.py deleted file mode 100644 index c6092a173..000000000 --- a/tests/retworkx_backwards_compat/graph/test_edgelist.py +++ /dev/null @@ -1,209 +0,0 @@ -# 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 os -import tempfile -import unittest - -import retworkx - - -class TestEdgeList(unittest.TestCase): - def test_empty_edge_list_graph(self): - with tempfile.NamedTemporaryFile() as fd: - graph = retworkx.PyGraph.read_edge_list(fd.name) - self.assertEqual(graph.nodes(), []) - - def test_invalid_path_graph(self): - path = os.path.join(tempfile.gettempdir(), "fake_file_name.txt") - with self.assertRaises(FileNotFoundError): - retworkx.PyGraph.read_edge_list(path) - - def test_simple_example_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_blank_line_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2 # test comments\n") - fd.write("#2 3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_leading_space_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2 # test comments\n") - fd.write(" #2 3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_weight_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 0\n") - fd.write("1 2 1# test comments\n") - fd.write("#2 3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_delim_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0,1,0\n") - fd.write("1,2,1# test comments\n") - fd.write("#2,3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#", deliminator=",") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("//c|d\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_graph_target_existing(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("a|c\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1", None]) - - def test_write_edge_list_empty_digraph(self): - path = os.path.join(tempfile.gettempdir(), "empty.txt") - graph = retworkx.PyGraph() - graph.write_edge_list(path) - self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: - self.assertEqual("", edge_file.read()) - - def test_write_edge_list_round_trip(self): - path = os.path.join(tempfile.gettempdir(), "round_trip.txt") - graph = retworkx.generators.star_graph(5) - count = iter(range(5)) - - def weight_fn(edge): - return str(next(count)) - - graph.write_edge_list(path, weight_fn=weight_fn) - self.addCleanup(os.remove, path) - new_graph = retworkx.PyGraph.read_edge_list(path) - expected = [ - (0, 1, "0"), - (0, 2, "1"), - (0, 3, "2"), - (0, 4, "3"), - ] - self.assertEqual(expected, new_graph.weighted_edge_list()) - - def test_custom_delim(self): - path = os.path.join(tempfile.gettempdir(), "custom_delim.txt") - graph = retworkx.generators.path_graph(5) - graph.write_edge_list(path, deliminator=",") - self.addCleanup(os.remove, path) - expected = """0,1 -1,2 -2,3 -3,4 -""" - with open(path, "rt") as edge_file: - self.assertEqual(edge_file.read(), expected) - - def test_invalid_return_type_weight_fn(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.undirected_gnm_random_graph(5, 4) - self.addCleanup(cleanup_file, path) - with self.assertRaises(TypeError): - graph.write_edge_list(path, weight_fn=lambda _: 4.5) - - def test_weight_fn_raises(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.undirected_gnm_random_graph(5, 4) - - def weight_fn(edge): - raise KeyError - - self.addCleanup(cleanup_file, path) - with self.assertRaises(KeyError): - graph.write_edge_list(path, weight_fn=weight_fn) - - -def cleanup_file(path): - try: - os.remove(path) - except Exception: - pass diff --git a/tests/retworkx_backwards_compat/graph/test_edges.py b/tests/retworkx_backwards_compat/graph/test_edges.py deleted file mode 100644 index bcb7fd252..000000000 --- a/tests/retworkx_backwards_compat/graph/test_edges.py +++ /dev/null @@ -1,819 +0,0 @@ -# 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 TestEdges(unittest.TestCase): - def test_get_edge_data(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - res = graph.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph.add_edge(node_a, node_b, "b") - res = graph.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertIn("Edgy", res) - - def test_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_edge_data, node_a, node_b) - - def test_num_edges(self): - graph = retworkx.PyGraph() - graph.add_node(1) - graph.add_node(42) - graph.add_node(146) - graph.add_edges_from_no_data([(0, 1), (1, 2)]) - self.assertEqual(2, graph.num_edges()) - - def test_num_edges_no_edges(self): - graph = retworkx.PyGraph() - graph.add_node(1) - graph.add_node(42) - self.assertEqual(0, graph.num_edges()) - - def test_update_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge(node_a, node_b, "Edgy") - self.assertEqual([(0, 1, "Edgy")], graph.weighted_edge_list()) - - def test_update_edge_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.update_edge, node_a, node_b, None) - - def test_update_edge_by_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - edge_index = graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge_by_index(edge_index, "Edgy") - self.assertEqual([(0, 1, "Edgy")], graph.weighted_edge_list()) - - def test_update_edge_invalid_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - self.assertRaises(IndexError, graph.update_edge_by_index, 0, None) - - def test_update_edge_parallel_edges(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "not edgy") - edge_index = graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge_by_index(edge_index, "Edgy") - self.assertEqual( - [(0, 1, "not edgy"), (0, 1, "Edgy")], - list(graph.weighted_edge_list()), - ) - - def test_no_edge_get_all_edge_data(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_all_edge_data, node_a, node_b) - - def test_has_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {}) - self.assertTrue(graph.has_edge(node_a, node_b)) - self.assertTrue(graph.has_edge(node_b, node_a)) - - def test_has_edge_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertFalse(graph.has_edge(node_a, node_b)) - - def test_edges(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], graph.edges()) - - def test_edges_empty(self): - graph = retworkx.PyGraph() - graph.add_node("a") - self.assertEqual([], graph.edges()) - - def test_edge_indices(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual([0, 1], graph.edge_indices()) - - def test_get_edge_indices_empty(self): - graph = retworkx.PyGraph() - graph.add_node("a") - self.assertEqual([], graph.edge_indices()) - - def test_add_duplicates(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("a") - graph.add_edge(node_a, node_b, "a") - graph.add_edge(node_a, node_b, "b") - self.assertEqual(["a", "b"], graph.edges()) - - def test_remove_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge(node_a, node_b) - self.assertEqual([], graph.edges()) - - def test_remove_multiple(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_b, "super_edgy") - graph.remove_edge_from_index(0) - self.assertEqual(["super_edgy"], graph.edges()) - - def test_remove_edge_from_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_no_edge(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edges_from(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - graph.remove_edges_from([(node_a, node_b), (node_a, node_c)]) - self.assertEqual([], graph.edges()) - - def test_remove_edges_from_invalid(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - with self.assertRaises(retworkx.NoEdgeBetweenNodes): - graph.remove_edges_from([(node_b, node_c), (node_a, node_c)]) - - def test_degree(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(2, graph.degree(node_b)) - - def test_degree_with_self_loops(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 0), (0, 1), (0, 0)]) - self.assertEqual(5, graph.degree(0)) - - def test_add_edge_from(self): - graph = retworkx.PyGraph() - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - res = graph.add_edges_from(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty(self): - graph = retworkx.PyGraph() - res = graph.add_edges_from([]) - self.assertEqual([], res) - - def test_add_edge_from_no_data(self): - graph = retworkx.PyGraph() - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - res = graph.add_edges_from_no_data(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual([None, None, None, None, None], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty_no_data(self): - graph = retworkx.PyGraph() - res = graph.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_extend_from_weighted_edge_list_empty(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_weighted_edge_list_edges_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - (0, 1, "not_a"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e", "not_a"], graph.edges()) - - def test_edge_list(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.add_edges_from(edge_list) - self.assertEqual([(x[0], x[1]) for x in edge_list], graph.edge_list()) - - def test_edge_list_empty(self): - graph = retworkx.PyGraph() - self.assertEqual([], graph.edge_list()) - - def test_weighted_edge_list(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.add_edges_from(edge_list) - self.assertEqual(edge_list, graph.weighted_edge_list()) - - def test_weighted_edge_list_empty(self): - graph = retworkx.PyGraph() - self.assertEqual([], graph.weighted_edge_list()) - - def test_extend_from_edge_list(self): - graph = retworkx.PyGraph() - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_extend_from_edge_list_empty(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_edge_list_nodes_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_extend_from_edge_list_existing_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3), (0, 1)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 6, graph.edges()) - - def test_extend_from_weighted_edge_list(self): - graph = retworkx.PyGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - - def test_add_edges_from_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from([(0, 1, False), (1, 0, True)]) - self.assertEqual([0, 1], res) - self.assertEqual([False, True], graph.edges()) - - def test_add_edges_from_no_data_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from_no_data([(0, 1), (1, 0)]) - self.assertEqual([0, 1], res) - self.assertEqual([None, None], graph.edges()) - - def test_multigraph_attr(self): - graph = retworkx.PyGraph() - self.assertTrue(graph.multigraph) - - def test_has_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(1, 0, 0) - self.assertTrue(graph.has_parallel_edges()) - - def test_has_parallel_edges_no_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - self.assertFalse(graph.has_parallel_edges()) - - def test_has_parallel_edges_empty(self): - graph = retworkx.PyGraph() - self.assertFalse(graph.has_parallel_edges()) - - def test_edge_index_map(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_c, node_d, "edge c") - self.assertEqual( - { - 0: (node_a, node_c, "edge a"), - 1: (node_b, node_d, "edge_b"), - 2: (node_c, node_d, "edge c"), - }, - graph.edge_index_map(), - ) - - def test_incident_edges(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_c, node_d, "edge c") - res = graph.incident_edges(node_d) - self.assertEqual({1, 2}, set(res)) - - def test_incident_edges_invalid_node(self): - graph = retworkx.PyGraph() - res = graph.incident_edges(42) - self.assertEqual([], res) - - def test_incident_edge_index_map(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_c, node_d, "edge c") - res = graph.incident_edge_index_map(node_d) - self.assertEqual({2: (3, 2, "edge c"), 1: (3, 1, "edge_b")}, res) - - def test_incident_edge_index_map_invalid_node(self): - graph = retworkx.PyGraph() - res = graph.incident_edge_index_map(42) - self.assertEqual({}, res) - - def test_single_neighbor_out_edges(self): - g = retworkx.PyGraph() - node_a = g.add_node("a") - node_b = g.add_node("b") - g.add_edge(node_a, node_b, {"a": 1}) - node_c = g.add_node("c") - g.add_edge(node_a, node_c, {"a": 2}) - res = g.out_edges(node_a) - self.assertEqual([(node_a, node_c, {"a": 2}), (node_a, node_b, {"a": 1})], res) - - def test_neighbor_surrounded_in_out_edges(self): - g = retworkx.PyGraph() - node_a = g.add_node("a") - node_b = g.add_node("b") - node_c = g.add_node("c") - g.add_edge(node_a, node_b, {"a": 1}) - g.add_edge(node_b, node_c, {"a": 2}) - res = g.out_edges(node_b) - self.assertEqual([(node_b, node_c, {"a": 2}), (node_b, node_a, {"a": 1})], res) - res = g.in_edges(node_b) - self.assertEqual([(node_c, node_b, {"a": 2}), (node_a, node_b, {"a": 1})], res) - - def test_edge_index_map_empty(self): - graph = retworkx.PyGraph() - self.assertEqual({}, graph.edge_index_map()) - - def test_get_edge_data_by_index(self): - graph = retworkx.PyGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_data_by_index(2) - self.assertEqual("c", res) - - def test_get_edge_data_by_index_invalid_index(self): - graph = retworkx.PyGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_data_by_index(2) - - def test_get_edge_endpoints_by_index(self): - graph = retworkx.PyGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_endpoints_by_index(2) - self.assertEqual((0, 2), res) - - def test_get_edge_endpoints_by_index_invalid_index(self): - graph = retworkx.PyGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_endpoints_by_index(2) - - -class TestEdgesMultigraphFalse(unittest.TestCase): - def test_multigraph_attr(self): - graph = retworkx.PyGraph(multigraph=False) - self.assertFalse(graph.multigraph) - - def test_has_parallel_edges(self): - graph = retworkx.PyGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(1, 0, 0) - self.assertFalse(graph.has_parallel_edges()) - - def test_parallel_edges_not_in_edge_list(self): - graph = retworkx.PyGraph(multigraph=False) - edge_list = [ - (8, 6), - (6, 5), - (6, 5), - (4, 5), - (5, 4), - (4, 5), - (3, 4), - (4, 3), - (3, 4), - (2, 3), - (0, 2), - (2, 0), - (0, 2), - (2, 3), - ] - graph.extend_from_edge_list(edge_list) - graph_edge_list = graph.edge_list() - expected_edges = [(6, 8), (5, 6), (4, 5), (3, 4), (2, 3), (0, 2)] - self.assertEqual(len(graph_edge_list), len(expected_edges)) - for edge in expected_edges: - if edge not in graph_edge_list and (edge[1], edge[0]) not in graph_edge_list: - self.fail(f"{edge} not found in graph edge list {graph_edge_list}") - - def test_get_edge_data(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - res = graph.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph.add_edge(node_a, node_b, "b") - res = graph.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertNotIn("Edgy", res) - - def test_no_edge(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_edge_data, node_a, node_b) - - def test_no_edge_get_all_edge_data(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_all_edge_data, node_a, node_b) - - def test_has_edge(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {}) - self.assertTrue(graph.has_edge(node_a, node_b)) - self.assertTrue(graph.has_edge(node_b, node_a)) - - def test_has_edge_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertFalse(graph.has_edge(node_a, node_b)) - - def test_edges(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], graph.edges()) - - def test_edges_empty(self): - graph = retworkx.PyGraph(False) - graph.add_node("a") - self.assertEqual([], graph.edges()) - - def test_add_duplicates(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("a") - graph.add_edge(node_a, node_b, "a") - graph.add_edge(node_a, node_b, "b") - self.assertEqual(["b"], graph.edges()) - - def test_remove_no_edge(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge(node_a, node_b) - self.assertEqual([], graph.edges()) - - def test_remove_multiple(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_b, "super_edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_from_index(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_no_edge(self): - graph = retworkx.PyGraph(False) - graph.add_node("a") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_degree(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(2, graph.degree(node_b)) - - def test_add_edge_from(self): - graph = retworkx.PyGraph(False) - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - res = graph.add_edges_from(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty(self): - graph = retworkx.PyGraph(False) - res = graph.add_edges_from([]) - self.assertEqual([], res) - - def test_add_edge_from_no_data(self): - graph = retworkx.PyGraph(False) - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - res = graph.add_edges_from_no_data(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual([None, None, None, None, None], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty_no_data(self): - graph = retworkx.PyGraph(False) - res = graph.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_add_edges_from_parallel_edges(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from([(0, 1, False), (1, 0, True)]) - self.assertEqual([0, 0], res) - self.assertEqual([True], graph.edges()) - - def test_add_edges_from_no_data_parallel_edges(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from_no_data([(0, 1), (1, 0)]) - self.assertEqual([0, 0], res) - self.assertEqual([None], graph.edges()) - - def test_extend_from_weighted_edge_list_empty(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_weighted_edge_list_edges_exist(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - (0, 1, "not_a"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["not_a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_edge_list(self): - graph = retworkx.PyGraph(False) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_edge_list_empty(self): - graph = retworkx.PyGraph(False) - graph.extend_from_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_edge_list_nodes_exist(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_extend_from_edge_list_existing_edge(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3), (0, 1)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_weighted_edge_list(self): - graph = retworkx.PyGraph(False) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) diff --git a/tests/retworkx_backwards_compat/graph/test_floyd_warshall.py b/tests/retworkx_backwards_compat/graph/test_floyd_warshall.py deleted file mode 100644 index a7fc4452e..000000000 --- a/tests/retworkx_backwards_compat/graph/test_floyd_warshall.py +++ /dev/null @@ -1,201 +0,0 @@ -# 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 numpy - -import retworkx - - -class TestFloydWarshall(unittest.TestCase): - parallel_threshold = 300 - - def test_vs_dijkstra_all_pairs(self): - graph = retworkx.PyGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - - dijkstra_lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.graph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_vs_dijkstra_all_pairs_with_node_removal(self): - graph = retworkx.PyGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - graph.remove_node(d) - - dijkstra_lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.graph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_floyd_warshall_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_floyd_warshall(graph, float)) - - def test_floyd_warshall_graph_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_floyd_warshall(graph, float), - ) - - def test_floyd_warshall_numpy_three_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(6))) - weights = [2, 12, 1, 5, 1] - graph.add_edges_from([(i, i + 1, weights[i]) for i in range(5)]) - graph.add_edge(5, 0, 10) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 15) - self.assertEqual(dist[3, 0], 15) - - def test_weighted_numpy_two_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from( - [ - (0, 1, 2), - (1, 2, 2), - (2, 3, 1), - (3, 4, 1), - (4, 5, 1), - (5, 6, 1), - (6, 7, 1), - (7, 0, 1), - ] - ) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 2], 4) - self.assertEqual(dist[2, 0], 4) - - def test_weighted_numpy_negative_cycle(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertTrue(numpy.all(numpy.diag(dist) < 0)) - - def test_floyd_warshall_numpy_cycle(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 3) - - def test_numpy_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - expected = numpy.full((4, 4), numpy.inf) - numpy.fill_diagonal(expected, 0) - self.assertTrue(numpy.array_equal(dist, expected)) - - def test_floyd_warshall_numpy_graph_cycle_with_removals(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 3) - - def test_floyd_warshall_numpy_graph_cycle_no_weight_fn(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.graph_floyd_warshall_numpy(graph) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 3) - - def test_floyd_warshall_numpy_graph_cycle_default_weight(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.graph_floyd_warshall_numpy( - graph, default_weight=2, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 6) - self.assertEqual(dist[0, 4], 6) - - -class TestParallelFloydWarshall(TestFloydWarshall): - parallel_threshold = 0 diff --git a/tests/retworkx_backwards_compat/graph/test_graph_attrs.py b/tests/retworkx_backwards_compat/graph/test_graph_attrs.py deleted file mode 100644 index d91ab1666..000000000 --- a/tests/retworkx_backwards_compat/graph/test_graph_attrs.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 TestAttributes(unittest.TestCase): - def test_no_attrs(self): - graph = retworkx.PyGraph() - self.assertIsNone(graph.attrs) - - def test_attrs_set_at_init(self): - graph = retworkx.PyGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - - def test_attrs_set_at_init_override(self): - graph = retworkx.PyGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - graph.attrs = "ABC" - self.assertEqual("ABC", graph.attrs) diff --git a/tests/retworkx_backwards_compat/graph/test_isomorphic.py b/tests/retworkx_backwards_compat/graph/test_isomorphic.py deleted file mode 100644 index e034b6751..000000000 --- a/tests/retworkx_backwards_compat/graph/test_isomorphic.py +++ /dev/null @@ -1,313 +0,0 @@ -# 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 TestIsomorphic(unittest.TestCase): - def test_empty_isomorphic_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_isomorphic_compare_nodes(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_isomorphic_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_isomorphic_compare_nodes_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_is_isomorphic_nodes_compare_raises(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises(TypeError, retworkx.is_isomorphic, (g_a, g_b, compare_nodes)) - - def test_isomorphic_compare_nodes_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_compare_edges_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic( - g_a, - g_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_isomorphic_removed_nodes_in_second_graph(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_0", "a_2", "a_1", "a_3"]) - g_b.add_edges_from( - [ - (nodes[0], nodes[1], "e_01"), - (nodes[0], nodes[3], "e_03"), - (nodes[2], nodes[1], "a_1"), - (nodes[1], nodes[3], "a_2"), - ] - ) - g_b.remove_node(nodes[0]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_node_count_not_equal(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1")]) - - nodes = g_b.add_nodes_from(["a_0", "a_1"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1")]) - g_b.remove_node(nodes[0]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_same_degrees_non_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4", "b_1", "b_2", "b_3", "b_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[3], "a_3"), - (nodes[3], nodes[0], "a_4"), - (nodes[4], nodes[5], "b_1"), - (nodes[5], nodes[6], "b_2"), - (nodes[6], nodes[7], "b_3"), - (nodes[7], nodes[4], "b_4"), - (nodes[0], nodes[4], "e_1"), - (nodes[1], nodes[5], "e_2"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3", "a_4", "b_1", "b_2", "b_3", "b_4"]) - g_b.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[3], "a_3"), - (nodes[3], nodes[0], "a_4"), - (nodes[4], nodes[5], "b_1"), - (nodes[5], nodes[6], "b_2"), - (nodes[6], nodes[7], "b_3"), - (nodes[7], nodes[4], "b_4"), - (nodes[0], nodes[4], "e_1"), - (nodes[2], nodes[6], "e_2"), - ] - ) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_graph_isomorphic_self_loop(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edges_from_no_data([(0, 0), (0, 1)]) - self.assertTrue(retworkx.is_isomorphic(graph, graph)) - - def test_graph_isomorphic_petersen(self): - """Based on 'The isomorphism classes of the generalized Petersen graphs' - by Steimle and Staton: https://doi.org/10.1016/j.disc.2007.12.074 - - For 2 <= k <= n- 2 with gcd(n, k) = 1, - G(n, k) is isomorphic to G(n, l) if and only if: - k ≡ -l (mod n) or kl ≡ ±1 (mod n) - """ - n = 23 - upper_bound_k = (n - 1) // 2 - for k in range(1, upper_bound_k + 1): - for t in range(k, upper_bound_k + 1): - with self.subTest(k=k, t=t): - self.assertEqual( - retworkx.is_isomorphic( - retworkx.generators.generalized_petersen_graph(n, k), - retworkx.generators.generalized_petersen_graph(n, t), - ), - (k == t) or (k == n - t) or (k * t % n == 1) or (k * t % n == n - 1), - ) - - def test_isomorphic_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_edge_list([(0, 1), (0, 1), (1, 2), (2, 3)]) - second = retworkx.PyGraph() - second.extend_from_edge_list([(0, 1), (1, 2), (1, 2), (2, 3)]) - self.assertFalse(retworkx.is_isomorphic(first, second)) - - def test_isomorphic_parallel_edges_with_edge_matcher(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "b"), (1, 2, "c")]) - self.assertTrue(retworkx.is_isomorphic(graph, graph, edge_matcher=lambda x, y: x == y)) - - def test_graph_isomorphic_insufficient_call_limit(self): - graph = retworkx.generators.path_graph(5) - self.assertFalse(retworkx.is_isomorphic(graph, graph, call_limit=2)) - - def test_graph_vf2_mapping_identical(self): - graph = retworkx.generators.grid_graph(2, 2) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_graph_vf2_mapping_identical_removals(self): - graph = retworkx.generators.path_graph(2) - second_graph = retworkx.generators.path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping(graph, second_graph) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_graph_vf2_mapping_identical_removals_first(self): - second_graph = retworkx.generators.path_graph(2) - graph = retworkx.generators.path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping( - graph, - second_graph, - ) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_graph_vf2_mapping_identical_vf2pp(self): - graph = retworkx.generators.grid_graph(2, 2) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_graph_vf2_mapping_identical_removals_vf2pp(self): - graph = retworkx.generators.path_graph(2) - second_graph = retworkx.generators.path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_graph_vf2_mapping_identical_removals_first_vf2pp(self): - second_graph = retworkx.generators.path_graph(2) - graph = retworkx.generators.path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_graph_vf2_number_of_valid_mappings(self): - graph = retworkx.generators.mesh_graph(3) - mapping = retworkx.graph_vf2_mapping(graph, graph, id_order=True) - total = 0 - for _ in mapping: - total += 1 - self.assertEqual(total, 6) - - def test_empty_graph_vf2_mapping(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.graph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=False) - self.assertEqual({}, next(mapping)) diff --git a/tests/retworkx_backwards_compat/graph/test_k_shortest_path.py b/tests/retworkx_backwards_compat/graph/test_k_shortest_path.py deleted file mode 100644 index 8c01b6497..000000000 --- a/tests/retworkx_backwards_compat/graph/test_k_shortest_path.py +++ /dev/null @@ -1,75 +0,0 @@ -# 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 TestKShortestpath(unittest.TestCase): - def test_graph_k_shortest_path_lengths(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (4, 5), - (1, 4), - (5, 6), - (6, 7), - (7, 5), - ] - ) - res = retworkx.graph_k_shortest_path_lengths(graph, 1, 2, lambda _: 1) - expected = {0: 3, 1: 2, 2: 3, 3: 2, 4: 3, 5: 4, 6: 4, 7: 4} - self.assertEqual(res, expected) - - def test_k_graph_shortest_path_with_goal(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - res = retworkx.graph_k_shortest_path_lengths(graph, 0, 2, lambda _: 1, 3) - self.assertEqual({3: 4}, res) - - def test_k_graph_shortest_path_with_goal_node_hole(self): - graph = retworkx.generators.path_graph(4) - graph.remove_node(0) - res = retworkx.graph_k_shortest_path_lengths( - graph, start=1, k=1, edge_cost=lambda _: 1, goal=3 - ) - self.assertEqual({3: 2}, res) - - def test_graph_k_shortest_path_with_invalid_weight(self): - graph = retworkx.generators.path_graph(4) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_k_shortest_path_lengths( - graph, - start=1, - k=1, - edge_cost=lambda _: invalid_weight, - goal=3, - ) - - def test_k_shortest_path_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.graph_k_shortest_path_lengths( - g, start=a, k=1, edge_cost=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) diff --git a/tests/retworkx_backwards_compat/graph/test_layout.py b/tests/retworkx_backwards_compat/graph/test_layout.py deleted file mode 100644 index 38e56737d..000000000 --- a/tests/retworkx_backwards_compat/graph/test_layout.py +++ /dev/null @@ -1,477 +0,0 @@ -# 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 LayoutTest(unittest.TestCase): - thres = 1e-6 - - def assertLayoutEquiv(self, exp, res): - for k in exp: - ev = exp[k] - rv = res[k] - if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: - self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) - ) - - -class TestRandomLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_random_layout(self): - res = retworkx.graph_random_layout(self.graph, seed=42) - expected = { - 0: (0.2265125179283135, 0.23910669031859955), - 4: (0.8025885957751138, 0.37085692752109345), - 5: (0.23635127852185123, 0.9286365888207462), - 1: (0.760833410686741, 0.5278396573581516), - 3: (0.1879083014236631, 0.524657662927804), - 2: (0.9704763177409157, 0.37546268141451944), - 6: (0.462700947802672, 0.44025745918644743), - 7: (0.3125895420208278, 0.0893209773065271), - 8: (0.5567725240957387, 0.21079648777222115), - 9: (0.7586719404939911, 0.43090704138697045), - } - self.assertEqual(expected, res) - - def test_random_layout_center(self): - res = retworkx.graph_random_layout(self.graph, center=(0.5, 0.5), seed=42) - expected = { - 1: [1.260833410686741, 1.0278396573581516], - 5: [0.7363512785218512, 1.4286365888207462], - 7: [0.8125895420208278, 0.5893209773065271], - 4: [1.3025885957751138, 0.8708569275210934], - 8: [1.0567725240957389, 0.7107964877722212], - 9: [1.2586719404939912, 0.9309070413869704], - 0: [0.7265125179283135, 0.7391066903185995], - 2: [1.4704763177409157, 0.8754626814145194], - 6: [0.962700947802672, 0.9402574591864474], - 3: [0.6879083014236631, 1.0246576629278041], - } - self.assertEqual(expected, res) - - def test_random_layout_no_seed(self): - res = retworkx.graph_random_layout(self.graph) - # Random output, just assert structurally correct - self.assertIsInstance(res, retworkx.Pos2DMapping) - self.assertEqual(len(res), 10) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - -class TestBipartiteLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_bipartite_layout_empty(self): - res = retworkx.bipartite_layout(retworkx.PyGraph(), set()) - self.assertEqual({}, res) - - def test_bipartite_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.bipartite_layout(g, set()) - expected = { - 0: (0.0, -1.0), - 2: (0.0, -0.3333333333333333), - 3: (0.0, 0.3333333333333333), - 4: (0.0, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3, 4}) - expected = { - 0: (-1.0, -0.75), - 1: (-1.0, -0.375), - 2: (-1.0, 0.0), - 3: (-1.0, 0.375), - 4: (-1.0, 0.75), - 5: (1.0, -0.75), - 6: (1.0, -0.375), - 7: (1.0, 0.0), - 8: (1.0, 0.375), - 9: (1.0, 0.75), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_horizontal(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3}, horizontal=True) - expected = { - 0: (1.0, -0.9), - 1: (0.3333333333333333, -0.9), - 2: (-0.333333333333333, -0.9), - 3: (-1.0, -0.9), - 4: (1.0, 0.6), - 5: (0.6, 0.6), - 6: (0.2, 0.6), - 7: (-0.2, 0.6), - 8: (-0.6, 0.6), - 9: (-1.0, 0.6), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_scale(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2}, scale=2) - expected = { - 0: (-2.0, -1.0714285714285714), - 1: (-2.0, 2.3790493384824785e-17), - 2: (-2.0, 1.0714285714285714), - 3: (0.8571428571428571, -1.0714285714285714), - 4: (0.8571428571428571, -0.7142857142857143), - 5: (0.8571428571428571, -0.35714285714285715), - 6: (0.8571428571428571, 2.3790493384824785e-17), - 7: (0.8571428571428571, 0.35714285714285704), - 8: (0.8571428571428571, 0.7142857142857141), - 9: (0.8571428571428571, 1.0714285714285714), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_center(self): - res = retworkx.bipartite_layout(self.graph, {4, 5, 6}, center=(0.5, 0.5)) - expected = { - 4: (-0.5, -0.0357142857142857), - 5: (-0.5, 0.5), - 6: (-0.5, 1.0357142857142856), - 0: (0.9285714285714286, -0.0357142857142857), - 1: (0.9285714285714286, 0.14285714285714285), - 2: (0.9285714285714286, 0.3214285714285714), - 3: (0.9285714285714286, 0.5), - 7: (0.9285714285714286, 0.6785714285714285), - 8: (0.9285714285714286, 0.857142857142857), - 9: (0.9285714285714286, 1.0357142857142856), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_ratio(self): - res = retworkx.bipartite_layout(self.graph, {2, 4, 8}, aspect_ratio=4) - expected = { - 8: [-1.0, 0.17857142857142858], - 2: [-1.0, -0.17857142857142858], - 4: [-1.0, 0], - 0: [0.42857142857142855, -0.17857142857142858], - 1: [0.42857142857142855, -0.11904761904761907], - 3: [0.42857142857142855, -0.05952380952380952], - 5: [0.42857142857142855, 0], - 6: [0.42857142857142855, 0.05952380952380952], - 7: [0.42857142857142855, 0.11904761904761903], - 9: [0.42857142857142855, 0.17857142857142858], - } - self.assertLayoutEquiv(expected, res) - - -class TestCircularLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_circular_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyGraph()) - self.assertEqual({}, res) - - def test_circular_layout_one_node(self): - res = retworkx.circular_layout(retworkx.generators.path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_circular_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.circular_layout(g) - expected = { - 0: (0.999999986090933, 2.1855693665697608e-08), - 2: (-3.576476059301554e-08, 1.0), - 3: (-0.9999999701976796, -6.556708099709282e-08), - 4: (1.987150711625619e-08, -0.9999999562886126), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout(self): - res = retworkx.circular_layout(self.graph) - expected = { - 0: (1.0, 2.662367085193061e-08), - 1: (0.8090170042900712, 0.5877852653564984), - 2: (0.3090169789580973, 0.9510565581329226), - 3: (-0.3090170206813483, 0.9510564985282783), - 4: (-0.8090170460133221, 0.5877852057518542), - 5: (-0.9999999821186069, -6.079910493992474e-08), - 6: (-0.8090169268040337, -0.5877853313184453), - 7: (-0.3090170802859925, -0.9510564452809367), - 8: (0.3090171279697079, -0.9510564452809367), - 9: (0.809016944685427, -0.587785271713801), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_scale(self): - res = retworkx.circular_layout(self.graph, scale=2) - expected = { - 0: (2.0, 5.324734170386122e-08), - 1: (1.6180340085801423, 1.1755705307129969), - 2: (0.6180339579161946, 1.9021131162658451), - 3: (-0.6180340413626966, 1.9021129970565567), - 4: (-1.6180340920266443, 1.1755704115037084), - 5: (-1.9999999642372137, -1.2159820987984948e-07), - 6: (-1.6180338536080674, -1.1755706626368907), - 7: (-0.618034160571985, -1.9021128905618734), - 8: (0.6180342559394159, -1.9021128905618734), - 9: (1.618033889370854, -1.175570543427602), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_center(self): - res = retworkx.circular_layout(self.graph, center=(0.5, 0.5)) - expected = { - 0: (1.5, 0.5000000266236708), - 1: (1.3090170042900713, 1.0877852653564983), - 2: (0.8090169789580973, 1.4510565581329224), - 3: (0.1909829793186517, 1.4510564985282783), - 4: (-0.30901704601332214, 1.0877852057518542), - 5: (-0.49999998211860686, 0.4999999392008951), - 6: (-0.3090169268040337, -0.08778533131844535), - 7: (0.1909829197140075, -0.4510564452809367), - 8: (0.8090171279697079, -0.4510564452809367), - 9: (1.309016944685427, -0.08778527171380102), - } - self.assertLayoutEquiv(expected, res) - - -class TestShellLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_shell_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyGraph()) - self.assertEqual({}, res) - - def test_shell_layout_one_node(self): - res = retworkx.shell_layout(retworkx.generators.path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_shell_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.shell_layout(g) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 2: (1.1924880638503055e-08, -1.0), - 3: (1.0, 1.7484555314695172e-07), - 4: (-3.3776623808989825e-07, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_hole_two_shells(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([2]) - res = retworkx.shell_layout(g, [[0, 1], [3, 4]]) - expected = { - 0: (-2.1855694143368964e-08, 0.5), - 1: (5.962440319251527e-09, -0.5), - 3: (-1.0, -8.742277657347586e-08), - 4: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout(self): - res = retworkx.shell_layout(self.graph) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 1: (-0.8090169429779053, -0.5877853631973267), - 2: (-0.3090170919895172, -0.9510564804077148), - 3: (0.3090171217918396, -0.9510564804077148), - 4: (0.8090172410011292, -0.5877849459648132), - 5: (1.0, 1.7484555314695172e-07), - 6: (0.80901700258255, 0.5877852439880371), - 7: (0.30901679396629333, 0.9510565996170044), - 8: (-0.30901744961738586, 0.9510563611984253), - 9: (-0.8090168833732605, 0.5877854228019714), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_nlist(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 2], [1, 3], [4, 9], [8, 7], [6, 5]]) - expected = { - 0: (0.16180340945720673, 0.11755704879760742), - 2: (-0.16180339455604553, -0.11755707114934921), - 1: (0.12360679358243942, 0.3804226219654083), - 3: (-0.123606838285923, -0.38042259216308594), - 4: (-0.18541023135185242, 0.5706338882446289), - 9: (0.185410276055336, -0.5706338882446289), - 8: (-0.6472136378288269, 0.4702281653881073), - 7: (0.6472138166427612, -0.4702279567718506), - 6: (-1.0, -8.742277657347586e-08), - 5: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_rotate(self): - res = retworkx.shell_layout( - self.graph, nlist=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]], rotate=0.5 - ) - expected = { - 0: (0.21939563751220703, 0.11985638737678528), - 1: (-0.21349650621414185, 0.13007399439811707), - 2: (-0.005899117328226566, -0.24993039667606354), - 3: (0.27015113830566406, 0.4207354784011841), - 4: (-0.4994432032108307, 0.023589985445141792), - 5: (0.229292094707489, -0.4443254768848419), - 6: (0.05305289849638939, 0.7481212615966797), - 7: (-0.6744184494018555, -0.3281154930591583), - 8: (0.6213656067848206, -0.420005738735199), - 9: (-0.416146844625473, 0.9092974066734314), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_scale(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], scale=2) - expected = { - 0: (-4.371138828673793e-08, 1.0), - 1: (-0.9510565996170044, 0.30901679396629333), - 2: (-0.5877850651741028, -0.8090171217918396), - 3: (0.5877854824066162, -0.8090168237686157), - 4: (0.9510564208030701, 0.30901727080345154), - 9: (-2.0, -1.7484555314695172e-07), - 8: (-0.6180341839790344, -1.9021129608154297), - 7: (1.6180344820022583, -1.1755698919296265), - 6: (1.6180340051651, 1.1755704879760742), - 5: (-0.6180348992347717, 1.9021127223968506), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_center(self): - res = retworkx.shell_layout( - self.graph, - nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], - center=(0.5, 0.5), - ) - expected = { - 0: (0.49999997814430586, 1.0), - 1: (0.024471700191497803, 0.6545083969831467), - 2: (0.2061074674129486, 0.0954914391040802), - 3: (0.7938927412033081, 0.09549158811569214), - 4: (0.975528210401535, 0.6545086354017258), - 9: (-0.5, 0.4999999125772234), - 8: (0.1909829080104828, -0.45105648040771484), - 7: (1.3090172410011292, -0.08778494596481323), - 6: (1.30901700258255, 1.087785243988037), - 5: (0.19098255038261414, 1.4510563611984253), - } - self.assertLayoutEquiv(expected, res) - - -class TestSpiralLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_spiral_layout_empty(self): - res = retworkx.spiral_layout(retworkx.PyGraph()) - self.assertEqual({}, res) - - def test_spiral_layout_one_node(self): - res = retworkx.spiral_layout(retworkx.generators.path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_spiral_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.spiral_layout(g) - expected = { - 0: (-0.6415327868391166, -0.6855508729419231), - 2: (-0.03307913182988828, -0.463447951079834), - 3: (0.34927952438480797, 0.1489988240217569), - 4: (0.32533239428419697, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout(self): - res = retworkx.spiral_layout(self.graph) - expected = { - 0: (0.3083011152777303, -0.36841870322845377), - 1: (0.4448595378922136, -0.3185709877650719), - 2: (0.5306742824266687, -0.18111636841212878), - 3: (0.5252997033017661, 0.009878257518578544), - 4: (0.40713492048969163, 0.20460820654918466), - 5: (0.17874125121181098, 0.3468009691240852), - 6: (-0.1320415949011884, 0.3844997574641717), - 7: (-0.4754889029311045, 0.28057288841663486), - 8: (-0.7874803127675889, 0.021164283410983312), - 9: (-0.9999999999999999, -0.3794183030779839), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_scale(self): - res = retworkx.spiral_layout(self.graph, scale=2) - expected = { - 0: (0.6166022305554606, -0.7368374064569075), - 1: (0.8897190757844272, -0.6371419755301438), - 2: (1.0613485648533374, -0.36223273682425755), - 3: (1.0505994066035322, 0.01975651503715709), - 4: (0.8142698409793833, 0.4092164130983693), - 5: (0.35748250242362195, 0.6936019382481704), - 6: (-0.2640831898023768, 0.7689995149283434), - 7: (-0.950977805862209, 0.5611457768332697), - 8: (-1.5749606255351778, 0.042328566821966625), - 9: (-1.9999999999999998, -0.7588366061559678), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_center(self): - res = retworkx.spiral_layout(self.graph, center=(1, 1)) - expected = { - 0: (1.3083011152777302, 0.6315812967715462), - 1: (1.4448595378922136, 0.681429012234928), - 2: (1.5306742824266686, 0.8188836315878713), - 3: (1.5252997033017661, 1.0098782575185785), - 4: (1.4071349204896917, 1.2046082065491848), - 5: (1.178741251211811, 1.3468009691240852), - 6: (0.8679584050988116, 1.3844997574641718), - 7: (0.5245110970688955, 1.2805728884166347), - 8: (0.2125196872324111, 1.0211642834109833), - 9: (1.1102230246251565e-16, 0.6205816969220161), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_resolution(self): - res = retworkx.spiral_layout(self.graph, resolution=0.6) - expected = { - 0: (0.14170895375949058, 0.22421978768273812), - 1: (0.2657196183870804, 0.30906004798138936), - 2: (0.2506009612140119, 0.5043065412934762), - 3: (0.039294315670400995, 0.6631957258449066), - 4: (-0.3014789232909145, 0.6301862160709318), - 5: (-0.602046830323471, 0.3302396035952633), - 6: (-0.66674476042188, -0.17472522299849289), - 7: (-0.3739394496041176, -0.6924895145748617), - 8: (0.2468861146093996, -0.9732085843739783), - 9: (1.0, -0.8207846005213728), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_equidistant(self): - res = retworkx.spiral_layout(self.graph, equidistant=True) - expected = { - 0: (-0.13161882865656718, -0.7449342807652114), - 1: (0.7160560542246066, -0.6335352483233974), - 2: (0.6864868274284994, -0.34165899654603915), - 3: (0.5679822628330004, -0.07281296883784087), - 4: (0.375237081214659, 0.14941210155952697), - 5: (0.12730720268992277, 0.30830226777240866), - 6: (-0.15470865936858091, 0.3939608192236113), - 7: (-0.4495426197217269, 0.4027809258196645), - 8: (-0.7371993206438128, 0.33662707199446507), - 9: (-1.0, 0.2018583081028111), - } - self.assertLayoutEquiv(expected, res) diff --git a/tests/retworkx_backwards_compat/graph/test_matching.py b/tests/retworkx_backwards_compat/graph/test_matching.py deleted file mode 100644 index 820a6a38a..000000000 --- a/tests/retworkx_backwards_compat/graph/test_matching.py +++ /dev/null @@ -1,56 +0,0 @@ -# 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 TestMatching(unittest.TestCase): - def test_valid(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (2, 3)} - self.assertTrue(retworkx.is_maximal_matching(graph, matching)) - - def test_not_matching(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (1, 2), (2, 3)} - self.assertFalse(retworkx.is_maximal_matching(graph, matching)) - - def test_not_maximal(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1)} - self.assertFalse(retworkx.is_maximal_matching(graph, matching)) - - def test_is_matching_empty(self): - graph = retworkx.generators.path_graph(4) - matching = set() - self.assertTrue(retworkx.is_matching(graph, matching)) - - def test_is_matching_single_edge(self): - graph = retworkx.generators.path_graph(4) - matching = {(1, 2)} - self.assertTrue(retworkx.is_matching(graph, matching)) - - def test_is_matching_valid(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (2, 3)} - self.assertTrue(retworkx.is_matching(graph, matching)) - - def test_is_matching_invalid(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (1, 2), (2, 3)} - self.assertFalse(retworkx.is_matching(graph, matching)) - - def test_is_matching_invalid_edge(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 3), (1, 2)} - self.assertFalse(retworkx.is_matching(graph, matching)) diff --git a/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py b/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py deleted file mode 100644 index 091626da3..000000000 --- a/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py +++ /dev/null @@ -1,569 +0,0 @@ -# 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. - -# These tests are adapated from the networkx test cases: -# https://github.com/networkx/networkx/blob/3351206a3ce5b3a39bb2fc451e93ef545b96c95b/networkx/algorithms/tests/test_matching.py - -import random -import unittest - -import networkx - -import retworkx - - -def match_dict_to_set(match): - return {(u, v) for (u, v) in set(map(frozenset, match.items()))} - - -class TestMaxWeightMatching(unittest.TestCase): - def compare_match_sets(self, rx_match, expected_match): - for (u, v) in rx_match: - if (u, v) not in expected_match and (v, u) not in expected_match: - self.fail( - "Element %s and it's reverse %s not found in " - "expected output.\nretworkx output: %s\nexpected " - "output: %s" % ((u, v), (v, u), rx_match, expected_match) - ) - - def compare_rx_nx_sets(self, rx_graph, rx_matches, nx_matches, seed, nx_graph): - def get_rx_weight(edge): - weight = rx_graph.get_edge_data(*edge) - if weight is None: - return 1 - return weight - - def get_nx_weight(edge): - weight = nx_graph.get_edge_data(*edge) - if not weight: - return 1 - return weight["weight"] - - not_match = False - for (u, v) in rx_matches: - if (u, v) not in nx_matches: - if (v, u) not in nx_matches: - print( - "seed %s failed. Element %s and it's " - "reverse %s not found in networkx output.\nretworkx" - " output: %s\nnetworkx output: %s\nedge list: %s\n" - "falling back to checking for a valid solution" - % ( - seed, - (u, v), - (v, u), - rx_matches, - nx_matches, - list(rx_graph.weighted_edge_list()), - ) - ) - not_match = True - break - if not_match: - self.assertTrue( - retworkx.is_matching(rx_graph, rx_matches), - "%s is not a valid matching" % rx_matches, - ) - self.assertTrue( - retworkx.is_maximal_matching(rx_graph, rx_matches), - "%s is not a maximal matching" % rx_matches, - ) - self.assertEqual( - sum(map(get_rx_weight, rx_matches)), - sum(map(get_nx_weight, nx_matches)), - ) - - def test_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual(retworkx.max_weight_matching(graph), set()) - - def test_single_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edges_from([(0, 1, 1)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, verify_optimum=True), - { - (0, 1), - }, - ) - - def test_single_edge_no_verification(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edges_from([(0, 1, 1)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, verify_optimum=False), - { - (0, 1), - }, - ) - - def test_single_self_edge(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(0, 0, 100)]) - self.assertEqual(retworkx.max_weight_matching(graph), set()) - - def test_small_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(1, 2, 10), (2, 3, 11)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - { - (2, 3), - }, - ) - - def test_path_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(1, 2, 5), (2, 3, 11), (3, 4, 5)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - { - (2, 3), - }, - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, True, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 4)}, - ) - - def test_negative_weights(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 2), - (1, 3, -2), - (2, 3, 1), - (2, 4, -1), - (3, 4, -6), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - { - (1, 2), - }, - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, True, weight_fn=lambda x: x, verify_optimum=True), - {(1, 3), (2, 4)}, - ) - - def test_s_blossom(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (0, 1, 8), - (0, 2, 9), - (1, 2, 10), - (2, 3, 7), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(0, 1), (2, 3)}, - ) - graph.extend_from_weighted_edge_list([(0, 5, 5), (3, 4, 6)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(0, 5), (1, 2), (3, 4)}, - ) - - def test_s_t_blossom(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 9), - (1, 3, 8), - (2, 3, 10), - (1, 4, 5), - (4, 5, 4), - (1, 6, 3), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 5)}, - ) - graph.remove_edge(1, 6) - graph.remove_edge(4, 5) - graph.extend_from_weighted_edge_list([(4, 5, 3), (1, 6, 4)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 5)}, - ) - graph.remove_edge(1, 6) - graph.add_edge(3, 6, 4) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 6), (4, 5)}, - ) - - def test_s_t_blossom_with_removed_nodes(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 9), - (1, 3, 8), - (2, 3, 10), - (1, 4, 5), - (4, 5, 4), - (1, 6, 3), - ] - ) - node_id = graph.add_node(None) - graph.remove_node(5) - graph.add_edge(4, node_id, 4) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 7)}, - ) - graph.remove_edge(1, 6) - graph.remove_edge(4, 7) - graph.extend_from_weighted_edge_list([(4, node_id, 3), (1, 6, 4)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 7)}, - ) - graph.remove_edge(1, 6) - graph.add_edge(3, 6, 4) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 6), (4, 7)}, - ) - - def test_nested_s_blossom(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 9), - (1, 3, 9), - (2, 3, 10), - (2, 4, 8), - (3, 5, 8), - (4, 5, 10), - (5, 6, 6), - ] - ) - expected = {(1, 3), (2, 4), (5, 6)} - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - expected, - ) - - def test_nested_s_blossom_relabel(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 10), - (1, 7, 10), - (2, 3, 12), - (3, 4, 20), - (3, 5, 20), - (4, 5, 25), - (5, 6, 10), - (6, 7, 10), - (7, 8, 8), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 4), (5, 6), (7, 8)}, - ) - - def test_nested_s_blossom_expand(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 8), - (1, 3, 8), - (2, 3, 10), - (2, 4, 12), - (3, 5, 12), - (4, 5, 14), - (4, 6, 12), - (5, 7, 12), - (6, 7, 14), - (7, 8, 12), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 5), (4, 6), (7, 8)}, - ) - - def test_s_blossom_relabel_expand(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 23), - (1, 5, 22), - (1, 6, 15), - (2, 3, 25), - (3, 4, 22), - (4, 5, 25), - (4, 8, 14), - (5, 7, 13), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 8), (5, 7)}, - ) - - def test_nested_s_blossom_relabel_expand(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 19), - (1, 3, 20), - (1, 8, 8), - (2, 3, 25), - (2, 4, 18), - (3, 5, 18), - (4, 5, 13), - (4, 7, 7), - (5, 6, 7), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 8, 2: 3, 3: 2, 4: 7, 5: 6, 6: 5, 7: 4, 8: 1}), - ) - - def test_blossom_relabel_multiple_paths(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 45), - (1, 5, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 50), - (1, 6, 30), - (3, 9, 35), - (4, 8, 35), - (5, 7, 26), - (9, 10, 5), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4, 9: 10, 10: 9}), - ) - - def test_blossom_relabel_multiple_path_alternate(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 45), - (1, 5, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 50), - (1, 6, 30), - (3, 9, 35), - (4, 8, 26), - (5, 7, 40), - (9, 10, 5), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4, 9: 10, 10: 9}), - ) - - def test_blossom_relabel_multiple_paths_least_slack(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 45), - (1, 5, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 50), - (1, 6, 30), - (3, 9, 35), - (4, 8, 28), - (5, 7, 26), - (9, 10, 5), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4, 9: 10, 10: 9}), - ) - - def test_nested_blossom_expand_recursively(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 40), - (1, 3, 40), - (2, 3, 60), - (2, 4, 55), - (3, 5, 55), - (4, 5, 50), - (1, 8, 15), - (5, 7, 30), - (7, 6, 10), - (8, 10, 10), - (4, 9, 30), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 2, 2: 1, 3: 5, 4: 9, 5: 3, 6: 7, 7: 6, 8: 10, 9: 4, 10: 8}), - ) - - def test_nested_blossom_augmented(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 45), - (1, 7, 45), - (2, 3, 50), - (3, 4, 45), - (4, 5, 95), - (4, 6, 94), - (5, 6, 94), - (6, 7, 50), - (1, 8, 30), - (3, 11, 35), - (5, 9, 36), - (7, 10, 26), - (11, 12, 5), - ] - ) - expected = { - 1: 8, - 2: 3, - 3: 2, - 4: 6, - 5: 9, - 6: 4, - 7: 10, - 8: 1, - 9: 5, - 10: 7, - 11: 12, - 12: 11, - } - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set(expected), - ) - - def test_gnp_random_against_networkx(self): - for i in range(1024): - with self.subTest(i=i): - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching(rx_graph, verify_optimum=True) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random_against_networkx_with_weight(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(0, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching( - rx_graph, weight_fn=lambda x: x, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random_against_networkx_with_negative_weight(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(-5000, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching( - rx_graph, weight_fn=lambda x: x, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random_against_networkx_max_cardinality(self): - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.78, seed=428) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, max_cardinality=True, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 428, nx_graph) - - def test_gnp_random_against_networkx_with_weight_max_cardinality(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(0, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, - weight_fn=lambda x: x, - max_cardinality=True, - verify_optimum=True, - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random__networkx_with_negative_weight_max_cardinality(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(-5000, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, - weight_fn=lambda x: x, - max_cardinality=True, - verify_optimum=True, - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnm_random_against_networkx(self): - rx_graph = retworkx.undirected_gnm_random_graph(10, 13, seed=42) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching(rx_graph, verify_optimum=True) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42, nx_graph) - - def test_gnm_random_against_networkx_max_cardinality(self): - rx_graph = retworkx.undirected_gnm_random_graph(10, 12, seed=42) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, max_cardinality=True, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42, nx_graph) diff --git a/tests/retworkx_backwards_compat/graph/test_mst.py b/tests/retworkx_backwards_compat/graph/test_mst.py deleted file mode 100644 index 895d2328b..000000000 --- a/tests/retworkx_backwards_compat/graph/test_mst.py +++ /dev/null @@ -1,122 +0,0 @@ -# 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 TestMinimumSpanningTree(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - - edge_list = [ - (self.a, self.b, 3), - (self.a, self.d, 2), - (self.b, self.c, 4), - (self.c, self.d, 1), - (self.a, self.f, 1), - (self.b, self.f, 6), - (self.d, self.e, 5), - (self.c, self.e, 7), - ] - self.graph.add_edges_from(edge_list) - - self.expected_edges = [ - (self.a, self.b, 3), - (self.a, self.d, 2), - (self.c, self.d, 1), - (self.a, self.f, 1), - (self.d, self.e, 5), - ] - - def assertEqualEdgeList(self, expected, actual): - self.assertEqual(len(expected), len(actual)) - for edge in actual: - self.assertTrue(edge in expected) - - def test_edges(self): - mst_edges = retworkx.minimum_spanning_edges(self.graph, weight_fn=lambda x: x) - self.assertEqual(len(self.graph.nodes()) - 1, len(mst_edges)) - for edge in mst_edges: - self.assertTrue(edge in self.expected_edges) - - def test_tree(self): - mst_graph = retworkx.minimum_spanning_tree(self.graph, weight_fn=lambda x: x) - self.assertEqual(self.graph.nodes(), mst_graph.nodes()) - self.assertEqual(len(self.graph.nodes()) - 1, len(mst_graph.edge_list())) - self.assertEqualEdgeList(self.expected_edges, mst_graph.weighted_edge_list()) - - def test_forest(self): - s = self.graph.add_node("S") - t = self.graph.add_node("T") - u = self.graph.add_node("U") - self.graph.add_edges_from([(s, t, 10), (t, u, 9), (s, u, 8)]) - forest_expected_edges = self.expected_edges + [(s, u, 8), (t, u, 9)] - - msf_graph = retworkx.minimum_spanning_tree(self.graph, weight_fn=lambda x: x) - self.assertEqual(self.graph.nodes(), msf_graph.nodes()) - self.assertEqual(len(self.graph.nodes()) - 2, len(msf_graph.edge_list())) - self.assertEqualEdgeList(forest_expected_edges, msf_graph.weighted_edge_list()) - - def test_isolated(self): - s = self.graph.add_node("S") - - msf_graph = retworkx.minimum_spanning_tree(self.graph, weight_fn=lambda x: x) - self.assertEqual("S", msf_graph.nodes()[s]) - self.assertEqual(self.graph.nodes(), msf_graph.nodes()) - self.assertEqual(len(self.graph.nodes()) - 2, len(msf_graph.edge_list())) - self.assertEqualEdgeList(self.expected_edges, msf_graph.weighted_edge_list()) - - def test_multigraph(self): - mutligraph = retworkx.PyGraph(multigraph=True) - mutligraph.extend_from_weighted_edge_list( - [(0, 1, 1), (0, 2, 3), (1, 2, 2), (0, 0, -10), (1, 2, 1)] - ) - - mst_graph = retworkx.minimum_spanning_tree(mutligraph, weight_fn=lambda x: x) - self.assertEqualEdgeList([(0, 1, 1), (1, 2, 1)], mst_graph.weighted_edge_list()) - - def test_default_weight(self): - weightless_graph = retworkx.PyGraph() - weightless_graph.extend_from_edge_list( - [(0, 1), (0, 2), (0, 3), (0, 4), (1, 5), (2, 6), (3, 7), (4, 8)] - ) # MST of the graph is itself - - mst_graph_default_weight = retworkx.minimum_spanning_tree(weightless_graph) - mst_graph_weight_2 = retworkx.minimum_spanning_tree(weightless_graph, default_weight=2.0) - - self.assertTrue( - retworkx.is_isomorphic( - weightless_graph, - mst_graph_default_weight, - ) - ) - self.assertTrue( - retworkx.is_isomorphic( - weightless_graph, - mst_graph_weight_2, - ) - ) - - def test_nan_weight(self): - invalid_graph = retworkx.PyGraph() - invalid_graph.extend_from_weighted_edge_list([(0, 1, 0.5), (0, 2, float("nan"))]) - - with self.assertRaises(ValueError): - retworkx.minimum_spanning_tree(invalid_graph, lambda x: x) diff --git a/tests/retworkx_backwards_compat/graph/test_neighbors.py b/tests/retworkx_backwards_compat/graph/test_neighbors.py deleted file mode 100644 index 25ec06258..000000000 --- a/tests/retworkx_backwards_compat/graph/test_neighbors.py +++ /dev/null @@ -1,43 +0,0 @@ -# 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 TestNeighbors(unittest.TestCase): - def test_single_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {"a": 1}) - node_c = graph.add_node("c") - graph.add_edge(node_a, node_c, {"a": 2}) - res = graph.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_unique_neighbors_on_graphs(self): - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - dag.add_edge(node_a, node_b, ["edge a->b"]) - dag.add_edge(node_a, node_b, ["edge a->b bis"]) - dag.add_edge(node_a, node_c, ["edge a->c"]) - res = dag.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_no_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - self.assertEqual([], graph.neighbors(node_a)) diff --git a/tests/retworkx_backwards_compat/graph/test_nodes.py b/tests/retworkx_backwards_compat/graph/test_nodes.py deleted file mode 100644 index c9bfe053e..000000000 --- a/tests/retworkx_backwards_compat/graph/test_nodes.py +++ /dev/null @@ -1,181 +0,0 @@ -# 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 TestNodes(unittest.TestCase): - def test_nodes(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - res = graph.nodes() - self.assertEqual(["a", "b"], res) - self.assertEqual([0, 1], graph.node_indexes()) - - def test_node_indices(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - self.assertEqual([0, 1], graph.node_indices()) - - def test_no_nodes(self): - graph = retworkx.PyGraph() - self.assertEqual([], graph.nodes()) - self.assertEqual([], graph.node_indexes()) - self.assertEqual([], graph.node_indices()) - - def test_remove_node(self): - graph = retworkx.PyGraph() - graph.add_node("a") - node_b = graph.add_node("b") - graph.add_node("c") - graph.remove_node(node_b) - res = graph.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], graph.node_indexes()) - - def test_remove_node_invalid_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.remove_node(76) - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) - - def test_remove_nodes_from(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Edgy_mk2") - graph.remove_nodes_from([node_b, node_c]) - res = graph.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], graph.node_indexes()) - - def test_remove_nodes_from_with_invalid_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Edgy_mk2") - graph.remove_nodes_from([node_b, node_c, 76]) - res = graph.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], graph.node_indexes()) - - def test_get_node_data(self): - graph = retworkx.PyGraph() - graph.add_node("a") - node_b = graph.add_node("b") - self.assertEqual("b", graph.get_node_data(node_b)) - - def test_get_node_data_bad_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - self.assertRaises(IndexError, graph.get_node_data, 42) - - def test_pygraph_length(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "An_edge") - self.assertEqual(2, len(graph)) - - def test_pygraph_num_nodes(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "An_edge") - self.assertEqual(2, graph.num_nodes()) - - def test_pygraph_length_empty(self): - graph = retworkx.PyGraph() - self.assertEqual(0, len(graph)) - - def test_pygraph_num_nodes_empty(self): - graph = retworkx.PyGraph() - self.assertEqual(0, graph.num_nodes()) - - def test_add_nodes_from(self): - graph = retworkx.PyGraph() - nodes = list(range(100)) - res = graph.add_nodes_from(nodes) - self.assertEqual(len(res), 100) - self.assertEqual(res, nodes) - - def test_add_node_from_empty(self): - graph = retworkx.PyGraph() - res = graph.add_nodes_from([]) - self.assertEqual(len(res), 0) - - def test_get_node_data_getitem(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - self.assertEqual("b", graph[node_b]) - - def test_get_node_data_getitem_bad_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - with self.assertRaises(IndexError): - graph[42] - - def test_set_node_data_setitem(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph[node_b] = "Oh so cool" - self.assertEqual("Oh so cool", graph[node_b]) - - def test_set_node_data_setitem_bad_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - with self.assertRaises(IndexError): - graph[42] = "Oh so cool" - - def test_remove_node_delitem(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Edgy_mk2") - del graph[node_b] - res = graph.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], graph.node_indexes()) - - def test_remove_node_delitem_invalid_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - with self.assertRaises(IndexError): - del graph[76] - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) diff --git a/tests/retworkx_backwards_compat/graph/test_num_shortest_path.py b/tests/retworkx_backwards_compat/graph/test_num_shortest_path.py deleted file mode 100644 index c1182eb8f..000000000 --- a/tests/retworkx_backwards_compat/graph/test_num_shortest_path.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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 TestNumShortestpath(unittest.TestCase): - def test_num_shortest_path_unweighted(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node("end") - for i in range(3): - node = graph.add_node(i) - graph.add_edge(node_a, node, None) - graph.add_edge(node, node_b, None) - res = retworkx.graph_num_shortest_paths_unweighted(graph, node_a) - expected = {2: 1, 4: 1, 3: 1, 1: 3} - self.assertEqual(expected, res) - - def test_parallel_paths(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (0, 4), - (4, 5), - (5, 3), - ] - ) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 2, - 4: 1, - 5: 1, - } - self.assertEqual(expected, res) - - def test_grid_graph(self): - """Test num shortest paths for a 5x5 grid graph - 0 - 1 - 2 - 3 - 4 - | | | | | - 5 - 6 - 7 - 8 - 9 - | | | | | - 10- 11- 12- 13- 14 - | | | | | - 15- 16- 17- 18- 19 - | | | | | - 20- 21- 22- 23- 24 - """ - graph = retworkx.generators.grid_graph(5, 5) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 2, - 7: 3, - 8: 4, - 9: 5, - 10: 1, - 11: 3, - 12: 6, - 13: 10, - 14: 15, - 15: 1, - 16: 4, - 17: 10, - 18: 20, - 19: 35, - 20: 1, - 21: 5, - 22: 15, - 23: 35, - 24: 70, - } - self.assertEqual(expected, res) - - def test_node_with_no_path(self): - graph = retworkx.generators.path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - expected = {1: 1, 2: 1, 3: 1, 4: 1} - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - res = retworkx.num_shortest_paths_unweighted(graph, 6) - expected = {7: 1, 8: 1, 9: 1, 10: 1, 11: 1} - self.assertEqual(expected, res) - - def test_node_indices_with_holes(self): - graph = retworkx.generators.path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - graph.add_edge(4, 6, None) - graph.remove_node(5) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 6: 1, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - - def test_no_edges(self): - graph = retworkx.PyGraph() - graph.add_node(0) - graph.add_node(1) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual({}, res) - - def test_invalid_source_index(self): - graph = retworkx.PyGraph() - graph.add_node(0) - graph.add_node(1) - graph.add_edge(0, 1, None) - with self.assertRaises(IndexError): - retworkx.num_shortest_paths_unweighted(graph, 4) diff --git a/tests/retworkx_backwards_compat/graph/test_spring_layout.py b/tests/retworkx_backwards_compat/graph/test_spring_layout.py deleted file mode 100644 index 48a51fe38..000000000 --- a/tests/retworkx_backwards_compat/graph/test_spring_layout.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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 TestSpringLayout(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - node_a = self.graph.add_node(1) - node_b = self.graph.add_node(2) - self.graph.add_edge(node_a, node_b, 1) - node_c = self.graph.add_node(3) - self.graph.add_edge(node_a, node_c, 2) - - def test_empty_graph(self): - graph = retworkx.PyGraph() - res = retworkx.spring_layout(graph) - self.assertEqual({}, res) - - def test_simple_graph(self): - res = retworkx.spring_layout(self.graph, seed=42) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_with_edge_weights(self): - res = retworkx.spring_layout(self.graph, weight_fn=lambda e: e) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_center(self): - res = retworkx.spring_layout(self.graph, center=[0.5, 0.5]) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_fixed(self): - pos = {0: [0.1, 0.1]} - res = retworkx.spring_layout(self.graph, pos=pos, fixed={0}) - self.assertEqual(res[0], pos[0]) - - def test_simple_graph_fixed_not_pos(self): - with self.assertRaises(ValueError): - retworkx.spring_layout(self.graph, fixed={0}) - - def test_simple_graph_linear_cooling(self): - res = retworkx.spring_layout(self.graph, adaptive_cooling=False) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_graph_with_removed_nodes(self): - graph = retworkx.PyGraph() - nodes = graph.add_nodes_from([0, 1, 2]) - graph.remove_node(nodes[1]) - res = retworkx.spring_layout(graph) - self.assertEqual(len(res), 2) - self.assertTrue(nodes[0] in res) - self.assertTrue(nodes[2] in res) - self.assertFalse(nodes[1] in res) diff --git a/tests/retworkx_backwards_compat/graph/test_steiner_tree.py b/tests/retworkx_backwards_compat/graph/test_steiner_tree.py deleted file mode 100644 index 703caf499..000000000 --- a/tests/retworkx_backwards_compat/graph/test_steiner_tree.py +++ /dev/null @@ -1,188 +0,0 @@ -# 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 pprint -import unittest - -import retworkx - - -class TestSteinerTree(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph(multigraph=False) - self.graph.add_node(None) - self.graph.extend_from_weighted_edge_list( - [ - (1, 2, 10), - (2, 3, 10), - (3, 4, 10), - (4, 5, 10), - (5, 6, 10), - (2, 7, 1), - (7, 5, 1), - ] - ) - self.graph.remove_node(0) - - def test_metric_closure(self): - closure_graph = retworkx.metric_closure(self.graph, weight_fn=float) - expected_edges = [ - (1, 2, (10.0, [1, 2])), - (1, 3, (20.0, [1, 2, 3])), - (1, 4, (22.0, [1, 2, 7, 5, 4])), - (1, 5, (12.0, [1, 2, 7, 5])), - (1, 6, (22.0, [1, 2, 7, 5, 6])), - (1, 7, (11.0, [1, 2, 7])), - (2, 3, (10.0, [2, 3])), - (2, 4, (12.0, [2, 7, 5, 4])), - (2, 5, (2.0, [2, 7, 5])), - (2, 6, (12, [2, 7, 5, 6])), - (2, 7, (1.0, [2, 7])), - (3, 4, (10.0, [3, 4])), - (3, 5, (12.0, [3, 2, 7, 5])), - (3, 6, (22.0, [3, 2, 7, 5, 6])), - (3, 7, (11.0, [3, 2, 7])), - (4, 5, (10.0, [4, 5])), - (4, 6, (20.0, [4, 5, 6])), - (4, 7, (11.0, [4, 5, 7])), - (5, 6, (10.0, [5, 6])), - (5, 7, (1.0, [5, 7])), - (6, 7, (11.0, [6, 5, 7])), - ] - edges = list(closure_graph.weighted_edge_list()) - for edge in expected_edges: - found = False - if edge in edges: - found = True - if not found: - - if ( - edge[1], - edge[0], - (edge[2][0], list(reversed(edge[2][1]))), - ) in edges: - found = True - if not found: - self.fail( - f"edge: {edge} nor it's reverse not found in metric " - f"closure output:\n{pprint.pformat(edges)}" - ) - - def test_not_connected_metric_closure(self): - self.graph.add_node(None) - with self.assertRaises(ValueError): - retworkx.metric_closure(self.graph, weight_fn=float) - - def test_partially_connected_metric_closure(self): - graph = retworkx.PyGraph() - graph.add_node(None) - graph.extend_from_weighted_edge_list( - [ - (1, 2, 10), - (2, 3, 10), - (3, 4, 10), - (4, 5, 10), - (5, 6, 10), - (2, 7, 1), - (7, 5, 1), - ] - ) - graph.extend_from_weighted_edge_list( - [ - (0, 8, 20), - (0, 9, 20), - (0, 10, 20), - (8, 10, 10), - (9, 10, 5), - ] - ) - with self.assertRaises(ValueError): - retworkx.metric_closure(graph, weight_fn=float) - - def test_metric_closure_empty_graph(self): - graph = retworkx.PyGraph() - closure = retworkx.metric_closure(graph, weight_fn=float) - self.assertEqual([], closure.weighted_edge_list()) - - def test_steiner_graph(self): - steiner_tree = retworkx.steiner_tree(self.graph, [1, 2, 3, 4, 5], weight_fn=float) - expected_steiner_tree = [ - (1, 2, 10), - (2, 3, 10), - (2, 7, 1), - (3, 4, 10), - (7, 5, 1), - ] - steiner_tree_edge_list = steiner_tree.weighted_edge_list() - for edge in expected_steiner_tree: - self.assertIn(edge, steiner_tree_edge_list) - - def test_steiner_graph_multigraph(self): - edge_list = [ - (1, 2, 1), - (2, 3, 999), - (2, 3, 1), - (3, 4, 1), - (3, 5, 1), - ] - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list(edge_list) - graph.remove_node(0) - terminal_nodes = [2, 4, 5] - tree = retworkx.steiner_tree(graph, terminal_nodes, weight_fn=float) - expected_edges = [ - (2, 3, 1), - (3, 4, 1), - (3, 5, 1), - ] - steiner_tree_edge_list = tree.weighted_edge_list() - for edge in expected_edges: - self.assertIn(edge, steiner_tree_edge_list) - - def test_not_connected_steiner_tree(self): - self.graph.add_node(None) - with self.assertRaises(ValueError): - retworkx.steiner_tree(self.graph, [1, 2, 8], weight_fn=float) - - def test_steiner_tree_empty_graph(self): - graph = retworkx.PyGraph() - tree = retworkx.steiner_tree(graph, [], weight_fn=float) - self.assertEqual([], tree.weighted_edge_list()) - - def test_equal_distance_graph(self): - n = 3 - graph = retworkx.PyGraph() - graph.add_nodes_from(range(n + 5)) - graph.add_edges_from( - [ - (n, n + 1, 0.5), - (n, n + 2, 0.5), - (n + 1, n + 2, 0.5), - (n, n + 3, 0.5), - (n + 1, n + 4, 0.5), - ] - ) - graph.add_edges_from([(i, n + 2, 2) for i in range(n)]) - terminals = list(range(5)) + [n + 3, n + 4] - tree = retworkx.steiner_tree(graph, terminals, weight_fn=float) - # Assert no cycle - self.assertEqual(retworkx.cycle_basis(tree), []) - expected_edges = [ - (3, 4, 0.5), - (4, 5, 0.5), - (3, 6, 0.5), - (4, 7, 0.5), - (0, 5, 2), - (1, 5, 2), - (2, 5, 2), - ] - self.assertEqual(tree.weighted_edge_list(), expected_edges) diff --git a/tests/retworkx_backwards_compat/graph/test_subgraph.py b/tests/retworkx_backwards_compat/graph/test_subgraph.py deleted file mode 100644 index 2f0259640..000000000 --- a/tests/retworkx_backwards_compat/graph/test_subgraph.py +++ /dev/null @@ -1,150 +0,0 @@ -# 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 TestSubgraph(unittest.TestCase): - def test_subgraph(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3]) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - - def test_subgraph_empty_list(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_invalid_entry(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([42]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_pass_by_reference(self): - graph = retworkx.PyGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0]["a"] = 4 - self.assertEqual(subgraph[0]["a"], 4) - - def test_subgraph_replace_weight_no_reference(self): - graph = retworkx.PyGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0] = 4 - self.assertEqual(subgraph[0]["a"], 0) - - def test_edge_subgraph(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.edge_subgraph([(0, 1), (1, 3)]) - self.assertEqual(["a", "b", "d"], subgraph.nodes()) - self.assertEqual([(0, 1, 1), (1, 3, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_parallel_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([(0, 1), (1, 2)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_empty_list(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([]) - self.assertEqual([], subgraph.nodes()) - - def test_edge_subgraph_non_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - # 1->3 isn't an edge in graph - subgraph = graph.edge_subgraph([(0, 1), (1, 2), (1, 3)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_preserve_attrs(self): - graph = retworkx.PyGraph(attrs="My attribute") - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3], preserve_attrs=True) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - self.assertEqual(graph.attrs, subgraph.attrs) diff --git a/tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py b/tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py deleted file mode 100644 index 3fa842443..000000000 --- a/tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py +++ /dev/null @@ -1,296 +0,0 @@ -# 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 TestSubgraphIsomorphic(unittest.TestCase): - def test_empty_subgraph_isomorphic_identical(self): - g_a = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_empty_subgraph_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_subgraph_isomorphic_compare_nodes(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_identical(self): - g_a = retworkx.PyGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_subgraph_isomorphic_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_subgraph_isomorphic_compare_nodes_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_compare_nodes_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_is_subgraph_isomorphic_nodes_compare_raises(self): - g_a = retworkx.PyGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises( - TypeError, - retworkx.is_subgraph_isomorphic, - (g_a, g_a, compare_nodes), - ) - - def test_subgraph_isomorphic_compare_edges_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, - g_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_subgraph_isomorphic_node_count_not_ge(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1")]) - - nodes = g_b.add_nodes_from(["a_0", "a_1", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_non_induced_subgraph_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[0], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order, induced=True): - self.assertFalse( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=True) - ) - with self.subTest(id_order=id_order, induced=False): - self.assertTrue( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=False) - ) - - def test_subgraph_isomorphic_edge_matcher(self): - first = retworkx.PyGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b")]) - - self.assertTrue( - retworkx.is_subgraph_isomorphic( - first, second, induced=False, edge_matcher=lambda x, y: x == y - ) - ) - - def test_subgraph_isomorphic_mismatch_edge_data_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "f"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "a"), (1, 2, "b")]) - - self.assertFalse( - retworkx.is_subgraph_isomorphic( - first, second, id_order=True, edge_matcher=lambda x, y: x == y - ) - ) - - def test_subgraph_isomorphic_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_edge_list([(0, 1), (1, 2), (2, 3)]) - second = retworkx.PyGraph() - second.extend_from_edge_list([(0, 1), (0, 1)]) - self.assertFalse(retworkx.is_subgraph_isomorphic(first, second, induced=True)) - self.assertFalse(retworkx.is_subgraph_isomorphic(first, second, induced=False)) - - def test_non_induced_grid_subgraph_isomorphic(self): - g_a = retworkx.generators.grid_graph(2, 2) - g_b = retworkx.PyGraph() - g_b.add_nodes_from([0, 1, 2, 3]) - g_b.add_edges_from_no_data([(0, 1), (2, 3)]) - - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=True)) - - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=False)) - - def test_non_induced_subgraph_isomorphic_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_edge_list([(0, 1), (0, 1), (1, 2), (1, 2)]) - second = retworkx.PyGraph() - second.extend_from_edge_list([(0, 1), (1, 2), (1, 2)]) - self.assertFalse(retworkx.is_subgraph_isomorphic(first, second, induced=True)) - self.assertTrue(retworkx.is_subgraph_isomorphic(first, second, induced=False)) - - def test_subgraph_vf2_mapping(self): - graph = retworkx.generators.grid_graph(10, 10) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True) - self.assertEqual(next(mapping), {0: 0, 1: 1, 10: 2, 11: 3}) - - def test_subgraph_vf2_all_mappings(self): - graph = retworkx.generators.path_graph(3) - second_graph = retworkx.generators.path_graph(2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True, id_order=True) - self.assertEqual(next(mapping), {0: 0, 1: 1}) - self.assertEqual(next(mapping), {0: 1, 1: 0}) - self.assertEqual(next(mapping), {2: 1, 1: 0}) - self.assertEqual(next(mapping), {1: 1, 2: 0}) - - def test_subgraph_vf2_mapping_vf2pp(self): - graph = retworkx.generators.grid_graph(3, 3) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {4: 0, 3: 2, 0: 3, 1: 1}) - - def test_vf2pp_remapping(self): - temp = retworkx.generators.grid_graph(3, 3) - - graph = retworkx.PyGraph() - dummy = graph.add_node(0) - - graph.compose(temp, dict()) - graph.remove_node(dummy) - - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {5: 0, 4: 2, 1: 3, 2: 1}) - - def test_empty_subgraph_vf2_mapping(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.graph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=True) - self.assertEqual({}, next(mapping)) - - def test_subgraph_vf2_mapping_out_size(self): - first = retworkx.PyGraph() - first.add_nodes_from([0, 1, 2, 3]) - first.add_edges_from_no_data([(0, 1), (0, 2), (1, 2), (2, 3)]) - second = retworkx.PyGraph() - second.add_nodes_from([0, 1, 2, 3]) - second.add_edges_from_no_data([(0, 1), (0, 2), (1, 3)]) - mapping = retworkx.graph_vf2_mapping( - first, second, subgraph=True, id_order=True, induced=False - ) - self.assertEqual(next(mapping), {0: 0, 1: 2, 2: 1, 3: 3}) diff --git a/tests/retworkx_backwards_compat/graph/test_tensor_product.py b/tests/retworkx_backwards_compat/graph/test_tensor_product.py deleted file mode 100644 index 9d282b0bb..000000000 --- a/tests/retworkx_backwards_compat/graph/test_tensor_product.py +++ /dev/null @@ -1,112 +0,0 @@ -# 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 TestTensorProduct(unittest.TestCase): - def test_null_tensor_null(self): - graph_1 = retworkx.PyGraph() - graph_2 = retworkx.PyGraph() - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 0) - self.assertEqual(graph_product.num_edges(), 0) - - def test_path_2_tensor_path_2(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, node_map = retworkx.graph_tensor_product(graph_1, graph_2) - - expected_node_map = {(0, 0): 0, (0, 1): 1, (1, 0): 2, (1, 1): 3} - self.assertEqual(node_map, expected_node_map) - - expected_edges = [(0, 3), (1, 2)] - self.assertEqual(graph_product.num_nodes(), 4) - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_path_2_tensor_path_3(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(3) - - graph_product, node_map = retworkx.graph_tensor_product(graph_1, graph_2) - expected_node_map = {(0, 1): 1, (1, 0): 3, (0, 0): 0, (1, 2): 5, (0, 2): 2, (1, 1): 4} - self.assertEqual(dict(node_map), expected_node_map) - - expected_edges = [(0, 4), (1, 5), (1, 3), (2, 4)] - self.assertEqual(graph_product.num_nodes(), 6) - self.assertEqual(graph_product.num_edges(), 4) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_node_weights_tensor(self): - graph_1 = retworkx.PyGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_edge_weights_tensor(self): - graph_1 = retworkx.PyGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - - graph_2 = retworkx.PyGraph() - graph_2.add_nodes_from([0, 1]) - graph_2.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - self.assertEqual([("w_1", "w_2"), ("w_1", "w_2")], graph_product.edges()) - - def test_multi_graph_1(self): - graph_1 = retworkx.generators.path_graph(2) - graph_1.add_edge(0, 1, None) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3), (1, 2), (1, 2)] - self.assertEqual(graph_product.num_edges(), 4) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_2(self): - graph_1 = retworkx.generators.path_graph(2) - graph_1.add_edge(0, 0, None) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 1), (1, 2)] - self.assertEqual(graph_product.num_edges(), 3) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_3(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - graph_2.add_edge(0, 1, None) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3), (1, 2), (1, 2)] - self.assertEqual(graph_product.num_edges(), 4) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_4(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - graph_2.add_edge(0, 0, None) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 2), (1, 2)] - self.assertEqual(graph_product.num_edges(), 3) - self.assertEqual(graph_product.edge_list(), expected_edges) diff --git a/tests/retworkx_backwards_compat/graph/test_to_directed.py b/tests/retworkx_backwards_compat/graph/test_to_directed.py deleted file mode 100644 index 16b97b866..000000000 --- a/tests/retworkx_backwards_compat/graph/test_to_directed.py +++ /dev/null @@ -1,79 +0,0 @@ -# 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 TestToDirected(unittest.TestCase): - def test_to_undirected_empty_graph(self): - graph = retworkx.PyGraph() - digraph = graph.to_directed() - self.assertEqual(0, len(digraph)) - - def test_path_graph(self): - graph = retworkx.generators.path_graph(5) - digraph = graph.to_directed() - expected = [ - (0, 1, None), - (1, 0, None), - (1, 2, None), - (2, 1, None), - (2, 3, None), - (3, 2, None), - (3, 4, None), - (4, 3, None), - ] - self.assertEqual(digraph.weighted_edge_list(), expected) - - def test_parallel_edge_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (0, 1, "A"), - (0, 1, "B"), - (0, 2, "C"), - (0, 3, "D"), - ] - ) - digraph = graph.to_directed() - expected = [ - (0, 1, "A"), - (1, 0, "A"), - (0, 1, "B"), - (1, 0, "B"), - (0, 2, "C"), - (2, 0, "C"), - (0, 3, "D"), - (3, 0, "D"), - ] - self.assertEqual(digraph.weighted_edge_list(), expected) - - def test_shared_ref(self): - graph = retworkx.PyGraph() - node_weight = {"a": 1} - node_a = graph.add_node(node_weight) - edge_weight = {"a": 1} - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, edge_weight) - digraph = graph.to_directed() - self.assertEqual(digraph[node_a], {"a": 1}) - self.assertEqual(graph[node_a], {"a": 1}) - node_weight["b"] = 2 - self.assertEqual(digraph[node_a], {"a": 1, "b": 2}) - self.assertEqual(graph[node_a], {"a": 1, "b": 2}) - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1}) - edge_weight["b"] = 2 - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1, "b": 2}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1, "b": 2}) diff --git a/tests/retworkx_backwards_compat/graph/test_transitivity.py b/tests/retworkx_backwards_compat/graph/test_transitivity.py deleted file mode 100644 index 5d7d8fed8..000000000 --- a/tests/retworkx_backwards_compat/graph/test_transitivity.py +++ /dev/null @@ -1,49 +0,0 @@ -# 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 TestTransitivity(unittest.TestCase): - def test_transitivity(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(5))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 3 / 8) - - def test_transitivity_triangle(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(3))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 1.0) - - def test_transitivity_star(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(5))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (0, 4)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) - - def test_transitivity_empty(self): - graph = retworkx.PyGraph() - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) - - def test_transitivity_disconnected(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(3))) - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) diff --git a/tests/retworkx_backwards_compat/graph/test_union.py b/tests/retworkx_backwards_compat/graph/test_union.py deleted file mode 100644 index 6ada9c331..000000000 --- a/tests/retworkx_backwards_compat/graph/test_union.py +++ /dev/null @@ -1,74 +0,0 @@ -# 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 TestUnion(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.add_nodes_from(["a_1", "a_2", "a_3"]) - self.graph.extend_from_weighted_edge_list([(0, 1, "e_1"), (1, 2, "e_2")]) - - def test_union_basic_merge_none(self): - final = retworkx.graph_union(self.graph, self.graph, merge_nodes=False, merge_edges=False) - self.assertTrue(len(final.nodes()) == 6) - self.assertTrue(len(final.edge_list()) == 4) - - def test_union_merge_all(self): - final = retworkx.graph_union(self.graph, self.graph, merge_nodes=True, merge_edges=True) - self.assertTrue(retworkx.is_isomorphic(final, self.graph)) - - def test_union_basic_merge_nodes_only(self): - final = retworkx.graph_union(self.graph, self.graph, merge_nodes=True, merge_edges=False) - self.assertTrue(len(final.edge_list()) == 4) - self.assertTrue(len(final.get_all_edge_data(0, 1)) == 2) - self.assertTrue(len(final.nodes()) == 3) - - def test_union_mismatch_edge_weight(self): - first = retworkx.PyGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyGraph() - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.graph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 1, "b")]) - - def test_union_node_hole(self): - first = retworkx.PyGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyGraph() - dummy = second.add_node("dummy") - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "a")]) - second.remove_node(dummy) - - final = retworkx.graph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a")]) - - def test_union_edge_between_merged_and_unmerged_nodes(self): - first = retworkx.PyGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyGraph() - nodes = second.add_nodes_from([0, 2]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.graph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 2, "b")]) diff --git a/tests/retworkx_backwards_compat/test_converters.py b/tests/retworkx_backwards_compat/test_converters.py deleted file mode 100644 index df753b72c..000000000 --- a/tests/retworkx_backwards_compat/test_converters.py +++ /dev/null @@ -1,117 +0,0 @@ -# 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 -import networkx - - -class TestNetworkxConverter(unittest.TestCase): - def test_undirected_gnm_graph(self): - g = networkx.gnm_random_graph(10, 10, seed=42) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_directed_gnm_graph(self): - g = networkx.gnm_random_graph(10, 10, seed=42, directed=True) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_graph(self): - g = networkx.Graph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_multigraph(self): - g = networkx.MultiGraph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_directed_graph(self): - g = networkx.DiGraph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_directed_multigraph(self): - g = networkx.MultiDiGraph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_cubical_graph(self): - g = networkx.cubical_graph(networkx.Graph) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_cubical_multigraph(self): - g = networkx.cubical_graph(networkx.MultiGraph) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_random_k_out_graph(self): - g = networkx.random_k_out_graph(100, 50, 3.14159, True, 42) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_networkx_graph_attributes_are_converted(self): - g = networkx.Graph() - for node in range(100): - g.add_node(str(node), test=True) - - out_graph = retworkx.networkx_converter(g, keep_attributes=True) - for node in out_graph.node_indexes(): - self.assertEqual(out_graph[node]["test"], True) - self.assertEqual(out_graph[node]["__networkx_node__"], str(node)) diff --git a/tests/retworkx_backwards_compat/test_custom_return_types.py b/tests/retworkx_backwards_compat/test_custom_return_types.py deleted file mode 100644 index a3bb14260..000000000 --- a/tests/retworkx_backwards_compat/test_custom_return_types.py +++ /dev/null @@ -1,1561 +0,0 @@ -# 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 copy -import pickle -import unittest - -import retworkx -import numpy as np - - -class TestBFSSuccessorsComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_child(self.node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) == [("a", ["b"])]) - - def test__eq__not_match(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) == [("b", ["c"])]) - - def test_eq_not_match_inner(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) == [("a", ["c"])]) - - def test__eq__different_length(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) == [("a", ["b"]), ("b", ["c"])]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - retworkx.bfs_successors(self.dag, 0) == ["a"] - - def test__ne__match(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) != [("a", ["b"])]) - - def test__ne__not_match(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) != [("b", ["c"])]) - - def test_ne_not_match_inner(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) != [("a", ["c"])]) - - def test__ne__different_length(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) != [("a", ["b"]), ("b", ["c"])]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - retworkx.bfs_successors(self.dag, 0) != ["a"] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.bfs_successors(self.dag, 0) > [("b", ["c"])] - - def test_deepcopy(self): - bfs = retworkx.bfs_successors(self.dag, 0) - bfs_copy = copy.deepcopy(bfs) - self.assertEqual(bfs, bfs_copy) - - def test_pickle(self): - bfs = retworkx.bfs_successors(self.dag, 0) - bfs_pickle = pickle.dumps(bfs) - bfs_copy = pickle.loads(bfs_pickle) - self.assertEqual(bfs, bfs_copy) - - def test_str(self): - res = retworkx.bfs_successors(self.dag, 0) - self.assertEqual("BFSSuccessors[(a, [b])]", str(res)) - - def test_hash(self): - res = retworkx.bfs_successors(self.dag, 0) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_hash_invalid_type(self): - self.dag.add_child(0, [1, 2, 3], "edgy") - res = retworkx.bfs_successors(self.dag, 0) - with self.assertRaises(TypeError): - hash(res) - - def test_slices(self): - self.dag.add_child(self.node_a, "c", "New edge") - self.dag.add_child(self.node_b, "d", "New edge to d") - successors = retworkx.bfs_successors(self.dag, 0) - slice_return = successors[0:3:2] - self.assertEqual([("a", ["c", "b"])], slice_return) - - -class TestNodeIndicesComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.node_indexes() == [0, 1]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.node_indexes() == [1, 2]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.node_indexes() == [0, 1, 2, 3]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.node_indexes() == ["a", None] - - def test__ne__match(self): - self.assertFalse(self.dag.node_indexes() != [0, 1]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.node_indexes() != [1, 2]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.node_indexes() != [0, 1, 2, 3]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.node_indexes() != ["a", None] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.node_indexes() > [2, 1] - - def test_deepcopy(self): - nodes = self.dag.node_indexes() - nodes_copy = copy.deepcopy(nodes) - self.assertEqual(nodes, nodes_copy) - - def test_pickle(self): - nodes = self.dag.node_indexes() - nodes_pickle = pickle.dumps(nodes) - nodes_copy = pickle.loads(nodes_pickle) - self.assertEqual(nodes, nodes_copy) - - def test_str(self): - res = self.dag.node_indexes() - self.assertEqual("NodeIndices[0, 1]", str(res)) - - def test_hash(self): - res = self.dag.node_indexes() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_slices(self): - self.dag.add_node("new") - self.dag.add_node("fun") - nodes = self.dag.node_indices() - slice_return = nodes[0:3:2] - self.assertEqual([0, 2], slice_return) - self.assertEqual(nodes[0:-1], [0, 1, 2]) - - def test_slices_negatives(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(range(5)) - indices = graph.node_indices() - slice_return = indices[-1:-3:-1] - self.assertEqual([4, 3], slice_return) - slice_return = indices[3:1:-2] - self.assertEqual([3], slice_return) - slice_return = indices[-3:-1] - self.assertEqual([2, 3], slice_return) - self.assertEqual([], indices[-1:-2]) - - def test_numpy_conversion(self): - res = self.dag.node_indexes() - np.testing.assert_array_equal(np.asarray(res, dtype=np.uintp), np.array([0, 1])) - - -class TestNodesCountMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {1: 1}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {2: 1}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {1: 2}) - - def test__eq__different_length(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {1: 1, 2: 2}) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.num_shortest_paths_unweighted(self.dag, 0), - retworkx.num_shortest_paths_unweighted(self.dag, 0), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == ["a", None]) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {0: "a"}) - - def test__ne__match(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {1: 1}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {2: 1}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {1: 2}) - - def test__ne__different_length(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {1: 1, 2: 2}) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.num_shortest_paths_unweighted(self.dag, 0) > {1: 1} - - def test_deepcopy(self): - paths = retworkx.num_shortest_paths_unweighted(self.dag, 0) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.num_shortest_paths_unweighted(self.dag, 0) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - self.assertEqual("NodesCountMapping{1: 1}", str(res)) - - def test_hash(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.num_shortest_paths_unweighted(self.dag, 0).keys() - self.assertEqual([1], list(keys)) - - def test_values(self): - values = retworkx.num_shortest_paths_unweighted(self.dag, 0).values() - self.assertEqual([1], list(values)) - - def test_items(self): - items = retworkx.num_shortest_paths_unweighted(self.dag, 0).items() - self.assertEqual([(1, 1)], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.num_shortest_paths_unweighted(self.dag, 0)) - output = list(mapping_iter) - self.assertEqual(output, [1]) - - def test_contains(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - self.assertNotIn(0, res) - - -class TestEdgeIndicesComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDiGraph() - node_a = self.dag.add_node("a") - node_b = self.dag.add_child(node_a, "b", "Edgy") - self.dag.add_child(node_b, "c", "Super Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.edge_indices() == [0, 1]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.edge_indices() == [1, 2]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.edge_indices() == [0, 1, 2, 3]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.edge_indices() == ["a", None] - - def test__ne__match(self): - self.assertFalse(self.dag.edge_indices() != [0, 1]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.edge_indices() != [1, 2]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.edge_indices() != [0, 1, 2, 3]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.edge_indices() != ["a", None] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.edge_indices() > [2, 1] - - def test_deepcopy(self): - edges = self.dag.edge_indices() - edges_copy = copy.deepcopy(edges) - self.assertEqual(edges, edges_copy) - - def test_pickle(self): - edges = self.dag.edge_indices() - edges_pickle = pickle.dumps(edges) - edges_copy = pickle.loads(edges_pickle) - self.assertEqual(edges, edges_copy) - - def test_str(self): - res = self.dag.edge_indices() - self.assertEqual("EdgeIndices[0, 1]", str(res)) - - def test_hash(self): - res = self.dag.edge_indices() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_slices(self): - self.dag.add_edge(0, 1, None) - edges = self.dag.edge_indices() - slice_return = edges[0:-1] - self.assertEqual([0, 1], slice_return) - - -class TestEdgeListComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.edge_list() == [(0, 1)]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.edge_list() == [(1, 2)]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.edge_list() == [(0, 1), (2, 3)]) - - def test__eq__invalid_type(self): - self.assertFalse(self.dag.edge_list() == ["a", None]) - - def test__ne__match(self): - self.assertFalse(self.dag.edge_list() != [(0, 1)]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.edge_list() != [(1, 2)]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.edge_list() != [(0, 1), (2, 3)]) - - def test__ne__invalid_type(self): - self.assertTrue(self.dag.edge_list() != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.edge_list() > [(2, 1)] - - def test_deepcopy(self): - edges = self.dag.edge_list() - edges_copy = copy.deepcopy(edges) - self.assertEqual(edges, edges_copy) - - def test_pickle(self): - edges = self.dag.edge_list() - edges_pickle = pickle.dumps(edges) - edges_copy = pickle.loads(edges_pickle) - self.assertEqual(edges, edges_copy) - - def test_str(self): - res = self.dag.edge_list() - self.assertEqual("EdgeList[(0, 1)]", str(res)) - - def test_hash(self): - res = self.dag.edge_list() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_slice(self): - self.dag.add_edge(0, 1, None) - self.dag.add_edge(0, 1, None) - edges = self.dag.edge_list() - slice_return = edges[0:3:2] - self.assertEqual([(0, 1), (0, 1)], slice_return) - - @staticmethod - def test_numpy_conversion(): - g = retworkx.generators.directed_star_graph(5) - res = g.edge_list() - - np.testing.assert_array_equal( - np.asarray(res, dtype=np.uintp), np.array([[0, 1], [0, 2], [0, 3], [0, 4]]) - ) - - -class TestWeightedEdgeListComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.weighted_edge_list() == [(0, 1, "Edgy")]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.weighted_edge_list() == [(1, 2, None)]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.weighted_edge_list() == [(0, 1, "Edgy"), (2, 3, "Not Edgy")]) - - def test__eq__invalid_type(self): - self.assertFalse(self.dag.weighted_edge_list() == ["a", None]) - - def test__ne__match(self): - self.assertFalse(self.dag.weighted_edge_list() != [(0, 1, "Edgy")]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.weighted_edge_list() != [(1, 2, "Not Edgy")]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.node_indexes() != [0, 1, 2, 3]) - - def test__ne__invalid_type(self): - self.assertTrue(self.dag.weighted_edge_list() != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.weighted_edge_list() > [(2, 1, "Not Edgy")] - - def test_deepcopy(self): - edges = self.dag.weighted_edge_list() - edges_copy = copy.deepcopy(edges) - self.assertEqual(edges, edges_copy) - - def test_pickle(self): - edges = self.dag.weighted_edge_list() - edges_pickle = pickle.dumps(edges) - edges_copy = pickle.loads(edges_pickle) - self.assertEqual(edges, edges_copy) - - def test_str(self): - res = self.dag.weighted_edge_list() - self.assertEqual("WeightedEdgeList[(0, 1, Edgy)]", str(res)) - - def test_hash(self): - res = self.dag.weighted_edge_list() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_hash_invalid_type(self): - self.dag.add_child(0, "c", ["edgy", "not_edgy"]) - res = self.dag.weighted_edge_list() - with self.assertRaises(TypeError): - hash(res) - - def test_slice(self): - self.dag.add_edge(0, 1, None) - self.dag.add_edge(0, 1, None) - edges = self.dag.weighted_edge_list() - slice_return = edges[0:3:2] - self.assertEqual([(0, 1, "Edgy"), (0, 1, None)], slice_return) - - def test_numpy_conversion(self): - np.testing.assert_array_equal( - np.asarray(self.dag.weighted_edge_list()), np.array([(0, 1, "Edgy")], dtype=object) - ) - - -class TestPathMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) == {1: [0, 1]}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {2: [0, 1]}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {1: [0, 2]}) - - def test__eq__different_length(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {1: [0, 1], 2: [0, 2]}) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.dijkstra_shortest_paths(self.dag, 0), - retworkx.dijkstra_shortest_paths(self.dag, 0), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == ["a", None]) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {0: {"a": None}}) - - def test__ne__match(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) != {1: [0, 1]}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != {2: [0, 1]}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != {1: [0, 2]}) - - def test__ne__different_length(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != {1: [0, 1], 2: [0, 2]}) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.dijkstra_shortest_paths(self.dag, 0) > {1: [0, 2]} - - def test_deepcopy(self): - paths = retworkx.dijkstra_shortest_paths(self.dag, 0) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.dijkstra_shortest_paths(self.dag, 0) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - self.assertEqual("PathMapping{1: [0, 1]}", str(res)) - - def test_hash(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.dijkstra_shortest_paths(self.dag, 0).keys() - self.assertEqual([1], list(keys)) - - def test_values(self): - values = retworkx.dijkstra_shortest_paths(self.dag, 0).values() - self.assertEqual([[0, 1]], list(values)) - - def test_items(self): - items = retworkx.dijkstra_shortest_paths(self.dag, 0).items() - self.assertEqual([(1, [0, 1])], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.dijkstra_shortest_paths(self.dag, 0)) - output = list(mapping_iter) - self.assertEqual(output, [1]) - - def test_contains(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - self.assertNotIn(0, res) - - -class TestPathLengthMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - self.fn = lambda _: 1.0 - - def test__eq__match(self): - self.assertTrue(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {1: 1.0}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {2: 1.0}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {1: 2.0}) - - def test__eq__different_length(self): - self.assertFalse( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {1: 1.0, 2: 2.0} - ) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn), - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn), - ) - - def test__eq__invalid_type(self): - self.assertFalse( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == ["a", None] - ) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {0: "a"}) - - def test__ne__match(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {1: 1.0}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {2: 1.0}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {1: 2.0}) - - def test__ne__different_length(self): - self.assertTrue( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {1: 1.0, 2: 2.0} - ) - - def test__ne__invalid_type(self): - self.assertTrue( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != ["a", None] - ) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) > {1: 1.0} - - def test_deepcopy(self): - paths = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, lambda _: 3.14) - self.assertEqual("PathLengthMapping{1: 3.14}", str(res)) - - def test_hash(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn).keys() - self.assertEqual([1], list(keys)) - - def test_values(self): - values = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn).values() - self.assertEqual([1.0], list(values)) - - def test_items(self): - items = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn).items() - self.assertEqual([(1, 1.0)], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn)) - output = list(mapping_iter) - self.assertEqual(output, [1]) - - def test_contains(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - self.assertNotIn(0, res) - - -class TestPos2DMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDiGraph() - self.dag.add_node("a") - - def test__eq__match(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertTrue(res == {0: (0.4883489113112722, 0.6545867364101975)}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.random_layout(self.dag, seed=10244242) == {2: 1.0}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.random_layout(self.dag, seed=10244242) == {1: 2.0}) - - def test__eq__different_length(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertFalse(res == {1: 1.0, 2: 2.0}) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.random_layout(self.dag, seed=10244242), - retworkx.random_layout(self.dag, seed=10244242), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.random_layout(self.dag, seed=10244242) == {"a": None}) - - def test__ne__match(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertFalse(res != {0: (0.4883489113112722, 0.6545867364101975)}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.random_layout(self.dag, seed=10244242) != {2: 1.0}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.random_layout(self.dag, seed=10244242) != {1: 2.0}) - - def test__ne__different_length(self): - res = retworkx.random_layout(self.dag, seed=10244242) - - self.assertTrue(res != {1: 1.0, 2: 2.0}) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.random_layout(self.dag, seed=10244242) != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.random_layout(self.dag, seed=10244242) > {1: 1.0} - - def test_deepcopy(self): - positions = retworkx.random_layout(self.dag) - positions_copy = copy.deepcopy(positions) - self.assertEqual(positions_copy, positions) - - def test_pickle(self): - pos = retworkx.random_layout(self.dag) - pos_pickle = pickle.dumps(pos) - pos_copy = pickle.loads(pos_pickle) - self.assertEqual(pos, pos_copy) - - def test_str(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertEqual( - "Pos2DMapping{0: [0.4883489113112722, 0.6545867364101975]}", - str(res), - ) - - def test_hash(self): - res = retworkx.random_layout(self.dag, seed=10244242) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.random_layout(self.dag, seed=10244242) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.random_layout(self.dag, seed=10244242).keys() - self.assertEqual([0], list(keys)) - - def test_values(self): - values = retworkx.random_layout(self.dag, seed=10244242).values() - expected = [[0.4883489113112722, 0.6545867364101975]] - self.assertEqual(expected, list(values)) - - def test_items(self): - items = retworkx.random_layout(self.dag, seed=10244242).items() - self.assertEqual([(0, [0.4883489113112722, 0.6545867364101975])], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.random_layout(self.dag, seed=10244242)) - output = list(mapping_iter) - self.assertEqual(output, [0]) - - def test_contains(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertIn(0, res) - - def test_not_contains(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertNotIn(1, res) - - -class TestEdgeIndices(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDiGraph() - self.dag.add_node("a") - self.dag.add_child(0, "b", "edge") - - def test__eq__match(self): - res = self.dag.edge_index_map() - self.assertTrue(res == {0: (0, 1, "edge")}) - - def test__eq__not_match_keys(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {2: (0, 1, "edge")}) - - def test__eq__not_match_values(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {0: (1, 2, "edge")}) - self.assertFalse(res == {0: (0, 1, "not edge")}) - - def test__eq__different_length(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {1: (0, 1, "edge"), 0: (0, 1, "double edge")}) - - def test_eq__same_type(self): - self.assertEqual(self.dag.edge_index_map(), self.dag.edge_index_map()) - - def test__eq__invalid_type(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {"a": ("a", "b", "c")}) - - def test__ne__match(self): - res = self.dag.edge_index_map() - self.assertFalse(res != {0: (0, 1, "edge")}) - - def test__ne__not_match(self): - res = self.dag.edge_index_map() - self.assertTrue(res, {2: (0, 1, "edge")}) - - def test__ne__not_match_values(self): - res = self.dag.edge_index_map() - self.assertTrue(res, {0: (0, 2, "edge")}) - - def test__ne__different_length(self): - res = self.dag.edge_index_map() - self.assertTrue(res != {1: (0, 1, "double edge"), 0: (0, 1, "edge")}) - - def test__ne__invalid_type(self): - res = self.dag.edge_index_map() - self.assertTrue(res != {"a": ("a", "b", "c")}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.edge_index_map() > {0: (0, 1, "edge")} - - def test_deepcopy(self): - edge_map = self.dag.edge_index_map() - edge_map_copy = copy.deepcopy(edge_map) - self.assertEqual(edge_map_copy, edge_map) - - def test_pickle(self): - edge_map = self.dag.edge_index_map() - edge_map_pickle = pickle.dumps(edge_map) - edge_map_copy = pickle.loads(edge_map_pickle) - self.assertEqual(edge_map, edge_map_copy) - - def test_str(self): - res = self.dag.edge_index_map() - self.assertEqual( - "EdgeIndexMap{0: (0, 1, edge)}", - str(res), - ) - - def test_hash(self): - res = self.dag.edge_index_map() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = self.dag.edge_index_map() - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = self.dag.edge_index_map().keys() - self.assertEqual([0], list(keys)) - - def test_values(self): - values = self.dag.edge_index_map().values() - expected = [(0, 1, "edge")] - self.assertEqual(expected, list(values)) - - def test_items(self): - items = self.dag.edge_index_map().items() - self.assertEqual([(0, (0, 1, "edge"))], list(items)) - - def test_iter(self): - mapping_iter = iter(self.dag.edge_index_map()) - output = list(mapping_iter) - self.assertEqual(output, [0]) - - def test_contains(self): - res = self.dag.edge_index_map() - self.assertIn(0, res) - - def test_not_contains(self): - res = self.dag.edge_index_map() - self.assertNotIn(1, res) - - -class TestAllPairsPathMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - self.fn = lambda _: 1.0 - - def test__eq__match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {0: {1: [0, 1]}, 1: {}} - ) - - def test__eq__not_match_keys(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {2: {2: [0, 1]}, 1: {}} - ) - - def test__eq__not_match_values(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {0: {1: [0, 2]}, 1: {}} - ) - - def test__eq__different_length(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {1: [0, 1], 2: [0, 2]} - ) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn), - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {"a": []}) - - def test__eq__invalid_inner_type(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {0: {1: None}} - ) - - def test__ne__match(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {0: {1: [0, 1]}, 1: {}} - ) - - def test__ne__not_match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {2: [0, 1]} - ) - - def test__ne__not_match_values(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {1: [0, 2]} - ) - - def test__ne__different_length(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {1: [0, 1], 2: [0, 2]} - ) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {"a": {}}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) > {1: [0, 2]} - - def test_deepcopy(self): - paths = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - # Since run in parallel the order is not deterministic - expected_valid = [ - "AllPairsPathMapping{1: PathMapping{}, 0: PathMapping{1: [0, 1]}}", - "AllPairsPathMapping{0: PathMapping{1: [0, 1]}, 1: PathMapping{}}", - ] - self.assertIn(str(res), expected_valid) - - def test_hash(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn).keys() - self.assertEqual([0, 1], list(sorted(keys))) - - def test_values(self): - values = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn).values() - # Since run in parallel the order is not deterministic - expected_valid = [[{1: [0, 1]}, {}], [{}, {1: [0, 1]}]] - self.assertIn(list(values), expected_valid) - - def test_items(self): - items = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn).items() - # Since run in parallel the order is not deterministic - expected_valid = [ - [(0, {1: [0, 1]}), (1, {})], - [(1, {}), (0, {1: [0, 1]})], - ] - self.assertIn(list(items), expected_valid) - - def test_iter(self): - mapping_iter = iter(retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn)) - output = list(sorted(mapping_iter)) - self.assertEqual(output, [0, 1]) - - def test_contains(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - self.assertNotIn(2, res) - - -class TestAllPairsPathLengthMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - self.fn = lambda _: 1.0 - - def test__eq__match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: {1: 1.0}, 1: {}} - ) - - def test__eq__not_match_keys(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {1: {2: 1.0}} - ) - - def test__eq__not_match_values(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: {2: 2.0}} - ) - - def test__eq__different_length(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: {1: 1.0, 2: 2.0}} - ) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn), - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {"a": 2}) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: "a"}) - - def test__ne__match(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {0: {1: 1.0}, 1: {}} - ) - - def test__ne__not_match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {0: {2: 1.0}} - ) - - def test__ne__not_match_values(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {0: {1: 2.0}} - ) - - def test__ne__different_length(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - != {0: {1: 1.0}, 2: {1: 2.0}} - ) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {1: []}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) > {1: 1.0} - - def test_deepcopy(self): - paths = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, lambda _: 3.14) - # Since all_pairs_dijkstra_path_lengths() is parallel the order of the - # output is non-determinisitic - valid_values = [ - "AllPairsPathLengthMapping{1: PathLengthMapping{}, " "0: PathLengthMapping{1: 3.14}}", - "AllPairsPathLengthMapping{" - "0: PathLengthMapping{1: 3.14}, " - "1: PathLengthMapping{}}", - ] - self.assertIn(str(res), valid_values) - - def test_hash(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).keys() - self.assertEqual([0, 1], list(sorted((keys)))) - - def test_values(self): - values = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).values() - # Since run in parallel the order is not deterministic - valid_expected = [[{}, {1: 1.0}], [{1: 1.0}, {}]] - self.assertIn(list(values), valid_expected) - - def test_items(self): - items = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).items() - # Since run in parallel the order is not deterministic - valid_expected = [[(0, {1: 1.0}), (1, {})], [(1, {}), (0, {1: 1.0})]] - self.assertIn(list(items), valid_expected) - - def test_iter(self): - mapping_iter = iter(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn)) - output = list(sorted(mapping_iter)) - self.assertEqual(output, [0, 1]) - - def test_contains(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - self.assertIn(0, res) - - def test_not_contains(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - self.assertNotIn(2, res) - - -class TestNodeMap(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - self.dag.add_node("a") - self.in_dag = retworkx.generators.directed_path_graph(1) - - def test__eq__match(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) == {0: 1} - ) - - def test__eq__not_match_keys(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) == {2: 1} - ) - - def test__eq__not_match_values(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) == {0: 2} - ) - - def test__eq__different_length(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - == {0: 1, 1: 2} - ) - - def test_eq__same_type(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertEqual(res, res) - - def test__ne__match(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) != {0: 1} - ) - - def test__ne__not_match(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) != {2: 2} - ) - - def test__ne__not_match_values(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) != {0: 2} - ) - - def test__ne__different_length(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - != {0: 1, 1: 2} - ) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) > {1: 2} - - def test__len__(self): - in_dag = retworkx.generators.directed_grid_graph(5, 5) - node_map = self.dag.substitute_node_with_subgraph(0, in_dag, lambda *args: None) - self.assertEqual(25, len(node_map)) - - def test_deepcopy(self): - node_map = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - node_map_copy = copy.deepcopy(node_map) - self.assertEqual(node_map, node_map_copy) - - def test_pickle(self): - node_map = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - node_map_pickle = pickle.dumps(node_map) - node_map_copy = pickle.loads(node_map_pickle) - self.assertEqual(node_map, node_map_copy) - - def test_str(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertEqual("NodeMap{0: 1}", str(res)) - - def test_hash(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None).keys() - self.assertEqual([0], list(keys)) - - def test_values(self): - values = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None).values() - self.assertEqual([1], list(values)) - - def test_items(self): - items = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None).items() - self.assertEqual([(0, 1)], list(items)) - - def test_iter(self): - mapping_iter = iter( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - ) - output = list(mapping_iter) - self.assertEqual(output, [0]) - - def test_contains(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertIn(0, res) - - def test_not_contains(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertNotIn(2, res) - - def test_iter_stable_for_same_obj(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - in_graph = retworkx.generators.directed_path_graph(5) - res = self.dag.substitute_node_with_subgraph(0, in_graph, lambda *args: None) - first_iter = list(iter(res)) - second_iter = list(iter(res)) - third_iter = list(iter(res)) - self.assertEqual(first_iter, second_iter) - self.assertEqual(first_iter, third_iter) - - -class TestChainsComparisons(unittest.TestCase): - def setUp(self): - self.graph = retworkx.generators.cycle_graph(3) - self.chains = retworkx.chain_decomposition(self.graph) - - def test__eq__match(self): - self.assertTrue(self.chains == [[(0, 2), (2, 1), (1, 0)]]) - - def test__eq__not_match(self): - self.assertFalse(self.chains == [[(0, 2), (2, 1), (2, 0)]]) - - def test__eq__different_length(self): - self.assertFalse(self.chains == [[(0, 2)]]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - self.chains == [0] - - def test__ne__match(self): - self.assertFalse(self.chains != [[(0, 2), (2, 1), (1, 0)]]) - - def test__ne__not_match(self): - self.assertTrue(self.chains != [[(0, 2), (2, 1), (2, 0)]]) - - def test__ne__different_length(self): - self.assertTrue(self.chains != [[(0, 2)]]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - self.chains != [0] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.chains > [[(0, 2)]] - - def test_deepcopy(self): - chains_copy = copy.deepcopy(self.chains) - self.assertEqual(self.chains, chains_copy) - - def test_pickle(self): - chains_pickle = pickle.dumps(self.chains) - chains_copy = pickle.loads(chains_pickle) - self.assertEqual(self.chains, chains_copy) - - def test_str(self): - self.assertEqual("Chains[EdgeList[(0, 2), (2, 1), (1, 0)]]", str(self.chains)) - - def test_hash(self): - hash_res = hash(self.chains) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(self.chains)) - - def test_numpy_conversion(self): - # this test assumes the array is 1-dimensional which avoids issues with jagged arrays - self.assertTrue(np.asarray(self.chains).shape, (1,)) - - -class TestProductNodeMap(unittest.TestCase): - def setUp(self): - self.first = retworkx.PyGraph() - self.first.add_node("a0") - self.first.add_node("a1") - - self.second = retworkx.PyGraph() - self.second.add_node("b") - _, self.node_map = retworkx.graph_cartesian_product(self.first, self.second) - - def test__eq__match(self): - self.assertTrue(self.node_map == {(0, 0): 0, (1, 0): 1}) - - def test__eq__not_match_keys(self): - self.assertFalse(self.node_map == {(0, 0): 0, (2, 0): 1}) - - def test__eq__not_match_values(self): - self.assertFalse(self.node_map == {(0, 0): 0, (1, 0): 2}) - - def test__eq__different_length(self): - self.assertFalse(self.node_map == {(0, 0): 0}) - - def test_eq__same_type(self): - _, res = retworkx.graph_cartesian_product(self.first, self.second) - self.assertEqual(self.node_map, res) - - def test__ne__match(self): - self.assertFalse(self.node_map != {(0, 0): 0, (1, 0): 1}) - - def test__ne__not_match(self): - self.assertTrue(self.node_map != {(0, 0): 0, (2, 0): 1}) - - def test__ne__not_match_values(self): - self.assertTrue(self.node_map != {(0, 0): 0, (1, 0): 2}) - - def test__ne__different_length(self): - self.assertTrue(self.node_map != {(0, 0): 0}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.node_map > {1: 2} - - def test__len__(self): - self.assertEqual(2, len(self.node_map)) - - def test_deepcopy(self): - node_map_copy = copy.deepcopy(self.node_map) - self.assertEqual(self.node_map, node_map_copy) - - def test_pickle(self): - node_map_pickle = pickle.dumps(self.node_map) - node_map_copy = pickle.loads(node_map_pickle) - self.assertEqual(self.node_map, node_map_copy) - - def test_str(self): - valid_str_output = [ - "ProductNodeMap{(0, 0): 0, (1, 0): 1}", - "ProductNodeMap{(1, 0): 1, (0, 0): 0}", - ] - self.assertTrue(str(self.node_map) in valid_str_output) - - def test_hash(self): - hash_res = hash(self.node_map) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(self.node_map)) - - def test_index_error(self): - with self.assertRaises(IndexError): - self.node_map[(1, 1)] - - def test_keys(self): - keys = self.node_map.keys() - self.assertEqual(set([(0, 0), (1, 0)]), set(keys)) - - def test_values(self): - values = self.node_map.values() - self.assertEqual(set([0, 1]), set(values)) - - def test_items(self): - items = self.node_map.items() - self.assertEqual(set([((0, 0), 0), ((1, 0), 1)]), set(items)) - - def test_iter(self): - mapping_iter = iter(self.node_map) - output = set(mapping_iter) - self.assertEqual(output, set([(0, 0), (1, 0)])) - - def test_contains(self): - self.assertIn((0, 0), self.node_map) - - def test_not_contains(self): - self.assertNotIn((1, 1), self.node_map) - - -class TestBiconnectedComponentsMap(unittest.TestCase): - def setUp(self): - self.graph = retworkx.generators.path_graph(3) - self.bicon_map = retworkx.biconnected_components(self.graph) - - def test__eq__match(self): - self.assertTrue(self.bicon_map == {(0, 1): 1, (1, 2): 0}) - - def test__eq__not_match_keys(self): - self.assertFalse(self.bicon_map == {(0, 0): 1, (2, 0): 0}) - - def test__eq__not_match_values(self): - self.assertFalse(self.bicon_map == {(0, 1): 2, (1, 2): 0}) - - def test__eq__different_length(self): - self.assertFalse(self.bicon_map == {(0, 1): 1}) - - def test_eq__same_type(self): - res = retworkx.biconnected_components(self.graph) - self.assertEqual(self.bicon_map, res) - - def test__ne__match(self): - self.assertFalse(self.bicon_map != {(0, 1): 1, (1, 2): 0}) - - def test__ne__not_match(self): - self.assertTrue(self.bicon_map != {(0, 2): 1, (1, 2): 0}) - - def test__ne__not_match_values(self): - self.assertTrue(self.bicon_map != {(0, 1): 0, (1, 2): 0}) - - def test__ne__different_length(self): - self.assertTrue(self.bicon_map != {(0, 1): 1}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.bicon_map > {1: 2} - - def test__len__(self): - self.assertEqual(2, len(self.bicon_map)) - - def test_deepcopy(self): - bicon_map_copy = copy.deepcopy(self.bicon_map) - self.assertEqual(self.bicon_map, bicon_map_copy) - - def test_pickle(self): - bicon_map_pickle = pickle.dumps(self.bicon_map) - bicon_map_copy = pickle.loads(bicon_map_pickle) - self.assertEqual(self.bicon_map, bicon_map_copy) - - def test_str(self): - valid_str_output = [ - "BiconnectedComponents{(0, 1): 1, (1, 2): 0}", - "BiconnectedComponents{(1, 2): 0, (0, 1): 1}", - ] - self.assertTrue(str(self.bicon_map) in valid_str_output) - - def test_hash(self): - hash_res = hash(self.bicon_map) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(self.bicon_map)) - - def test_index_error(self): - with self.assertRaises(IndexError): - self.bicon_map[(1, 1)] - - def test_keys(self): - keys = self.bicon_map.keys() - self.assertEqual(set([(0, 1), (1, 2)]), set(keys)) - - def test_values(self): - values = self.bicon_map.values() - self.assertEqual(set([0, 1]), set(values)) - - def test_items(self): - items = self.bicon_map.items() - self.assertEqual(set([((0, 1), 1), ((1, 2), 0)]), set(items)) - - def test_iter(self): - mapping_iter = iter(self.bicon_map) - output = set(mapping_iter) - self.assertEqual(output, set([(0, 1), (1, 2)])) - - def test_contains(self): - self.assertIn((0, 1), self.bicon_map) - - def test_not_contains(self): - self.assertNotIn((0, 2), self.bicon_map) diff --git a/tests/retworkx_backwards_compat/test_dispatch.py b/tests/retworkx_backwards_compat/test_dispatch.py deleted file mode 100644 index 5bdc83e55..000000000 --- a/tests/retworkx_backwards_compat/test_dispatch.py +++ /dev/null @@ -1,111 +0,0 @@ -# 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 - -import numpy - - -class TestDispatchPyGraph(unittest.TestCase): - - class_type = "PyGraph" - - def setUp(self): - super().setUp() - if self.class_type == "PyGraph": - self.graph = retworkx.undirected_gnp_random_graph(10, 0.5, seed=42) - else: - self.graph = retworkx.directed_gnp_random_graph(10, 0.5, seed=42) - - def test_distance_matrix(self): - res = retworkx.distance_matrix(self.graph) - self.assertIsInstance(res, numpy.ndarray) - - def test_distance_matrix_as_undirected(self): - if self.class_type == "PyGraph": - with self.assertRaises(TypeError): - retworkx.distance_matrix(self.graph, as_undirected=True) - else: - res = retworkx.distance_matrix(self.graph, as_undirected=True) - self.assertIsInstance(res, numpy.ndarray) - - def test_adjacency_matrix(self): - res = retworkx.adjacency_matrix(self.graph) - self.assertIsInstance(res, numpy.ndarray) - - def test_all_simple_paths(self): - res = retworkx.all_simple_paths(self.graph, 0, 1) - self.assertIsInstance(res, list) - - def test_floyd_warshall(self): - res = retworkx.floyd_warshall(self.graph) - self.assertIsInstance(res, retworkx.AllPairsPathLengthMapping) - - def test_floyd_warshall_numpy(self): - res = retworkx.floyd_warshall_numpy(self.graph) - self.assertIsInstance(res, numpy.ndarray) - - if self.class_type == "PyGraph": - expected_res = retworkx.graph_floyd_warshall_numpy(self.graph) - else: - expected_res = retworkx.digraph_floyd_warshall_numpy(self.graph) - - self.assertTrue(numpy.array_equal(expected_res, res)) - - def test_astar_shortest_path(self): - res = retworkx.astar_shortest_path(self.graph, 0, lambda _: True, lambda _: 1, lambda _: 1) - self.assertIsInstance(list(res), list) - - def test_dijkstra_shortest_paths(self): - res = retworkx.dijkstra_shortest_paths(self.graph, 0) - self.assertIsInstance(res, retworkx.PathMapping) - - def test_dijkstra_shortest_path_lengths(self): - res = retworkx.dijkstra_shortest_path_lengths(self.graph, 0, lambda _: 1) - self.assertIsInstance(res, retworkx.PathLengthMapping) - - def test_k_shortest_path_lengths(self): - res = retworkx.k_shortest_path_lengths(self.graph, 0, 2, lambda _: 1) - self.assertIsInstance(res, retworkx.PathLengthMapping) - - def test_dfs_edges(self): - res = retworkx.dfs_edges(self.graph, 0) - self.assertIsInstance(list(res), list) - - def test_all_pairs_dijkstra_shortest_paths(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.graph, lambda _: 1) - self.assertIsInstance(res, retworkx.AllPairsPathMapping) - - def test_all_pairs_dijkstra_path_lengthss(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.graph, lambda _: 1) - self.assertIsInstance(res, retworkx.AllPairsPathLengthMapping) - - def test_is_isomorphic_nodes_incompatible_raises(self): - with self.assertRaises(TypeError): - if self.class_type == "PyGraph": - retworkx.is_isomorphic(self.graph, retworkx.PyDiGraph()) - else: - retworkx.is_isomorphic(self.graph, retworkx.PyGraph()) - - def test_betweenness_centrality(self): - res = retworkx.betweenness_centrality(self.graph) - self.assertIsInstance(res, retworkx.CentralityMapping) - - def test_closeness_centrality(self): - res = retworkx.closeness_centrality(self.graph) - self.assertIsInstance(res, retworkx.CentralityMapping) - - -class TestDispatchPyDiGraph(TestDispatchPyGraph): - - class_type = "PyDiGraph" diff --git a/tests/retworkx_backwards_compat/test_graphml.py b/tests/retworkx_backwards_compat/test_graphml.py deleted file mode 100644 index 1750d68c7..000000000 --- a/tests/retworkx_backwards_compat/test_graphml.py +++ /dev/null @@ -1,512 +0,0 @@ -# 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 tempfile -import numpy - -import retworkx - - -class TestGraphML(unittest.TestCase): - HEADER = """ - - - {} - - """ - - def assertDictPayloadEqual(self, xs, ys): - self.assertEqual(len(xs), len(ys)) - for key, va in xs.items(): - vb = ys.get(key, None) - self.assertTrue( - (isinstance(va, float) and isinstance(vb, float) and numpy.allclose(va, vb)) - or (va == vb) - ) - - def assertGraphEqual(self, graph, nodes, edges, directed=True, attrs={}): - self.assertTrue(isinstance(graph, retworkx.PyDiGraph if directed else retworkx.PyGraph)) - self.assertEqual(len(graph), len(nodes)) - self.assertEqual(graph.attrs, attrs) - for node_a, node_b in zip(graph.nodes(), nodes): - self.assertDictPayloadEqual(node_a, node_b) - - for ((s, t, data), edge) in zip(graph.weighted_edge_list(), edges): - self.assertEqual((graph[s]["id"], graph[t]["id"]), (edge[0], edge[1])) - self.assertDictPayloadEqual(data, edge[2]) - - def assertGraphMLRaises(self, graph_xml): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - with self.assertRaises(Exception): - retworkx.read_graphml(fd.name) - - def test_simple(self): - graph_xml = self.HEADER.format( - """ - - yellow - - - 0.95 - - - - blue - - - - green - - - 0.98 - - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "color": "blue"}, - {"id": "n1", "color": "yellow"}, - {"id": "n2", "color": "green"}, - ] - edges = [ - ("n0", "n1", {"fidelity": 0.98}), - ("n0", "n2", {"fidelity": 0.95}), - ] - self.assertGraphEqual(graph, nodes, edges, directed=False) - - def test_multiple_graphs_in_single_file(self): - graph_xml = self.HEADER.format( - """ - - yellow - - - 0.95 - - - - blue - - - - 0.98 - - - - - red - - - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - self.assertEqual(len(graphml), 2) - graph = graphml[0] - nodes = [ - {"id": "n0", "color": "blue"}, - {"id": "n1", "color": "yellow"}, - ] - edges = [ - ("n0", "n1", {"id": "e01", "fidelity": 0.98}), - ] - self.assertGraphEqual(graph, nodes, edges, directed=False) - graph = graphml[1] - nodes = [ - {"id": "n0", "color": "red"}, - {"id": "n1", "color": "yellow"}, - ] - edges = [ - ("n0", "n1", {"id": "e01", "fidelity": 0.95}), - ] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_key_for_graph(self): - graph_xml = self.HEADER.format( - """ - - - true - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [{"id": "n0"}] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True, attrs={"test": True}) - - def test_key_for_all(self): - graph_xml = self.HEADER.format( - """ - - - I'm a graph. - - I'm a node. - - - I'm a node. - - - I'm an edge. - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": "I'm a node."}, - {"id": "n1", "test": "I'm a node."}, - ] - edges = [("n0", "n1", {"test": "I'm an edge."})] - self.assertGraphEqual( - graph, nodes, edges, directed=True, attrs={"test": "I'm a graph."} - ) - - def test_key_default_undefined(self): - graph_xml = self.HEADER.format( - """ - - - - true - - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": True}, - {"id": "n1", "test": None}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_bool(self): - graph_xml = self.HEADER.format( - """ - - false - - - - true - - - - false - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": True}, - {"id": "n1", "test": False}, - {"id": "n2", "test": False}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_int(self): - graph_xml = self.HEADER.format( - """ - - 42 - - - - 8 - - - - 42 - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": 8}, - {"id": "n1", "test": 42}, - {"id": "n2", "test": 42}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_float(self): - graph_xml = self.HEADER.format( - """ - - 4.2 - - - - 1.8 - - - - 4.2 - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": 1.8}, - {"id": "n1", "test": 4.2}, - {"id": "n2", "test": 4.2}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_double(self): - graph_xml = self.HEADER.format( - """ - - 4.2 - - - - 1.8 - - - - 4.2 - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": 1.8}, - {"id": "n1", "test": 4.2}, - {"id": "n2", "test": 4.2}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_string(self): - graph_xml = self.HEADER.format( - """ - - yellow - - - - blue - - - - yellow - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": "blue"}, - {"id": "n1", "test": "yellow"}, - {"id": "n2", "test": "yellow"}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_convert_error(self): - graph_xml = self.HEADER.format( - """ - - blah - - """ - ) - - for type in ["boolean", "int", "float", "double"]: - self.assertGraphMLRaises(graph_xml=graph_xml.format(type)) - - def test_invalid_xml(self): - graph_xml = self.HEADER.format( - """ - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_invalid_edgedefault(self): - graph_xml = self.HEADER.format( - """ - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_missing_node_id(self): - graph_xml = self.HEADER.format( - """ - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_missing_key_for_node(self): - graph_xml = self.HEADER.format( - """ - - - - blue - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_invalid_key_type(self): - graph_xml = self.HEADER.format( - """ - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_key_domain(self): - graph_xml = self.HEADER.format( - """ - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_nested_graphs(self): - graph_xml = self.HEADER.format( - """ - - - - - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_hyperedges(self): - graph_xml = self.HEADER.format( - """ - - - - - - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_ports(self): - graph_xml = self.HEADER.format( - """ - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_nested_ports(self): - graph_xml = self.HEADER.format( - """ - - - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) diff --git a/tests/retworkx_backwards_compat/test_random.py b/tests/retworkx_backwards_compat/test_random.py deleted file mode 100644 index 67a60760c..000000000 --- a/tests/retworkx_backwards_compat/test_random.py +++ /dev/null @@ -1,222 +0,0 @@ -# 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 random - -import retworkx - - -class TestGNPRandomGraph(unittest.TestCase): - def test_random_gnp_directed(self): - graph = retworkx.directed_gnp_random_graph(20, 0.5, seed=10) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 104) - - def test_random_gnp_directed_empty_graph(self): - graph = retworkx.directed_gnp_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnp_directed_complete_graph(self): - graph = retworkx.directed_gnp_random_graph(20, 1) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20 * (20 - 1)) - - def test_random_gnp_directed_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.directed_gnp_random_graph(0, 0.5) - - def test_random_gnp_directed_invalid_probability(self): - with self.assertRaises(ValueError): - retworkx.directed_gnp_random_graph(23, 123.5) - - def test_random_gnp_undirected(self): - graph = retworkx.undirected_gnp_random_graph(20, 0.5, seed=10) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 105) - - def test_random_gnp_undirected_empty_graph(self): - graph = retworkx.undirected_gnp_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnp_undirected_complete_graph(self): - graph = retworkx.undirected_gnp_random_graph(20, 1) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20 * (20 - 1) / 2) - - def test_random_gnp_undirected_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.undirected_gnp_random_graph(0, 0.5) - - def test_random_gnp_undirected_invalid_probability(self): - with self.assertRaises(ValueError): - retworkx.undirected_gnp_random_graph(23, 123.5) - - -class TestGNMRandomGraph(unittest.TestCase): - def test_random_gnm_directed(self): - graph = retworkx.directed_gnm_random_graph(20, 100) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 100) - # with other arguments equal, same seed results in same graph - graph_s1 = retworkx.directed_gnm_random_graph(20, 100, seed=10) - graph_s2 = retworkx.directed_gnm_random_graph(20, 100, seed=10) - self.assertEqual(graph_s1.edge_list(), graph_s2.edge_list()) - - def test_random_gnm_directed_empty_graph(self): - graph = retworkx.directed_gnm_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - # passing a seed when passing zero edges has no effect - graph = retworkx.directed_gnm_random_graph(20, 0, 44) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnm_directed_complete_graph(self): - n = 20 - max_m = n * (n - 1) - # passing the max edges for the passed number of nodes - graph = retworkx.directed_gnm_random_graph(n, max_m) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing m > the max edges n(n-1) still returns the max edges - graph = retworkx.directed_gnm_random_graph(n, max_m + 1) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing a seed when passing max edges has no effect - graph = retworkx.directed_gnm_random_graph(n, max_m, 55) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - - def test_random_gnm_directed_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.directed_gnm_random_graph(0, 5) - - def test_random_gnm_directed_invalid_num_edges(self): - with self.assertRaises(OverflowError): - retworkx.directed_gnm_random_graph(23, -5) - - def test_random_gnm_undirected(self): - graph = retworkx.undirected_gnm_random_graph(20, 100) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 100) - # with other arguments equal, same seed results in same graph - graph_s1 = retworkx.undirected_gnm_random_graph(20, 100, seed=10) - graph_s2 = retworkx.undirected_gnm_random_graph(20, 100, seed=10) - self.assertEqual(graph_s1.edge_list(), graph_s2.edge_list()) - - def test_random_gnm_undirected_empty_graph(self): - graph = retworkx.undirected_gnm_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - # passing a seed when passing zero edges has no effect - graph = retworkx.undirected_gnm_random_graph(20, 0, 44) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnm_undirected_complete_graph(self): - n = 20 - max_m = n * (n - 1) // 2 - # passing the max edges for the passed number of nodes - graph = retworkx.undirected_gnm_random_graph(n, max_m) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing m > the max edges n(n-1)/2 still returns the max edges - graph = retworkx.undirected_gnm_random_graph(n, max_m + 1) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing a seed when passing max edges has no effect - graph = retworkx.undirected_gnm_random_graph(n, max_m, 55) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - - def test_random_gnm_undirected_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.undirected_gnm_random_graph(0, 5) - - def test_random_gnm_undirected_invalid_num_edges(self): - with self.assertRaises(OverflowError): - retworkx.undirected_gnm_random_graph(23, -5) - - -class TestGeometricRandomGraph(unittest.TestCase): - def test_random_geometric_empty(self): - graph = retworkx.random_geometric_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_geometric_complete(self): - r = 1.42 # > sqrt(2) - graph = retworkx.random_geometric_graph(10, r) - self.assertEqual(len(graph), 10) - self.assertEqual(len(graph.edges()), 45) - - def test_random_geometric_same_seed(self): - # with other arguments equal, same seed results in same graph - graph_s1 = retworkx.random_geometric_graph(20, 0.5, seed=10) - graph_s2 = retworkx.random_geometric_graph(20, 0.5, seed=10) - self.assertEqual(graph_s1.edge_list(), graph_s2.edge_list()) - - def test_random_geometric_dim(self): - graph = retworkx.random_geometric_graph(10, 0.5, dim=3) - self.assertEqual(len(graph[0]["pos"]), 3) - - def test_random_geometric_pos(self): - pos = [[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]] - graph = retworkx.random_geometric_graph(3, 0.15, pos=pos) - self.assertEqual(set(graph.edge_list()), {(0, 1), (1, 2)}) - for i in range(3): - self.assertEqual(graph[i]["pos"], pos[i]) - - def test_random_geometric_pos_1norm(self): - pos = [[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]] - graph = retworkx.random_geometric_graph(3, 0.21, pos=pos, p=1.0) - self.assertEqual(set(graph.edge_list()), {(0, 1), (1, 2)}) - - def test_random_geometric_pos_inf_norm(self): - pos = [[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]] - graph = retworkx.random_geometric_graph(3, 0.11, pos=pos, p=float("inf")) - self.assertEqual(set(graph.edge_list()), {(0, 1), (1, 2)}) - - def test_random_geometric_num_nodes_invalid(self): - with self.assertRaises(ValueError): - retworkx.random_geometric_graph(0, 1.0) - - def test_random_geometric_pos_num_nodes_incomp(self): - with self.assertRaises(ValueError): - retworkx.random_geometric_graph(3, 0.15, pos=[[0.5, 0.5]]) - - -class TestRandomSubGraphIsomorphism(unittest.TestCase): - def test_random_gnm_induced_subgraph_isomorphism(self): - graph = retworkx.undirected_gnm_random_graph(50, 150) - nodes = random.sample(range(50), 25) - subgraph = graph.subgraph(nodes) - - self.assertTrue( - retworkx.is_subgraph_isomorphic(graph, subgraph, id_order=True, induced=True) - ) - - def test_random_gnm_non_induced_subgraph_isomorphism(self): - graph = retworkx.undirected_gnm_random_graph(50, 150) - nodes = random.sample(range(50), 25) - subgraph = graph.subgraph(nodes) - - indexes = list(subgraph.edge_indices()) - for idx in random.sample(indexes, len(indexes) // 2): - subgraph.remove_edge_from_index(idx) - - self.assertTrue( - retworkx.is_subgraph_isomorphic(graph, subgraph, id_order=True, induced=False) - ) diff --git a/tests/retworkx_backwards_compat/visualization/__init__.py b/tests/retworkx_backwards_compat/visualization/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/visualization/test_graphviz.py b/tests/retworkx_backwards_compat/visualization/test_graphviz.py deleted file mode 100644 index 5d9039537..000000000 --- a/tests/retworkx_backwards_compat/visualization/test_graphviz.py +++ /dev/null @@ -1,152 +0,0 @@ -# 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 os -import subprocess -import tempfile -import unittest - -import retworkx -from retworkx.visualization import graphviz_draw - -try: - import PIL - - subprocess.run( - ["dot", "-V"], - cwd=tempfile.gettempdir(), - check=True, - capture_output=True, - ) - HAS_PILLOW = True -except Exception: - HAS_PILLOW = False - -SAVE_IMAGES = os.getenv("RUSTWORKX_TEST_PRESERVE_IMAGES", None) - - -def _save_image(image, path): - if SAVE_IMAGES: - image.save(path) - - -@unittest.skipUnless(HAS_PILLOW, "pillow and graphviz are required for running these tests") -class TestGraphvizDraw(unittest.TestCase): - def test_draw_no_args(self): - graph = retworkx.generators.star_graph(24) - image = graphviz_draw(graph) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw.png") - - def test_draw_node_attr_fn(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - image = graphviz_draw(graph, lambda node: node) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_node_attr.png") - - def test_draw_edge_attr_fn(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - image = graphviz_draw(graph, lambda node: node, lambda edge: edge) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_edge_attr.png") - - def test_draw_graph_attr(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - graph_attr = {"bgcolor": "red"} - image = graphviz_draw(graph, lambda node: node, lambda edge: edge, graph_attr) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_graph_attr.png") - - def test_image_type(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - image = graphviz_draw(graph, image_type="jpg") - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_image_type.jpg") - - def test_image_type_invalid_type(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - with self.assertRaises(ValueError): - graphviz_draw(graph, image_type="raw") - - def test_method(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - image = graphviz_draw(graph, method="sfdp") - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_method.png") - - def test_method_invalid_method(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - with self.assertRaises(ValueError): - graphviz_draw(graph, method="special") - - def test_filename(self): - graph = retworkx.generators.grid_graph(20, 20) - graphviz_draw( - graph, - filename="test_graphviz_filename.svg", - image_type="svg", - method="neato", - ) - self.assertTrue(os.path.isfile("test_graphviz_filename.svg")) - if not SAVE_IMAGES: - self.addCleanup(os.remove, "test_graphviz_filename.svg") diff --git a/tests/retworkx_backwards_compat/visualization/test_mpl.py b/tests/retworkx_backwards_compat/visualization/test_mpl.py deleted file mode 100644 index 4d600c19b..000000000 --- a/tests/retworkx_backwards_compat/visualization/test_mpl.py +++ /dev/null @@ -1,194 +0,0 @@ -# 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. - -# Based on the equivalent tests for the networkx matplotlib drawer: -# https://github.com/networkx/networkx/blob/ead0e65bda59862e329f2e6f1da47919c6b07ca9/networkx/drawing/tests/test_pylab.py - -import os -import unittest - -import retworkx -from retworkx.visualization import mpl_draw - -try: - import matplotlib as mpl - import matplotlib.pyplot as plt - - mpl.use("PS") - plt.rcParams["text.usetex"] = False - HAS_MPL = True -except ImportError: - HAS_MPL = False - -SAVE_IMAGES = os.getenv("RUSTWORKX_TEST_PRESERVE_IMAGES", None) - - -def _save_images(fig, path): - fig.savefig(path, dpi=400) - if not SAVE_IMAGES: - try: - os.unlink(path) - except OSError: - pass - - -@unittest.skipUnless(HAS_MPL, "matplotlib is required for running these tests") -class TestMPLDraw(unittest.TestCase): - def test_draw(self): - graph = retworkx.generators.star_graph(24) - options = {"node_color": "black", "node_size": 100, "width": 3} - fig = mpl_draw(graph, **options) - _save_images(fig, "test.png") - - def test_node_list(self): - graph = retworkx.generators.star_graph(24) - node_list = list(range(4)) + list(range(4, 10)) + list(range(10, 14)) - fig = mpl_draw(graph, node_list=node_list) - _save_images(fig, "test_node_list.png") - - def test_edge_colormap(self): - graph = retworkx.generators.star_graph(24) - colors = range(len(graph.edge_list())) - fig = mpl_draw( - graph, - edge_color=colors, - width=4, - edge_cmap=plt.cm.Blues, - with_labels=True, - ) - _save_images(fig, "test_edge_colors.png") - - def test_arrows(self): - graph = retworkx.generators.directed_star_graph(24) - fig = mpl_draw(graph) - _save_images(fig, "test_arrows.png") - - def test_empty_graph(self): - graph = retworkx.PyGraph() - fig = mpl_draw(graph) - _save_images(fig, "test_empty.png") - - def test_axes(self): - fig, ax = plt.subplots() - graph = retworkx.directed_gnp_random_graph(50, 0.75) - mpl_draw(graph, ax=ax) - _save_images(fig, "test_axes.png") - - def test_selfloop_with_single_edge_in_edge_list(self): - fig, ax = plt.subplots() - # Graph with selfloop - graph = retworkx.generators.path_graph(2) - graph.add_edge(1, 1, None) - pos = {n: (n, n) for n in graph.node_indexes()} - mpl_draw(graph, pos, ax=ax, edge_list=[(1, 1)]) - _save_images(fig, "test_self_loop.png") - - def test_draw_edges_min_source_target_margins(self): - """Test that there is a wider gap between the node and the start of an - incident edge when min_source_margin is specified. - - This test checks that the use of min_{source/target}_margin kwargs - result in shorter (more padding) between the edges and source and - target nodes. As a crude visual example, let 's' and 't' represent - source and target nodes, respectively: - Default: - s-----------------------------t - With margins: - s ----------------------- t - """ - node_shapes = ["o", "s"] - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 1)]) - pos = {0: (0, 0), 1: (1, 0)} # horizontal layout - - for node_shape in node_shapes: - with self.subTest(shape=node_shape): - fig, ax = plt.subplots() - mpl_draw( - graph, - pos=pos, - ax=ax, - node_shape=node_shape, - min_source_margin=100, - min_target_margin=100, - ) - _save_images(fig, "test_node_shape_%s.png" % node_shape) - - def test_alpha_iter(self): - graph = retworkx.generators.grid_graph(4, 6) - # with fewer alpha elements than nodes - plt.subplot(131) - mpl_draw(graph, alpha=[0.1, 0.2]) - # with equal alpha elements and nodes - num_nodes = len(graph) - alpha = [x / num_nodes for x in range(num_nodes)] - colors = range(num_nodes) - plt.subplot(132) - mpl_draw(graph, node_color=colors, alpha=alpha) - # with more alpha elements than nodes - alpha.append(1) - plt.subplot(133) - mpl_draw(graph, alpha=alpha) - fig = plt.gcf() - _save_images(fig, "test_alpha_iter.png") - - def test_labels_and_colors(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - edge_list = [ - (0, 1, 5), - (1, 2, 2), - (2, 3, 7), - (3, 0, 6), - (5, 6, 1), - (4, 5, 7), - (6, 7, 3), - (7, 4, 7), - ] - labels = {} - labels[0] = r"$a$" - labels[1] = r"$b$" - labels[2] = r"$c$" - labels[3] = r"$d$" - labels[4] = r"$\alpha$" - labels[5] = r"$\beta$" - labels[6] = r"$\gamma$" - labels[7] = r"$\delta$" - graph.add_edges_from(edge_list) - pos = retworkx.random_layout(graph) - mpl_draw( - graph, - pos=pos, - node_list=[0, 1, 2, 3], - node_color="r", - edge_list=[(0, 1), (1, 2), (2, 3), (3, 0)], - node_size=500, - alpha=0.75, - width=1.0, - labels=lambda x: labels[x], - font_size=16, - ) - mpl_draw( - graph, - pos=pos, - node_list=[4, 5, 6, 7], - node_color="b", - node_size=500, - alpha=0.5, - edge_list=[(4, 5), (5, 6), (6, 7), (7, 4)], - width=8, - edge_color="r", - rotate=False, - edge_labels=lambda edge: labels[edge], - ) - fig = plt.gcf() - _save_images(fig, "test_labels_and_colors.png") From 2a6f718645e19002f9c3581881f577797dab182a Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 16 Oct 2023 13:11:53 -0400 Subject: [PATCH 10/12] Update pyo3 and numpy to 0.20.0 (#1005) This commit updates PyO3 to the latest release 0.20.0 [1] and also moves rust-numpy to 0.20.0 [2] as well. The major change for rustworkx is official support for Python 3.12.0 final. We were previously using the 3.12 pre-release support in PyO3 to publish rustworkx for 3.12, but moving to the latest PyO3 officially supports the stable releases of 3.12. The are some small changes needed to adapt to API changes in PyO3, mostly around updates to the `PyDict.get_item()` api. [1] https://github.com/PyO3/pyo3/releases/tag/v0.20.0 [2] https://github.com/PyO3/rust-numpy/releases/tag/v0.20.0 --- Cargo.lock | 76 ++++++++++++++++++++++++-------------------------- Cargo.toml | 4 +-- src/digraph.rs | 18 ++++++++---- src/graph.rs | 16 +++++++---- 4 files changed, 61 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05ccca190..90a5de9ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,6 +137,12 @@ dependencies = [ "rayon", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -166,9 +172,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.9" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "itertools" @@ -196,15 +202,15 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "lock_api" @@ -228,9 +234,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -341,9 +347,9 @@ dependencies = [ [[package]] name = "numpy" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437213adf41bbccf4aeae535fbfcdad0f6fed241e1ae182ebe97fa1f3ce19389" +checksum = "bef41cbb417ea83b30525259e30ccef6af39b31c240bda578889494c5392d331" dependencies = [ "libc", "ndarray", @@ -411,18 +417,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" +checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b" dependencies = [ "cfg-if", "hashbrown 0.14.1", @@ -441,9 +447,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5" +checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" dependencies = [ "once_cell", "target-lexicon", @@ -451,9 +457,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9" +checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b" dependencies = [ "libc", "pyo3-build-config", @@ -461,25 +467,26 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1" +checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "pyo3-macros-backend" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536" +checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424" dependencies = [ + "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -663,7 +670,7 @@ checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] [[package]] @@ -700,20 +707,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -734,9 +730,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unindent" -version = "0.1.11" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] name = "version_check" diff --git a/Cargo.toml b/Cargo.toml index eed872da0..d8fba5163 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ fixedbitset = "0.4.2" hashbrown = { version = ">=0.13, <0.15", features = ["rayon"] } indexmap = { version = ">=1.9, <3", features = ["rayon"] } num-traits = "0.2" -numpy = "0.19.0" +numpy = "0.20.0" petgraph = "0.6.4" rand = "0.8" rand_pcg = "0.3" @@ -60,7 +60,7 @@ serde_json = "1.0" rustworkx-core = { path = "rustworkx-core", version = "=0.14.0" } [dependencies.pyo3] -version = "0.19.2" +version = "0.20.0" features = ["extension-module", "hashbrown", "num-bigint", "num-complex", "indexmap"] [dependencies.ndarray] diff --git a/src/digraph.rs b/src/digraph.rs index bf5395084..02de16885 100644 --- a/src/digraph.rs +++ b/src/digraph.rs @@ -332,27 +332,33 @@ impl PyDiGraph { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { let dict_state = state.downcast::(py)?; - let nodes_lst = dict_state.get_item("nodes").unwrap().downcast::()?; - let edges_lst = dict_state.get_item("edges").unwrap().downcast::()?; + let nodes_lst = dict_state + .get_item("nodes")? + .unwrap() + .downcast::()?; + let edges_lst = dict_state + .get_item("edges")? + .unwrap() + .downcast::()?; self.graph = StablePyGraph::::new(); let dict_state = state.downcast::(py)?; self.multigraph = dict_state - .get_item("multigraph") + .get_item("multigraph")? .unwrap() .downcast::()? .extract()?; self.node_removed = dict_state - .get_item("nodes_removed") + .get_item("nodes_removed")? .unwrap() .downcast::()? .extract()?; - let attrs = match dict_state.get_item("attrs") { + let attrs = match dict_state.get_item("attrs")? { Some(attr) => attr.into(), None => py.None(), }; self.attrs = attrs; self.check_cycle = dict_state - .get_item("check_cycle") + .get_item("check_cycle")? .unwrap() .downcast::()? .extract()?; diff --git a/src/graph.rs b/src/graph.rs index 58d463813..45d8902a7 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -229,21 +229,27 @@ impl PyGraph { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { let dict_state = state.downcast::(py)?; - let nodes_lst = dict_state.get_item("nodes").unwrap().downcast::()?; - let edges_lst = dict_state.get_item("edges").unwrap().downcast::()?; + let nodes_lst = dict_state + .get_item("nodes")? + .unwrap() + .downcast::()?; + let edges_lst = dict_state + .get_item("edges")? + .unwrap() + .downcast::()?; self.graph = StablePyGraph::::default(); self.multigraph = dict_state - .get_item("multigraph") + .get_item("multigraph")? .unwrap() .downcast::()? .extract()?; self.node_removed = dict_state - .get_item("nodes_removed") + .get_item("nodes_removed")? .unwrap() .downcast::()? .extract()?; - self.attrs = match dict_state.get_item("attrs") { + self.attrs = match dict_state.get_item("attrs")? { Some(attr) => attr.into(), None => py.None(), }; From de3eb0cf4fda687fe8137ddeec91568300f80dcc Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 16 Oct 2023 13:47:07 -0400 Subject: [PATCH 11/12] Add two_color and is_bipartite (#1002) * Add two_color and is_bipartite This commit adds new functions to rustworkx, two_color() and is_bipartite(), which are used to compute a two coloring for a graph and then determine if a givn graph is bipartite. The two_color() function is added to rustworkx-core as the python is_bipartite() function just wraps it and converts the output to a bool if a two coloring is possible or not. This commit is based on top of #998 and will need to be rebased after that merges. * Remove special isolates handling * Expand test coverage --- .../notes/add-bipartite-9df3898a156e799c.yaml | 22 +++ rustworkx-core/src/coloring.rs | 157 +++++++++++++++++- rustworkx/__init__.py | 31 ++++ src/coloring.rs | 52 +++++- src/connectivity/mod.rs | 21 +++ src/lib.rs | 4 + .../rustworkx_tests/digraph/test_bipartite.py | 76 +++++++++ tests/rustworkx_tests/graph/test_bipartite.py | 89 ++++++++++ 8 files changed, 445 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/add-bipartite-9df3898a156e799c.yaml create mode 100644 tests/rustworkx_tests/digraph/test_bipartite.py create mode 100644 tests/rustworkx_tests/graph/test_bipartite.py diff --git a/releasenotes/notes/add-bipartite-9df3898a156e799c.yaml b/releasenotes/notes/add-bipartite-9df3898a156e799c.yaml new file mode 100644 index 000000000..dba6c7ed3 --- /dev/null +++ b/releasenotes/notes/add-bipartite-9df3898a156e799c.yaml @@ -0,0 +1,22 @@ +--- +features: + - | + Added a new function ``two_color`` to the rustworkx-core ``rustworkx_core::coloring`` + module. This function is used to compute a two coloring of a graph and can + also be used to determine if a graph is bipartite as it returns ``None`` + when a two coloring is not possible. + - | + Added a new function, :func:`~.two_color`, which is used to compute a + two coloring for a graph. For example: + + .. jupyter-execute:: + + import rustworkx as rx + from rustworkx.visualization import mpl_draw + + graph = rx.generators.heavy_square_graph(5) + colors = rx.two_color(graph) + mpl_draw(graph, node_color=list(colors.values())) + - | + Added a new function, :func:`~.is_bipartite` to determine whether a given + graph object is bipartite or not. diff --git a/rustworkx-core/src/coloring.rs b/rustworkx-core/src/coloring.rs index 99eb27a9f..60fda14da 100644 --- a/rustworkx-core/src/coloring.rs +++ b/rustworkx-core/src/coloring.rs @@ -17,9 +17,84 @@ use crate::dictmap::*; use crate::line_graph::line_graph; use hashbrown::{HashMap, HashSet}; use petgraph::graph::NodeIndex; -use petgraph::visit::{EdgeCount, EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeCount}; +use petgraph::visit::{ + EdgeCount, EdgeRef, GraphBase, GraphProp, IntoEdges, IntoNeighborsDirected, + IntoNodeIdentifiers, NodeCount, NodeIndexable, +}; +use petgraph::{Incoming, Outgoing}; use rayon::prelude::*; +/// Compute a two-coloring of a graph +/// +/// If a two coloring is not possible for the input graph (meaning it is not +/// bipartite), `None` is returned. +/// +/// Arguments: +/// +/// * `graph` - The graph to find the coloring for +/// +/// # Example +/// +/// ```rust +/// use rustworkx_core::petgraph::prelude::*; +/// use rustworkx_core::coloring::two_color; +/// use rustworkx_core::dictmap::*; +/// +/// let edge_list = vec![ +/// (0, 1), +/// (1, 2), +/// (2, 3), +/// (3, 4), +/// ]; +/// +/// let graph = UnGraph::::from_edges(&edge_list); +/// let coloring = two_color(&graph).unwrap(); +/// let mut expected_colors = DictMap::new(); +/// expected_colors.insert(NodeIndex::new(0), 1); +/// expected_colors.insert(NodeIndex::new(1), 0); +/// expected_colors.insert(NodeIndex::new(2), 1); +/// expected_colors.insert(NodeIndex::new(3), 0); +/// expected_colors.insert(NodeIndex::new(4), 1); +/// assert_eq!(coloring, expected_colors) +/// ``` +pub fn two_color(graph: G) -> Option> +where + G: NodeIndexable + + IntoNodeIdentifiers + + IntoNeighborsDirected + + GraphBase + + GraphProp + + NodeCount, + ::NodeId: std::cmp::Eq + Hash, +{ + let mut colors = DictMap::with_capacity(graph.node_count()); + for node in graph.node_identifiers() { + if colors.contains_key(&node) { + continue; + } + let mut queue = vec![node]; + colors.insert(node, 1); + while let Some(v) = queue.pop() { + let v_color: u8 = *colors.get(&v).unwrap(); + let color: u8 = 1 - v_color; + for w in graph + .neighbors_directed(v, Outgoing) + .chain(graph.neighbors_directed(v, Incoming)) + { + if let Some(color_w) = colors.get(&w) { + if *color_w == v_color { + return None; + } + } else { + colors.insert(w, color); + queue.push(w); + } + } + } + } + Some(colors) +} + /// Color a graph using a greedy graph coloring algorithm. /// /// This function uses a `largest-first` strategy as described in: @@ -150,11 +225,12 @@ where mod test_node_coloring { use crate::coloring::greedy_node_color; - use crate::dictmap::DictMap; - use crate::petgraph::Graph; + use crate::coloring::two_color; + use crate::dictmap::*; + use crate::petgraph::prelude::*; - use petgraph::graph::NodeIndex; - use petgraph::Undirected; + use crate::petgraph::graph::NodeIndex; + use crate::petgraph::Undirected; #[test] fn test_greedy_node_color_empty_graph() { @@ -201,6 +277,77 @@ mod test_node_coloring { .collect(); assert_eq!(colors, expected_colors); } + + #[test] + fn test_two_color_directed() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)]; + + let graph = DiGraph::::from_edges(&edge_list); + let coloring = two_color(&graph).unwrap(); + let mut expected_colors = DictMap::new(); + expected_colors.insert(NodeIndex::new(0), 1); + expected_colors.insert(NodeIndex::new(1), 0); + expected_colors.insert(NodeIndex::new(2), 1); + expected_colors.insert(NodeIndex::new(3), 0); + expected_colors.insert(NodeIndex::new(4), 1); + assert_eq!(coloring, expected_colors) + } + + #[test] + fn test_two_color_directed_not_bipartite() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 0), (3, 1)]; + + let graph = DiGraph::::from_edges(&edge_list); + let coloring = two_color(&graph); + assert_eq!(None, coloring) + } + + #[test] + fn test_two_color_undirected_not_bipartite() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 0), (3, 1)]; + + let graph = UnGraph::::from_edges(&edge_list); + let coloring = two_color(&graph); + assert_eq!(None, coloring) + } + + #[test] + fn test_two_color_directed_with_isolates() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)]; + + let mut graph = DiGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let coloring = two_color(&graph).unwrap(); + let mut expected_colors = DictMap::new(); + expected_colors.insert(NodeIndex::new(0), 1); + expected_colors.insert(NodeIndex::new(1), 0); + expected_colors.insert(NodeIndex::new(2), 1); + expected_colors.insert(NodeIndex::new(3), 0); + expected_colors.insert(NodeIndex::new(4), 1); + expected_colors.insert(NodeIndex::new(5), 1); + expected_colors.insert(NodeIndex::new(6), 1); + assert_eq!(coloring, expected_colors) + } + + #[test] + fn test_two_color_undirected_with_isolates() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)]; + + let mut graph = UnGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let coloring = two_color(&graph).unwrap(); + let mut expected_colors = DictMap::new(); + expected_colors.insert(NodeIndex::new(0), 1); + expected_colors.insert(NodeIndex::new(1), 0); + expected_colors.insert(NodeIndex::new(2), 1); + expected_colors.insert(NodeIndex::new(3), 0); + expected_colors.insert(NodeIndex::new(4), 1); + expected_colors.insert(NodeIndex::new(5), 1); + expected_colors.insert(NodeIndex::new(6), 1); + assert_eq!(coloring, expected_colors) + } } #[cfg(test)] diff --git a/rustworkx/__init__.py b/rustworkx/__init__.py index b97eada4f..90c83ccce 100644 --- a/rustworkx/__init__.py +++ b/rustworkx/__init__.py @@ -2071,3 +2071,34 @@ def isolates(graph): isolates.register(PyDiGraph, digraph_isolates) isolates.register(PyGraph, graph_isolates) + + +@functools.singledispatch +def two_color(graph): + """Compute a two-coloring of a directed graph + + If a two coloring is not possible for the input graph (meaning it is not + bipartite), ``None`` is returned. + + :param graph: The graph to find the coloring for + :returns: If a coloring is possible return a dictionary of node indices to the color as an integer (0 or 1) + :rtype: dict + """ + + +two_color.register(PyDiGraph, digraph_two_color) +two_color.register(PyGraph, graph_two_color) + + +@functools.singledispatch +def is_bipartite(graph): + """Determine if a given graph is bipartite + + :param graph: The graph to check if it's bipartite + :returns: ``True`` if the graph is bipartite and ``False`` if it is not + :rtype: bool + """ + + +is_bipartite.register(PyDiGraph, digraph_is_bipartite) +is_bipartite.register(PyGraph, graph_is_bipartite) diff --git a/src/coloring.rs b/src/coloring.rs index 9440bd9e4..83eca1c49 100644 --- a/src/coloring.rs +++ b/src/coloring.rs @@ -10,9 +10,9 @@ // License for the specific language governing permissions and limitations // under the License. -use crate::graph; +use crate::{digraph, graph}; -use rustworkx_core::coloring::{greedy_edge_color, greedy_node_color}; +use rustworkx_core::coloring::{greedy_edge_color, greedy_node_color, two_color}; use pyo3::prelude::*; use pyo3::types::PyDict; @@ -88,3 +88,51 @@ pub fn graph_greedy_edge_color(py: Python, graph: &graph::PyGraph) -> PyResult

PyResult> { + match two_color(&graph.graph) { + Some(colors) => { + let out_dict = PyDict::new(py); + for (node, color) in colors { + out_dict.set_item(node.index(), color)?; + } + Ok(Some(out_dict.into())) + } + None => Ok(None), + } +} + +/// Compute a two-coloring of a directed graph +/// +/// If a two coloring is not possible for the input graph (meaning it is not +/// bipartite), ``None`` is returned. +/// +/// :param PyDiGraph graph: The graph to find the coloring for +/// +/// :returns: If a coloring is possible return a dictionary of node indices to the color as an +/// integer (0 or 1) +/// :rtype: dict +#[pyfunction] +pub fn digraph_two_color(py: Python, graph: &digraph::PyDiGraph) -> PyResult> { + match two_color(&graph.graph) { + Some(colors) => { + let out_dict = PyDict::new(py); + for (node, color) in colors { + out_dict.set_item(node.index(), color)?; + } + Ok(Some(out_dict.into())) + } + None => Ok(None), + } +} diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 8274538c7..11c49c951 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -39,6 +39,7 @@ use crate::iterators::{ }; use crate::{EdgeType, StablePyGraph}; +use rustworkx_core::coloring::two_color; use rustworkx_core::connectivity; /// Return a list of cycles which form a basis for cycles of a given PyGraph @@ -1035,3 +1036,23 @@ pub fn digraph_isolates(graph: digraph::PyDiGraph) -> NodeIndices { .collect(), } } + +/// Determine if a given graph is bipartite +/// +/// :param PyGraph graph: The graph to check if it's bipartite +/// :returns: ``True`` if the graph is bipartite and ``False`` if it is not +/// :rtype: bool +#[pyfunction] +pub fn graph_is_bipartite(graph: graph::PyGraph) -> bool { + two_color(&graph.graph).is_some() +} + +/// Determine if a given graph is bipartite +/// +/// :param PyDiGraph graph: The graph to check if it's bipartite +/// :returns: ``True`` if the graph is bipartite and ``False`` if it is not +/// :rtype: bool +#[pyfunction] +pub fn digraph_is_bipartite(graph: digraph::PyDiGraph) -> bool { + two_color(&graph.graph).is_some() +} diff --git a/src/lib.rs b/src/lib.rs index 6f889be85..bae7d05d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -442,6 +442,10 @@ fn rustworkx(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(digraph_astar_shortest_path))?; m.add_wrapped(wrap_pyfunction!(graph_greedy_color))?; m.add_wrapped(wrap_pyfunction!(graph_greedy_edge_color))?; + m.add_wrapped(wrap_pyfunction!(graph_two_color))?; + m.add_wrapped(wrap_pyfunction!(digraph_two_color))?; + m.add_wrapped(wrap_pyfunction!(graph_is_bipartite))?; + m.add_wrapped(wrap_pyfunction!(digraph_is_bipartite))?; m.add_wrapped(wrap_pyfunction!(graph_line_graph))?; m.add_wrapped(wrap_pyfunction!(graph_tensor_product))?; m.add_wrapped(wrap_pyfunction!(digraph_tensor_product))?; diff --git a/tests/rustworkx_tests/digraph/test_bipartite.py b/tests/rustworkx_tests/digraph/test_bipartite.py new file mode 100644 index 000000000..f3e29bdde --- /dev/null +++ b/tests/rustworkx_tests/digraph/test_bipartite.py @@ -0,0 +1,76 @@ +# 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 TestBipartite(unittest.TestCase): + def test_is_bipartite(self): + graph = rustworkx.generators.directed_heavy_square_graph(5) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors(self): + graph = rustworkx.generators.directed_star_graph(5) + self.assertEqual(rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) + + def test_two_colors_reverse_direction(self): + graph = rustworkx.generators.directed_star_graph(5, inward=True) + self.assertEqual(rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) + + def test_two_colors_with_isolates(self): + graph = rustworkx.generators.directed_star_graph(5) + graph.add_nodes_from(range(3)) + self.assertEqual( + rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 1, 7: 1} + ) + + def test_is_bipartite_with_isolates(self): + graph = rustworkx.generators.directed_star_graph(5) + graph.add_nodes_from(range(3)) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors_not_biparite_with_isolates(self): + graph = rustworkx.generators.directed_complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_not_biparite_with_isolates(self): + graph = rustworkx.generators.directed_complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_not_biparite(self): + graph = rustworkx.generators.directed_complete_graph(5) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_two_color_not_biparite(self): + graph = rustworkx.generators.directed_complete_graph(5) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_grid_graph(self): + for i in range(10): + for j in range(10): + with self.subTest((i, j)): + graph = rustworkx.generators.directed_grid_graph(i, j) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_cycle_graph(self): + for i in range(20): + with self.subTest(i): + graph = rustworkx.generators.directed_cycle_graph(i) + res = rustworkx.is_bipartite(graph) + if i % 2: + self.assertFalse(res) + else: + self.assertTrue(res) diff --git a/tests/rustworkx_tests/graph/test_bipartite.py b/tests/rustworkx_tests/graph/test_bipartite.py new file mode 100644 index 000000000..59c2eb9da --- /dev/null +++ b/tests/rustworkx_tests/graph/test_bipartite.py @@ -0,0 +1,89 @@ +# 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 TestBipartite(unittest.TestCase): + def test_is_bipartite(self): + graph = rustworkx.generators.heavy_square_graph(5) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors(self): + graph = rustworkx.generators.star_graph(5) + self.assertEqual(rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) + + def test_two_colors_with_isolates(self): + graph = rustworkx.generators.star_graph(5) + graph.add_nodes_from(range(3)) + self.assertEqual( + rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 1, 7: 1} + ) + + def test_is_bipartite_with_isolates(self): + graph = rustworkx.generators.star_graph(5) + graph.add_nodes_from(range(3)) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors_not_biparite_with_isolates(self): + graph = rustworkx.generators.complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_not_biparite_with_isolates(self): + graph = rustworkx.generators.complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_not_biparite(self): + graph = rustworkx.generators.complete_graph(5) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_two_color_not_biparite(self): + graph = rustworkx.generators.complete_graph(5) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_bipartite_petersen_graph(self): + # Per Lemma 3 of https://arxiv.org/pdf/1008.3208.pdf A petersen graph is bipartite + # for any even value of n and odd value of k + for i in range(3, 30): + for j in range(30): + n = 2 * i + k = 2 * j + 1 + if n <= k * 2: + continue + + with self.subTest((n, k)): + graph = rustworkx.generators.generalized_petersen_graph(n, k) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_not_bipartite_petersen_graph(self): + # Per Lemma 3 of https://arxiv.org/pdf/1008.3208.pdf A petersen graph is bipartite + # for any even value of n and odd value of k + for n in range(3, 30): + for k in range(1, 31): + with self.subTest((2 * n, 2 * k)): + if 2 * n > k * 4: + graph = rustworkx.generators.generalized_petersen_graph(2 * n, 2 * k) + self.assertFalse(rustworkx.is_bipartite(graph)) + with self.subTest((2 * n + 1, 2 * k)): + if 2 * n + 1 > k * 4: + graph = rustworkx.generators.generalized_petersen_graph(2 * n + 1, 2 * k) + self.assertFalse(rustworkx.is_bipartite(graph)) + with self.subTest((2 * n + 1, 2 * k + 1)): + if 2 * n + 1 > k * 4 + 2: + graph = rustworkx.generators.generalized_petersen_graph( + 2 * n + 1, 2 * k + 1 + ) + self.assertFalse(rustworkx.is_bipartite(graph)) From b1537d973c0f3213c83b20996cabab9063b84265 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 16 Oct 2023 18:40:28 -0400 Subject: [PATCH 12/12] Pivot to from flake8 to ruff for Python linting (#1006) Since the start of the 0.3.x release of the retworkx project we have been using flake8 for Python linting and this has worked well for us. However, recently a new project, ruff [1][2], has shown increasing popularity becuase it provides the same linting coverage but is signficantly faster. Also just from a language solidatry PoV ruff is also written in rust. This commit migrates our linting jobs to use ruff instead of flake8 and sets up a reasonable set of rules as a starting point, which includes the rules equivalent to what we were using before with flake8, pyupgrade, and flake8-pyi, and flake8-quotes. [1] https://docs.astral.sh/ruff/ [2] https://github.com/astral-sh/ruff Co-authored-by: Ivan Carvalho <8753214+IvanIsCoding@users.noreply.github.com> --- .github/workflows/main.yml | 4 +- pyproject.toml | 29 +++++++ rustworkx/digraph.pyi | 76 +++++++++---------- rustworkx/graph.pyi | 60 +++++++-------- rustworkx/iterators.pyi | 24 +++--- setup.py | 18 ++--- tests/rustworkx_tests/digraph/test_dot.py | 2 +- .../rustworkx_tests/digraph/test_edgelist.py | 4 +- tests/rustworkx_tests/digraph/test_layout.py | 5 +- tests/rustworkx_tests/graph/test_dot.py | 2 +- tests/rustworkx_tests/graph/test_edgelist.py | 4 +- tests/rustworkx_tests/graph/test_layout.py | 5 +- .../graph/test_max_weight_matching.py | 15 ++-- .../test_substitute_node_with_subgraph.py | 2 +- .../test_custom_return_types.py | 2 +- tox.ini | 15 +--- 16 files changed, 136 insertions(+), 131 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b55878ce4..82b591d60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: 3.8 - - run: pip install -U flake8 black~=22.0 + - run: pip install -U ruff black~=22.0 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt @@ -38,7 +38,7 @@ jobs: - name: Black Codestyle Format run: black --check --diff retworkx rustworkx retworkx tests - name: Python Lint - run: flake8 --per-file-ignores='retworkx/__init__.py:F405,F403' setup.py retworkx tests rustworkx + run: ruff check rustworkx retworkx setup.py tests - name: Check stray release notes run: python tools/find_stray_release_notes.py - name: rustworkx-core Rust Tests diff --git a/pyproject.toml b/pyproject.toml index 4aee0fecb..4a913c495 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,35 @@ build-backend = "setuptools.build_meta" line-length = 100 target-version = ['py38', 'py39', 'py310', 'py311'] +[tool.ruff] +line-length = 100 +src = ["rustworkx", "setup.py", "retworkx", "tests"] +select = [ + "E", # pycodestyle + "F", # pyflakes + "UP", # pyupgrade + "PYI", # flake8-pyi + "Q", # flake8-quotes +] +target-version = "py38" +exclude = [ + ".venv", + ".git", + ".tox", + ".eggs", + "dist", + "doc", + "build", +] + +[tool.ruff.per-file-ignores] +"rustworkx/__init__.py" = ["F405", "F403"] +"rustworkx/__init__.pyi" = ["F403", "F405", "PYI001"] +"rustworkx/digraph.pyi" = ["F403", "F405", "PYI001"] +"rustworkx/graph.pyi" = ["F403", "F405", "PYI001"] +"rustworkx/iterators.pyi" = ["F403", "F405", "PYI001"] +"rustworkx/rustworkx.pyi" = ["F403", "F405", "PYI001"] + [tool.cibuildwheel] manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" diff --git a/rustworkx/digraph.pyi b/rustworkx/digraph.pyi index 13735b5fc..1eb54a083 100644 --- a/rustworkx/digraph.pyi +++ b/rustworkx/digraph.pyi @@ -13,7 +13,7 @@ import numpy as np from .iterators import * from .graph import PyGraph -from typing import Any, Callable, Dict, Generic, TypeVar, Optional, List, Tuple, Sequence +from typing import Any, Callable, Generic, TypeVar, Sequence __all__ = ["PyDiGraph"] @@ -33,36 +33,36 @@ class PyDiGraph(Generic[S, T]): def add_edge(self, parent: int, child: int, edge: T, /) -> int: ... def add_edges_from( self, - obj_list: Sequence[Tuple[int, int, T]], + obj_list: Sequence[tuple[int, int, T]], /, - ) -> List[int]: ... + ) -> list[int]: ... def add_edges_from_no_data( - self: PyDiGraph[S, Optional[T]], obj_list: Sequence[Tuple[int, int]], / - ) -> List[int]: ... + self: PyDiGraph[S, T | None], obj_list: Sequence[tuple[int, int]], / + ) -> list[int]: ... def add_node(self, obj: S, /) -> int: ... def add_nodes_from(self, obj_list: Sequence[S], /) -> NodeIndices: ... def add_parent(self, child: int, obj: S, edge: T, /) -> int: ... - def adj(self, node: int, /) -> Dict[int, T]: ... - def adj_direction(self, node: int, direction: bool, /) -> Dict[int, T]: ... + def adj(self, node: int, /) -> dict[int, T]: ... + def adj_direction(self, node: int, direction: bool, /) -> dict[int, T]: ... def compose( self, other: PyDiGraph[S, T], - node_map: Dict[int, Tuple[int, T]], + node_map: dict[int, tuple[int, T]], /, - node_map_func: Optional[Callable[[S], int]] = ..., - edge_map_func: Optional[Callable[[T], int]] = ..., - ) -> Dict[int, int]: ... + node_map_func: Callable[[S], int] | None = ..., + edge_map_func: Callable[[T], int] | None = ..., + ) -> dict[int, int]: ... def copy(self) -> PyDiGraph[S, T]: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... - def edges(self) -> List[T]: ... + def edges(self) -> list[T]: ... def extend_from_edge_list( - self: PyDiGraph[Optional[S], Optional[T]], edge_list: Sequence[Tuple[int, int]], / + self: PyDiGraph[S | None, T | None], edge_list: Sequence[tuple[int, int]], / ) -> None: ... def extend_from_weighted_edge_list( - self: PyDiGraph[Optional[S], T], - edge_list: Sequence[Tuple[int, int, T]], + self: PyDiGraph[S | None, T], + edge_list: Sequence[tuple[int, int, T]], /, ) -> None: ... def find_adjacent_node_by_edge(self, node: int, predicate: Callable[[T], bool], /) -> S: ... @@ -70,11 +70,11 @@ class PyDiGraph(Generic[S, T]): self, obj: Callable[[S], bool], /, - ) -> Optional[int]: ... + ) -> int | None: ... def find_predecessors_by_edge( self, node: int, filter_fn: Callable[[T], bool], / - ) -> List[S]: ... - def find_successors_by_edge(self, node: int, filter_fn: Callable[[T], bool], /) -> List[S]: ... + ) -> list[S]: ... + def find_successors_by_edge(self, node: int, filter_fn: Callable[[T], bool], /) -> list[S]: ... @staticmethod def from_adjacency_matrix( matrix: np.ndarray, /, null_value: float = ... @@ -83,7 +83,7 @@ class PyDiGraph(Generic[S, T]): def from_complex_adjacency_matrix( matrix: np.ndarray, /, null_value: complex = ... ) -> PyDiGraph[int, complex]: ... - def get_all_edge_data(self, node_a: int, node_b: int, /) -> List[T]: ... + def get_all_edge_data(self, node_a: int, node_b: int, /) -> list[T]: ... def get_edge_data(self, node_a: int, node_b: int, /) -> T: ... def get_node_data(self, node: int, /) -> S: ... def has_edge(self, node_a: int, node_b: int, /) -> bool: ... @@ -97,31 +97,31 @@ class PyDiGraph(Generic[S, T]): def merge_nodes(self, u: int, v: int, /) -> None: ... def neighbors(self, node: int, /) -> NodeIndices: ... def node_indexes(self) -> NodeIndices: ... - def nodes(self) -> List[S]: ... + def nodes(self) -> list[S]: ... def num_edges(self) -> int: ... def num_nodes(self) -> int: ... def out_degree(self, node: int, /) -> int: ... def out_edges(self, node: int, /) -> WeightedEdgeList[T]: ... def predecessor_indices(self, node: int, /) -> NodeIndices: ... - def predecessors(self, node: int, /) -> List[S]: ... + def predecessors(self, node: int, /) -> list[S]: ... @staticmethod def read_edge_list( path: str, /, - comment: Optional[str] = ..., - deliminator: Optional[str] = ..., + comment: str | None = ..., + deliminator: str | None = ..., labels: bool = ..., ) -> PyDiGraph: ... def remove_edge(self, parent: int, child: int, /) -> None: ... def remove_edge_from_index(self, edge: int, /) -> None: ... - def remove_edges_from(self, index_list: Sequence[Tuple[int, int]], /) -> None: ... + def remove_edges_from(self, index_list: Sequence[tuple[int, int]], /) -> None: ... def remove_node(self, node: int, /) -> None: ... def remove_node_retain_edges( self, node: int, /, - use_outgoing: Optional[bool] = ..., - condition: Optional[Callable[[S, S], bool]] = ..., + use_outgoing: bool | None = ..., + condition: Callable[[S, S], bool] | None = ..., ) -> None: ... def remove_nodes_from(self, index_list: Sequence[int], /) -> None: ... def subgraph(self, nodes: Sequence[int], /, preserve_attrs: bool = ...) -> PyDiGraph[S, T]: ... @@ -129,26 +129,26 @@ class PyDiGraph(Generic[S, T]): self, node: int, other: PyDiGraph[S, T], - edge_map_fn: Callable[[int, int, T], Optional[int]], + edge_map_fn: Callable[[int, int, T], int | None], /, - node_filter: Optional[Callable[[S], bool]] = ..., - edge_weight_map: Optional[Callable[[T], T]] = ..., + node_filter: Callable[[S], bool] | None = ..., + edge_weight_map: Callable[[T], T] | None = ..., ) -> NodeMap: ... def successor_indices(self, node: int, /) -> NodeIndices: ... - def successors(self, node: int, /) -> List[S]: ... + def successors(self, node: int, /) -> list[S]: ... def to_dot( self, /, - node_attr: Optional[Callable[[S], Dict[str, str]]] = ..., - edge_attr: Optional[Callable[[T], Dict[str, str]]] = ..., - graph_attr: Optional[Dict[str, str]] = ..., - filename: Optional[str] = ..., - ) -> Optional[str]: ... + node_attr: Callable[[S], dict[str, str]] | None = ..., + edge_attr: Callable[[T], dict[str, str]] | None = ..., + graph_attr: dict[str, str] | None = ..., + filename: str | None = ..., + ) -> str | None: ... def to_undirected( self, /, multigraph: bool = ..., - weight_combo_fn: Optional[Callable[[T, T], T]] = ..., + weight_combo_fn: Callable[[T, T], T] | None = ..., ) -> PyGraph[S, T]: ... def update_edge( self, @@ -163,8 +163,8 @@ class PyDiGraph(Generic[S, T]): self, path: str, /, - deliminator: Optional[str] = ..., - weight_fn: Optional[Callable[[T], str]] = ..., + deliminator: str | None = ..., + weight_fn: Callable[[T], str] | None = ..., ) -> None: ... def reverse(self) -> None: ... def __delitem__(self, idx: int, /) -> None: ... diff --git a/rustworkx/graph.pyi b/rustworkx/graph.pyi index 44eb37260..e491b4c8f 100644 --- a/rustworkx/graph.pyi +++ b/rustworkx/graph.pyi @@ -15,12 +15,8 @@ from .iterators import * from typing import ( Any, Callable, - Dict, Generic, TypeVar, - Optional, - List, - Tuple, Sequence, ) @@ -35,35 +31,35 @@ class PyGraph(Generic[S, T]): def add_edge(self, node_a: int, node_b: int, edge: T, /) -> int: ... def add_edges_from( self, - obj_list: Sequence[Tuple[int, int, T]], + obj_list: Sequence[tuple[int, int, T]], /, - ) -> List[int]: ... + ) -> list[int]: ... def add_edges_from_no_data( - self: PyGraph[S, Optional[T]], obj_list: Sequence[Tuple[int, int]], / - ) -> List[int]: ... + self: PyGraph[S, T | None], obj_list: Sequence[tuple[int, int]], / + ) -> list[int]: ... def add_node(self, obj: S, /) -> int: ... def add_nodes_from(self, obj_list: Sequence[S], /) -> NodeIndices: ... - def adj(self, node: int, /) -> Dict[int, T]: ... + def adj(self, node: int, /) -> dict[int, T]: ... def compose( self, other: PyGraph[S, T], - node_map: Dict[int, Tuple[int, T]], + node_map: dict[int, tuple[int, T]], /, - node_map_func: Optional[Callable[[S], int]] = ..., - edge_map_func: Optional[Callable[[T], int]] = ..., - ) -> Dict[int, int]: ... + node_map_func: Callable[[S], int] | None = ..., + edge_map_func: Callable[[T], int] | None = ..., + ) -> dict[int, int]: ... def copy(self) -> PyGraph[S, T]: ... def degree(self, node: int, /) -> int: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... - def edges(self) -> List[T]: ... + def edges(self) -> list[T]: ... def extend_from_edge_list( - self: PyGraph[Optional[S], Optional[T]], edge_list: Sequence[Tuple[int, int]], / + self: PyGraph[S | None, T | None], edge_list: Sequence[tuple[int, int]], / ) -> None: ... def extend_from_weighted_edge_list( - self: PyGraph[Optional[S], T], - edge_list: Sequence[Tuple[int, int, T]], + self: PyGraph[S | None, T], + edge_list: Sequence[tuple[int, int, T]], /, ) -> None: ... @staticmethod @@ -74,26 +70,26 @@ class PyGraph(Generic[S, T]): def from_complex_adjacency_matrix( matrix: np.ndarray, /, null_value: complex = ... ) -> PyGraph[int, complex]: ... - def get_all_edge_data(self, node_a: int, node_b: int, /) -> List[T]: ... + def get_all_edge_data(self, node_a: int, node_b: int, /) -> list[T]: ... def get_edge_data(self, node_a: int, node_b: int, /) -> T: ... def get_node_data(self, node: int, /) -> S: ... def has_edge(self, node_a: int, node_b: int, /) -> bool: ... def neighbors(self, node: int, /) -> NodeIndices: ... def node_indexes(self) -> NodeIndices: ... - def nodes(self) -> List[S]: ... + def nodes(self) -> list[S]: ... def num_edges(self) -> int: ... def num_nodes(self) -> int: ... @staticmethod def read_edge_list( path: str, /, - comment: Optional[str] = ..., - deliminator: Optional[str] = ..., + comment: str | None = ..., + deliminator: str | None = ..., labels: bool = ..., ) -> PyGraph: ... def remove_edge(self, node_a: int, node_b: int, /) -> None: ... def remove_edge_from_index(self, edge: int, /) -> None: ... - def remove_edges_from(self, index_list: Sequence[Tuple[int, int]], /) -> None: ... + def remove_edges_from(self, index_list: Sequence[tuple[int, int]], /) -> None: ... def remove_node(self, node: int, /) -> None: ... def remove_nodes_from(self, index_list: Sequence[int], /) -> None: ... def subgraph(self, nodes: Sequence[int], /, preserve_attrs: bool = ...) -> PyGraph[S, T]: ... @@ -101,19 +97,19 @@ class PyGraph(Generic[S, T]): self, node: int, other: PyGraph[S, T], - edge_map_fn: Callable[[int, int, T], Optional[int]], + edge_map_fn: Callable[[int, int, T], int | None], /, - node_filter: Optional[Callable[[S], bool]] = ..., - edge_weight_map: Optional[Callable[[T], T]] = ..., + node_filter: Callable[[S], bool] | None = ..., + edge_weight_map: Callable[[T], T] | None = ..., ) -> NodeMap: ... def to_dot( self, /, - node_attr: Optional[Callable[[S], Dict[str, str]]] = ..., - edge_attr: Optional[Callable[[T], Dict[str, str]]] = ..., - graph_attr: Optional[Dict[str, str]] = ..., - filename: Optional[str] = ..., - ) -> Optional[str]: ... + node_attr: Callable[[S], dict[str, str]] | None = ..., + edge_attr: Callable[[T], dict[str, str]] | None = ..., + graph_attr: dict[str, str] | None = ..., + filename: str | None = ..., + ) -> str | None: ... def update_edge( self, source: int, @@ -127,8 +123,8 @@ class PyGraph(Generic[S, T]): self, path: str, /, - deliminator: Optional[str] = ..., - weight_fn: Optional[Callable[[T], str]] = ..., + deliminator: str | None = ..., + weight_fn: Callable[[T], str] | None = ..., ) -> None: ... def __delitem__(self, idx: int, /) -> None: ... def __getitem__(self, idx: int, /) -> S: ... diff --git a/rustworkx/iterators.pyi b/rustworkx/iterators.pyi index e0d32c2f8..20779aa18 100644 --- a/rustworkx/iterators.pyi +++ b/rustworkx/iterators.pyi @@ -12,18 +12,14 @@ from typing import ( Any, Generic, - List, - Dict, ItemsView, KeysView, ValuesView, Iterator, Mapping, TypeVar, - Tuple, overload, final, - Optional, ) from abc import ABC from collections.abc import Sequence @@ -65,11 +61,10 @@ class RustworkxCustomVecIter(Generic[T_co], Sequence[T_co], ABC): def __getitem__(self: Self, index: slice) -> Self: ... def __getstate__(self) -> Any: ... def __hash__(self) -> int: ... - def __str__(self) -> str: ... def __len__(self) -> int: ... def __ne__(self, other: object) -> bool: ... def __setstate__(self, state: Sequence[T_co]) -> None: ... - def __array__(self, _dt: Optional[np.dtype] = ...) -> np.ndarray: ... + def __array__(self, _dt: np.dtype | None = ...) -> np.ndarray: ... class RustworkxCustomHashMapIter(Generic[S, T_co], Mapping[S, T_co], ABC): def __init__(self) -> None: ... @@ -81,7 +76,6 @@ class RustworkxCustomHashMapIter(Generic[S, T_co], Mapping[S, T_co], ABC): def __getitem__(self, index: S) -> T_co: ... def __getstate__(self) -> Any: ... def __hash__(self) -> int: ... - def __str__(self) -> str: ... def __iter__(self) -> Iterator[S]: ... def __len__(self) -> int: ... def __ne__(self, other: object) -> bool: ... @@ -103,10 +97,10 @@ class AllPairsPathLengthMapping(RustworkxCustomHashMapIter[int, PathLengthMappin class AllPairsPathMapping(RustworkxCustomHashMapIter[int, PathMapping]): ... @final -class BFSSuccessors(Generic[T_co], RustworkxCustomVecIter[Tuple[T_co, List[T_co]]]): ... +class BFSSuccessors(Generic[T_co], RustworkxCustomVecIter[tuple[T_co, list[T_co]]]): ... @final -class EdgeIndexMap(Generic[T_co], RustworkxCustomHashMapIter[int, Tuple[int, int, T_co]]): ... +class EdgeIndexMap(Generic[T_co], RustworkxCustomHashMapIter[int, tuple[int, int, T_co]]): ... @final class EdgeIndices(RustworkxCustomVecIter[int]): ... @@ -115,7 +109,7 @@ class EdgeIndices(RustworkxCustomVecIter[int]): ... class Chains(RustworkxCustomVecIter[EdgeIndices]): ... @final -class EdgeList(RustworkxCustomVecIter[Tuple[int, int]]): ... +class EdgeList(RustworkxCustomVecIter[tuple[int, int]]): ... @final class NodeMap(RustworkxCustomHashMapIter[int, int]): ... @@ -124,22 +118,22 @@ class NodeMap(RustworkxCustomHashMapIter[int, int]): ... class NodesCountMapping(RustworkxCustomHashMapIter[int, int]): ... @final -class Pos2DMapping(RustworkxCustomHashMapIter[int, Tuple[float, float]]): ... +class Pos2DMapping(RustworkxCustomHashMapIter[int, tuple[float, float]]): ... @final -class WeightedEdgeList(Generic[T_co], RustworkxCustomVecIter[Tuple[int, int, T_co]]): ... +class WeightedEdgeList(Generic[T_co], RustworkxCustomVecIter[tuple[int, int, T_co]]): ... @final class CentralityMapping(RustworkxCustomHashMapIter[int, float]): ... @final -class BiconnectedComponents(RustworkxCustomHashMapIter[Tuple[int, int], int]): ... +class BiconnectedComponents(RustworkxCustomHashMapIter[tuple[int, int], int]): ... @final -class ProductNodeMap(RustworkxCustomHashMapIter[Tuple[int, int], int]): ... +class ProductNodeMap(RustworkxCustomHashMapIter[tuple[int, int], int]): ... @final -class MultiplePathMapping(RustworkxCustomHashMapIter[int, List[List[int]]]): ... +class MultiplePathMapping(RustworkxCustomHashMapIter[int, list[list[int]]]): ... @final class AllPairsMultiplePathMapping(RustworkxCustomHashMapIter[int, MultiplePathMapping]): ... diff --git a/setup.py b/setup.py index f9ba66454..7c0eac95d 100644 --- a/setup.py +++ b/setup.py @@ -18,17 +18,17 @@ def readme(): - with open('README.md') as f: + with open("README.md") as f: return f.read() -mpl_extras = ['matplotlib>=3.0'] -graphviz_extras = ['pillow>=5.4'] +mpl_extras = ["matplotlib>=3.0"] +graphviz_extras = ["pillow>=5.4"] -PKG_NAME = os.getenv('RUSTWORKX_PKG_NAME', "rustworkx") +PKG_NAME = os.getenv("RUSTWORKX_PKG_NAME", "rustworkx") PKG_VERSION = "0.14.0" PKG_PACKAGES = ["rustworkx", "rustworkx.visualization"] -PKG_INSTALL_REQUIRES = ['numpy>=1.16.0'] +PKG_INSTALL_REQUIRES = ["numpy>=1.16.0"] RUST_EXTENSIONS = [RustExtension("rustworkx.rustworkx", "Cargo.toml", binding=Binding.PyO3, debug=rustworkx_debug)] @@ -55,7 +55,7 @@ def readme(): version=PKG_VERSION, description="A python graph library implemented in Rust", long_description=README, - long_description_content_type='text/markdown', + long_description_content_type="text/markdown", author="Matthew Treinish", author_email="mtreinish@kortar.org", license="Apache 2.0", @@ -88,8 +88,8 @@ def readme(): python_requires=">=3.8", install_requires=PKG_INSTALL_REQUIRES, extras_require={ - 'mpl': mpl_extras, - 'graphviz': graphviz_extras, - 'all': mpl_extras + graphviz_extras, + "mpl": mpl_extras, + "graphviz": graphviz_extras, + "all": mpl_extras + graphviz_extras, } ) diff --git a/tests/rustworkx_tests/digraph/test_dot.py b/tests/rustworkx_tests/digraph/test_dot.py index 64957ef04..f2dc98428 100644 --- a/tests/rustworkx_tests/digraph/test_dot.py +++ b/tests/rustworkx_tests/digraph/test_dot.py @@ -50,7 +50,7 @@ def test_digraph_to_dot_to_file(self): res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) self.addCleanup(os.remove, self.path) self.assertIsNone(res) - with open(self.path, "r") as fd: + with open(self.path) as fd: res = fd.read() self.assertEqual(expected, res) diff --git a/tests/rustworkx_tests/digraph/test_edgelist.py b/tests/rustworkx_tests/digraph/test_edgelist.py index d47d9f781..d51a08c29 100644 --- a/tests/rustworkx_tests/digraph/test_edgelist.py +++ b/tests/rustworkx_tests/digraph/test_edgelist.py @@ -152,7 +152,7 @@ def test_write_edge_list_empty_digraph(self): graph = rustworkx.PyDiGraph() graph.write_edge_list(path) self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual("", edge_file.read()) def test_write_edge_list_round_trip(self): @@ -184,7 +184,7 @@ def test_custom_delim(self): 2,3 3,4 """ - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual(edge_file.read(), expected) def test_invalid_return_type_weight_fn(self): diff --git a/tests/rustworkx_tests/digraph/test_layout.py b/tests/rustworkx_tests/digraph/test_layout.py index 792557556..5d5b1a0b0 100644 --- a/tests/rustworkx_tests/digraph/test_layout.py +++ b/tests/rustworkx_tests/digraph/test_layout.py @@ -24,9 +24,8 @@ def assertLayoutEquiv(self, exp, res): rv = res[k] if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) + f"The position for node {k}, {rv}, differs from the expected " + f"position, {ev} by more than the allowed threshold of {self.thres}" ) diff --git a/tests/rustworkx_tests/graph/test_dot.py b/tests/rustworkx_tests/graph/test_dot.py index 5ab04d656..63c98804e 100644 --- a/tests/rustworkx_tests/graph/test_dot.py +++ b/tests/rustworkx_tests/graph/test_dot.py @@ -104,7 +104,7 @@ def test_graph_to_dot_to_file(self): res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) self.addCleanup(os.remove, self.path) self.assertIsNone(res) - with open(self.path, "r") as fd: + with open(self.path) as fd: res = fd.read() self.assertEqual(expected, res) diff --git a/tests/rustworkx_tests/graph/test_edgelist.py b/tests/rustworkx_tests/graph/test_edgelist.py index 95063e54f..6b4165e44 100644 --- a/tests/rustworkx_tests/graph/test_edgelist.py +++ b/tests/rustworkx_tests/graph/test_edgelist.py @@ -148,7 +148,7 @@ def test_write_edge_list_empty_digraph(self): graph = rustworkx.PyGraph() graph.write_edge_list(path) self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual("", edge_file.read()) def test_write_edge_list_round_trip(self): @@ -180,7 +180,7 @@ def test_custom_delim(self): 2,3 3,4 """ - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual(edge_file.read(), expected) def test_invalid_return_type_weight_fn(self): diff --git a/tests/rustworkx_tests/graph/test_layout.py b/tests/rustworkx_tests/graph/test_layout.py index 032857899..c656b7fe5 100644 --- a/tests/rustworkx_tests/graph/test_layout.py +++ b/tests/rustworkx_tests/graph/test_layout.py @@ -24,9 +24,8 @@ def assertLayoutEquiv(self, exp, res): rv = res[k] if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) + f"The position for node {k}, {rv}, differs from the expected " + f"position, {ev} by more than the allowed threshold of {self.thres}" ) diff --git a/tests/rustworkx_tests/graph/test_max_weight_matching.py b/tests/rustworkx_tests/graph/test_max_weight_matching.py index 29e5a3382..429036649 100644 --- a/tests/rustworkx_tests/graph/test_max_weight_matching.py +++ b/tests/rustworkx_tests/graph/test_max_weight_matching.py @@ -30,9 +30,9 @@ def compare_match_sets(self, rx_match, expected_match): for (u, v) in rx_match: if (u, v) not in expected_match and (v, u) not in expected_match: self.fail( - "Element %s and it's reverse %s not found in " - "expected output.\nrustworkx output: %s\nexpected " - "output: %s" % ((u, v), (v, u), rx_match, expected_match) + f"Element {(u, v)} and it's reverse {(v, u)} not found in " + f"expected output.\nrustworkx output: {rx_match}\nexpected " + f"output: {expected_match}" ) def compare_rx_nx_sets(self, rx_graph, rx_matches, nx_matches, seed, nx_graph): @@ -53,11 +53,10 @@ def get_nx_weight(edge): if (u, v) not in nx_matches: if (v, u) not in nx_matches: print( - "seed %s failed. Element %s and it's " - "reverse %s not found in networkx output.\nrustworkx" - " output: %s\nnetworkx output: %s\nedge list: %s\n" - "falling back to checking for a valid solution" - % ( + "seed {} failed. Element {} and it's " + "reverse {} not found in networkx output.\nrustworkx" + " output: {}\nnetworkx output: {}\nedge list: {}\n" + "falling back to checking for a valid solution".format( seed, (u, v), (v, u), diff --git a/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py b/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py index 2ddd8bf3e..e76f1f56c 100644 --- a/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py +++ b/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py @@ -34,7 +34,7 @@ def test_single_node(self): def test_node_filter(self): in_graph = rustworkx.generators.complete_graph(5) res = self.graph.substitute_node_with_subgraph( - 0, in_graph, lambda _, __, ___: 2, node_filter=lambda node: node == None + 0, in_graph, lambda _, __, ___: 2, node_filter=lambda node: node is None ) self.assertEqual(res, {i: i + 5 for i in range(5)}) self.assertEqual( diff --git a/tests/rustworkx_tests/test_custom_return_types.py b/tests/rustworkx_tests/test_custom_return_types.py index 2362f125b..48aeb7c0a 100644 --- a/tests/rustworkx_tests/test_custom_return_types.py +++ b/tests/rustworkx_tests/test_custom_return_types.py @@ -1175,7 +1175,7 @@ def test_index_error(self): def test_keys(self): keys = rustworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).keys() - self.assertEqual([0, 1], list(sorted((keys)))) + self.assertEqual([0, 1], list(sorted(keys))) def test_values(self): values = rustworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).values() diff --git a/tox.ini b/tox.ini index 12f6d1ec8..82ee34eaa 100644 --- a/tox.ini +++ b/tox.ini @@ -33,12 +33,12 @@ commands = basepython = python3 deps = black~=22.0 - flake8 + ruff setuptools-rust whitelist_externals=cargo commands = black --check --diff {posargs} '../rustworkx' '../tests' '../retworkx' - flake8 --per-file-ignores='../rustworkx/__init__.py:F405,F403' ../setup.py ../rustworkx ../retworkx . + ruff check ../rustworkx ../retworkx . ../setup.py cargo fmt --all -- --check python {toxinidir}/tools/find_stray_release_notes.py @@ -77,14 +77,3 @@ basepython = python3 deps = mypy==1.0.1 commands = python -m mypy.stubtest --concise --ignore-missing-stub rustworkx.rustworkx - -[flake8] -# E125 is deliberately excluded. See https://github.com/jcrocholl/pep8/issues/126 -# E123 skipped because it is ignored by default in the default pep8 -# E129 skipped because it is too limiting when combined with other rules -# E711 skipped because sqlalchemy filter() requires using == instead of is -# max-line-length, E203, W503 are added for black compatibility -max-line-length = 110 -ignore = E125,E123,E129,E711 -extend-ignore = E203, W503 -exclude = .venv,.git,.tox,dist,doc,*egg,build