1use std::ops::ControlFlow;
38
39use ahash::AHashSet;
40use petgraph::{
41 algo::tarjan_scc,
42 visit::{GraphBase, IntoNeighbors, IntoNodeIdentifiers, NodeIndexable},
43};
44
45pub trait Cycles {
47 type NodeId;
49
50 fn visit_cycles<F, B>(&self, visitor: F) -> Option<B>
59 where
60 F: FnMut(&Self, &[Self::NodeId]) -> ControlFlow<B>;
61
62 fn visit_all_cycles<F>(&self, mut visitor: F)
68 where
69 F: FnMut(&Self, &[Self::NodeId]),
70 {
71 self.visit_cycles(|g, n| {
72 visitor(g, n);
73 ControlFlow::<(), ()>::Continue(())
74 });
75 }
76
77 fn cycles(&self) -> Vec<Vec<Self::NodeId>>;
81}
82
83impl<Graph: GraphBase> Cycles for Graph
84where
85 for<'a> &'a Graph: IntoNodeIdentifiers
86 + IntoNeighbors
87 + NodeIndexable
88 + GraphBase<NodeId = <Graph as GraphBase>::NodeId>,
89{
90 type NodeId = <Graph as GraphBase>::NodeId;
91 fn visit_cycles<F, B>(&self, mut visitor: F) -> Option<B>
92 where
93 F: FnMut(&Graph, &[Self::NodeId]) -> ControlFlow<B>,
94 {
95 for component in tarjan_scc(self) {
96 let mut finder = CycleFinder::new(self, component);
97 if let ControlFlow::Break(b) = finder.visit(&mut visitor) {
98 return Some(b);
99 }
100 }
101 None
102 }
103 fn cycles(&self) -> Vec<Vec<Self::NodeId>> {
104 let mut cycles = Vec::new();
105 self.visit_cycles(|_, cycle| {
106 cycles.push(cycle.to_vec());
107 ControlFlow::<(), ()>::Continue(())
108 });
109 cycles
110 }
111}
112
113#[derive(Clone, Debug, Eq, PartialEq)]
114struct CycleFinder<G, N> {
115 graph: G,
116 scc: Vec<N>,
117 blocked: Vec<bool>,
118 b: Vec<AHashSet<usize>>,
119 stack: Vec<N>,
120 s: usize,
121}
122
123impl<G> CycleFinder<G, G::NodeId>
124where
125 G: IntoNodeIdentifiers + IntoNeighbors + NodeIndexable,
126{
127 fn new(graph: G, scc: Vec<G::NodeId>) -> Self {
128 let num_vertices = scc.len();
129 Self {
130 graph,
131 scc,
132 blocked: vec![false; num_vertices],
133 b: vec![Default::default(); num_vertices],
134 stack: Default::default(),
135 s: Default::default(),
136 }
137 }
138
139 fn visit<F, B>(&mut self, visitor: &mut F) -> ControlFlow<B>
140 where
141 F: FnMut(G, &[G::NodeId]) -> ControlFlow<B>,
142 {
143 for s in 0..self.scc.len() {
145 self.s = s;
146 self.blocked[s..].fill(false);
147 for b in &mut self.b[s + 1..] {
148 b.clear();
149 }
150 if let ControlFlow::Break(b) = self.circuit(s, visitor) {
151 return ControlFlow::Break(b);
152 }
153 self.blocked[s] = true;
154 }
155 ControlFlow::Continue(())
156 }
157
158 fn circuit<B, F>(
159 &mut self,
160 v: usize,
161 visitor: &mut F,
162 ) -> ControlFlow<B, bool>
163 where
164 F: FnMut(G, &[G::NodeId]) -> ControlFlow<B>,
165 {
166 let mut f = false;
167 self.stack.push(self.scc[v]);
168 self.blocked[v] = true;
169
170 for w in self.adjacent_vertices(v) {
172 if w == self.s {
173 if let ControlFlow::Break(b) = visitor(self.graph, &self.stack)
174 {
175 return ControlFlow::Break(b);
176 }
177 f = true;
178 } else if !self.blocked[w]
179 && matches!(
180 self.circuit(w, visitor),
181 ControlFlow::Continue(true)
182 )
183 {
184 f = true;
185 }
186 }
187
188 if f {
190 self.unblock(v)
191 } else {
192 for w in self.adjacent_vertices(v) {
193 self.b[w].insert(v);
194 }
195 }
196
197 self.stack.pop(); ControlFlow::Continue(f)
199 }
200
201 fn unblock(&mut self, v: usize) {
202 self.blocked[v] = false;
203 let tmp = self.b[v].clone();
204 for w in tmp {
205 if self.blocked[w] {
206 self.unblock(w)
207 }
208 }
209 self.b[v].clear()
210 }
211
212 fn adjacent_vertices(&self, v: usize) -> Vec<usize> {
213 self.graph
214 .neighbors(self.scc[v])
215 .filter_map(|n| self.scc.iter().position(|v| *v == n))
216 .collect()
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use petgraph::{Directed, graph::Graph, graphmap::GraphMap};
223
224 #[test]
225 fn test_graph() {
226 let g: Graph<usize, (), Directed> = Graph::new();
227 crate::Cycles::cycles(&g);
228 }
229
230 #[test]
231 fn test_graph_map() {
232 let g: GraphMap<usize, (), Directed> = GraphMap::new();
233 crate::Cycles::cycles(&g);
234 }
235}