petgraph/algo/mod.rs
1//! Graph algorithms.
2//!
3//! It is a goal to gradually migrate the algorithms to be based on graph traits
4//! so that they are generally applicable. For now, some of these still require
5//! the `Graph` type.
6
7pub mod articulation_points;
8pub mod astar;
9pub mod bellman_ford;
10pub mod bridges;
11pub mod coloring;
12pub mod dijkstra;
13pub mod dominators;
14pub mod feedback_arc_set;
15pub mod floyd_warshall;
16pub mod ford_fulkerson;
17pub mod isomorphism;
18pub mod johnson;
19pub mod k_shortest_path;
20pub mod matching;
21pub mod maximal_cliques;
22pub mod min_spanning_tree;
23pub mod page_rank;
24pub mod simple_paths;
25pub mod spfa;
26#[cfg(feature = "stable_graph")]
27pub mod steiner_tree;
28pub mod tred;
29
30use alloc::{vec, vec::Vec};
31use core::num::NonZeroUsize;
32
33use crate::prelude::*;
34
35use super::graph::IndexType;
36use super::unionfind::UnionFind;
37use super::visit::{
38 GraphBase, GraphRef, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected,
39 IntoNodeIdentifiers, NodeCompactIndexable, NodeIndexable, Reversed, VisitMap, Visitable,
40};
41use super::EdgeType;
42use crate::visit::Walker;
43
44pub use astar::astar;
45pub use bellman_ford::{bellman_ford, find_negative_cycle};
46pub use bridges::bridges;
47pub use coloring::dsatur_coloring;
48pub use dijkstra::dijkstra;
49pub use feedback_arc_set::greedy_feedback_arc_set;
50pub use floyd_warshall::floyd_warshall;
51pub use ford_fulkerson::ford_fulkerson;
52pub use isomorphism::{
53 is_isomorphic, is_isomorphic_matching, is_isomorphic_subgraph, is_isomorphic_subgraph_matching,
54 subgraph_isomorphisms_iter,
55};
56pub use johnson::johnson;
57pub use k_shortest_path::k_shortest_path;
58pub use matching::{greedy_matching, maximum_matching, Matching};
59pub use maximal_cliques::maximal_cliques;
60pub use min_spanning_tree::{min_spanning_tree, min_spanning_tree_prim};
61pub use page_rank::page_rank;
62pub use simple_paths::all_simple_paths;
63pub use spfa::spfa;
64#[cfg(feature = "stable_graph")]
65pub use steiner_tree::steiner_tree;
66
67#[cfg(feature = "rayon")]
68pub use johnson::parallel_johnson;
69
70/// \[Generic\] Return the number of connected components of the graph.
71///
72/// For a directed graph, this is the *weakly* connected components.
73///
74/// # Arguments
75/// * `g`: an input graph.
76///
77/// # Returns
78/// * `usize`: the number of connected components if `g` is undirected
79/// or number of *weakly* connected components if `g` is directed.
80///
81/// # Complexity
82/// * Time complexity: amortized **O(|E| + |V|log|V|)**.
83/// * Auxiliary space: **O(|V|)**.
84///
85/// where **|V|** is the number of nodes and **|E|** is the number of edges.
86///
87/// # Example
88/// ```rust
89/// use petgraph::Graph;
90/// use petgraph::algo::connected_components;
91/// use petgraph::prelude::*;
92///
93/// let mut graph : Graph<(),(),Directed>= Graph::new();
94/// let a = graph.add_node(()); // node with no weight
95/// let b = graph.add_node(());
96/// let c = graph.add_node(());
97/// let d = graph.add_node(());
98/// let e = graph.add_node(());
99/// let f = graph.add_node(());
100/// let g = graph.add_node(());
101/// let h = graph.add_node(());
102///
103/// graph.extend_with_edges(&[
104/// (a, b),
105/// (b, c),
106/// (c, d),
107/// (d, a),
108/// (e, f),
109/// (f, g),
110/// (g, h),
111/// (h, e)
112/// ]);
113/// // a ----> b e ----> f
114/// // ^ | ^ |
115/// // | v | v
116/// // d <---- c h <---- g
117///
118/// assert_eq!(connected_components(&graph),2);
119/// graph.add_edge(b,e,());
120/// assert_eq!(connected_components(&graph),1);
121/// ```
122pub fn connected_components<G>(g: G) -> usize
123where
124 G: NodeCompactIndexable + IntoEdgeReferences,
125{
126 let mut node_sets = UnionFind::new(g.node_bound());
127 for edge in g.edge_references() {
128 let (a, b) = (edge.source(), edge.target());
129
130 // union the two nodes of the edge
131 node_sets.union(g.to_index(a), g.to_index(b));
132 }
133
134 let mut labels = node_sets.into_labeling();
135 labels.sort_unstable();
136 labels.dedup();
137 labels.len()
138}
139
140/// \[Generic\] Return `true` if the input graph contains a cycle.
141///
142/// Always treats the input graph as if undirected.
143///
144/// # Arguments:
145/// `g`: an input graph that always treated as undirected.
146///
147/// # Returns
148/// `true`: if the input graph contains a cycle.
149/// `false`: otherwise.
150///
151/// # Complexity
152/// * Time complexity: amortized **O(|E|)**.
153/// * Auxiliary space: **O(|V|)**.
154///
155/// where **|V|** is the number of nodes and **|E|** is the number of edges.
156pub fn is_cyclic_undirected<G>(g: G) -> bool
157where
158 G: NodeIndexable + IntoEdgeReferences,
159{
160 let mut edge_sets = UnionFind::new(g.node_bound());
161 for edge in g.edge_references() {
162 let (a, b) = (edge.source(), edge.target());
163
164 // union the two nodes of the edge
165 // -- if they were already the same, then we have a cycle
166 if !edge_sets.union(g.to_index(a), g.to_index(b)) {
167 return true;
168 }
169 }
170 false
171}
172
173/// \[Generic\] Perform a topological sort of a directed graph.
174///
175/// `toposort` returns `Err` on graphs with cycles.
176/// To handle graphs with cycles, use the one of scc algorithms or
177/// [`DfsPostOrder`](struct@crate::visit::DfsPostOrder)
178/// instead of this function.
179///
180/// The implementation is iterative.
181///
182/// # Arguments
183/// * `g`: an acyclic directed graph.
184/// * `space`: optional [`DfsSpace`]. If `space` is not `None`,
185/// it is used instead of creating a new workspace for graph traversal.
186///
187/// # Returns
188/// * `Ok`: a vector of nodes in topological order: each node is ordered before its successors
189/// (if the graph was acyclic).
190/// * `Err`: [`Cycle`] if the graph was not acyclic. Self loops are also cycles this case.
191///
192/// # Complexity
193/// * Time complexity: **O(|V| + |E|)**.
194/// * Auxiliary space: **O(|V|)**.
195///
196/// where **|V|** is the number of nodes and **|E|** is the number of edges.
197pub fn toposort<G>(
198 g: G,
199 space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
200) -> Result<Vec<G::NodeId>, Cycle<G::NodeId>>
201where
202 G: IntoNeighborsDirected + IntoNodeIdentifiers + Visitable,
203{
204 // based on kosaraju scc
205 with_dfs(g, space, |dfs| {
206 dfs.reset(g);
207 let mut finished = g.visit_map();
208
209 let mut finish_stack = Vec::new();
210 for i in g.node_identifiers() {
211 if dfs.discovered.is_visited(&i) {
212 continue;
213 }
214 dfs.stack.push(i);
215 while let Some(&nx) = dfs.stack.last() {
216 if dfs.discovered.visit(nx) {
217 // First time visiting `nx`: Push neighbors, don't pop `nx`
218 for succ in g.neighbors(nx) {
219 if succ == nx {
220 // self cycle
221 return Err(Cycle(nx));
222 }
223 if !dfs.discovered.is_visited(&succ) {
224 dfs.stack.push(succ);
225 }
226 }
227 } else {
228 dfs.stack.pop();
229 if finished.visit(nx) {
230 // Second time: All reachable nodes must have been finished
231 finish_stack.push(nx);
232 }
233 }
234 }
235 }
236 finish_stack.reverse();
237
238 dfs.reset(g);
239 for &i in &finish_stack {
240 dfs.move_to(i);
241 let mut cycle = false;
242 while let Some(j) = dfs.next(Reversed(g)) {
243 if cycle {
244 return Err(Cycle(j));
245 }
246 cycle = true;
247 }
248 }
249
250 Ok(finish_stack)
251 })
252}
253
254/// \[Generic\] Return `true` if the input directed graph contains a cycle.
255///
256/// This implementation is recursive; use [`toposort`] if an alternative is needed.
257///
258/// # Arguments:
259/// `g`: a directed graph.
260///
261/// # Returns
262/// `true`: if the input graph contains a cycle.
263/// `false`: otherwise.
264///
265/// # Complexity
266/// * Time complexity: **O(|V| + |E|)**.
267/// * Auxiliary space: **O(|V|)**.
268///
269/// where **|V|** is the number of nodes and **|E|** is the number of edges.
270pub fn is_cyclic_directed<G>(g: G) -> bool
271where
272 G: IntoNodeIdentifiers + IntoNeighbors + Visitable,
273{
274 use crate::visit::{depth_first_search, DfsEvent};
275
276 depth_first_search(g, g.node_identifiers(), |event| match event {
277 DfsEvent::BackEdge(_, _) => Err(()),
278 _ => Ok(()),
279 })
280 .is_err()
281}
282
283type DfsSpaceType<G> = DfsSpace<<G as GraphBase>::NodeId, <G as Visitable>::Map>;
284
285/// Workspace for a graph traversal.
286#[derive(Clone, Debug)]
287pub struct DfsSpace<N, VM> {
288 dfs: Dfs<N, VM>,
289}
290
291impl<N, VM> DfsSpace<N, VM>
292where
293 N: Copy + PartialEq,
294 VM: VisitMap<N>,
295{
296 pub fn new<G>(g: G) -> Self
297 where
298 G: GraphRef + Visitable<NodeId = N, Map = VM>,
299 {
300 DfsSpace { dfs: Dfs::empty(g) }
301 }
302}
303
304impl<N, VM> Default for DfsSpace<N, VM>
305where
306 VM: VisitMap<N> + Default,
307{
308 fn default() -> Self {
309 DfsSpace {
310 dfs: Dfs {
311 stack: <_>::default(),
312 discovered: <_>::default(),
313 },
314 }
315 }
316}
317
318/// Create a Dfs if it's needed
319fn with_dfs<G, F, R>(g: G, space: Option<&mut DfsSpaceType<G>>, f: F) -> R
320where
321 G: GraphRef + Visitable,
322 F: FnOnce(&mut Dfs<G::NodeId, G::Map>) -> R,
323{
324 let mut local_visitor;
325 let dfs = if let Some(v) = space {
326 &mut v.dfs
327 } else {
328 local_visitor = Dfs::empty(g);
329 &mut local_visitor
330 };
331 f(dfs)
332}
333
334/// \[Generic\] Check if there exists a path starting at `from` and reaching `to`.
335///
336/// If `from` and `to` are equal, this function returns true.
337///
338/// # Arguments:
339/// * `g`: an input graph.
340/// * `from`: the first node of a desired path.
341/// * `to`: the last node of a desired path.
342/// * `space`: optional [`DfsSpace`]. If `space` is not `None`,
343/// it is used instead of creating a new workspace for graph traversal.
344///
345/// # Returns
346/// * `true`: if there exists a path starting at `from` and reaching
347/// `to` or `from` and `to` are equal.
348/// * `false`: otherwise.
349///
350/// # Complexity
351/// * Time complexity: **O(|V| + |E|)**.
352/// * Auxiliary space: **O(|V|)** or **O(1)** if `space` was provided.
353///
354/// where **|V|** is the number of nodes and **|E|** is the number of edges.
355pub fn has_path_connecting<G>(
356 g: G,
357 from: G::NodeId,
358 to: G::NodeId,
359 space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
360) -> bool
361where
362 G: IntoNeighbors + Visitable,
363{
364 with_dfs(g, space, |dfs| {
365 dfs.reset(g);
366 dfs.move_to(from);
367 dfs.iter(g).any(|x| x == to)
368 })
369}
370
371/// Renamed to `kosaraju_scc`.
372#[deprecated(note = "renamed to kosaraju_scc")]
373pub fn scc<G>(g: G) -> Vec<Vec<G::NodeId>>
374where
375 G: IntoNeighborsDirected + Visitable + IntoNodeIdentifiers,
376{
377 kosaraju_scc(g)
378}
379
380/// \[Generic\] Compute the *strongly connected components* using [Kosaraju's algorithm][1].
381///
382/// This implementation is iterative and does two passes over the nodes.
383///
384/// # Arguments
385/// * `g`: a directed or undirected graph.
386///
387/// # Returns
388/// Return a vector where each element is a strongly connected component (scc).
389/// The order of node ids within each scc is arbitrary, but the order of
390/// the sccs is their postorder (reverse topological sort).
391///
392/// For an undirected graph, the sccs are simply the connected components.
393///
394/// # Complexity
395/// * Time complexity: **O(|V| + |E|)**.
396/// * Auxiliary space: **O(|V|)**.
397///
398/// where **|V|** is the number of nodes and **|E|** is the number of edges.
399///
400/// [1]: https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
401pub fn kosaraju_scc<G>(g: G) -> Vec<Vec<G::NodeId>>
402where
403 G: IntoNeighborsDirected + Visitable + IntoNodeIdentifiers,
404{
405 let mut dfs = DfsPostOrder::empty(g);
406
407 // First phase, reverse dfs pass, compute finishing times.
408 // http://stackoverflow.com/a/26780899/161659
409 let mut finish_order = Vec::with_capacity(0);
410 for i in g.node_identifiers() {
411 if dfs.discovered.is_visited(&i) {
412 continue;
413 }
414
415 dfs.move_to(i);
416 while let Some(nx) = dfs.next(Reversed(g)) {
417 finish_order.push(nx);
418 }
419 }
420
421 let mut dfs = Dfs::from_parts(dfs.stack, dfs.discovered);
422 dfs.reset(g);
423 let mut sccs = Vec::new();
424
425 // Second phase
426 // Process in decreasing finishing time order
427 for i in finish_order.into_iter().rev() {
428 if dfs.discovered.is_visited(&i) {
429 continue;
430 }
431 // Move to the leader node `i`.
432 dfs.move_to(i);
433 let mut scc = Vec::new();
434 while let Some(nx) = dfs.next(g) {
435 scc.push(nx);
436 }
437 sccs.push(scc);
438 }
439 sccs
440}
441
442#[derive(Copy, Clone, Debug)]
443struct NodeData {
444 rootindex: Option<NonZeroUsize>,
445}
446
447/// A reusable state for computing the *strongly connected components* using [Tarjan's algorithm][1].
448///
449/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
450#[derive(Debug)]
451pub struct TarjanScc<N> {
452 index: usize,
453 componentcount: usize,
454 nodes: Vec<NodeData>,
455 stack: Vec<N>,
456}
457
458impl<N> Default for TarjanScc<N> {
459 fn default() -> Self {
460 Self::new()
461 }
462}
463
464impl<N> TarjanScc<N> {
465 /// Creates a new `TarjanScc`
466 pub fn new() -> Self {
467 TarjanScc {
468 index: 1, // Invariant: index < componentcount at all times.
469 componentcount: usize::MAX, // Will hold if componentcount is initialized to number of nodes - 1 or higher.
470 nodes: Vec::new(),
471 stack: Vec::new(),
472 }
473 }
474
475 /// \[Generic\] Compute the *strongly connected components* using Algorithm 3 in
476 /// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
477 /// which is a memory-efficient variation of [Tarjan's algorithm][2].
478 ///
479 ///
480 /// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
481 /// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
482 ///
483 /// Calls `f` for each strongly strongly connected component (scc).
484 /// The order of node ids within each scc is arbitrary, but the order of
485 /// the sccs is their postorder (reverse topological sort).
486 ///
487 /// For an undirected graph, the sccs are simply the connected components.
488 ///
489 /// This implementation is recursive and does one pass over the nodes.
490 pub fn run<G, F>(&mut self, g: G, mut f: F)
491 where
492 G: IntoNodeIdentifiers<NodeId = N> + IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
493 F: FnMut(&[N]),
494 N: Copy + PartialEq,
495 {
496 self.nodes.clear();
497 self.nodes
498 .resize(g.node_bound(), NodeData { rootindex: None });
499
500 for n in g.node_identifiers() {
501 let visited = self.nodes[g.to_index(n)].rootindex.is_some();
502 if !visited {
503 self.visit(n, g, &mut f);
504 }
505 }
506
507 debug_assert!(self.stack.is_empty());
508 }
509
510 fn visit<G, F>(&mut self, v: G::NodeId, g: G, f: &mut F)
511 where
512 G: IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
513 F: FnMut(&[N]),
514 N: Copy + PartialEq,
515 {
516 macro_rules! node {
517 ($node:expr) => {
518 self.nodes[g.to_index($node)]
519 };
520 }
521
522 let node_v = &mut node![v];
523 debug_assert!(node_v.rootindex.is_none());
524
525 let mut v_is_local_root = true;
526 let v_index = self.index;
527 node_v.rootindex = NonZeroUsize::new(v_index);
528 self.index += 1;
529
530 for w in g.neighbors(v) {
531 if node![w].rootindex.is_none() {
532 self.visit(w, g, f);
533 }
534 if node![w].rootindex < node![v].rootindex {
535 node![v].rootindex = node![w].rootindex;
536 v_is_local_root = false
537 }
538 }
539
540 if v_is_local_root {
541 // Pop the stack and generate an SCC.
542 let mut indexadjustment = 1;
543 let c = NonZeroUsize::new(self.componentcount);
544 let nodes = &mut self.nodes;
545 let start = self
546 .stack
547 .iter()
548 .rposition(|&w| {
549 if nodes[g.to_index(v)].rootindex > nodes[g.to_index(w)].rootindex {
550 true
551 } else {
552 nodes[g.to_index(w)].rootindex = c;
553 indexadjustment += 1;
554 false
555 }
556 })
557 .map(|x| x + 1)
558 .unwrap_or_default();
559 nodes[g.to_index(v)].rootindex = c;
560 self.stack.push(v); // Pushing the component root to the back right before getting rid of it is somewhat ugly, but it lets it be included in f.
561 f(&self.stack[start..]);
562 self.stack.truncate(start);
563 self.index -= indexadjustment; // Backtrack index back to where it was before we ever encountered the component.
564 self.componentcount -= 1;
565 } else {
566 self.stack.push(v); // Stack is filled up when backtracking, unlike in Tarjans original algorithm.
567 }
568 }
569
570 /// Returns the index of the component in which v has been assigned. Allows for using self as a lookup table for an scc decomposition produced by self.run().
571 pub fn node_component_index<G>(&self, g: G, v: N) -> usize
572 where
573 G: IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
574 N: Copy + PartialEq,
575 {
576 let rindex: usize = self.nodes[g.to_index(v)]
577 .rootindex
578 .map(NonZeroUsize::get)
579 .unwrap_or(0); // Compiles to no-op.
580 debug_assert!(
581 rindex != 0,
582 "Tried to get the component index of an unvisited node."
583 );
584 debug_assert!(
585 rindex > self.componentcount,
586 "Given node has been visited but not yet assigned to a component."
587 );
588 usize::MAX - rindex
589 }
590}
591
592/// \[Generic\] Compute the *strongly connected components* using [Tarjan's algorithm][1].
593///
594/// This implementation is recursive and does one pass over the nodes. It is based on
595/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][2] by David J. Pierce,
596/// to provide a memory-efficient implementation of [Tarjan's algorithm][1].
597///
598/// # Arguments
599/// * `g`: a directed or undirected graph.
600///
601/// # Returns
602/// Return a vector where each element is a strongly connected component (scc).
603/// The order of node ids within each scc is arbitrary, but the order of
604/// the sccs is their postorder (reverse topological sort).
605///
606/// For an undirected graph, the sccs are simply the connected components.
607///
608/// # Complexity
609/// * Time complexity: **O(|V| + |E|)**.
610/// * Auxiliary space: **O(|V|)**.
611///
612/// where **|V|** is the number of nodes and **|E|** is the number of edges.
613///
614/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
615/// [2]: https://www.researchgate.net/publication/283024636_A_space-efficient_algorithm_for_finding_strongly_connected_components
616pub fn tarjan_scc<G>(g: G) -> Vec<Vec<G::NodeId>>
617where
618 G: IntoNodeIdentifiers + IntoNeighbors + NodeIndexable,
619{
620 let mut sccs = Vec::new();
621 {
622 let mut tarjan_scc = TarjanScc::new();
623 tarjan_scc.run(g, |scc| sccs.push(scc.to_vec()));
624 }
625 sccs
626}
627
628/// [Graph] Condense every strongly connected component into a single node and return the result.
629///
630/// # Arguments
631/// * `g`: an input [`Graph`].
632/// * `make_acyclic`: if `true`, self-loops and multi edges are ignored, guaranteeing that
633/// the output is acyclic.
634///
635/// # Returns
636/// Returns a `Graph` with nodes `Vec<N>` representing strongly connected components.
637///
638/// # Complexity
639/// * Time complexity: **O(|V| + |E|)**.
640/// * Auxiliary space: **O(|V| + |E|)**.
641///
642/// where **|V|** is the number of nodes and **|E|** is the number of edges.
643///
644/// # Examples
645/// ```rust
646/// use petgraph::Graph;
647/// use petgraph::algo::condensation;
648/// use petgraph::prelude::*;
649///
650/// let mut graph : Graph<(),(),Directed> = Graph::new();
651/// let a = graph.add_node(()); // node with no weight
652/// let b = graph.add_node(());
653/// let c = graph.add_node(());
654/// let d = graph.add_node(());
655/// let e = graph.add_node(());
656/// let f = graph.add_node(());
657/// let g = graph.add_node(());
658/// let h = graph.add_node(());
659///
660/// graph.extend_with_edges(&[
661/// (a, b),
662/// (b, c),
663/// (c, d),
664/// (d, a),
665/// (b, e),
666/// (e, f),
667/// (f, g),
668/// (g, h),
669/// (h, e)
670/// ]);
671///
672/// // a ----> b ----> e ----> f
673/// // ^ | ^ |
674/// // | v | v
675/// // d <---- c h <---- g
676///
677/// let condensed_graph = condensation(graph,false);
678/// let A = NodeIndex::new(0);
679/// let B = NodeIndex::new(1);
680/// assert_eq!(condensed_graph.node_count(), 2);
681/// assert_eq!(condensed_graph.edge_count(), 9);
682/// assert_eq!(condensed_graph.neighbors(A).collect::<Vec<_>>(), vec![A, A, A, A]);
683/// assert_eq!(condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A, B, B, B, B]);
684/// ```
685/// If `make_acyclic` is true, self-loops and multi edges are ignored:
686///
687/// ```rust
688/// # use petgraph::Graph;
689/// # use petgraph::algo::condensation;
690/// # use petgraph::prelude::*;
691/// #
692/// # let mut graph : Graph<(),(),Directed> = Graph::new();
693/// # let a = graph.add_node(()); // node with no weight
694/// # let b = graph.add_node(());
695/// # let c = graph.add_node(());
696/// # let d = graph.add_node(());
697/// # let e = graph.add_node(());
698/// # let f = graph.add_node(());
699/// # let g = graph.add_node(());
700/// # let h = graph.add_node(());
701/// #
702/// # graph.extend_with_edges(&[
703/// # (a, b),
704/// # (b, c),
705/// # (c, d),
706/// # (d, a),
707/// # (b, e),
708/// # (e, f),
709/// # (f, g),
710/// # (g, h),
711/// # (h, e)
712/// # ]);
713/// let acyclic_condensed_graph = condensation(graph, true);
714/// let A = NodeIndex::new(0);
715/// let B = NodeIndex::new(1);
716/// assert_eq!(acyclic_condensed_graph.node_count(), 2);
717/// assert_eq!(acyclic_condensed_graph.edge_count(), 1);
718/// assert_eq!(acyclic_condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A]);
719/// ```
720pub fn condensation<N, E, Ty, Ix>(
721 g: Graph<N, E, Ty, Ix>,
722 make_acyclic: bool,
723) -> Graph<Vec<N>, E, Ty, Ix>
724where
725 Ty: EdgeType,
726 Ix: IndexType,
727{
728 let sccs = kosaraju_scc(&g);
729 let mut condensed: Graph<Vec<N>, E, Ty, Ix> = Graph::with_capacity(sccs.len(), g.edge_count());
730
731 // Build a map from old indices to new ones.
732 let mut node_map = vec![NodeIndex::end(); g.node_count()];
733 for comp in sccs {
734 let new_nix = condensed.add_node(Vec::new());
735 for nix in comp {
736 node_map[nix.index()] = new_nix;
737 }
738 }
739
740 // Consume nodes and edges of the old graph and insert them into the new one.
741 let (nodes, edges) = g.into_nodes_edges();
742 for (nix, node) in nodes.into_iter().enumerate() {
743 condensed[node_map[nix]].push(node.weight);
744 }
745 for edge in edges {
746 let source = node_map[edge.source().index()];
747 let target = node_map[edge.target().index()];
748 if make_acyclic {
749 if source != target {
750 condensed.update_edge(source, target, edge.weight);
751 }
752 } else {
753 condensed.add_edge(source, target, edge.weight);
754 }
755 }
756 condensed
757}
758
759/// An algorithm error: a cycle was found in the graph.
760#[derive(Clone, Debug, PartialEq)]
761pub struct Cycle<N>(pub(crate) N);
762
763impl<N> Cycle<N> {
764 /// Return a node id that participates in the cycle
765 pub fn node_id(&self) -> N
766 where
767 N: Copy,
768 {
769 self.0
770 }
771}
772
773/// An algorithm error: a cycle of negative weights was found in the graph.
774#[derive(Clone, Debug, PartialEq)]
775pub struct NegativeCycle(pub ());
776
777/// Return `true` if the graph\* is bipartite.
778///
779/// A graph is bipartite if its nodes can be divided into
780/// two disjoint and indepedent sets U and V such that every edge connects U to one in V.
781///
782/// This algorithm implements 2-coloring algorithm based on the BFS algorithm.
783/// Always treats the input graph as if undirected.
784///
785/// \* The algorithm checks only the subgraph that is reachable from the `start`.
786///
787/// # Arguments
788/// * `g`: an input graph.
789/// * `start`: some node of the graph.
790///
791/// # Returns
792/// * `true`: if the subgraph accessible from the start node is bipartite.
793/// * `false`: if such a subgraph is not bipartite.
794///
795/// # Complexity
796/// * Time complexity: **O(|V| + |E|)**.
797/// * Auxiliary space: **O(|V|)**.
798///
799/// where **|V|** is the number of nodes and **|E|** is the number of edges.
800pub fn is_bipartite_undirected<G, N, VM>(g: G, start: N) -> bool
801where
802 G: GraphRef + Visitable<NodeId = N, Map = VM> + IntoNeighbors<NodeId = N>,
803 N: Copy + PartialEq + core::fmt::Debug,
804 VM: VisitMap<N>,
805{
806 let mut red = g.visit_map();
807 red.visit(start);
808 let mut blue = g.visit_map();
809
810 let mut stack = ::alloc::collections::VecDeque::new();
811 stack.push_front(start);
812
813 while let Some(node) = stack.pop_front() {
814 let is_red = red.is_visited(&node);
815 let is_blue = blue.is_visited(&node);
816
817 assert!(is_red ^ is_blue);
818
819 for neighbour in g.neighbors(node) {
820 let is_neigbour_red = red.is_visited(&neighbour);
821 let is_neigbour_blue = blue.is_visited(&neighbour);
822
823 if (is_red && is_neigbour_red) || (is_blue && is_neigbour_blue) {
824 return false;
825 }
826
827 if !is_neigbour_red && !is_neigbour_blue {
828 //hasn't been visited yet
829
830 match (is_red, is_blue) {
831 (true, false) => {
832 blue.visit(neighbour);
833 }
834 (false, true) => {
835 red.visit(neighbour);
836 }
837 (_, _) => {
838 panic!("Invariant doesn't hold");
839 }
840 }
841
842 stack.push_back(neighbour);
843 }
844 }
845 }
846
847 true
848}
849
850use core::fmt::Debug;
851use core::ops::Add;
852
853/// Associated data that can be used for measures (such as length).
854pub trait Measure: Debug + PartialOrd + Add<Self, Output = Self> + Default + Clone {}
855
856impl<M> Measure for M where M: Debug + PartialOrd + Add<M, Output = M> + Default + Clone {}
857
858/// A floating-point measure.
859pub trait FloatMeasure: Measure + Copy {
860 fn zero() -> Self;
861 fn infinite() -> Self;
862 fn from_f32(val: f32) -> Self;
863 fn from_f64(val: f64) -> Self;
864}
865
866impl FloatMeasure for f32 {
867 fn zero() -> Self {
868 0.
869 }
870 fn infinite() -> Self {
871 1. / 0.
872 }
873 fn from_f32(val: f32) -> Self {
874 val
875 }
876 fn from_f64(val: f64) -> Self {
877 val as f32
878 }
879}
880
881impl FloatMeasure for f64 {
882 fn zero() -> Self {
883 0.
884 }
885 fn infinite() -> Self {
886 1. / 0.
887 }
888 fn from_f32(val: f32) -> Self {
889 val as f64
890 }
891 fn from_f64(val: f64) -> Self {
892 val
893 }
894}
895
896pub trait BoundedMeasure: Measure + core::ops::Sub<Self, Output = Self> {
897 fn min() -> Self;
898 fn max() -> Self;
899 fn overflowing_add(self, rhs: Self) -> (Self, bool);
900 fn from_f32(val: f32) -> Self;
901 fn from_f64(val: f64) -> Self;
902}
903
904macro_rules! impl_bounded_measure_integer(
905 ( $( $t:ident ),* ) => {
906 $(
907 impl BoundedMeasure for $t {
908 fn min() -> Self {
909 $t::MIN
910 }
911
912 fn max() -> Self {
913 $t::MAX
914 }
915
916 fn overflowing_add(self, rhs: Self) -> (Self, bool) {
917 self.overflowing_add(rhs)
918 }
919
920 fn from_f32(val: f32) -> Self {
921 val as $t
922 }
923
924 fn from_f64(val: f64) -> Self {
925 val as $t
926 }
927 }
928 )*
929 };
930);
931
932impl_bounded_measure_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
933
934macro_rules! impl_bounded_measure_float(
935 ( $( $t:ident ),* ) => {
936 $(
937 impl BoundedMeasure for $t {
938 fn min() -> Self {
939 $t::MIN
940 }
941
942 fn max() -> Self {
943 $t::MAX
944 }
945
946 fn overflowing_add(self, rhs: Self) -> (Self, bool) {
947 // for an overflow: a + b > max: both values need to be positive and a > max - b must be satisfied
948 let overflow = self > Self::default() && rhs > Self::default() && self > $t::MAX - rhs;
949
950 // for an underflow: a + b < min: overflow can not happen and both values must be negative and a < min - b must be satisfied
951 let underflow = !overflow && self < Self::default() && rhs < Self::default() && self < $t::MIN - rhs;
952
953 (self + rhs, overflow || underflow)
954 }
955
956 fn from_f32(val: f32) -> Self {
957 val as $t
958 }
959
960 fn from_f64(val: f64) -> Self {
961 val as $t
962 }
963 }
964 )*
965 };
966);
967
968impl_bounded_measure_float!(f32, f64);
969
970/// A floating-point measure that can be computed from `usize`
971/// and with a default measure of proximity.
972pub trait UnitMeasure:
973 Measure
974 + core::ops::Sub<Self, Output = Self>
975 + core::ops::Mul<Self, Output = Self>
976 + core::ops::Div<Self, Output = Self>
977 + core::iter::Sum
978{
979 fn zero() -> Self;
980 fn one() -> Self;
981 fn from_usize(nb: usize) -> Self;
982 fn default_tol() -> Self;
983 fn from_f32(val: f32) -> Self;
984 fn from_f64(val: f64) -> Self;
985}
986
987macro_rules! impl_unit_measure(
988 ( $( $t:ident ),* )=> {
989 $(
990 impl UnitMeasure for $t {
991 fn zero() -> Self {
992 0 as $t
993 }
994 fn one() -> Self {
995 1 as $t
996 }
997
998 fn from_usize(nb: usize) -> Self {
999 nb as $t
1000 }
1001
1002 fn default_tol() -> Self {
1003 1e-6 as $t
1004 }
1005
1006 fn from_f32(val: f32) -> Self {
1007 val as $t
1008 }
1009
1010 fn from_f64(val: f64) -> Self {
1011 val as $t
1012 }
1013 }
1014
1015 )*
1016 }
1017);
1018impl_unit_measure!(f32, f64);
1019
1020/// Some measure of positive numbers, assuming positive
1021/// float-pointing numbers
1022pub trait PositiveMeasure: Measure + Copy {
1023 fn zero() -> Self;
1024 fn max() -> Self;
1025}
1026
1027macro_rules! impl_positive_measure(
1028 ( $( $t:ident ),* )=> {
1029 $(
1030 impl PositiveMeasure for $t {
1031 fn zero() -> Self {
1032 0 as $t
1033 }
1034 fn max() -> Self {
1035 $t::MAX
1036 }
1037 }
1038
1039 )*
1040 }
1041);
1042
1043impl_positive_measure!(u8, u16, u32, u64, u128, usize, f32, f64);