problemreductions/topology/
directed_graph.rs1use petgraph::algo::{kosaraju_scc, toposort};
17use petgraph::graph::{DiGraph, NodeIndex};
18use petgraph::visit::EdgeRef;
19use serde::{Deserialize, Serialize};
20
21#[derive(Debug, Clone)]
40pub struct DirectedGraph {
41 inner: DiGraph<(), ()>,
42}
43
44impl DirectedGraph {
45 pub fn new(num_vertices: usize, arcs: Vec<(usize, usize)>) -> Self {
56 Self::try_new(num_vertices, arcs).unwrap_or_else(|error| panic!("{error}"))
57 }
58
59 fn try_new(
60 num_vertices: usize,
61 arcs: Vec<(usize, usize)>,
62 ) -> Result<Self, crate::registry::ConstructionError> {
63 let mut inner = DiGraph::new();
64 for _ in 0..num_vertices {
65 inner.add_node(());
66 }
67 for (u, v) in arcs {
68 if !(u < num_vertices && v < num_vertices) {
69 return Err(format!(
70 "arc ({}, {}) references vertex >= num_vertices ({})",
71 u, v, num_vertices
72 )
73 .into());
74 }
75 inner.add_edge(NodeIndex::new(u), NodeIndex::new(v), ());
76 }
77 Ok(Self { inner })
78 }
79
80 pub fn empty(num_vertices: usize) -> Self {
82 Self::new(num_vertices, vec![])
83 }
84
85 pub fn num_vertices(&self) -> usize {
87 self.inner.node_count()
88 }
89
90 pub fn num_arcs(&self) -> usize {
92 self.inner.edge_count()
93 }
94
95 pub fn arcs(&self) -> Vec<(usize, usize)> {
97 self.inner
98 .edge_references()
99 .map(|e| (e.source().index(), e.target().index()))
100 .collect()
101 }
102
103 pub fn has_arc(&self, u: usize, v: usize) -> bool {
105 self.inner
106 .find_edge(NodeIndex::new(u), NodeIndex::new(v))
107 .is_some()
108 }
109
110 pub fn successors(&self, v: usize) -> Vec<usize> {
114 self.inner
115 .neighbors(NodeIndex::new(v))
116 .map(|n| n.index())
117 .collect()
118 }
119
120 pub fn predecessors(&self, v: usize) -> Vec<usize> {
124 self.inner
125 .neighbors_directed(NodeIndex::new(v), petgraph::Incoming)
126 .map(|n| n.index())
127 .collect()
128 }
129
130 pub fn out_degree(&self, v: usize) -> usize {
132 self.successors(v).len()
133 }
134
135 pub fn in_degree(&self, v: usize) -> usize {
137 self.predecessors(v).len()
138 }
139
140 pub fn is_empty(&self) -> bool {
142 self.num_vertices() == 0
143 }
144
145 pub fn is_dag(&self) -> bool {
150 toposort(&self.inner, None).is_ok()
151 }
152
153 pub fn is_strongly_connected(&self) -> bool {
155 kosaraju_scc(&self.inner).len() <= 1
156 }
157
158 pub fn is_acyclic_subgraph(&self, kept_arcs: &[bool]) -> bool {
166 assert_eq!(
167 kept_arcs.len(),
168 self.num_arcs(),
169 "kept_arcs slice length must equal num_arcs"
170 );
171 let n = self.num_vertices();
172 let arcs = self.arcs();
173
174 let mut adj = vec![vec![]; n];
176 let mut in_degree = vec![0usize; n];
177 for (i, &(u, v)) in arcs.iter().enumerate() {
178 if kept_arcs[i] {
179 adj[u].push(v);
180 in_degree[v] += 1;
181 }
182 }
183
184 let mut queue: Vec<usize> = (0..n).filter(|&v| in_degree[v] == 0).collect();
186 let mut visited = 0;
187 while let Some(u) = queue.pop() {
188 visited += 1;
189 for &v in &adj[u] {
190 in_degree[v] -= 1;
191 if in_degree[v] == 0 {
192 queue.push(v);
193 }
194 }
195 }
196 visited == n
197 }
198
199 pub fn induced_subgraph(&self, keep: &[bool]) -> Self {
209 assert_eq!(
210 keep.len(),
211 self.num_vertices(),
212 "keep slice length must equal num_vertices"
213 );
214
215 let mut new_index = vec![usize::MAX; self.num_vertices()];
217 let mut count = 0;
218 for (v, &kept) in keep.iter().enumerate() {
219 if kept {
220 new_index[v] = count;
221 count += 1;
222 }
223 }
224
225 let new_arcs: Vec<(usize, usize)> = self
226 .arcs()
227 .into_iter()
228 .filter(|&(u, v)| keep[u] && keep[v])
229 .map(|(u, v)| (new_index[u], new_index[v]))
230 .collect();
231
232 Self::new(count, new_arcs)
233 }
234}
235
236impl PartialEq for DirectedGraph {
237 fn eq(&self, other: &Self) -> bool {
238 if self.num_vertices() != other.num_vertices() {
239 return false;
240 }
241 if self.num_arcs() != other.num_arcs() {
242 return false;
243 }
244 let mut self_arcs = self.arcs();
245 let mut other_arcs = other.arcs();
246 self_arcs.sort();
247 other_arcs.sort();
248 self_arcs == other_arcs
249 }
250}
251
252impl Eq for DirectedGraph {}
253
254impl Serialize for DirectedGraph {
255 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
256 use serde::ser::SerializeStruct;
257 let mut state = serializer.serialize_struct("DirectedGraph", 2)?;
258 state.serialize_field("num_vertices", &self.num_vertices())?;
259 let arcs: Vec<(usize, usize)> = self.arcs();
260 state.serialize_field("arcs", &arcs)?;
261 state.end()
262 }
263}
264
265impl<'de> Deserialize<'de> for DirectedGraph {
266 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
267 #[derive(Deserialize)]
268 struct GraphData {
269 num_vertices: usize,
270 arcs: Vec<(usize, usize)>,
271 }
272 let data = GraphData::deserialize(deserializer)?;
273 DirectedGraph::try_new(data.num_vertices, data.arcs).map_err(serde::de::Error::custom)
274 }
275}
276
277use crate::impl_variant_param;
278impl_variant_param!(DirectedGraph, "graph");
279
280#[cfg(test)]
281#[path = "../unit_tests/topology/directed_graph.rs"]
282mod tests;