From 21456e3020214052827e6031fb8689fb2b55ce65 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Tue, 16 Jan 2024 12:48:46 +0100 Subject: [PATCH 1/6] add edge_indices_from_endpoints for graph and digraph --- rustworkx/digraph.pyi | 1 + rustworkx/graph.pyi | 1 + src/digraph.rs | 19 +++++++++++++++++++ src/graph.rs | 19 +++++++++++++++++++ tests/rustworkx_tests/digraph/test_edges.py | 21 +++++++++++++++++++++ tests/rustworkx_tests/graph/test_edges.py | 20 ++++++++++++++++++++ 6 files changed, 81 insertions(+) diff --git a/rustworkx/digraph.pyi b/rustworkx/digraph.pyi index ae470846f..d597531eb 100644 --- a/rustworkx/digraph.pyi +++ b/rustworkx/digraph.pyi @@ -68,6 +68,7 @@ class PyDiGraph(Generic[S, T]): def copy(self) -> PyDiGraph[S, T]: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... + def edge_indices_from_endpoints(self, int, int) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... def edges(self) -> list[T]: ... def edge_subgraph(self, edge_list: Sequence[tuple[int, int]], /) -> PyDiGraph[S, T]: ... diff --git a/rustworkx/graph.pyi b/rustworkx/graph.pyi index d710f6a1d..c008bd299 100644 --- a/rustworkx/graph.pyi +++ b/rustworkx/graph.pyi @@ -66,6 +66,7 @@ class PyGraph(Generic[S, T]): def degree(self, node: int, /) -> int: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... + def edge_indices_from_endpoints(self, int, int) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... def edges(self) -> list[T]: ... def edge_subgraph(self, edge_list: Sequence[tuple[int, int]], /) -> PyGraph[S, T]: ... diff --git a/src/digraph.rs b/src/digraph.rs index 2d8a97d18..f21b956c9 100644 --- a/src/digraph.rs +++ b/src/digraph.rs @@ -547,6 +547,25 @@ impl PyDiGraph { } } + /// Return a list of indices of all directed edges between specified nodes + /// + /// :returns: A list of all the edge indices connecting the specified start and end node + /// :rtype: EdgeIndices + #[pyo3(text_signature = "(self)")] + pub fn edge_indices_from_endpoints(&self, node_a: usize, node_b: usize) -> EdgeIndices { + let node_a_index = NodeIndex::new(node_a); + let node_b_index = NodeIndex::new(node_b); + + EdgeIndices { + edges: self + .graph + .edges_directed(node_a_index, petgraph::Direction::Outgoing) + .filter(|edge| edge.target() == node_b_index) + .map(|edge| edge.id().index()) + .collect(), + } + } + /// Return a list of all node data. /// /// :returns: A list of all the node data objects in the graph diff --git a/src/graph.rs b/src/graph.rs index 45d8902a7..f62553073 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -422,6 +422,25 @@ impl PyGraph { } } + /// Return a list of indices of all edges between specified nodes + /// + /// :returns: A list of all the edge indices connecting the specified start and end node + /// :rtype: EdgeIndices + #[pyo3(text_signature = "(self)")] + pub fn edge_indices_from_endpoints(&self, node_a: usize, node_b: usize) -> EdgeIndices { + let node_a_index = NodeIndex::new(node_a); + let node_b_index = NodeIndex::new(node_b); + + EdgeIndices { + edges: self + .graph + .edges_directed(node_a_index, petgraph::Direction::Outgoing) + .filter(|edge| edge.target() == node_b_index) + .map(|edge| edge.id().index()) + .collect(), + } + } + /// Return a list of all node data. /// /// :returns: A list of all the node data objects in the graph diff --git a/tests/rustworkx_tests/digraph/test_edges.py b/tests/rustworkx_tests/digraph/test_edges.py index ef0af66dd..dc5a676b7 100644 --- a/tests/rustworkx_tests/digraph/test_edges.py +++ b/tests/rustworkx_tests/digraph/test_edges.py @@ -370,6 +370,27 @@ def test_weighted_edge_list_empty(self): dag = rustworkx.PyDiGraph() self.assertEqual([], dag.weighted_edge_list()) + def test_edge_indices_from_endpoints(self): + dag = rustworkx.PyDiGraph() + dag.add_nodes_from(list(range(4))) + edge_list = [ + (0, 1), + (1, 2), + (0, 2), + (2, 3), + (0, 3), + (0, 2), + ] + dag.add_edges_from(edge_list) + indices = dag.edge_indices_from_endpoints(0, 0) + self.assertEqual(indices, []) + indices = dag.edge_indices_from_endpoints(0, 1) + self.assertEqual(indices, [0]) + indices = dag.edge_indices_from_endpoints(0, 2) + self.assertEqual(indices, [2, 5]) + + + def test_extend_from_edge_list(self): dag = rustworkx.PyDAG() edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] diff --git a/tests/rustworkx_tests/graph/test_edges.py b/tests/rustworkx_tests/graph/test_edges.py index 04f24af1a..cbfee5b1d 100644 --- a/tests/rustworkx_tests/graph/test_edges.py +++ b/tests/rustworkx_tests/graph/test_edges.py @@ -331,6 +331,26 @@ def test_weighted_edge_list_empty(self): graph = rustworkx.PyGraph() self.assertEqual([], graph.weighted_edge_list()) + def test_edge_indices_from_endpoints(self): + dag = rustworkx.PyGraph() + dag.add_nodes_from(list(range(4))) + edge_list = [ + (0, 1, None), + (1, 2, None), + (0, 2, None), + (2, 3, None), + (0, 3, None), + (0, 2, None), + (2, 0, None), + ] + dag.add_edges_from(edge_list) + indices = dag.edge_indices_from_endpoints(0, 0) + self.assertEqual(indices, []) + indices = dag.edge_indices_from_endpoints(0, 1) + self.assertEqual(indices, [0]) + indices = dag.edge_indices_from_endpoints(0, 2) + self.assertEqual(indices, [2, 5, 6]) + def test_extend_from_edge_list(self): graph = rustworkx.PyGraph() edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] From 55e6324f99468b4e46d7bbd90fdb36f67ffc14f2 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Tue, 16 Jan 2024 12:51:25 +0100 Subject: [PATCH 2/6] fix tests --- tests/rustworkx_tests/digraph/test_edges.py | 14 +++++++------- tests/rustworkx_tests/graph/test_edges.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/rustworkx_tests/digraph/test_edges.py b/tests/rustworkx_tests/digraph/test_edges.py index dc5a676b7..0549c9ba6 100644 --- a/tests/rustworkx_tests/digraph/test_edges.py +++ b/tests/rustworkx_tests/digraph/test_edges.py @@ -374,12 +374,12 @@ def test_edge_indices_from_endpoints(self): dag = rustworkx.PyDiGraph() dag.add_nodes_from(list(range(4))) edge_list = [ - (0, 1), - (1, 2), - (0, 2), - (2, 3), - (0, 3), - (0, 2), + (0, 1, None), + (1, 2, None), + (0, 2, None), + (2, 3, None), + (0, 3, None), + (0, 2, None), ] dag.add_edges_from(edge_list) indices = dag.edge_indices_from_endpoints(0, 0) @@ -387,7 +387,7 @@ def test_edge_indices_from_endpoints(self): indices = dag.edge_indices_from_endpoints(0, 1) self.assertEqual(indices, [0]) indices = dag.edge_indices_from_endpoints(0, 2) - self.assertEqual(indices, [2, 5]) + self.assertEqual(set(indices), {2, 5}) diff --git a/tests/rustworkx_tests/graph/test_edges.py b/tests/rustworkx_tests/graph/test_edges.py index cbfee5b1d..628a9788b 100644 --- a/tests/rustworkx_tests/graph/test_edges.py +++ b/tests/rustworkx_tests/graph/test_edges.py @@ -347,9 +347,9 @@ def test_edge_indices_from_endpoints(self): indices = dag.edge_indices_from_endpoints(0, 0) self.assertEqual(indices, []) indices = dag.edge_indices_from_endpoints(0, 1) - self.assertEqual(indices, [0]) + self.assertEqual(set(indices), {0}) indices = dag.edge_indices_from_endpoints(0, 2) - self.assertEqual(indices, [2, 5, 6]) + self.assertEqual(set(indices), {2, 5, 6}) def test_extend_from_edge_list(self): graph = rustworkx.PyGraph() From 7d6c19379c26b68d604bd2b75db86f1643bc65b0 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 18 Jan 2024 21:34:53 +0100 Subject: [PATCH 3/6] Add release notes --- ...ces_from_endpoints-method-to-graph-d58dc98719c4db39.yaml | 6 ++++++ tests/rustworkx_tests/digraph/test_edges.py | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/add-edge_indices_from_endpoints-method-to-graph-d58dc98719c4db39.yaml diff --git a/releasenotes/notes/add-edge_indices_from_endpoints-method-to-graph-d58dc98719c4db39.yaml b/releasenotes/notes/add-edge_indices_from_endpoints-method-to-graph-d58dc98719c4db39.yaml new file mode 100644 index 000000000..2a7082b48 --- /dev/null +++ b/releasenotes/notes/add-edge_indices_from_endpoints-method-to-graph-d58dc98719c4db39.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added method :meth:`~rustworkx.PyGraph.edge_indices_from_endpoints` which returns the indices of all edges + between the specified endpoints. For :class:`~rustworkx.PyDiGraph` there is a corresponding method that returns the + directed edges. diff --git a/tests/rustworkx_tests/digraph/test_edges.py b/tests/rustworkx_tests/digraph/test_edges.py index 0549c9ba6..9ec06d31a 100644 --- a/tests/rustworkx_tests/digraph/test_edges.py +++ b/tests/rustworkx_tests/digraph/test_edges.py @@ -389,8 +389,6 @@ def test_edge_indices_from_endpoints(self): indices = dag.edge_indices_from_endpoints(0, 2) self.assertEqual(set(indices), {2, 5}) - - def test_extend_from_edge_list(self): dag = rustworkx.PyDAG() edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] From 7526e7437c88db529162676edb7c0d913bf53405 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 18 Jan 2024 22:55:13 +0100 Subject: [PATCH 4/6] linter --- rustworkx/digraph.pyi | 2 +- rustworkx/graph.pyi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rustworkx/digraph.pyi b/rustworkx/digraph.pyi index d597531eb..b63e0f85b 100644 --- a/rustworkx/digraph.pyi +++ b/rustworkx/digraph.pyi @@ -68,7 +68,7 @@ class PyDiGraph(Generic[S, T]): def copy(self) -> PyDiGraph[S, T]: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... - def edge_indices_from_endpoints(self, int, int) -> EdgeIndices: ... + def edge_indices_from_endpoints(self, node_a : int, node_b : int) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... def edges(self) -> list[T]: ... def edge_subgraph(self, edge_list: Sequence[tuple[int, int]], /) -> PyDiGraph[S, T]: ... diff --git a/rustworkx/graph.pyi b/rustworkx/graph.pyi index c008bd299..2271a2833 100644 --- a/rustworkx/graph.pyi +++ b/rustworkx/graph.pyi @@ -66,7 +66,7 @@ class PyGraph(Generic[S, T]): def degree(self, node: int, /) -> int: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... - def edge_indices_from_endpoints(self, int, int) -> EdgeIndices: ... + def edge_indices_from_endpoints(self, node_a : int, node_b : int) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... def edges(self) -> list[T]: ... def edge_subgraph(self, edge_list: Sequence[tuple[int, int]], /) -> PyGraph[S, T]: ... From 5846c8407886794ee0597c44992e96265aa5388c Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 18 Jan 2024 22:59:21 +0100 Subject: [PATCH 5/6] black --- rustworkx/digraph.pyi | 2 +- rustworkx/graph.pyi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rustworkx/digraph.pyi b/rustworkx/digraph.pyi index b63e0f85b..9648ca62e 100644 --- a/rustworkx/digraph.pyi +++ b/rustworkx/digraph.pyi @@ -68,7 +68,7 @@ class PyDiGraph(Generic[S, T]): def copy(self) -> PyDiGraph[S, T]: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... - def edge_indices_from_endpoints(self, node_a : int, node_b : int) -> EdgeIndices: ... + def edge_indices_from_endpoints(self, node_a: int, node_b: int) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... def edges(self) -> list[T]: ... def edge_subgraph(self, edge_list: Sequence[tuple[int, int]], /) -> PyDiGraph[S, T]: ... diff --git a/rustworkx/graph.pyi b/rustworkx/graph.pyi index 2271a2833..956c39c8c 100644 --- a/rustworkx/graph.pyi +++ b/rustworkx/graph.pyi @@ -66,7 +66,7 @@ class PyGraph(Generic[S, T]): def degree(self, node: int, /) -> int: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... - def edge_indices_from_endpoints(self, node_a : int, node_b : int) -> EdgeIndices: ... + def edge_indices_from_endpoints(self, node_a: int, node_b: int) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... def edges(self) -> list[T]: ... def edge_subgraph(self, edge_list: Sequence[tuple[int, int]], /) -> PyGraph[S, T]: ... From f8ee67e31ff579a9e3f73993f98aa9a74c36741e Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 19 Jan 2024 16:47:14 -0500 Subject: [PATCH 6/6] Fix text_signature for new method --- src/digraph.rs | 1 - src/graph.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/digraph.rs b/src/digraph.rs index f21b956c9..1afb1ba98 100644 --- a/src/digraph.rs +++ b/src/digraph.rs @@ -551,7 +551,6 @@ impl PyDiGraph { /// /// :returns: A list of all the edge indices connecting the specified start and end node /// :rtype: EdgeIndices - #[pyo3(text_signature = "(self)")] pub fn edge_indices_from_endpoints(&self, node_a: usize, node_b: usize) -> EdgeIndices { let node_a_index = NodeIndex::new(node_a); let node_b_index = NodeIndex::new(node_b); diff --git a/src/graph.rs b/src/graph.rs index f62553073..0ad81c25b 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -426,7 +426,6 @@ impl PyGraph { /// /// :returns: A list of all the edge indices connecting the specified start and end node /// :rtype: EdgeIndices - #[pyo3(text_signature = "(self)")] pub fn edge_indices_from_endpoints(&self, node_a: usize, node_b: usize) -> EdgeIndices { let node_a_index = NodeIndex::new(node_a); let node_b_index = NodeIndex::new(node_b);