summaryrefslogtreecommitdiffstats
path: root/vendor/petgraph/tests/graph.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/petgraph/tests/graph.rs')
-rw-r--r--vendor/petgraph/tests/graph.rs2369
1 files changed, 2369 insertions, 0 deletions
diff --git a/vendor/petgraph/tests/graph.rs b/vendor/petgraph/tests/graph.rs
new file mode 100644
index 000000000..e76c04f02
--- /dev/null
+++ b/vendor/petgraph/tests/graph.rs
@@ -0,0 +1,2369 @@
+extern crate petgraph;
+
+use std::collections::HashSet;
+use std::hash::Hash;
+
+use petgraph::prelude::*;
+use petgraph::EdgeType;
+
+use petgraph as pg;
+
+use petgraph::algo::{
+ dominators, has_path_connecting, is_bipartite_undirected, is_cyclic_undirected,
+ is_isomorphic_matching, min_spanning_tree,
+};
+
+use petgraph::graph::node_index as n;
+use petgraph::graph::IndexType;
+
+use petgraph::algo::{astar, dijkstra, DfsSpace};
+use petgraph::visit::{
+ IntoEdges, IntoEdgesDirected, IntoNeighbors, IntoNodeIdentifiers, NodeFiltered, Reversed, Topo,
+ VisitMap, Walker,
+};
+
+use petgraph::dot::Dot;
+
+fn set<I>(iter: I) -> HashSet<I::Item>
+where
+ I: IntoIterator,
+ I::Item: Hash + Eq,
+{
+ iter.into_iter().collect()
+}
+
+#[test]
+fn undirected() {
+ let mut og = Graph::new_undirected();
+ let a = og.add_node(0);
+ let b = og.add_node(1);
+ let c = og.add_node(2);
+ let d = og.add_node(3);
+ let _ = og.add_edge(a, b, 0);
+ let _ = og.add_edge(a, c, 1);
+ og.add_edge(c, a, 2);
+ og.add_edge(a, a, 3);
+ og.add_edge(b, c, 4);
+ og.add_edge(b, a, 5);
+ og.add_edge(a, d, 6);
+ assert_eq!(og.node_count(), 4);
+ assert_eq!(og.edge_count(), 7);
+
+ assert!(og.find_edge(a, b).is_some());
+ assert!(og.find_edge(d, a).is_some());
+ assert!(og.find_edge(a, a).is_some());
+
+ for edge in og.raw_edges() {
+ assert!(og.find_edge(edge.source(), edge.target()).is_some());
+ assert!(og.find_edge(edge.target(), edge.source()).is_some());
+ }
+
+ assert_eq!(og.neighbors(b).collect::<Vec<_>>(), vec![a, c, a]);
+
+ og.remove_node(a);
+ assert_eq!(og.neighbors(b).collect::<Vec<_>>(), vec![c]);
+ assert_eq!(og.node_count(), 3);
+ assert_eq!(og.edge_count(), 1);
+ assert!(og.find_edge(a, b).is_none());
+ assert!(og.find_edge(d, a).is_none());
+ assert!(og.find_edge(a, a).is_none());
+ assert!(og.find_edge(b, c).is_some());
+ assert_graph_consistent(&og);
+}
+
+#[test]
+fn dfs() {
+ let mut gr = Graph::new();
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ let k = gr.add_node("K");
+ // Z is disconnected.
+ let _ = gr.add_node("Z");
+ gr.add_edge(h, i, 1.);
+ gr.add_edge(h, j, 3.);
+ gr.add_edge(i, j, 1.);
+ gr.add_edge(i, k, 2.);
+
+ println!("{}", Dot::new(&gr));
+
+ assert_eq!(Dfs::new(&gr, h).iter(&gr).count(), 4);
+ assert_eq!(Dfs::new(&gr, h).iter(&gr).clone().count(), 4);
+
+ assert_eq!(Dfs::new(&gr, h).iter(Reversed(&gr)).count(), 1);
+
+ assert_eq!(Dfs::new(&gr, k).iter(Reversed(&gr)).count(), 3);
+
+ assert_eq!(Dfs::new(&gr, i).iter(&gr).count(), 3);
+}
+
+#[test]
+fn dfs_order() {
+ let mut gr = Graph::new();
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ let k = gr.add_node("K");
+ gr.add_edge(h, i, ());
+ gr.add_edge(h, j, ());
+ gr.add_edge(h, k, ());
+ gr.add_edge(i, k, ());
+ gr.add_edge(k, i, ());
+
+ // H
+ // / | \
+ // I J K
+ // \___/
+ //
+ // J cannot be visited between I and K in a depth-first search from H
+
+ let mut seen_i = false;
+ let mut seen_k = false;
+ for node in Dfs::new(&gr, h).iter(&gr) {
+ seen_i |= i == node;
+ seen_k |= k == node;
+ assert!(!(j == node && (seen_i ^ seen_k)), "Invalid DFS order");
+ }
+}
+
+#[test]
+fn bfs() {
+ let mut gr = Graph::new();
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ let k = gr.add_node("K");
+ // Z is disconnected.
+ let _ = gr.add_node("Z");
+ gr.add_edge(h, i, 1.);
+ gr.add_edge(h, j, 3.);
+ gr.add_edge(i, j, 1.);
+ gr.add_edge(i, k, 2.);
+
+ assert_eq!(Bfs::new(&gr, h).iter(&gr).count(), 4);
+ assert_eq!(Bfs::new(&gr, h).iter(&gr).clone().count(), 4);
+
+ assert_eq!(Bfs::new(&gr, h).iter(Reversed(&gr)).count(), 1);
+
+ assert_eq!(Bfs::new(&gr, k).iter(Reversed(&gr)).count(), 3);
+
+ assert_eq!(Bfs::new(&gr, i).iter(&gr).count(), 3);
+
+ let mut bfs = Bfs::new(&gr, h);
+ let nx = bfs.next(&gr);
+ assert_eq!(nx, Some(h));
+
+ let nx1 = bfs.next(&gr);
+ assert!(nx1 == Some(i) || nx1 == Some(j));
+
+ let nx2 = bfs.next(&gr);
+ assert!(nx2 == Some(i) || nx2 == Some(j));
+ assert!(nx1 != nx2);
+
+ let nx = bfs.next(&gr);
+ assert_eq!(nx, Some(k));
+ assert_eq!(bfs.next(&gr), None);
+}
+
+#[test]
+fn mst() {
+ use petgraph::data::FromElements;
+
+ let mut gr = Graph::<_, _>::new();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+ let f = gr.add_node("F");
+ let g = gr.add_node("G");
+ gr.add_edge(a, b, 7.);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+
+ // add a disjoint part
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ gr.add_edge(h, i, 1.);
+ gr.add_edge(h, j, 3.);
+ gr.add_edge(i, j, 1.);
+
+ println!("{}", Dot::new(&gr));
+
+ let mst = UnGraph::from_elements(min_spanning_tree(&gr));
+
+ println!("{}", Dot::new(&mst));
+ println!("{:?}", Dot::new(&mst));
+ println!("MST is:\n{:#?}", mst);
+ assert!(mst.node_count() == gr.node_count());
+ // |E| = |N| - 2 because there are two disconnected components.
+ assert!(mst.edge_count() == gr.node_count() - 2);
+
+ // check the exact edges are there
+ assert!(mst.find_edge(a, b).is_some());
+ assert!(mst.find_edge(a, d).is_some());
+ assert!(mst.find_edge(b, e).is_some());
+ assert!(mst.find_edge(e, c).is_some());
+ assert!(mst.find_edge(e, g).is_some());
+ assert!(mst.find_edge(d, f).is_some());
+
+ assert!(mst.find_edge(h, i).is_some());
+ assert!(mst.find_edge(i, j).is_some());
+
+ assert!(mst.find_edge(d, b).is_none());
+ assert!(mst.find_edge(b, c).is_none());
+}
+
+#[test]
+fn selfloop() {
+ let mut gr = Graph::new();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+ gr.add_edge(a, b, 7.);
+ gr.add_edge(c, a, 6.);
+ let sed = gr.add_edge(a, a, 2.);
+
+ assert!(gr.find_edge(a, b).is_some());
+ assert!(gr.find_edge(b, a).is_none());
+ assert!(gr.find_edge_undirected(b, a).is_some());
+ assert!(gr.find_edge(a, a).is_some());
+ println!("{:?}", gr);
+
+ gr.remove_edge(sed);
+ assert!(gr.find_edge(a, a).is_none());
+ println!("{:?}", gr);
+}
+
+#[test]
+fn cyclic() {
+ let mut gr = Graph::new();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+
+ assert!(!is_cyclic_undirected(&gr));
+ gr.add_edge(a, b, 7.);
+ gr.add_edge(c, a, 6.);
+ assert!(!is_cyclic_undirected(&gr));
+ {
+ let e = gr.add_edge(a, a, 0.);
+ assert!(is_cyclic_undirected(&gr));
+ gr.remove_edge(e);
+ assert!(!is_cyclic_undirected(&gr));
+ }
+
+ {
+ let e = gr.add_edge(b, c, 0.);
+ assert!(is_cyclic_undirected(&gr));
+ gr.remove_edge(e);
+ assert!(!is_cyclic_undirected(&gr));
+ }
+
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+ gr.add_edge(b, d, 0.);
+ gr.add_edge(d, e, 0.);
+ assert!(!is_cyclic_undirected(&gr));
+ gr.add_edge(c, e, 0.);
+ assert!(is_cyclic_undirected(&gr));
+ assert_graph_consistent(&gr);
+}
+
+#[test]
+fn bipartite() {
+ {
+ let mut gr = Graph::new_undirected();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+ let f = gr.add_node("F");
+
+ gr.add_edge(a, d, 7.);
+ gr.add_edge(b, d, 6.);
+
+ assert!(is_bipartite_undirected(&gr, a));
+
+ let e_index = gr.add_edge(a, b, 6.);
+
+ assert!(!is_bipartite_undirected(&gr, a));
+
+ gr.remove_edge(e_index);
+
+ assert!(is_bipartite_undirected(&gr, a));
+
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(b, f, 6.);
+ gr.add_edge(c, e, 6.);
+
+ assert!(is_bipartite_undirected(&gr, a));
+ }
+ {
+ let mut gr = Graph::new_undirected();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+
+ let f = gr.add_node("F");
+ let g = gr.add_node("G");
+ let h = gr.add_node("H");
+
+ gr.add_edge(a, f, 7.);
+ gr.add_edge(a, g, 7.);
+ gr.add_edge(a, h, 7.);
+
+ gr.add_edge(b, f, 6.);
+ gr.add_edge(b, g, 6.);
+ gr.add_edge(b, h, 6.);
+
+ gr.add_edge(c, f, 6.);
+ gr.add_edge(c, g, 6.);
+ gr.add_edge(c, h, 6.);
+
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(d, g, 6.);
+ gr.add_edge(d, h, 6.);
+
+ gr.add_edge(e, f, 6.);
+ gr.add_edge(e, g, 6.);
+ gr.add_edge(e, h, 6.);
+
+ assert!(is_bipartite_undirected(&gr, a));
+
+ gr.add_edge(a, b, 6.);
+
+ assert!(!is_bipartite_undirected(&gr, a));
+ }
+}
+
+#[test]
+fn multi() {
+ let mut gr = Graph::new();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ gr.add_edge(a, b, ());
+ gr.add_edge(a, b, ());
+ assert_eq!(gr.edge_count(), 2);
+}
+
+#[test]
+fn iter_multi_edges() {
+ let mut gr = Graph::new();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let c = gr.add_node("c");
+
+ let mut connecting_edges = HashSet::new();
+
+ gr.add_edge(a, a, ());
+ connecting_edges.insert(gr.add_edge(a, b, ()));
+ gr.add_edge(a, c, ());
+ gr.add_edge(c, b, ());
+ connecting_edges.insert(gr.add_edge(a, b, ()));
+ gr.add_edge(b, a, ());
+
+ let mut iter = gr.edges_connecting(a, b);
+
+ let edge_id = iter.next().unwrap().id();
+ assert!(connecting_edges.contains(&edge_id));
+ connecting_edges.remove(&edge_id);
+
+ let edge_id = iter.next().unwrap().id();
+ assert!(connecting_edges.contains(&edge_id));
+ connecting_edges.remove(&edge_id);
+
+ assert_eq!(None, iter.next());
+ assert!(connecting_edges.is_empty());
+}
+
+#[test]
+fn iter_multi_undirected_edges() {
+ let mut gr = Graph::new_undirected();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let c = gr.add_node("c");
+
+ let mut connecting_edges = HashSet::new();
+
+ gr.add_edge(a, a, ());
+ connecting_edges.insert(gr.add_edge(a, b, ()));
+ gr.add_edge(a, c, ());
+ gr.add_edge(c, b, ());
+ connecting_edges.insert(gr.add_edge(a, b, ()));
+ connecting_edges.insert(gr.add_edge(b, a, ()));
+
+ let mut iter = gr.edges_connecting(a, b);
+
+ let edge_id = iter.next().unwrap().id();
+ assert!(connecting_edges.contains(&edge_id));
+ connecting_edges.remove(&edge_id);
+
+ let edge_id = iter.next().unwrap().id();
+ assert!(connecting_edges.contains(&edge_id));
+ connecting_edges.remove(&edge_id);
+
+ let edge_id = iter.next().unwrap().id();
+ assert!(connecting_edges.contains(&edge_id));
+ connecting_edges.remove(&edge_id);
+
+ assert_eq!(None, iter.next());
+ assert!(connecting_edges.is_empty());
+}
+
+#[test]
+fn update_edge() {
+ {
+ let mut gr = Graph::new();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let e = gr.update_edge(a, b, 1);
+ let f = gr.update_edge(a, b, 2);
+ let _ = gr.update_edge(b, a, 3);
+ assert_eq!(gr.edge_count(), 2);
+ assert_eq!(e, f);
+ assert_eq!(*gr.edge_weight(f).unwrap(), 2);
+ }
+
+ {
+ let mut gr = Graph::new_undirected();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let e = gr.update_edge(a, b, 1);
+ let f = gr.update_edge(b, a, 2);
+ assert_eq!(gr.edge_count(), 1);
+ assert_eq!(e, f);
+ assert_eq!(*gr.edge_weight(f).unwrap(), 2);
+ }
+}
+
+#[test]
+fn dijk() {
+ let mut g = Graph::new_undirected();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ let c = g.add_node("C");
+ let d = g.add_node("D");
+ let e = g.add_node("E");
+ let f = g.add_node("F");
+ g.add_edge(a, b, 7);
+ g.add_edge(c, a, 9);
+ g.add_edge(a, d, 14);
+ g.add_edge(b, c, 10);
+ g.add_edge(d, c, 2);
+ g.add_edge(d, e, 9);
+ g.add_edge(b, f, 15);
+ g.add_edge(c, f, 11);
+ g.add_edge(e, f, 6);
+ println!("{:?}", g);
+ for no in Bfs::new(&g, a).iter(&g) {
+ println!("Visit {:?} = {:?}", no, g.node_weight(no));
+ }
+
+ let scores = dijkstra(&g, a, None, |e| *e.weight());
+ let mut scores: Vec<_> = scores.into_iter().map(|(n, s)| (g[n], s)).collect();
+ scores.sort();
+ assert_eq!(
+ scores,
+ vec![
+ ("A", 0),
+ ("B", 7),
+ ("C", 9),
+ ("D", 11),
+ ("E", 20),
+ ("F", 20)
+ ]
+ );
+
+ let scores = dijkstra(&g, a, Some(c), |e| *e.weight());
+ assert_eq!(scores[&c], 9);
+}
+
+#[test]
+fn test_astar_null_heuristic() {
+ let mut g = Graph::new();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ let c = g.add_node("C");
+ let d = g.add_node("D");
+ let e = g.add_node("E");
+ let f = g.add_node("F");
+ g.add_edge(a, b, 7);
+ g.add_edge(c, a, 9);
+ g.add_edge(a, d, 14);
+ g.add_edge(b, c, 10);
+ g.add_edge(d, c, 2);
+ g.add_edge(d, e, 9);
+ g.add_edge(b, f, 15);
+ g.add_edge(c, f, 11);
+ g.add_edge(e, f, 6);
+
+ let path = astar(&g, a, |finish| finish == e, |e| *e.weight(), |_| 0);
+ assert_eq!(path, Some((23, vec![a, d, e])));
+
+ // check against dijkstra
+ let dijkstra_run = dijkstra(&g, a, Some(e), |e| *e.weight());
+ assert_eq!(dijkstra_run[&e], 23);
+
+ let path = astar(&g, e, |finish| finish == b, |e| *e.weight(), |_| 0);
+ assert_eq!(path, None);
+}
+
+#[test]
+fn test_astar_manhattan_heuristic() {
+ let mut g = Graph::new();
+ let a = g.add_node((0., 0.));
+ let b = g.add_node((2., 0.));
+ let c = g.add_node((1., 1.));
+ let d = g.add_node((0., 2.));
+ let e = g.add_node((3., 3.));
+ let f = g.add_node((4., 2.));
+ let _ = g.add_node((5., 5.)); // no path to node
+ g.add_edge(a, b, 2.);
+ g.add_edge(a, d, 4.);
+ g.add_edge(b, c, 1.);
+ g.add_edge(b, f, 7.);
+ g.add_edge(c, e, 5.);
+ g.add_edge(e, f, 1.);
+ g.add_edge(d, e, 1.);
+
+ let heuristic_for = |f: NodeIndex| {
+ let g = &g;
+ move |node: NodeIndex| -> f32 {
+ let (x1, y1): (f32, f32) = g[node];
+ let (x2, y2): (f32, f32) = g[f];
+
+ (x2 - x1).abs() + (y2 - y1).abs()
+ }
+ };
+ let path = astar(
+ &g,
+ a,
+ |finish| finish == f,
+ |e| *e.weight(),
+ heuristic_for(f),
+ );
+
+ assert_eq!(path, Some((6., vec![a, d, e, f])));
+
+ // check against dijkstra
+ let dijkstra_run = dijkstra(&g, a, None, |e| *e.weight());
+
+ for end in g.node_indices() {
+ let astar_path = astar(
+ &g,
+ a,
+ |finish| finish == end,
+ |e| *e.weight(),
+ heuristic_for(end),
+ );
+ assert_eq!(dijkstra_run.get(&end).cloned(), astar_path.map(|t| t.0));
+ }
+}
+
+#[cfg(feature = "generate")]
+#[test]
+fn test_generate_undirected() {
+ for size in 0..4 {
+ let mut gen = pg::generate::Generator::<Undirected>::all(size, true);
+ let nedges = (size * size - size) / 2 + size;
+ let mut n = 0;
+ while let Some(g) = gen.next_ref() {
+ n += 1;
+ println!("{:?}", g);
+ }
+
+ assert_eq!(n, 1 << nedges);
+ }
+}
+
+#[cfg(feature = "generate")]
+#[test]
+fn test_generate_directed() {
+ // Number of DAG out of all graphs (all permutations) per node size
+ // 0, 1, 2, 3, 4, 5 ..
+ let n_dag = &[1, 1, 3, 25, 543, 29281, 3781503];
+ for (size, &dags_exp) in (0..4).zip(n_dag) {
+ let mut gen = pg::generate::Generator::<Directed>::all(size, true);
+ let nedges = size * size;
+ let mut n = 0;
+ let mut dags = 0;
+ while let Some(g) = gen.next_ref() {
+ n += 1;
+ if !pg::algo::is_cyclic_directed(g) {
+ dags += 1;
+ }
+ }
+
+ /*
+ // check that all generated graphs have unique adjacency matrices
+ let mut adjmats = graphs.iter().map(Graph::adjacency_matrix).collect::<Vec<_>>();
+ adjmats.sort(); adjmats.dedup();
+ assert_eq!(adjmats.len(), n);
+ */
+ assert_eq!(dags_exp, dags);
+ assert_eq!(n, 1 << nedges);
+ }
+}
+
+#[cfg(feature = "generate")]
+#[test]
+fn test_generate_dag() {
+ use petgraph::visit::GetAdjacencyMatrix;
+ for size in 1..5 {
+ let gen = pg::generate::Generator::directed_acyclic(size);
+ let nedges = (size - 1) * size / 2;
+ let graphs = gen.collect::<Vec<_>>();
+
+ assert_eq!(graphs.len(), 1 << nedges);
+
+ // check that all generated graphs have unique adjacency matrices
+ let mut adjmats = graphs
+ .iter()
+ .map(Graph::adjacency_matrix)
+ .collect::<Vec<_>>();
+ adjmats.sort();
+ adjmats.dedup();
+ assert_eq!(adjmats.len(), graphs.len());
+ for gr in &graphs {
+ assert!(
+ !petgraph::algo::is_cyclic_directed(gr),
+ "Assertion failed: {:?} acyclic",
+ gr
+ );
+ }
+ }
+}
+
+#[test]
+fn without() {
+ let mut og = Graph::new_undirected();
+ let a = og.add_node(0);
+ let b = og.add_node(1);
+ let c = og.add_node(2);
+ let d = og.add_node(3);
+ let _ = og.add_edge(a, b, 0);
+ let _ = og.add_edge(a, c, 1);
+ let v: Vec<NodeIndex> = og.externals(Outgoing).collect();
+ assert_eq!(v, vec![d]);
+
+ let mut og = Graph::new();
+ let a = og.add_node(0);
+ let b = og.add_node(1);
+ let c = og.add_node(2);
+ let d = og.add_node(3);
+ let _ = og.add_edge(a, b, 0);
+ let _ = og.add_edge(a, c, 1);
+ let init: Vec<NodeIndex> = og.externals(Incoming).collect();
+ let term: Vec<NodeIndex> = og.externals(Outgoing).collect();
+ assert_eq!(init, vec![a, d]);
+ assert_eq!(term, vec![b, c, d]);
+}
+
+fn assert_is_topo_order<N, E>(gr: &Graph<N, E, Directed>, order: &[NodeIndex]) {
+ assert_eq!(gr.node_count(), order.len());
+ // check all the edges of the graph
+ for edge in gr.raw_edges() {
+ let a = edge.source();
+ let b = edge.target();
+ let ai = order.iter().position(|x| *x == a).unwrap();
+ let bi = order.iter().position(|x| *x == b).unwrap();
+ println!("Check that {:?} is before {:?}", a, b);
+ assert!(
+ ai < bi,
+ "Topo order: assertion that node {:?} is before {:?} failed",
+ a,
+ b
+ );
+ }
+}
+
+#[test]
+fn test_toposort() {
+ let mut gr = Graph::<_, _>::new();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+ let f = gr.add_node("F");
+ let g = gr.add_node("G");
+ gr.extend_with_edges(&[
+ (a, b, 7.),
+ (a, d, 5.),
+ (d, b, 9.),
+ (b, c, 8.),
+ (b, e, 7.),
+ (c, e, 5.),
+ (d, e, 15.),
+ (d, f, 6.),
+ (f, e, 8.),
+ (f, g, 11.),
+ (e, g, 9.),
+ ]);
+
+ // add a disjoint part
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ gr.add_edge(h, i, 1.);
+ gr.add_edge(h, j, 3.);
+ gr.add_edge(i, j, 1.);
+
+ let order = petgraph::algo::toposort(&gr, None).unwrap();
+ println!("{:?}", order);
+ assert_eq!(order.len(), gr.node_count());
+
+ assert_is_topo_order(&gr, &order);
+}
+
+#[test]
+fn test_toposort_eq() {
+ let mut g = Graph::<_, _>::new();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ g.add_edge(a, b, ());
+
+ assert_eq!(petgraph::algo::toposort(&g, None), Ok(vec![a, b]));
+}
+
+#[test]
+fn is_cyclic_directed() {
+ let mut gr = Graph::<_, _>::new();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+ let f = gr.add_node("F");
+ let g = gr.add_node("G");
+ gr.add_edge(a, b, 7.0);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+
+ assert!(!petgraph::algo::is_cyclic_directed(&gr));
+
+ // add a disjoint part
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ gr.add_edge(h, i, 1.);
+ gr.add_edge(h, j, 3.);
+ gr.add_edge(i, j, 1.);
+ assert!(!petgraph::algo::is_cyclic_directed(&gr));
+
+ gr.add_edge(g, e, 0.);
+ assert!(petgraph::algo::is_cyclic_directed(&gr));
+}
+
+/// Compare two scc sets. Inside each scc, the order does not matter,
+/// but the order of the sccs is significant.
+fn assert_sccs_eq(
+ mut res: Vec<Vec<NodeIndex>>,
+ mut answer: Vec<Vec<NodeIndex>>,
+ scc_order_matters: bool,
+) {
+ // normalize the result and compare with the answer.
+ for scc in &mut res {
+ scc.sort();
+ }
+ for scc in &mut answer {
+ scc.sort();
+ }
+ if !scc_order_matters {
+ res.sort();
+ answer.sort();
+ }
+ assert_eq!(res, answer);
+}
+
+#[test]
+fn scc() {
+ let gr: Graph<(), ()> = Graph::from_edges(&[
+ (6, 0),
+ (0, 3),
+ (3, 6),
+ (8, 6),
+ (8, 2),
+ (2, 5),
+ (5, 8),
+ (7, 5),
+ (1, 7),
+ (7, 4),
+ (4, 1),
+ ]);
+
+ assert_sccs_eq(
+ petgraph::algo::kosaraju_scc(&gr),
+ vec![
+ vec![n(0), n(3), n(6)],
+ vec![n(2), n(5), n(8)],
+ vec![n(1), n(4), n(7)],
+ ],
+ true,
+ );
+ // Reversed edges gives the same sccs (when sorted)
+ assert_sccs_eq(
+ petgraph::algo::kosaraju_scc(Reversed(&gr)),
+ vec![
+ vec![n(1), n(4), n(7)],
+ vec![n(2), n(5), n(8)],
+ vec![n(0), n(3), n(6)],
+ ],
+ true,
+ );
+
+ // Test an undirected graph just for fun.
+ // Sccs are just connected components.
+ let mut hr = gr.into_edge_type::<Undirected>();
+ // Delete an edge to disconnect it
+ let ed = hr.find_edge(n(6), n(8)).unwrap();
+ assert!(hr.remove_edge(ed).is_some());
+
+ assert_sccs_eq(
+ petgraph::algo::kosaraju_scc(&hr),
+ vec![
+ vec![n(0), n(3), n(6)],
+ vec![n(1), n(2), n(4), n(5), n(7), n(8)],
+ ],
+ false,
+ );
+
+ // acyclic non-tree, #14
+ let n = NodeIndex::new;
+ let mut gr = Graph::new();
+ gr.add_node(0);
+ gr.add_node(1);
+ gr.add_node(2);
+ gr.add_node(3);
+ gr.add_edge(n(3), n(2), ());
+ gr.add_edge(n(3), n(1), ());
+ gr.add_edge(n(2), n(0), ());
+ gr.add_edge(n(1), n(0), ());
+
+ assert_sccs_eq(
+ petgraph::algo::kosaraju_scc(&gr),
+ vec![vec![n(0)], vec![n(1)], vec![n(2)], vec![n(3)]],
+ true,
+ );
+
+ // Kosaraju bug from PR #60
+ let mut gr = Graph::<(), ()>::new();
+ gr.extend_with_edges(&[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]);
+ gr.add_node(());
+ // no order for the disconnected one
+ assert_sccs_eq(
+ petgraph::algo::kosaraju_scc(&gr),
+ vec![vec![n(0)], vec![n(1)], vec![n(2)], vec![n(3)]],
+ false,
+ );
+}
+
+#[test]
+fn tarjan_scc() {
+ let gr: Graph<(), ()> = Graph::from_edges(&[
+ (6, 0),
+ (0, 3),
+ (3, 6),
+ (8, 6),
+ (8, 2),
+ (2, 5),
+ (5, 8),
+ (7, 5),
+ (1, 7),
+ (7, 4),
+ (4, 1),
+ ]);
+
+ assert_sccs_eq(
+ petgraph::algo::tarjan_scc(&gr),
+ vec![
+ vec![n(0), n(3), n(6)],
+ vec![n(2), n(5), n(8)],
+ vec![n(1), n(4), n(7)],
+ ],
+ true,
+ );
+
+ // Test an undirected graph just for fun.
+ // Sccs are just connected components.
+ let mut hr = gr.into_edge_type::<Undirected>();
+ // Delete an edge to disconnect it
+ let ed = hr.find_edge(n(6), n(8)).unwrap();
+ assert!(hr.remove_edge(ed).is_some());
+
+ assert_sccs_eq(
+ petgraph::algo::tarjan_scc(&hr),
+ vec![
+ vec![n(1), n(2), n(4), n(5), n(7), n(8)],
+ vec![n(0), n(3), n(6)],
+ ],
+ false,
+ );
+
+ // acyclic non-tree, #14
+ let n = NodeIndex::new;
+ let mut gr = Graph::new();
+ gr.add_node(0);
+ gr.add_node(1);
+ gr.add_node(2);
+ gr.add_node(3);
+ gr.add_edge(n(3), n(2), ());
+ gr.add_edge(n(3), n(1), ());
+ gr.add_edge(n(2), n(0), ());
+ gr.add_edge(n(1), n(0), ());
+
+ assert_sccs_eq(
+ petgraph::algo::tarjan_scc(&gr),
+ vec![vec![n(0)], vec![n(1)], vec![n(2)], vec![n(3)]],
+ true,
+ );
+
+ // Kosaraju bug from PR #60
+ let mut gr = Graph::<(), ()>::new();
+ gr.extend_with_edges(&[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]);
+ gr.add_node(());
+ // no order for the disconnected one
+ assert_sccs_eq(
+ petgraph::algo::tarjan_scc(&gr),
+ vec![vec![n(0)], vec![n(1)], vec![n(2)], vec![n(3)]],
+ false,
+ );
+}
+
+#[test]
+fn condensation() {
+ let gr: Graph<(), ()> = Graph::from_edges(&[
+ (6, 0),
+ (0, 3),
+ (3, 6),
+ (8, 6),
+ (8, 2),
+ (2, 3),
+ (2, 5),
+ (5, 8),
+ (7, 5),
+ (1, 7),
+ (7, 4),
+ (4, 1),
+ ]);
+
+ // make_acyclic = true
+
+ let cond = petgraph::algo::condensation(gr.clone(), true);
+
+ assert!(cond.node_count() == 3);
+ assert!(cond.edge_count() == 2);
+ assert!(
+ !petgraph::algo::is_cyclic_directed(&cond),
+ "Assertion failed: {:?} acyclic",
+ cond
+ );
+
+ // make_acyclic = false
+
+ let cond = petgraph::algo::condensation(gr.clone(), false);
+
+ assert!(cond.node_count() == 3);
+ assert!(cond.edge_count() == gr.edge_count());
+}
+
+#[test]
+fn connected_comp() {
+ let n = NodeIndex::new;
+ let mut gr = Graph::new();
+ gr.add_node(0);
+ gr.add_node(1);
+ gr.add_node(2);
+ gr.add_node(3);
+ gr.add_node(4);
+ gr.add_node(5);
+ gr.add_node(6);
+ gr.add_node(7);
+ gr.add_node(8);
+ gr.add_edge(n(6), n(0), ());
+ gr.add_edge(n(0), n(3), ());
+ gr.add_edge(n(3), n(6), ());
+ gr.add_edge(n(8), n(6), ());
+ gr.add_edge(n(8), n(2), ());
+ gr.add_edge(n(2), n(5), ());
+ gr.add_edge(n(5), n(8), ());
+ gr.add_edge(n(7), n(5), ());
+ gr.add_edge(n(1), n(7), ());
+ gr.add_edge(n(7), n(4), ());
+ gr.add_edge(n(4), n(1), ());
+ assert_eq!(petgraph::algo::connected_components(&gr), 1);
+
+ gr.add_node(9);
+ gr.add_node(10);
+ assert_eq!(petgraph::algo::connected_components(&gr), 3);
+
+ gr.add_edge(n(9), n(10), ());
+ assert_eq!(petgraph::algo::connected_components(&gr), 2);
+
+ let gr = gr.into_edge_type::<Undirected>();
+ assert_eq!(petgraph::algo::connected_components(&gr), 2);
+}
+
+#[should_panic]
+#[test]
+fn oob_index() {
+ let mut gr = Graph::<_, ()>::new();
+ let a = gr.add_node(0);
+ let b = gr.add_node(1);
+ gr.remove_node(a);
+ gr[b];
+}
+
+#[test]
+fn usize_index() {
+ let mut gr = Graph::<_, _, Directed, usize>::with_capacity(0, 0);
+ let a = gr.add_node(0);
+ let b = gr.add_node(1);
+ let e = gr.add_edge(a, b, 1.2);
+ let mut dfs = Dfs::new(&gr, a);
+ while let Some(nx) = dfs.next(&gr) {
+ gr[nx] += 1;
+ }
+ assert_eq!(gr[a], 1);
+ assert_eq!(gr[b], 2);
+ assert_eq!(gr[e], 1.2);
+}
+
+#[test]
+fn u8_index() {
+ let mut gr = Graph::<_, (), Undirected, u8>::with_capacity(0, 0);
+ for _ in 0..255 {
+ gr.add_node(());
+ }
+}
+
+#[should_panic]
+#[test]
+fn u8_index_overflow() {
+ let mut gr = Graph::<_, (), Undirected, u8>::with_capacity(0, 0);
+ for _ in 0..256 {
+ gr.add_node(());
+ }
+}
+
+#[should_panic]
+#[test]
+fn u8_index_overflow_edges() {
+ let mut gr = Graph::<_, (), Undirected, u8>::with_capacity(0, 0);
+ let a = gr.add_node('a');
+ let b = gr.add_node('b');
+ for _ in 0..256 {
+ gr.add_edge(a, b, ());
+ }
+}
+
+#[test]
+fn test_weight_iterators() {
+ let mut gr = Graph::<_, _>::new();
+ let a = gr.add_node("A");
+ let b = gr.add_node("B");
+ let c = gr.add_node("C");
+ let d = gr.add_node("D");
+ let e = gr.add_node("E");
+ let f = gr.add_node("F");
+ let g = gr.add_node("G");
+ gr.add_edge(a, b, 7.0);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+
+ assert_eq!(gr.node_weights_mut().count(), gr.node_count());
+ assert_eq!(gr.edge_weights_mut().count(), gr.edge_count());
+
+ // add a disjoint part
+ let h = gr.add_node("H");
+ let i = gr.add_node("I");
+ let j = gr.add_node("J");
+ gr.add_edge(h, i, 1.);
+ gr.add_edge(h, j, 3.);
+ gr.add_edge(i, j, 1.);
+
+ assert_eq!(gr.node_weights_mut().count(), gr.node_count());
+ assert_eq!(gr.edge_weights_mut().count(), gr.edge_count());
+
+ for nw in gr.node_weights_mut() {
+ *nw = "x";
+ }
+ for node in gr.raw_nodes() {
+ assert_eq!(node.weight, "x");
+ }
+
+ let old = gr.clone();
+ for (index, ew) in gr.edge_weights_mut().enumerate() {
+ assert_eq!(old[EdgeIndex::new(index)], *ew);
+ *ew = -*ew;
+ }
+ for (index, edge) in gr.raw_edges().iter().enumerate() {
+ assert_eq!(edge.weight, -1. * old[EdgeIndex::new(index)]);
+ }
+}
+
+#[test]
+fn walk_edges() {
+ let mut gr = Graph::<_, _>::new();
+ let a = gr.add_node(0.);
+ let b = gr.add_node(1.);
+ let c = gr.add_node(2.);
+ let d = gr.add_node(3.);
+ let e0 = gr.add_edge(a, b, 0.);
+ let e1 = gr.add_edge(a, d, 0.);
+ let e2 = gr.add_edge(b, c, 0.);
+ let e3 = gr.add_edge(c, a, 0.);
+
+ // Set edge weights to difference: target - source.
+ let mut dfs = Dfs::new(&gr, a);
+ while let Some(source) = dfs.next(&gr) {
+ let mut edges = gr.neighbors_directed(source, Outgoing).detach();
+ while let Some((edge, target)) = edges.next(&gr) {
+ gr[edge] = gr[target] - gr[source];
+ }
+ }
+ assert_eq!(gr[e0], 1.);
+ assert_eq!(gr[e1], 3.);
+ assert_eq!(gr[e2], 1.);
+ assert_eq!(gr[e3], -2.);
+
+ let mut nedges = 0;
+ let mut dfs = Dfs::new(&gr, a);
+ while let Some(node) = dfs.next(&gr) {
+ let mut edges = gr.neighbors_directed(node, Incoming).detach();
+ while let Some((edge, source)) = edges.next(&gr) {
+ assert_eq!(gr.find_edge(source, node), Some(edge));
+ nedges += 1;
+ }
+
+ let mut edges = gr.neighbors_directed(node, Outgoing).detach();
+ while let Some((edge, target)) = edges.next(&gr) {
+ assert_eq!(gr.find_edge(node, target), Some(edge));
+ nedges += 1;
+ }
+ }
+ assert_eq!(nedges, 8);
+}
+
+#[test]
+fn index_twice_mut() {
+ let mut gr = Graph::<_, _>::new();
+ let a = gr.add_node(0.);
+ let b = gr.add_node(0.);
+ let c = gr.add_node(0.);
+ let d = gr.add_node(0.);
+ let e = gr.add_node(0.);
+ let f = gr.add_node(0.);
+ let g = gr.add_node(0.);
+ gr.add_edge(a, b, 7.0);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+
+ for dir in &[Incoming, Outgoing] {
+ for nw in gr.node_weights_mut() {
+ *nw = 0.;
+ }
+
+ // walk the graph and sum incoming edges
+ let mut dfs = Dfs::new(&gr, a);
+ while let Some(node) = dfs.next(&gr) {
+ let mut edges = gr.neighbors_directed(node, *dir).detach();
+ while let Some(edge) = edges.next_edge(&gr) {
+ let (nw, ew) = gr.index_twice_mut(node, edge);
+ *nw += *ew;
+ }
+ }
+
+ // check the sums
+ for i in 0..gr.node_count() {
+ let ni = NodeIndex::new(i);
+ let s = gr
+ .edges_directed(ni, *dir)
+ .map(|e| *e.weight())
+ .fold(0., |a, b| a + b);
+ assert_eq!(s, gr[ni]);
+ }
+ println!("Sum {:?}: {:?}", dir, gr);
+ }
+}
+
+fn make_edge_iterator_graph<Ty: EdgeType>() -> Graph<f64, f64, Ty> {
+ let mut gr = Graph::default();
+ let a = gr.add_node(0.);
+ let b = gr.add_node(0.);
+ let c = gr.add_node(0.);
+ let d = gr.add_node(0.);
+ let e = gr.add_node(0.);
+ let f = gr.add_node(0.);
+ let g = gr.add_node(0.);
+ gr.add_edge(a, b, 7.0);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, c, 8.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+
+ gr
+}
+
+#[test]
+fn test_edge_iterators_directed() {
+ let gr = make_edge_iterator_graph::<Directed>();
+
+ for i in gr.node_indices() {
+ itertools::assert_equal(gr.edges_directed(i, Outgoing), gr.edges(i));
+
+ // Reversed reverses edges, so target and source need to be reversed once more.
+ itertools::assert_equal(
+ gr.edges_directed(i, Outgoing)
+ .map(|edge| (edge.source(), edge.target())),
+ Reversed(&gr)
+ .edges_directed(i, Incoming)
+ .map(|edge| (edge.target(), edge.source())),
+ );
+
+ for edge in gr.edges_directed(i, Outgoing) {
+ assert_eq!(
+ edge.source(),
+ i,
+ "outgoing edges should have a fixed source"
+ );
+ }
+ for edge in Reversed(&gr).edges_directed(i, Incoming) {
+ assert_eq!(
+ edge.target(),
+ i,
+ "reversed incoming edges should have a fixed target"
+ );
+ }
+ }
+
+ let mut reversed_gr = gr.clone();
+ reversed_gr.reverse();
+
+ println!("{:#?}", gr);
+ for i in gr.node_indices() {
+ // Compare against reversed graphs two different ways: using .reverse() and Reversed.
+ itertools::assert_equal(gr.edges_directed(i, Incoming), reversed_gr.edges(i));
+
+ // Reversed reverses edges, so target and source need to be reversed once more.
+ itertools::assert_equal(
+ gr.edges_directed(i, Incoming)
+ .map(|edge| (edge.source(), edge.target())),
+ Reversed(&gr)
+ .edges(i)
+ .map(|edge| (edge.target(), edge.source())),
+ );
+
+ for edge in gr.edges_directed(i, Incoming) {
+ assert_eq!(
+ edge.target(),
+ i,
+ "incoming edges should have a fixed target"
+ );
+ }
+ for edge in Reversed(&gr).edges_directed(i, Outgoing) {
+ assert_eq!(
+ edge.source(),
+ i,
+ "reversed outgoing edges should have a fixed source"
+ );
+ }
+ }
+}
+
+#[test]
+fn test_edge_iterators_undir() {
+ let gr = make_edge_iterator_graph::<Undirected>();
+
+ for i in gr.node_indices() {
+ itertools::assert_equal(gr.edges_directed(i, Outgoing), gr.edges(i));
+
+ // Reversed reverses edges, so target and source need to be reversed once more.
+ itertools::assert_equal(
+ gr.edges_directed(i, Outgoing)
+ .map(|edge| (edge.source(), edge.target())),
+ Reversed(&gr)
+ .edges_directed(i, Incoming)
+ .map(|edge| (edge.target(), edge.source())),
+ );
+
+ for edge in gr.edges_directed(i, Outgoing) {
+ assert_eq!(
+ edge.source(),
+ i,
+ "outgoing edges should have a fixed source"
+ );
+ }
+ for edge in Reversed(&gr).edges_directed(i, Incoming) {
+ assert_eq!(
+ edge.target(),
+ i,
+ "reversed incoming edges should have a fixed target"
+ );
+ }
+ }
+
+ for i in gr.node_indices() {
+ itertools::assert_equal(gr.edges_directed(i, Incoming), gr.edges(i));
+
+ // Reversed reverses edges, so target and source need to be reversed once more.
+ itertools::assert_equal(
+ gr.edges_directed(i, Incoming)
+ .map(|edge| (edge.source(), edge.target())),
+ Reversed(&gr)
+ .edges(i)
+ .map(|edge| (edge.target(), edge.source())),
+ );
+
+ for edge in gr.edges_directed(i, Incoming) {
+ assert_eq!(
+ edge.target(),
+ i,
+ "incoming edges should have a fixed target"
+ );
+ }
+ for edge in Reversed(&gr).edges_directed(i, Outgoing) {
+ assert_eq!(
+ edge.source(),
+ i,
+ "reversed outgoing edges should have a fixed source"
+ );
+ }
+ }
+}
+
+#[test]
+fn toposort_generic() {
+ // This is a DAG, visit it in order
+ let mut gr = Graph::<_, _>::new();
+ let b = gr.add_node(("B", 0.));
+ let a = gr.add_node(("A", 0.));
+ let c = gr.add_node(("C", 0.));
+ let d = gr.add_node(("D", 0.));
+ let e = gr.add_node(("E", 0.));
+ let f = gr.add_node(("F", 0.));
+ let g = gr.add_node(("G", 0.));
+ gr.add_edge(a, b, 7.0);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+
+ assert!(!pg::algo::is_cyclic_directed(&gr));
+ let mut index = 0.;
+ let mut topo = Topo::new(&gr);
+ while let Some(nx) = topo.next(&gr) {
+ gr[nx].1 = index;
+ index += 1.;
+ }
+
+ let mut order = Vec::new();
+ index = 0.;
+ let mut topo = Topo::new(&gr);
+ while let Some(nx) = topo.next(&gr) {
+ order.push(nx);
+ assert_eq!(gr[nx].1, index);
+ index += 1.;
+ }
+ println!("{:?}", gr);
+ assert_is_topo_order(&gr, &order);
+
+ {
+ order.clear();
+ let mut topo = Topo::new(&gr);
+ while let Some(nx) = topo.next(&gr) {
+ order.push(nx);
+ }
+ println!("{:?}", gr);
+ assert_is_topo_order(&gr, &order);
+ }
+ let mut gr2 = gr.clone();
+ gr.add_edge(e, d, -1.);
+ assert!(pg::algo::is_cyclic_directed(&gr));
+ assert!(pg::algo::toposort(&gr, None).is_err());
+ gr2.add_edge(d, d, 0.);
+ assert!(pg::algo::is_cyclic_directed(&gr2));
+ assert!(pg::algo::toposort(&gr2, None).is_err());
+}
+
+#[test]
+fn test_has_path() {
+ // This is a DAG, visit it in order
+ let mut gr = Graph::<_, _>::new();
+ let b = gr.add_node(("B", 0.));
+ let a = gr.add_node(("A", 0.));
+ let c = gr.add_node(("C", 0.));
+ let d = gr.add_node(("D", 0.));
+ let e = gr.add_node(("E", 0.));
+ let f = gr.add_node(("F", 0.));
+ let g = gr.add_node(("G", 0.));
+ gr.add_edge(a, b, 7.0);
+ gr.add_edge(a, d, 5.);
+ gr.add_edge(d, b, 9.);
+ gr.add_edge(b, c, 8.);
+ gr.add_edge(b, e, 7.);
+ gr.add_edge(c, e, 5.);
+ gr.add_edge(d, e, 15.);
+ gr.add_edge(d, f, 6.);
+ gr.add_edge(f, e, 8.);
+ gr.add_edge(f, g, 11.);
+ gr.add_edge(e, g, 9.);
+ // disconnected island
+
+ let h = gr.add_node(("H", 0.));
+ let i = gr.add_node(("I", 0.));
+ gr.add_edge(h, i, 2.);
+ gr.add_edge(i, h, -2.);
+
+ let mut state = DfsSpace::default();
+
+ gr.add_edge(b, a, 99.);
+
+ assert!(has_path_connecting(&gr, c, c, None));
+
+ for edge in gr.edge_references() {
+ assert!(has_path_connecting(&gr, edge.source(), edge.target(), None));
+ }
+ assert!(has_path_connecting(&gr, a, g, Some(&mut state)));
+ assert!(!has_path_connecting(&gr, a, h, Some(&mut state)));
+ assert!(has_path_connecting(&gr, a, c, None));
+ assert!(has_path_connecting(&gr, a, c, Some(&mut state)));
+ assert!(!has_path_connecting(&gr, h, a, Some(&mut state)));
+}
+
+#[test]
+fn map_filter_map() {
+ let mut g = Graph::new_undirected();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ let c = g.add_node("C");
+ let d = g.add_node("D");
+ let e = g.add_node("E");
+ let f = g.add_node("F");
+ g.add_edge(a, b, 7);
+ g.add_edge(c, a, 9);
+ g.add_edge(a, d, 14);
+ g.add_edge(b, c, 10);
+ g.add_edge(d, c, 2);
+ g.add_edge(d, e, 9);
+ g.add_edge(b, f, 15);
+ g.add_edge(c, f, 11);
+ g.add_edge(e, f, 6);
+ println!("{:?}", g);
+
+ let g2 = g.filter_map(
+ |_, name| Some(*name),
+ |_, &weight| if weight >= 10 { Some(weight) } else { None },
+ );
+ assert_eq!(g2.edge_count(), 4);
+ for edge in g2.raw_edges() {
+ assert!(edge.weight >= 10);
+ }
+
+ let g3 = g.filter_map(
+ |i, &name| if i == a || i == e { None } else { Some(name) },
+ |i, &weight| {
+ let (source, target) = g.edge_endpoints(i).unwrap();
+ // don't map edges from a removed node
+ assert!(source != a);
+ assert!(target != a);
+ assert!(source != e);
+ assert!(target != e);
+ Some(weight)
+ },
+ );
+ assert_eq!(g3.node_count(), g.node_count() - 2);
+ assert_eq!(g3.edge_count(), g.edge_count() - 5);
+ assert_graph_consistent(&g3);
+
+ let mut g4 = g.clone();
+ g4.retain_edges(|gr, i| {
+ let (s, t) = gr.edge_endpoints(i).unwrap();
+ !(s == a || s == e || t == a || t == e)
+ });
+ assert_eq!(g4.edge_count(), g.edge_count() - 5);
+ assert_graph_consistent(&g4);
+}
+
+#[test]
+fn from_edges() {
+ let n = NodeIndex::new;
+ let gr =
+ Graph::<(), (), Undirected>::from_edges(&[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]);
+ assert_eq!(gr.node_count(), 4);
+ assert_eq!(gr.edge_count(), 6);
+ assert_eq!(gr.neighbors(n(0)).count(), 3);
+ assert_eq!(gr.neighbors(n(1)).count(), 3);
+ assert_eq!(gr.neighbors(n(2)).count(), 3);
+ assert_eq!(gr.neighbors(n(3)).count(), 3);
+ assert_graph_consistent(&gr);
+}
+
+#[test]
+fn retain() {
+ let mut gr = Graph::<i32, i32, Undirected>::from_edges(&[
+ (0, 1, 2),
+ (1, 1, 1),
+ (0, 2, 0),
+ (1, 2, 3),
+ (2, 3, 3),
+ ]);
+ gr.retain_edges(|mut gr, i| {
+ if gr[i] <= 0 {
+ false
+ } else {
+ gr[i] -= 1;
+ let (s, t) = gr.edge_endpoints(i).unwrap();
+ gr[s] += 1;
+ gr[t] += 1;
+
+ gr[i] > 0
+ }
+ });
+
+ assert_eq!(gr.edge_count(), 3);
+ assert_eq!(gr[n(0)], 1);
+ assert_eq!(gr[n(1)], 4);
+ assert_eq!(gr[n(2)], 2);
+ assert_eq!(gr[n(3)], 1);
+ assert!(gr.find_edge(n(1), n(1)).is_none());
+ assert!(gr.find_edge(n(0), n(2)).is_none());
+ assert_graph_consistent(&gr);
+}
+
+fn assert_graph_consistent<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>)
+where
+ Ty: EdgeType,
+ Ix: IndexType,
+{
+ assert_eq!(g.node_count(), g.node_indices().count());
+ assert_eq!(g.edge_count(), g.edge_indices().count());
+ for edge in g.raw_edges() {
+ assert!(
+ g.find_edge(edge.source(), edge.target()).is_some(),
+ "Edge not in graph! {:?} to {:?}",
+ edge.source(),
+ edge.target()
+ );
+ }
+}
+
+#[test]
+fn neighbors_selfloops() {
+ // Directed graph
+ let mut gr = Graph::<_, ()>::new();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let c = gr.add_node("c");
+ gr.extend_with_edges(&[(a, a), (a, b), (c, a), (a, a)]);
+
+ let out_edges = [a, a, b];
+ let in_edges = [a, a, c];
+ let undir_edges = [a, a, b, c];
+ let mut seen_out = gr.neighbors(a).collect::<Vec<_>>();
+ seen_out.sort();
+ assert_eq!(&seen_out, &out_edges);
+ let mut seen_in = gr.neighbors_directed(a, Incoming).collect::<Vec<_>>();
+ seen_in.sort();
+ assert_eq!(&seen_in, &in_edges);
+
+ let mut seen_undir = gr.neighbors_undirected(a).collect::<Vec<_>>();
+ seen_undir.sort();
+ assert_eq!(&seen_undir, &undir_edges);
+
+ let mut seen_out = gr.edges(a).map(|e| e.target()).collect::<Vec<_>>();
+ seen_out.sort();
+ assert_eq!(&seen_out, &out_edges);
+
+ let mut seen_walk = Vec::new();
+ let mut walk = gr.neighbors(a).detach();
+ while let Some(n) = walk.next_node(&gr) {
+ seen_walk.push(n);
+ }
+ seen_walk.sort();
+ assert_eq!(&seen_walk, &out_edges);
+
+ seen_walk.clear();
+ let mut walk = gr.neighbors_directed(a, Incoming).detach();
+ while let Some(n) = walk.next_node(&gr) {
+ seen_walk.push(n);
+ }
+ seen_walk.sort();
+ assert_eq!(&seen_walk, &in_edges);
+
+ seen_walk.clear();
+ let mut walk = gr.neighbors_undirected(a).detach();
+ while let Some(n) = walk.next_node(&gr) {
+ seen_walk.push(n);
+ }
+ seen_walk.sort();
+ assert_eq!(&seen_walk, &undir_edges);
+
+ // Undirected graph
+ let mut gr: Graph<_, (), _> = Graph::new_undirected();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let c = gr.add_node("c");
+ gr.extend_with_edges(&[(a, a), (a, b), (c, a)]);
+
+ let out_edges = [a, b, c];
+ let in_edges = [a, b, c];
+ let undir_edges = [a, b, c];
+ let mut seen_out = gr.neighbors(a).collect::<Vec<_>>();
+ seen_out.sort();
+ assert_eq!(&seen_out, &out_edges);
+
+ let mut seen_out = gr.edges(a).map(|e| e.target()).collect::<Vec<_>>();
+ seen_out.sort();
+ assert_eq!(&seen_out, &out_edges);
+
+ let mut seen_in = gr.neighbors_directed(a, Incoming).collect::<Vec<_>>();
+ seen_in.sort();
+ assert_eq!(&seen_in, &in_edges);
+
+ let mut seen_undir = gr.neighbors_undirected(a).collect::<Vec<_>>();
+ seen_undir.sort();
+ assert_eq!(&seen_undir, &undir_edges);
+}
+
+fn degree<'a, G>(g: G, node: G::NodeId) -> usize
+where
+ G: IntoNeighbors,
+ G::NodeId: PartialEq,
+{
+ // self loops count twice
+ let original_node = node.clone();
+ let mut degree = 0;
+ for v in g.neighbors(node) {
+ degree += if v == original_node { 2 } else { 1 };
+ }
+ degree
+}
+
+#[cfg(feature = "graphmap")]
+#[test]
+fn degree_sequence() {
+ let mut gr = Graph::<usize, (), Undirected>::from_edges(&[
+ (0, 1),
+ (1, 2),
+ (1, 3),
+ (2, 4),
+ (3, 4),
+ (4, 4),
+ (4, 5),
+ (3, 5),
+ ]);
+ gr.add_node(0); // add isolated node
+ let mut degree_sequence = gr
+ .node_indices()
+ .map(|i| degree(&gr, i))
+ .collect::<Vec<_>>();
+
+ degree_sequence.sort_by(|x, y| Ord::cmp(y, x));
+ assert_eq!(&degree_sequence, &[5, 3, 3, 2, 2, 1, 0]);
+
+ let mut gr = GraphMap::<_, (), Undirected>::from_edges(&[
+ (0, 1),
+ (1, 2),
+ (1, 3),
+ (2, 4),
+ (3, 4),
+ (4, 4),
+ (4, 5),
+ (3, 5),
+ ]);
+ gr.add_node(6); // add isolated node
+ let mut degree_sequence = gr.nodes().map(|i| degree(&gr, i)).collect::<Vec<_>>();
+
+ degree_sequence.sort_by(|x, y| Ord::cmp(y, x));
+ assert_eq!(&degree_sequence, &[5, 3, 3, 2, 2, 1, 0]);
+}
+
+#[test]
+fn neighbor_order() {
+ let mut gr = Graph::new();
+ let a = gr.add_node("a");
+ let b = gr.add_node("b");
+ let c = gr.add_node("c");
+ gr.add_edge(a, b, 0);
+ gr.add_edge(a, a, 1);
+
+ gr.add_edge(c, a, 2);
+
+ gr.add_edge(a, c, 3);
+
+ gr.add_edge(c, a, 4);
+ gr.add_edge(b, a, 5);
+
+ // neighbors (edges) are in lifo order, if it's a directed graph
+ assert_eq!(gr.neighbors(a).collect::<Vec<_>>(), vec![c, a, b]);
+ assert_eq!(
+ gr.neighbors_directed(a, Incoming).collect::<Vec<_>>(),
+ vec![b, c, c, a]
+ );
+}
+
+#[test]
+fn dot() {
+ // test alternate formatting
+ #[derive(Debug)]
+ struct Record {
+ a: i32,
+ b: &'static str,
+ };
+ let mut gr = Graph::new();
+ let a = gr.add_node(Record { a: 1, b: r"abc\" });
+ gr.add_edge(a, a, (1, 2));
+ let dot_output = format!("{:?}", Dot::new(&gr));
+ assert_eq!(
+ dot_output,
+ // The single \ turns into four \\\\ because of Debug which turns it to \\ and then escaping each \ to \\.
+ r#"digraph {
+ 0 [ label = "Record { a: 1, b: \"abc\\\\\" }" ]
+ 0 -> 0 [ label = "(1, 2)" ]
+}
+"#
+ );
+}
+
+#[test]
+fn filtered() {
+ let mut g = Graph::new();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ let c = g.add_node("C");
+ let d = g.add_node("D");
+ let e = g.add_node("E");
+ let f = g.add_node("F");
+ g.add_edge(a, b, 7);
+ g.add_edge(c, a, 9);
+ g.add_edge(a, d, 14);
+ g.add_edge(b, c, 10);
+ g.add_edge(d, c, 2);
+ g.add_edge(d, e, 9);
+ g.add_edge(b, f, 15);
+ g.add_edge(c, f, 11);
+ g.add_edge(e, f, 6);
+ println!("{:?}", g);
+
+ let filt = NodeFiltered(&g, |n: NodeIndex| n != c && n != e);
+
+ let mut dfs = DfsPostOrder::new(&filt, a);
+ let mut po = Vec::new();
+ while let Some(nx) = dfs.next(&filt) {
+ println!("Next: {:?}", nx);
+ po.push(nx);
+ }
+ assert_eq!(set(po), set(g.node_identifiers().filter(|n| (filt.1)(*n))));
+}
+
+#[test]
+fn filtered_edge_reverse() {
+ use petgraph::visit::EdgeFiltered;
+ #[derive(Eq, PartialEq)]
+ enum E {
+ A,
+ B,
+ }
+
+ // Start with single node graph with loop
+ let mut g = Graph::new();
+ let a = g.add_node("A");
+ g.add_edge(a, a, E::A);
+ let ef_a = EdgeFiltered::from_fn(&g, |edge| *edge.weight() == E::A);
+ let mut po = Vec::new();
+ let mut dfs = Dfs::new(&ef_a, a);
+ while let Some(next_n_ix) = dfs.next(&ef_a) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![a]));
+
+ // Check in reverse
+ let mut po = Vec::new();
+ let mut dfs = Dfs::new(&Reversed(&ef_a), a);
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_a)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![a]));
+
+ let mut g = Graph::new();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ let c = g.add_node("C");
+ let d = g.add_node("D");
+ let e = g.add_node("E");
+ let f = g.add_node("F");
+ let h = g.add_node("H");
+ let i = g.add_node("I");
+ let j = g.add_node("J");
+
+ g.add_edge(a, b, E::A);
+ g.add_edge(b, c, E::A);
+ g.add_edge(c, d, E::B);
+ g.add_edge(d, e, E::A);
+ g.add_edge(e, f, E::A);
+ g.add_edge(e, h, E::A);
+ g.add_edge(e, i, E::A);
+ g.add_edge(i, j, E::A);
+
+ let ef_a = EdgeFiltered::from_fn(&g, |edge| *edge.weight() == E::A);
+ let ef_b = EdgeFiltered::from_fn(&g, |edge| *edge.weight() == E::B);
+
+ // DFS down from a, filtered by E::A.
+ let mut po = Vec::new();
+ let mut dfs = Dfs::new(&ef_a, a);
+ while let Some(next_n_ix) = dfs.next(&ef_a) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![a, b, c]));
+
+ // Reversed DFS from f, filtered by E::A.
+ let mut dfs = Dfs::new(&Reversed(&ef_a), f);
+ let mut po = Vec::new();
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_a)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![d, e, f]));
+
+ // Reversed DFS from j, filtered by E::A.
+ let mut dfs = Dfs::new(&Reversed(&ef_a), j);
+ let mut po = Vec::new();
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_a)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![d, e, i, j]));
+
+ // Reversed DFS from c, filtered by E::A.
+ let mut dfs = Dfs::new(&Reversed(&ef_a), c);
+ let mut po = Vec::new();
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_a)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![a, b, c]));
+
+ // Reversed DFS from c, filtered by E::B.
+ let mut dfs = Dfs::new(&Reversed(&ef_b), c);
+ let mut po = Vec::new();
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_b)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![c]));
+
+ // Reversed DFS from d, filtered by E::B.
+ let mut dfs = Dfs::new(&Reversed(&ef_b), d);
+ let mut po = Vec::new();
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_b)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![c, d]));
+
+ // Now let's test the same graph but undirected
+
+ let mut g = Graph::new_undirected();
+ let a = g.add_node("A");
+ let b = g.add_node("B");
+ let c = g.add_node("C");
+ let d = g.add_node("D");
+ let e = g.add_node("E");
+ let f = g.add_node("F");
+ let h = g.add_node("H");
+ let i = g.add_node("I");
+ let j = g.add_node("J");
+
+ g.add_edge(a, b, E::A);
+ g.add_edge(b, c, E::A);
+ g.add_edge(c, d, E::B);
+ g.add_edge(d, e, E::A);
+ g.add_edge(e, f, E::A);
+ g.add_edge(e, h, E::A);
+ g.add_edge(e, i, E::A);
+ g.add_edge(i, j, E::A);
+
+ let ef_a = EdgeFiltered::from_fn(&g, |edge| *edge.weight() == E::A);
+ let ef_b = EdgeFiltered::from_fn(&g, |edge| *edge.weight() == E::B);
+ let mut po = Vec::new();
+ let mut dfs = Dfs::new(&Reversed(&ef_b), d);
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_b)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![c, d]));
+
+ let mut po = Vec::new();
+ let mut dfs = Dfs::new(&Reversed(&ef_a), h);
+ while let Some(next_n_ix) = dfs.next(&Reversed(&ef_a)) {
+ po.push(next_n_ix);
+ }
+ assert_eq!(set(po), set(vec![d, e, f, h, i, j]));
+}
+
+#[test]
+fn dfs_visit() {
+ use petgraph::visit::Control;
+ use petgraph::visit::DfsEvent::*;
+ use petgraph::visit::{depth_first_search, Time};
+ use petgraph::visit::{VisitMap, Visitable};
+ let gr: Graph<(), ()> = Graph::from_edges(&[
+ (0, 5),
+ (0, 2),
+ (0, 3),
+ (0, 1),
+ (1, 3),
+ (2, 3),
+ (2, 4),
+ (4, 0),
+ (4, 5),
+ ]);
+
+ let invalid_time = Time(!0);
+ let mut discover_time = vec![invalid_time; gr.node_count()];
+ let mut finish_time = vec![invalid_time; gr.node_count()];
+ let mut has_tree_edge = gr.visit_map();
+ let mut edges = HashSet::new();
+ depth_first_search(&gr, Some(n(0)), |evt| {
+ println!("Event: {:?}", evt);
+ match evt {
+ Discover(n, t) => discover_time[n.index()] = t,
+ Finish(n, t) => finish_time[n.index()] = t,
+ TreeEdge(u, v) => {
+ // v is an ancestor of u
+ assert!(has_tree_edge.visit(v), "Two tree edges to {:?}!", v);
+ assert!(discover_time[v.index()] == invalid_time);
+ assert!(discover_time[u.index()] != invalid_time);
+ assert!(finish_time[u.index()] == invalid_time);
+ edges.insert((u, v));
+ }
+ BackEdge(u, v) => {
+ // u is an ancestor of v
+ assert!(discover_time[v.index()] != invalid_time);
+ assert!(finish_time[v.index()] == invalid_time);
+ edges.insert((u, v));
+ }
+ CrossForwardEdge(u, v) => {
+ edges.insert((u, v));
+ }
+ }
+ });
+ assert!(discover_time.iter().all(|x| *x != invalid_time));
+ assert!(finish_time.iter().all(|x| *x != invalid_time));
+ assert_eq!(edges.len(), gr.edge_count());
+ assert_eq!(
+ edges,
+ set(gr.edge_references().map(|e| (e.source(), e.target())))
+ );
+ println!("{:?}", discover_time);
+ println!("{:?}", finish_time);
+
+ // find path from 0 to 4
+ let mut predecessor = vec![NodeIndex::end(); gr.node_count()];
+ let start = n(0);
+ let goal = n(4);
+ let ret = depth_first_search(&gr, Some(start), |event| {
+ if let TreeEdge(u, v) = event {
+ predecessor[v.index()] = u;
+ if v == goal {
+ return Control::Break(u);
+ }
+ }
+ Control::Continue
+ });
+ // assert we did terminate early
+ assert!(ret.break_value().is_some());
+ assert!(predecessor.iter().any(|x| *x == NodeIndex::end()));
+
+ let mut next = goal;
+ let mut path = vec![next];
+ while next != start {
+ let pred = predecessor[next.index()];
+ path.push(pred);
+ next = pred;
+ }
+ path.reverse();
+ assert_eq!(&path, &[n(0), n(2), n(4)]);
+
+ // check that if we prune 2, we never see 4.
+ let start = n(0);
+ let prune = n(2);
+ let nongoal = n(4);
+ let ret = depth_first_search(&gr, Some(start), |event| {
+ if let Discover(n, _) = event {
+ if n == prune {
+ return Control::Prune;
+ }
+ } else if let TreeEdge(u, v) = event {
+ if v == nongoal {
+ return Control::Break(u);
+ }
+ }
+ Control::Continue
+ });
+ assert!(ret.break_value().is_none());
+}
+
+#[test]
+fn filtered_post_order() {
+ use petgraph::visit::NodeFiltered;
+
+ let mut gr: Graph<(), ()> =
+ Graph::from_edges(&[(0, 2), (1, 2), (0, 3), (1, 4), (2, 4), (4, 5), (3, 5)]);
+ // map reachable nodes
+ let mut dfs = Dfs::new(&gr, n(0));
+ while let Some(_) = dfs.next(&gr) {}
+
+ let map = dfs.discovered;
+ gr.add_edge(n(0), n(1), ());
+ let mut po = Vec::new();
+ let mut dfs = DfsPostOrder::new(&gr, n(0));
+ let f = NodeFiltered(&gr, map);
+ while let Some(n) = dfs.next(&f) {
+ po.push(n);
+ }
+ assert!(!po.contains(&n(1)));
+}
+
+#[test]
+fn filter_elements() {
+ use petgraph::data::Element::{Edge, Node};
+ use petgraph::data::ElementIterator;
+ use petgraph::data::FromElements;
+ let elements = vec![
+ Node { weight: "A" },
+ Node { weight: "B" },
+ Node { weight: "C" },
+ Node { weight: "D" },
+ Node { weight: "E" },
+ Node { weight: "F" },
+ Edge {
+ source: 0,
+ target: 1,
+ weight: 7,
+ },
+ Edge {
+ source: 2,
+ target: 0,
+ weight: 9,
+ },
+ Edge {
+ source: 0,
+ target: 3,
+ weight: 14,
+ },
+ Edge {
+ source: 1,
+ target: 2,
+ weight: 10,
+ },
+ Edge {
+ source: 3,
+ target: 2,
+ weight: 2,
+ },
+ Edge {
+ source: 3,
+ target: 4,
+ weight: 9,
+ },
+ Edge {
+ source: 1,
+ target: 5,
+ weight: 15,
+ },
+ Edge {
+ source: 2,
+ target: 5,
+ weight: 11,
+ },
+ Edge {
+ source: 4,
+ target: 5,
+ weight: 6,
+ },
+ ];
+ let mut g = DiGraph::<_, _>::from_elements(elements.iter().cloned());
+ println!("{:#?}", g);
+ assert!(g.contains_edge(n(1), n(5)));
+ let g2 =
+ DiGraph::<_, _>::from_elements(elements.iter().cloned().filter_elements(|elt| match elt {
+ Node { ref weight } if **weight == "B" => false,
+ _ => true,
+ }));
+ println!("{:#?}", g2);
+ g.remove_node(n(1));
+ assert!(is_isomorphic_matching(
+ &g,
+ &g2,
+ PartialEq::eq,
+ PartialEq::eq
+ ));
+}
+
+#[test]
+fn test_edge_filtered() {
+ use petgraph::algo::connected_components;
+ use petgraph::visit::EdgeFiltered;
+ use petgraph::visit::IntoEdgeReferences;
+
+ let gr = UnGraph::<(), _>::from_edges(&[
+ // cycle
+ (0, 1, 7),
+ (1, 2, 9),
+ (2, 1, 14),
+ // cycle
+ (3, 4, 10),
+ (4, 5, 2),
+ (5, 3, 9),
+ // cross edges
+ (0, 3, -1),
+ (1, 4, -2),
+ (2, 5, -3),
+ ]);
+ assert_eq!(connected_components(&gr), 1);
+ let positive_edges = EdgeFiltered::from_fn(&gr, |edge| *edge.weight() >= 0);
+ assert_eq!(positive_edges.edge_references().count(), 6);
+ assert!(positive_edges
+ .edge_references()
+ .all(|edge| *edge.weight() >= 0));
+ assert_eq!(connected_components(&positive_edges), 2);
+
+ let mut dfs = DfsPostOrder::new(&positive_edges, n(0));
+ while let Some(_) = dfs.next(&positive_edges) {}
+
+ let n = n::<u32>;
+ for node in &[n(0), n(1), n(2)] {
+ assert!(dfs.discovered.is_visited(node));
+ }
+ for node in &[n(3), n(4), n(5)] {
+ assert!(!dfs.discovered.is_visited(node));
+ }
+}
+
+#[test]
+fn test_dominators_simple_fast() {
+ // Construct the following graph:
+ //
+ // .-----.
+ // | <--------------------------------.
+ // .--------+--------------| r |--------------. |
+ // | | | | | |
+ // | | '-----' | |
+ // | .--V--. .--V--. |
+ // | | | | | |
+ // | | b | | c |--------. |
+ // | | | | | | |
+ // | '-----' '-----' | |
+ // .--V--. | | .--V--. |
+ // | | | | | | |
+ // | a <-----+ | .----| g | |
+ // | | | .----' | | | |
+ // '-----' | | | '-----' |
+ // | | | | | |
+ // .--V--. | .-----. .--V--. | | |
+ // | | | | | | | | | |
+ // | d <-----+----> e <----. | f | | | |
+ // | | | | | | | | | |
+ // '-----' '-----' | '-----' | | |
+ // | .-----. | | | | .--V--. |
+ // | | | | | | .-' | | |
+ // '-----> l | | | | | | j | |
+ // | | '--. | | | | | |
+ // '-----' | | | | '-----' |
+ // | .--V--. | | .--V--. | |
+ // | | | | | | | | |
+ // '-------> h |-' '---> i <------' |
+ // | | .---------> | |
+ // '-----' | '-----' |
+ // | .-----. | |
+ // | | | | |
+ // '----------> k <---------' |
+ // | | |
+ // '-----' |
+ // | |
+ // '----------------------------'
+ //
+ // This graph has the following dominator tree:
+ //
+ // r
+ // |-- a
+ // |-- b
+ // |-- c
+ // | |-- f
+ // | `-- g
+ // | `-- j
+ // |-- d
+ // | `-- l
+ // |-- e
+ // |-- i
+ // |-- k
+ // `-- h
+ //
+ // This graph and dominator tree are taken from figures 1 and 2 of "A Fast
+ // Algorithm for Finding Dominators in a Flowgraph" by Lengauer et al:
+ // http://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf.
+
+ let mut graph = DiGraph::<_, _>::new();
+
+ let r = graph.add_node("r");
+ let a = graph.add_node("a");
+ let b = graph.add_node("b");
+ let c = graph.add_node("c");
+ let d = graph.add_node("d");
+ let e = graph.add_node("e");
+ let f = graph.add_node("f");
+ let g = graph.add_node("g");
+ let h = graph.add_node("h");
+ let i = graph.add_node("i");
+ let j = graph.add_node("j");
+ let k = graph.add_node("k");
+ let l = graph.add_node("l");
+
+ graph.add_edge(r, a, ());
+ graph.add_edge(r, b, ());
+ graph.add_edge(r, c, ());
+ graph.add_edge(a, d, ());
+ graph.add_edge(b, a, ());
+ graph.add_edge(b, d, ());
+ graph.add_edge(b, e, ());
+ graph.add_edge(c, f, ());
+ graph.add_edge(c, g, ());
+ graph.add_edge(d, l, ());
+ graph.add_edge(e, h, ());
+ graph.add_edge(f, i, ());
+ graph.add_edge(g, i, ());
+ graph.add_edge(g, j, ());
+ graph.add_edge(h, e, ());
+ graph.add_edge(h, k, ());
+ graph.add_edge(i, k, ());
+ graph.add_edge(j, i, ());
+ graph.add_edge(k, r, ());
+ graph.add_edge(k, i, ());
+ graph.add_edge(l, h, ());
+
+ let doms = dominators::simple_fast(&graph, r);
+
+ assert_eq!(doms.root(), r);
+ assert_eq!(
+ doms.immediate_dominator(r),
+ None,
+ "The root node has no idom"
+ );
+
+ assert_eq!(
+ doms.immediate_dominator(a),
+ Some(r),
+ "r is the immediate dominator of a"
+ );
+ assert_eq!(
+ doms.immediate_dominator(b),
+ Some(r),
+ "r is the immediate dominator of b"
+ );
+ assert_eq!(
+ doms.immediate_dominator(c),
+ Some(r),
+ "r is the immediate dominator of c"
+ );
+ assert_eq!(
+ doms.immediate_dominator(f),
+ Some(c),
+ "c is the immediate dominator of f"
+ );
+ assert_eq!(
+ doms.immediate_dominator(g),
+ Some(c),
+ "c is the immediate dominator of g"
+ );
+ assert_eq!(
+ doms.immediate_dominator(j),
+ Some(g),
+ "g is the immediate dominator of j"
+ );
+ assert_eq!(
+ doms.immediate_dominator(d),
+ Some(r),
+ "r is the immediate dominator of d"
+ );
+ assert_eq!(
+ doms.immediate_dominator(l),
+ Some(d),
+ "d is the immediate dominator of l"
+ );
+ assert_eq!(
+ doms.immediate_dominator(e),
+ Some(r),
+ "r is the immediate dominator of e"
+ );
+ assert_eq!(
+ doms.immediate_dominator(i),
+ Some(r),
+ "r is the immediate dominator of i"
+ );
+ assert_eq!(
+ doms.immediate_dominator(k),
+ Some(r),
+ "r is the immediate dominator of k"
+ );
+ assert_eq!(
+ doms.immediate_dominator(h),
+ Some(r),
+ "r is the immediate dominator of h"
+ );
+
+ let mut graph = graph.clone();
+ let z = graph.add_node("z");
+ let doms = dominators::simple_fast(&graph, r);
+ assert_eq!(
+ doms.immediate_dominator(z),
+ None,
+ "nodes that aren't reachable from the root do not have an idom"
+ );
+}