1use derivative::Derivative;
4use derive_more::Constructor;
5use indexmap::IndexMap;
6use std::collections::{HashMap, HashSet, VecDeque};
7use std::hash::Hash;
8
9use super::graph::*;
10use super::path::*;
11
12pub fn simple_paths<'a, G>(
29 graph: &'a G,
30 from: &'a G::V,
31 to: &'a G::V,
32) -> impl Iterator<Item = Path<G::V, G::E>> + 'a
33where
34 G: FinGraph,
35 G::V: Hash,
36 G::E: Hash,
37{
38 bounded_simple_paths(graph, from, to, None)
39}
40
41pub fn bounded_simple_paths<'a, G>(
47 graph: &'a G,
48 from: &'a G::V,
49 to: &'a G::V,
50 max_length: Option<usize>,
51) -> impl Iterator<Item = Path<G::V, G::E>> + 'a
52where
53 G: FinGraph,
54 G::V: Hash,
55 G::E: Hash,
56{
57 let mut path: Vec<G::E> = Vec::new();
59 let mut visited: HashSet<G::E> = HashSet::new();
62 let mut stack: Vec<Vec<G::E>> = vec![graph.out_edges(from).collect()];
64
65 let maybe_empty_path = if from == to {
66 Some(Path::Id(to.clone()))
67 } else {
68 None
69 };
70
71 let nonempty_paths = std::iter::from_fn(move || {
72 while let Some(out_edges) = stack.last_mut() {
73 let Some(e) = out_edges.pop() else {
74 stack.pop();
75 if let Some(e) = path.pop() {
76 visited.remove(&e);
77 }
78 continue;
79 };
80 if visited.contains(&e) || max_length.is_some_and(|n| path.len() >= n) {
81 continue;
82 }
83 let tgt = graph.tgt(&e);
84 path.push(e.clone());
85 visited.insert(e);
86 stack.push(graph.out_edges(&tgt).collect());
87 if tgt == *to {
88 let result = Path::collect(path.iter().cloned());
89 return Some(result.unwrap());
90 }
91 }
92 None
93 });
94
95 maybe_empty_path.into_iter().chain(nonempty_paths)
96}
97
98pub fn spec_order_all<G>(graph: &G) -> Vec<GraphElem<G::V, G::E>>
115where
116 G: FinGraph,
117 G::V: Hash,
118{
119 spec_order(graph, graph.vertices())
120}
121
122pub fn spec_order<G>(graph: &G, vertices: impl Iterator<Item = G::V>) -> Vec<GraphElem<G::V, G::E>>
127where
128 G: FinGraph,
129 G::V: Hash,
130{
131 let mut result = Vec::new();
132 let mut queue = VecDeque::new();
133 let mut visited = HashSet::new();
134 for v in vertices {
135 if !visited.contains(&v) {
136 queue.push_back(v);
137 }
138 while let Some(v) = queue.pop_front() {
139 if visited.contains(&v) {
140 continue;
141 }
142 result.push(GraphElem::Vertex(v.clone()));
143 for e in graph.out_edges(&v) {
144 let w = graph.tgt(&e);
145 if w == v || visited.contains(&w) {
146 result.push(GraphElem::Edge(e))
148 } else {
149 queue.push_back(w);
150 }
151 }
152 for e in graph.in_edges(&v) {
153 let w = graph.src(&e);
154 if w == v {
155 continue;
157 }
158 if visited.contains(&w) {
159 result.push(GraphElem::Edge(e))
160 } else {
161 queue.push_back(w);
162 }
163 }
164 visited.insert(v);
165 }
166 }
167 result
168}
169
170#[derive(Debug)]
173pub enum TraversalDirection {
174 Outward,
176 Inward,
178}
179
180#[derive(Debug, Derivative)]
189#[derivative(Default(bound = ""))]
190pub struct DFS<V, D, C>
191where
192 D: FnMut(V),
193 C: FnMut(V),
194{
195 discovered: HashSet<V>,
196 #[derivative(Default(value = "TraversalDirection::Outward"))]
197 traversal_direction: TraversalDirection,
198 on_discover: Option<D>,
199 on_complete: Option<C>,
200}
201
202impl<V> DFS<V, fn(V), fn(V)> {
203 pub fn new() -> Self {
208 Self::default()
209 }
210}
211
212impl<V, D, C> DFS<V, D, C>
213where
214 D: FnMut(V),
215 C: FnMut(V),
216{
217 pub fn traversal_direction(mut self, dir: TraversalDirection) -> Self {
220 self.traversal_direction = dir;
221 self
222 }
223
224 pub fn on_discover<D2: FnMut(V)>(self, on_discover: D2) -> DFS<V, D2, C> {
226 DFS {
227 traversal_direction: self.traversal_direction,
228 discovered: self.discovered,
229 on_discover: Some(on_discover),
230 on_complete: self.on_complete,
231 }
232 }
233
234 pub fn on_complete<C2: FnMut(V)>(self, on_complete: C2) -> DFS<V, D, C2> {
237 DFS {
238 traversal_direction: self.traversal_direction,
239 discovered: self.discovered,
240 on_discover: self.on_discover,
241 on_complete: Some(on_complete),
242 }
243 }
244
245 pub fn discovered(mut self, discovered: HashSet<V>) -> Self {
248 self.discovered = discovered;
249 self
250 }
251
252 pub fn reset(&mut self) {
254 self.discovered.clear();
255 }
256
257 pub fn traverse<G>(&mut self, graph: &G, start_vertex: V)
275 where
276 V: Clone + Eq + Hash,
277 G: FinGraph<V = V>,
278 {
279 let mut stack = Vec::new();
280 stack.push(start_vertex);
281
282 while let Some(nx) = stack.last().cloned() {
283 if self.discovered.insert(nx.clone()) {
284 if let Some(ref mut callback) = self.on_discover {
285 callback(nx.clone());
286 }
287 let successors: Vec<_> = match self.traversal_direction {
288 TraversalDirection::Outward => graph.out_neighbors(&nx).collect(),
289 TraversalDirection::Inward => graph.in_neighbors(&nx).collect(),
290 };
291 for succ in successors {
292 if !self.discovered.contains(&succ) {
293 stack.push(succ);
294 }
295 }
296 } else {
297 stack.pop();
298 if let Some(ref mut callback) = self.on_complete {
299 callback(nx.clone());
300 }
301 }
302 }
303 }
304}
305
306#[derive(Debug, Clone, Constructor)]
308pub struct ToposortData<V> {
309 pub stack: Vec<V>,
311
312 pub cycles: IndexMap<V, Vec<V>>,
314}
315
316type ToposortResult<V> = Result<ToposortData<V>, V>;
317
318pub fn toposort_strict<G>(graph: &G) -> Result<Vec<G::V>, G::V>
320where
321 G: FinGraph,
322 G::V: Hash + std::fmt::Debug,
323{
324 toposort_impl(graph, true).map(|t| t.stack)
325}
326
327pub fn toposort_lenient<G>(graph: &G) -> ToposortData<G::V>
329where
330 G: FinGraph,
331 G::V: Hash + std::fmt::Debug,
332{
333 toposort_impl(graph, false).expect("toposort in lenient mode should return a valid result")
334}
335
336fn toposort_impl<G>(graph: &G, is_strict: bool) -> ToposortResult<G::V>
341where
342 G: FinGraph,
343 G::V: Hash + std::fmt::Debug,
344{
345 let mut finished = HashSet::new();
346 let mut finish_stack = Vec::new();
347
348 let mut dfs =
349 DFS::new()
350 .traversal_direction(TraversalDirection::Outward)
351 .on_complete(|nx: G::V| {
352 if finished.insert(nx.clone()) {
353 finish_stack.push(nx);
354 }
355 });
356
357 for v in graph.vertices() {
358 if dfs.discovered.contains(&v) {
359 continue;
360 }
361 dfs.traverse(graph, v);
362 }
363 finish_stack.reverse();
364
365 let position: HashMap<G::V, usize> =
368 finish_stack.iter().enumerate().map(|(i, v)| (v.clone(), i)).collect();
369 let mut cycles = IndexMap::new();
370 for e in graph.edges() {
371 let s = graph.src(&e);
372 let t = graph.tgt(&e);
373 if position[&s] >= position[&t] {
376 if is_strict {
377 return Err(s);
378 } else {
379 let outs = graph.out_neighbors(&s).collect();
380 cycles.insert(s, outs);
381 }
382 }
383 }
384
385 Ok(ToposortData::new(finish_stack, cycles))
386}
387
388#[cfg(test)]
389mod tests {
390 use super::GraphElem::*;
391 use super::*;
392 use nonempty::nonempty;
393
394 #[test]
395 fn find_simple_paths() {
396 let mut g = SkelGraph::triangle();
397 let paths: Vec<_> = simple_paths(&g, &0, &2).collect();
398 assert_eq!(paths, vec![Path::single(2), Path::pair(0, 1)]);
399 assert_eq!(bounded_simple_paths(&g, &0, &2, None).count(), 2);
400 assert_eq!(bounded_simple_paths(&g, &0, &2, Some(2)).count(), 2);
401 assert_eq!(bounded_simple_paths(&g, &0, &2, Some(1)).count(), 1);
402 assert_eq!(bounded_simple_paths(&g, &0, &2, Some(0)).count(), 0);
403
404 g.add_vertices(2);
405 let s = g.add_edge(3, 0);
406 let t = g.add_edge(2, 4);
407 let paths: Vec<_> = simple_paths(&g, &3, &4).collect();
408 assert_eq!(paths, vec![Path::Seq(nonempty![s, 2, t]), Path::Seq(nonempty![s, 0, 1, t])]);
409
410 let g = SkelGraph::cycle(3);
411 let paths: Vec<_> = simple_paths(&g, &0, &0).collect();
412 assert_eq!(paths, vec![Path::Id(0), Path::Seq(nonempty![0, 1, 2])]);
413 let paths: Vec<_> = simple_paths(&g, &0, &2).collect();
414 assert_eq!(paths, vec![Path::Seq(nonempty![0, 1])]);
415
416 let mut g: HashGraph<_, _> = Default::default();
417 assert!(g.add_vertex('x'));
418 assert!(g.add_edge('f', 'x', 'x'));
419 assert!(g.add_edge('g', 'x', 'x'));
420 let paths: HashSet<_> = simple_paths(&g, &'x', &'x').collect();
421 let target = HashSet::from([
422 Path::Id('x'),
423 Path::Seq(nonempty!['f']),
424 Path::Seq(nonempty!['g']),
425 Path::Seq(nonempty!['f', 'g']),
426 Path::Seq(nonempty!['g', 'f']),
427 ]);
428 assert_eq!(paths, target);
429 }
430
431 #[test]
432 fn toposorting() {
433 let g = SkelGraph::path(5);
434 let result = toposort_strict(&g);
435 assert_eq!(result.unwrap(), vec![0, 1, 2, 3, 4]);
436
437 let mut g = SkelGraph::path(3);
438 g.add_vertices(1);
439 g.add_edge(2, 3);
440 g.add_edge(3, 0);
441 let t = &toposort_strict(&g).unwrap_err();
442 expect_test::expect!["3"].assert_eq(&format!("{t}"));
443
444 let g = SkelGraph::triangle();
445 assert_eq!(toposort_strict(&g).unwrap(), vec![0, 1, 2]);
446
447 let mut g = SkelGraph::path(4);
448 g.add_vertices(2);
449 g.add_edge(1, 4);
450 g.add_edge(4, 3);
451 g.add_edge(5, 2);
452
453 assert_eq!(toposort_strict(&g).unwrap(), vec![5, 0, 1, 2, 4, 3]);
454
455 let mut g: HashGraph<_, _> = Default::default();
456 g.add_vertices(vec![0, 1, 2, 3, 4, 5]);
457 g.add_edge("0-1", 0, 1);
458 g.add_edge("1-2", 1, 2);
459 g.add_edge("2-3", 2, 3);
460 g.add_edge("1-4", 1, 4);
461 g.add_edge("4-3", 4, 3);
462 g.add_edge("5-2", 5, 2);
463 if let Ok(sort) = toposort_strict(&g) {
464 let (i0, i1) = (sort.iter().position(|&x| x == 5), sort.iter().position(|&x| x == 2));
465 assert!(i0.unwrap() < i1.unwrap());
466 }
467 }
468
469 #[test]
470 fn spec_ordering() {
471 let g = SkelGraph::path(3);
472 assert_eq!(
473 spec_order(&g, Some(0).into_iter()),
474 vec![Vertex(0), Vertex(1), Edge(0), Vertex(2), Edge(1)]
475 );
476 assert_eq!(
477 spec_order(&g, Some(2).into_iter()),
478 vec![Vertex(2), Vertex(1), Edge(1), Vertex(0), Edge(0)]
479 );
480
481 let g = SkelGraph::triangle();
482 let desired = vec![Vertex(0), Vertex(1), Edge(0), Vertex(2), Edge(1), Edge(2)];
483 assert_eq!(spec_order_all(&g), desired);
484 assert_eq!(spec_order(&g, Some(0).into_iter()), desired);
485
486 let g = SkelGraph::cycle(1);
487 assert_eq!(spec_order_all(&g), vec![Vertex(0), Edge(0)]);
488 }
489
490 #[test]
491 fn dfs_with_callbacks() {
492 let g = SkelGraph::path(3);
494 let mut discovered_order = Vec::new();
495 let mut completed_order = Vec::new();
496 let mut dfs = DFS::new()
497 .traversal_direction(TraversalDirection::Outward)
498 .on_discover(|v| discovered_order.push(v))
499 .on_complete(|v| completed_order.push(v));
500 dfs.traverse(&g, 0);
501 assert_eq!(discovered_order, vec![0, 1, 2]);
503 assert_eq!(completed_order, vec![2, 1, 0]);
505
506 let g = SkelGraph::triangle();
508 let mut discovered_order = Vec::new();
509 let mut completed_order = Vec::new();
510 let mut dfs = DFS::new()
511 .traversal_direction(TraversalDirection::Outward)
512 .on_discover(|v| discovered_order.push(v))
513 .on_complete(|v| completed_order.push(v));
514 dfs.traverse(&g, 0);
515 assert_eq!(discovered_order.len(), 3);
517 assert_eq!(discovered_order.iter().collect::<HashSet<_>>(), [0, 1, 2].iter().collect());
518 assert_eq!(completed_order.last(), Some(&0));
520
521 let mut g: HashGraph<usize, &str> = Default::default();
523 g.add_vertices(vec![0, 1]);
524 g.add_edge("self", 0, 0);
525 g.add_edge("e", 0, 1);
526 let mut discovered_order = Vec::new();
527 let mut dfs = DFS::new()
528 .traversal_direction(TraversalDirection::Outward)
529 .on_discover(|v| discovered_order.push(v));
530 dfs.traverse(&g, 0);
531 assert_eq!(discovered_order.iter().collect::<HashSet<_>>(), [0, 1].iter().collect());
532 }
533}