rustworkx_core/graph_ext/
mod.rs

1// Licensed under the Apache License, Version 2.0 (the "License"); you may
2// not use this file except in compliance with the License. You may obtain
3// a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10// License for the specific language governing permissions and limitations
11// under the License.
12
13//! This module defines traits that extend PetGraph's graph
14//! data structures.
15//!
16//! The `-Directed` and `-Undirected` trait variants are implemented as
17//! applicable for directed and undirected graph types. For example, only
18//! directed graph types are concerned with cycle checking and corresponding
19//! error handling, so these traits provide applicable parameters and return
20//! types to account for this.
21//!
22//! ### Node Contraction
23//!
24//! There are four traits related to node contraction available for different
25//! graphs / configurations, including:
26//!
27//! - [`ContractNodesDirected`]
28//! - [`ContractNodesSimpleDirected`]
29//! - [`ContractNodesUndirected`]
30//! - [`ContractNodesSimpleUndirected`]
31//!
32//! Of these, the `ContractNodesSimple-` traits provide a
33//! `contract_nodes_simple` method for applicable graph types, which performs
34//! node contraction without introducing parallel edges between nodes (edges
35//! between any two given nodes are merged via the method's merge function).
36//! These traits can be used for node contraction within simple graphs to
37//! preserve this property, or on multi-graphs to ensure that the contraction
38//! does not introduce additional parallel edges.
39//!
40//! The other `ContractNodes-` traits provide a `contract_nodes` method, which
41//! happily introduces parallel edges when multiple nodes in the contraction
42//! have an incoming edge from the same source node or when multiple nodes in
43//! the contraction have an outgoing edge to the same target node.
44//!
45//! ### Multi-graph Extensions
46//!
47//! These traits provide additional helper methods for use with multi-graphs,
48//! e.g. [`HasParallelEdgesDirected`].
49//!
50//! ### Graph Extension Trait Implementations
51//!
52//! The following table lists the traits that are currently implemented for
53//! each graph type:
54//!
55//! |                               | Graph | StableGraph | GraphMap | MatrixGraph | Csr   | List  |
56//! | ----------------------------- | :---: | :---------: | :------: | :---------: | :---: | :---: |
57//! | ContractNodesDirected         |       |  x          |    x     |             |       |       |
58//! | ContractNodesSimpleDirected   |       |  x          |    x     |             |       |       |
59//! | ContractNodesUndirected       |       |  x          |    x     |             |       |       |
60//! | ContractNodesSimpleUndirected |       |  x          |    x     |             |       |       |
61//! | HasParallelEdgesDirected      | x     |  x          |    x     | x           | x     | x     |
62//! | HasParallelEdgesUndirected    | x     |  x          |    x     | x           | x     | x     |
63//! | NodeRemovable                 | x     |  x          |    x     | x           |       |       |
64//! | EdgeRemovable                 | x     |  x          |          |             |       |       |
65//! | EdgeFindable                  | x     |  x          |          |             |       |       |
66
67use std::hash::BuildHasher;
68
69use petgraph::graph::IndexType;
70use petgraph::graphmap::{GraphMap, NodeTrait};
71use petgraph::matrix_graph::{MatrixGraph, Nullable};
72use petgraph::stable_graph::StableGraph;
73use petgraph::visit::{Data, IntoNodeIdentifiers};
74use petgraph::{EdgeType, Graph};
75
76pub mod contraction;
77pub mod multigraph;
78
79pub use contraction::{
80    can_contract, ContractNodesDirected, ContractNodesSimpleDirected,
81    ContractNodesSimpleUndirected, ContractNodesUndirected,
82};
83pub use multigraph::{HasParallelEdgesDirected, HasParallelEdgesUndirected};
84
85/// A graph whose nodes may be removed.
86pub trait NodeRemovable: Data {
87    type Output;
88    fn remove_node(&mut self, node: Self::NodeId) -> Self::Output;
89}
90
91impl<N, E, Ty, Ix> NodeRemovable for StableGraph<N, E, Ty, Ix>
92where
93    Ty: EdgeType,
94    Ix: IndexType,
95{
96    type Output = Option<Self::NodeWeight>;
97    fn remove_node(&mut self, node: Self::NodeId) -> Option<Self::NodeWeight> {
98        self.remove_node(node)
99    }
100}
101
102impl<N, E, Ty, Ix> NodeRemovable for Graph<N, E, Ty, Ix>
103where
104    Ty: EdgeType,
105    Ix: IndexType,
106{
107    type Output = Option<Self::NodeWeight>;
108    fn remove_node(&mut self, node: Self::NodeId) -> Option<Self::NodeWeight> {
109        self.remove_node(node)
110    }
111}
112
113impl<N, E, Ty> NodeRemovable for GraphMap<N, E, Ty>
114where
115    N: NodeTrait,
116    Ty: EdgeType,
117{
118    type Output = bool;
119    fn remove_node(&mut self, node: Self::NodeId) -> Self::Output {
120        self.remove_node(node)
121    }
122}
123
124impl<N, E, S: BuildHasher, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> NodeRemovable
125    for MatrixGraph<N, E, S, Ty, Null, Ix>
126{
127    type Output = Option<Self::NodeWeight>;
128    fn remove_node(&mut self, node: Self::NodeId) -> Self::Output {
129        for n in self.node_identifiers() {
130            if node == n {
131                return Some(self.remove_node(node));
132            }
133        }
134        None
135    }
136}
137
138/// A graph whose edge may be removed by an edge id.
139pub trait EdgeRemovable: Data {
140    type Output;
141    fn remove_edge(&mut self, edge: Self::EdgeId) -> Self::Output;
142}
143
144impl<N, E, Ty, Ix> EdgeRemovable for StableGraph<N, E, Ty, Ix>
145where
146    Ty: EdgeType,
147    Ix: IndexType,
148{
149    type Output = Option<Self::EdgeWeight>;
150    fn remove_edge(&mut self, edge: Self::EdgeId) -> Option<Self::EdgeWeight> {
151        self.remove_edge(edge)
152    }
153}
154
155impl<N, E, Ty, Ix> EdgeRemovable for Graph<N, E, Ty, Ix>
156where
157    Ty: EdgeType,
158    Ix: IndexType,
159{
160    type Output = Option<Self::EdgeWeight>;
161    fn remove_edge(&mut self, edge: Self::EdgeId) -> Option<Self::EdgeWeight> {
162        self.remove_edge(edge)
163    }
164}
165
166/// A graph that can find edges by a pair of node ids.
167pub trait EdgeFindable: Data {
168    fn edge_find(&self, a: Self::NodeId, b: Self::NodeId) -> Option<Self::EdgeId>;
169}
170
171impl<N, E, Ty, Ix> EdgeFindable for &StableGraph<N, E, Ty, Ix>
172where
173    Ty: EdgeType,
174    Ix: IndexType,
175{
176    fn edge_find(&self, a: Self::NodeId, b: Self::NodeId) -> Option<Self::EdgeId> {
177        self.find_edge(a, b)
178    }
179}
180
181impl<N, E, Ty, Ix> EdgeFindable for &Graph<N, E, Ty, Ix>
182where
183    Ty: EdgeType,
184    Ix: IndexType,
185{
186    fn edge_find(&self, a: Self::NodeId, b: Self::NodeId) -> Option<Self::EdgeId> {
187        self.find_edge(a, b)
188    }
189}