use nalgebra_block_triangularization::scc::{condensation_dag, scc_id_map, tarjan_scc};
#[test]
fn scc_empty_graph() {
let graph: Vec<Vec<usize>> = vec![];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 0);
}
#[test]
fn scc_single_node_no_edges() {
let graph = vec![vec![]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 1);
assert_eq!(sccs[0], vec![0]);
}
#[test]
fn scc_single_node_self_loop() {
let graph = vec![vec![0]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 1);
assert_eq!(sccs[0], vec![0]);
}
#[test]
fn scc_two_nodes_no_edges() {
let graph = vec![vec![], vec![]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 2);
let mut all_nodes: Vec<_> = sccs.iter().flatten().copied().collect();
all_nodes.sort();
assert_eq!(all_nodes, vec![0, 1]);
}
#[test]
fn scc_two_nodes_cycle() {
let graph = vec![vec![1], vec![0]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 1);
let mut scc = sccs[0].clone();
scc.sort();
assert_eq!(scc, vec![0, 1]);
}
#[test]
fn scc_three_nodes_cycle() {
let graph = vec![vec![1], vec![2], vec![0]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 1);
let mut scc = sccs[0].clone();
scc.sort();
assert_eq!(scc, vec![0, 1, 2]);
}
#[test]
fn scc_dag_no_cycles() {
let graph = vec![vec![1], vec![2], vec![]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 3);
let mut all_nodes: Vec<_> = sccs.iter().flatten().copied().collect();
all_nodes.sort();
assert_eq!(all_nodes, vec![0, 1, 2]);
}
#[test]
fn scc_complex_graph() {
let graph = vec![
vec![1], vec![0, 2], vec![3], vec![2], ];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 2);
let scc_with_0: Vec<_> = sccs.iter().find(|scc| scc.contains(&0)).unwrap().to_vec();
let scc_with_2: Vec<_> = sccs.iter().find(|scc| scc.contains(&2)).unwrap().to_vec();
let mut sorted_0 = scc_with_0.clone();
sorted_0.sort();
let mut sorted_2 = scc_with_2.clone();
sorted_2.sort();
assert_eq!(sorted_0, vec![0, 1]);
assert_eq!(sorted_2, vec![2, 3]);
}
#[test]
fn scc_all_nodes_covered() {
let graph = vec![vec![1], vec![2], vec![0], vec![4], vec![3]];
let sccs = tarjan_scc(&graph);
let mut all_nodes: Vec<_> = sccs.iter().flatten().copied().collect();
all_nodes.sort();
assert_eq!(all_nodes, vec![0, 1, 2, 3, 4]);
all_nodes.dedup();
assert_eq!(all_nodes, vec![0, 1, 2, 3, 4]);
}
#[test]
fn scc_id_map_simple() {
let sccs = vec![vec![0, 1], vec![2], vec![3, 4]];
let comp_of = scc_id_map(&sccs, 5);
assert_eq!(comp_of[0], 0);
assert_eq!(comp_of[1], 0);
assert_eq!(comp_of[2], 1);
assert_eq!(comp_of[3], 2);
assert_eq!(comp_of[4], 2);
}
#[test]
fn scc_id_map_empty() {
let sccs: Vec<Vec<usize>> = vec![];
let comp_of = scc_id_map(&sccs, 0);
assert_eq!(comp_of.len(), 0);
}
#[test]
fn condensation_dag_empty() {
let graph: Vec<Vec<usize>> = vec![];
let comp_of: Vec<usize> = vec![];
let dag = condensation_dag(&graph, &comp_of, 0);
assert_eq!(dag.len(), 0);
}
#[test]
fn condensation_dag_single_scc() {
let graph = vec![vec![1], vec![0]];
let comp_of = vec![0, 0];
let dag = condensation_dag(&graph, &comp_of, 1);
assert_eq!(dag.len(), 1);
assert!(dag[0].is_empty());
}
#[test]
fn condensation_dag_two_sccs() {
let graph = vec![vec![1], vec![0, 2], vec![]];
let comp_of = vec![0, 0, 1];
let dag = condensation_dag(&graph, &comp_of, 2);
assert_eq!(dag.len(), 2);
assert_eq!(dag[0], vec![1]);
assert!(dag[1].is_empty());
}
#[test]
fn condensation_dag_removes_self_loops() {
let graph = vec![
vec![0, 1, 2], vec![0], vec![],
];
let comp_of = vec![0, 0, 1];
let dag = condensation_dag(&graph, &comp_of, 2);
assert_eq!(dag.len(), 2);
assert_eq!(dag[0], vec![1]); assert!(dag[1].is_empty());
}
#[test]
fn condensation_dag_deduplicates() {
let graph = vec![vec![2], vec![2], vec![]];
let comp_of = vec![0, 0, 1];
let dag = condensation_dag(&graph, &comp_of, 2);
assert_eq!(dag.len(), 2);
assert_eq!(dag[0], vec![1]); assert!(dag[1].is_empty());
}
#[test]
fn condensation_dag_sorted() {
let graph = vec![
vec![3, 1, 2], vec![],
vec![],
vec![],
];
let comp_of = vec![0, 0, 1, 2];
let dag = condensation_dag(&graph, &comp_of, 3);
assert_eq!(dag.len(), 3);
assert_eq!(dag[0], vec![1, 2]);
assert!(dag[1].is_empty());
assert!(dag[2].is_empty());
}
#[test]
fn scc_integration_test() {
let graph = vec![vec![1], vec![2], vec![0, 3], vec![4], vec![3]];
let sccs = tarjan_scc(&graph);
let comp_of = scc_id_map(&sccs, 5);
let dag = condensation_dag(&graph, &comp_of, sccs.len());
let mut all_nodes: Vec<_> = sccs.iter().flatten().copied().collect();
all_nodes.sort();
assert_eq!(all_nodes, vec![0, 1, 2, 3, 4]);
for (i, edges) in dag.iter().enumerate() {
assert!(!edges.contains(&i), "DAG has self-loop at component {}", i);
}
}
#[test]
fn scc_tarjan_order_independence() {
let graph = vec![vec![1], vec![2], vec![0], vec![4], vec![3]];
let sccs = tarjan_scc(&graph);
assert_eq!(sccs.len(), 2);
let mut scc_sizes: Vec<_> = sccs.iter().map(|s| s.len()).collect();
scc_sizes.sort();
assert_eq!(scc_sizes, vec![2, 3]);
}