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 let mut inner = DiGraph::new();
57 for _ in 0..num_vertices {
58 inner.add_node(());
59 }
60 for (u, v) in arcs {
61 assert!(
62 u < num_vertices && v < num_vertices,
63 "arc ({}, {}) references vertex >= num_vertices ({})",
64 u,
65 v,
66 num_vertices
67 );
68 inner.add_edge(NodeIndex::new(u), NodeIndex::new(v), ());
69 }
70 Self { inner }
71 }
72
73 pub fn empty(num_vertices: usize) -> Self {
75 Self::new(num_vertices, vec![])
76 }
77
78 pub fn num_vertices(&self) -> usize {
80 self.inner.node_count()
81 }
82
83 pub fn num_arcs(&self) -> usize {
85 self.inner.edge_count()
86 }
87
88 pub fn arcs(&self) -> Vec<(usize, usize)> {
90 self.inner
91 .edge_references()
92 .map(|e| (e.source().index(), e.target().index()))
93 .collect()
94 }
95
96 pub fn has_arc(&self, u: usize, v: usize) -> bool {
98 self.inner
99 .find_edge(NodeIndex::new(u), NodeIndex::new(v))
100 .is_some()
101 }
102
103 pub fn successors(&self, v: usize) -> Vec<usize> {
107 self.inner
108 .neighbors(NodeIndex::new(v))
109 .map(|n| n.index())
110 .collect()
111 }
112
113 pub fn predecessors(&self, v: usize) -> Vec<usize> {
117 self.inner
118 .neighbors_directed(NodeIndex::new(v), petgraph::Incoming)
119 .map(|n| n.index())
120 .collect()
121 }
122
123 pub fn out_degree(&self, v: usize) -> usize {
125 self.successors(v).len()
126 }
127
128 pub fn in_degree(&self, v: usize) -> usize {
130 self.predecessors(v).len()
131 }
132
133 pub fn is_empty(&self) -> bool {
135 self.num_vertices() == 0
136 }
137
138 pub fn is_dag(&self) -> bool {
143 toposort(&self.inner, None).is_ok()
144 }
145
146 pub fn is_strongly_connected(&self) -> bool {
148 kosaraju_scc(&self.inner).len() <= 1
149 }
150
151 pub fn is_acyclic_subgraph(&self, kept_arcs: &[bool]) -> bool {
159 assert_eq!(
160 kept_arcs.len(),
161 self.num_arcs(),
162 "kept_arcs slice length must equal num_arcs"
163 );
164 let n = self.num_vertices();
165 let arcs = self.arcs();
166
167 let mut adj = vec![vec![]; n];
169 let mut in_degree = vec![0usize; n];
170 for (i, &(u, v)) in arcs.iter().enumerate() {
171 if kept_arcs[i] {
172 adj[u].push(v);
173 in_degree[v] += 1;
174 }
175 }
176
177 let mut queue: Vec<usize> = (0..n).filter(|&v| in_degree[v] == 0).collect();
179 let mut visited = 0;
180 while let Some(u) = queue.pop() {
181 visited += 1;
182 for &v in &adj[u] {
183 in_degree[v] -= 1;
184 if in_degree[v] == 0 {
185 queue.push(v);
186 }
187 }
188 }
189 visited == n
190 }
191
192 pub fn induced_subgraph(&self, keep: &[bool]) -> Self {
202 assert_eq!(
203 keep.len(),
204 self.num_vertices(),
205 "keep slice length must equal num_vertices"
206 );
207
208 let mut new_index = vec![usize::MAX; self.num_vertices()];
210 let mut count = 0;
211 for (v, &kept) in keep.iter().enumerate() {
212 if kept {
213 new_index[v] = count;
214 count += 1;
215 }
216 }
217
218 let new_arcs: Vec<(usize, usize)> = self
219 .arcs()
220 .into_iter()
221 .filter(|&(u, v)| keep[u] && keep[v])
222 .map(|(u, v)| (new_index[u], new_index[v]))
223 .collect();
224
225 Self::new(count, new_arcs)
226 }
227}
228
229impl PartialEq for DirectedGraph {
230 fn eq(&self, other: &Self) -> bool {
231 if self.num_vertices() != other.num_vertices() {
232 return false;
233 }
234 if self.num_arcs() != other.num_arcs() {
235 return false;
236 }
237 let mut self_arcs = self.arcs();
238 let mut other_arcs = other.arcs();
239 self_arcs.sort();
240 other_arcs.sort();
241 self_arcs == other_arcs
242 }
243}
244
245impl Eq for DirectedGraph {}
246
247impl Serialize for DirectedGraph {
248 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
249 use serde::ser::SerializeStruct;
250 let mut state = serializer.serialize_struct("DirectedGraph", 2)?;
251 state.serialize_field("num_vertices", &self.num_vertices())?;
252 let arcs: Vec<(usize, usize)> = self.arcs();
253 state.serialize_field("arcs", &arcs)?;
254 state.end()
255 }
256}
257
258impl<'de> Deserialize<'de> for DirectedGraph {
259 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
260 #[derive(Deserialize)]
261 struct GraphData {
262 num_vertices: usize,
263 arcs: Vec<(usize, usize)>,
264 }
265 let data = GraphData::deserialize(deserializer)?;
266 Ok(DirectedGraph::new(data.num_vertices, data.arcs))
267 }
268}
269
270use crate::impl_variant_param;
271impl_variant_param!(DirectedGraph, "graph");
272
273#[cfg(test)]
274#[path = "../unit_tests/topology/directed_graph.rs"]
275mod tests;