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 petgraph::graph::IndexType;
68use petgraph::graphmap::{GraphMap, NodeTrait};
69use petgraph::matrix_graph::{MatrixGraph, Nullable};
70use petgraph::stable_graph::StableGraph;
71use petgraph::visit::{Data, IntoNodeIdentifiers};
72use petgraph::{EdgeType, Graph};
73
74pub mod contraction;
75pub mod multigraph;
76
77pub use contraction::{
78 ContractNodesDirected, ContractNodesSimpleDirected, ContractNodesSimpleUndirected,
79 ContractNodesUndirected,
80};
81pub use multigraph::{HasParallelEdgesDirected, HasParallelEdgesUndirected};
82
83/// A graph whose nodes may be removed.
84pub trait NodeRemovable: Data {
85 type Output;
86 fn remove_node(&mut self, node: Self::NodeId) -> Self::Output;
87}
88
89impl<N, E, Ty, Ix> NodeRemovable for StableGraph<N, E, Ty, Ix>
90where
91 Ty: EdgeType,
92 Ix: IndexType,
93{
94 type Output = Option<Self::NodeWeight>;
95 fn remove_node(&mut self, node: Self::NodeId) -> Option<Self::NodeWeight> {
96 self.remove_node(node)
97 }
98}
99
100impl<N, E, Ty, Ix> NodeRemovable for Graph<N, E, Ty, Ix>
101where
102 Ty: EdgeType,
103 Ix: IndexType,
104{
105 type Output = Option<Self::NodeWeight>;
106 fn remove_node(&mut self, node: Self::NodeId) -> Option<Self::NodeWeight> {
107 self.remove_node(node)
108 }
109}
110
111impl<N, E, Ty> NodeRemovable for GraphMap<N, E, Ty>
112where
113 N: NodeTrait,
114 Ty: EdgeType,
115{
116 type Output = bool;
117 fn remove_node(&mut self, node: Self::NodeId) -> Self::Output {
118 self.remove_node(node)
119 }
120}
121
122impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> NodeRemovable
123 for MatrixGraph<N, E, Ty, Null, Ix>
124{
125 type Output = Option<Self::NodeWeight>;
126 fn remove_node(&mut self, node: Self::NodeId) -> Self::Output {
127 for n in self.node_identifiers() {
128 if node == n {
129 return Some(self.remove_node(node));
130 }
131 }
132 None
133 }
134}
135
136/// A graph whose edge may be removed by an edge id.
137pub trait EdgeRemovable: Data {
138 type Output;
139 fn remove_edge(&mut self, edge: Self::EdgeId) -> Self::Output;
140}
141
142impl<N, E, Ty, Ix> EdgeRemovable for StableGraph<N, E, Ty, Ix>
143where
144 Ty: EdgeType,
145 Ix: IndexType,
146{
147 type Output = Option<Self::EdgeWeight>;
148 fn remove_edge(&mut self, edge: Self::EdgeId) -> Option<Self::EdgeWeight> {
149 self.remove_edge(edge)
150 }
151}
152
153impl<N, E, Ty, Ix> EdgeRemovable for Graph<N, E, Ty, Ix>
154where
155 Ty: EdgeType,
156 Ix: IndexType,
157{
158 type Output = Option<Self::EdgeWeight>;
159 fn remove_edge(&mut self, edge: Self::EdgeId) -> Option<Self::EdgeWeight> {
160 self.remove_edge(edge)
161 }
162}
163
164/// A graph that can find edges by a pair of node ids.
165pub trait EdgeFindable: Data {
166 fn edge_find(&self, a: Self::NodeId, b: Self::NodeId) -> Option<Self::EdgeId>;
167}
168
169impl<N, E, Ty, Ix> EdgeFindable for &StableGraph<N, E, Ty, Ix>
170where
171 Ty: EdgeType,
172 Ix: IndexType,
173{
174 fn edge_find(&self, a: Self::NodeId, b: Self::NodeId) -> Option<Self::EdgeId> {
175 self.find_edge(a, b)
176 }
177}
178
179impl<N, E, Ty, Ix> EdgeFindable for &Graph<N, E, Ty, Ix>
180where
181 Ty: EdgeType,
182 Ix: IndexType,
183{
184 fn edge_find(&self, a: Self::NodeId, b: Self::NodeId) -> Option<Self::EdgeId> {
185 self.find_edge(a, b)
186 }
187}