summaryrefslogtreecommitdiff
path: root/vendor/petgraph-0.6.5/tests/graph.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/petgraph-0.6.5/tests/graph.rs')
-rw-r--r--vendor/petgraph-0.6.5/tests/graph.rs2452
1 files changed, 0 insertions, 2452 deletions
diff --git a/vendor/petgraph-0.6.5/tests/graph.rs b/vendor/petgraph-0.6.5/tests/graph.rs
deleted file mode 100644
index de943b47..00000000
--- a/vendor/petgraph-0.6.5/tests/graph.rs
+++ /dev/null
@@ -1,2452 +0,0 @@
-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,
-};
-
-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 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));
- }
-}
-
-#[test]
-fn test_astar_runtime_optimal() {
- 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");
- g.add_edge(a, b, 2);
- g.add_edge(a, c, 3);
- g.add_edge(b, d, 3);
- g.add_edge(c, d, 1);
- g.add_edge(d, e, 1);
-
- let mut times_called = 0;
-
- let _ = astar(
- &g,
- a,
- |n| n == e,
- |edge| {
- times_called += 1;
- *edge.weight()
- },
- |_| 0,
- );
-
- // A* is runtime optimal in the sense it won't expand more nodes than needed, for the given
- // heuristic. Here, A* should expand, in order: A, B, C, D, E. This should should ask for the
- // costs of edges (A, B), (A, C), (B, D), (C, D), (D, E). Node D will be added to `visit_next`
- // twice, but should only be expanded once. If it is erroneously expanded twice, it will call
- // for (D, E) again and `times_called` will be 6.
- assert_eq!(times_called, 5);
-}
-
-#[test]
-fn test_astar_admissible_inconsistent() {
- 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");
- g.add_edge(a, b, 3);
- g.add_edge(b, c, 3);
- g.add_edge(c, d, 3);
- g.add_edge(a, c, 8);
- g.add_edge(a, d, 10);
-
- let admissible_inconsistent = |n: NodeIndex| match g[n] {
- "A" => 9,
- "B" => 6,
- "C" => 0,
- &_ => 0,
- };
-
- let optimal = astar(&g, a, |n| n == d, |e| *e.weight(), admissible_inconsistent);
- assert_eq!(optimal, Some((9, vec![a, b, c, d])));
-}
-
-#[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),
- ]);
-
- let mut tarjan_scc = petgraph::algo::TarjanScc::new();
-
- let mut result = Vec::new();
- tarjan_scc.run(&gr, |scc| result.push(scc.iter().rev().cloned().collect()));
- assert_sccs_eq(
- result,
- 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());
-
- let mut result = Vec::new();
- tarjan_scc.run(&hr, |scc| result.push(scc.iter().rev().cloned().collect()));
- assert_sccs_eq(
- result,
- 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), ());
-
- let mut result = Vec::new();
- tarjan_scc.run(&gr, |scc| result.push(scc.iter().rev().cloned().collect()));
- assert_sccs_eq(
- result,
- 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
- let mut result = Vec::new();
- tarjan_scc.run(&gr, |scc| result.push(scc.iter().rev().cloned().collect()));
- assert_sccs_eq(
- result,
- 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_filtered_iterators_directed() {
- use petgraph::{
- graph::EdgeReference,
- visit::{EdgeFiltered, IntoEdgesDirected},
- };
-
- let gr = make_edge_iterator_graph::<Directed>();
- let filter = |edge: EdgeReference<f64>| -> bool { *edge.weight() > 8.0 };
- let filtered = EdgeFiltered::from_fn(&gr, filter);
-
- for i in gr.node_indices() {
- itertools::assert_equal(
- filtered.edges_directed(i, Outgoing),
- gr.edges_directed(i, Outgoing).filter(|edge| filter(*edge)),
- );
- itertools::assert_equal(
- filtered.edges_directed(i, Incoming),
- gr.edges_directed(i, Incoming).filter(|edge| filter(*edge)),
- );
- }
-}
-
-#[test]
-fn test_node_filtered_iterators_directed() {
- use petgraph::{
- graph::NodeIndex,
- visit::{IntoEdgesDirected, NodeFiltered},
- };
-
- let gr = make_edge_iterator_graph::<Directed>();
- let filter = |node: NodeIndex<u32>| node.index() < 5; // < 5 makes sure there are edges going both ways between included and excluded nodes (e -> g, f -> e)
- let filtered = NodeFiltered::from_fn(&gr, filter);
-
- for i in gr.node_indices() {
- itertools::assert_equal(
- filtered.edges_directed(i, Outgoing),
- gr.edges_directed(i, Outgoing)
- .filter(|edge| filter(edge.source()) && filter(edge.target())),
- );
- itertools::assert_equal(
- filtered.edges_directed(i, Incoming),
- gr.edges_directed(i, Incoming)
- .filter(|edge| filter(edge.source()) && filter(edge.target())),
- );
- }
-}
-
-#[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 init_nodes = gr.node_identifiers().filter(|n| {
- gr.neighbors_directed(*n, Direction::Incoming)
- .next()
- .is_none()
- });
- let mut topo = Topo::with_initials(&gr, init_nodes);
- while let Some(nx) = topo.next(&gr) {
- order.push(nx);
- }
- assert_is_topo_order(&gr, &order);
- }
-
- {
- // test `with_initials` API using nodes with incoming edges
- order.clear();
- let mut topo = Topo::with_initials(&gr, gr.node_identifiers());
- while let Some(nx) = topo.next(&gr) {
- order.push(nx);
- }
- 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;
- 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 dfs.next(&gr).is_some() {}
-
- 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 dfs.next(&positive_edges).is_some() {}
-
- 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"
- );
-}