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}