#[test]
fn test_louvain_empty_graph() {
let g = Graph::new(false);
let communities = g.louvain();
assert_eq!(communities.len(), 0);
}
#[test]
fn test_louvain_single_node() {
let g = Graph::from_edges(&[(0, 0)], false);
let communities = g.louvain();
assert_eq!(communities.len(), 1);
assert_eq!(communities[0].len(), 1);
}
#[test]
fn test_louvain_two_nodes() {
let g = Graph::from_edges(&[(0, 1)], false);
let communities = g.louvain();
assert_eq!(communities.len(), 1);
assert_eq!(communities[0].len(), 2);
}
#[test]
fn test_louvain_triangle() {
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 0)], false);
let communities = g.louvain();
assert_eq!(communities.len(), 1);
assert_eq!(communities[0].len(), 3);
}
#[test]
fn test_louvain_two_triangles_connected() {
let g = Graph::from_edges(
&[
(0, 1),
(1, 2),
(2, 0), (3, 4),
(4, 5),
(5, 3), (2, 3), ],
false,
);
let communities = g.louvain();
assert_eq!(communities.len(), 2);
let all_nodes: Vec<_> = communities.iter().flat_map(|c| c.iter()).copied().collect();
assert_eq!(all_nodes.len(), 6);
}
#[test]
fn test_louvain_disconnected_components() {
let g = Graph::from_edges(
&[
(0, 1),
(1, 2),
(2, 0), (3, 4),
(4, 5),
(5, 3), ],
false,
);
let communities = g.louvain();
assert!(communities.len() >= 2);
let comm1_nodes: Vec<_> = communities
.iter()
.find(|c| c.contains(&0))
.expect("node 0 should be assigned to a community")
.clone();
let comm2_nodes: Vec<_> = communities
.iter()
.find(|c| c.contains(&3))
.expect("node 3 should be assigned to a community")
.clone();
assert!(comm1_nodes.contains(&0));
assert!(comm1_nodes.contains(&1));
assert!(comm1_nodes.contains(&2));
assert!(comm2_nodes.contains(&3));
assert!(comm2_nodes.contains(&4));
assert!(comm2_nodes.contains(&5));
assert!(!comm1_nodes.contains(&3));
assert!(!comm2_nodes.contains(&0));
}
#[test]
fn test_louvain_karate_club() {
let g = Graph::from_edges(
&[
(0, 1),
(0, 2),
(1, 2), (2, 3), (3, 4),
(3, 5),
(4, 5), ],
false,
);
let communities = g.louvain();
assert!(communities.len() >= 2);
let all_nodes: Vec<_> = communities.iter().flat_map(|c| c.iter()).copied().collect();
assert_eq!(all_nodes.len(), 6);
}
#[test]
fn test_louvain_star_graph() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (0, 4)], false);
let communities = g.louvain();
assert!(!communities.is_empty());
let all_nodes: Vec<_> = communities.iter().flat_map(|c| c.iter()).copied().collect();
assert_eq!(all_nodes.len(), 5);
}
#[test]
fn test_louvain_complete_graph() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)], false);
let communities = g.louvain();
assert_eq!(communities.len(), 1);
assert_eq!(communities[0].len(), 4);
}
#[test]
fn test_louvain_modularity_improves() {
let g = Graph::from_edges(
&[
(0, 1),
(1, 2),
(2, 0), (3, 4),
(4, 5),
(5, 3), ],
false,
);
let communities = g.louvain();
let modularity = g.modularity(&communities);
assert!(modularity > 0.3);
}
#[test]
fn test_louvain_all_nodes_assigned() {
let g = Graph::from_edges(
&[
(0, 1),
(1, 2),
(2, 3),
(3, 4),
(4, 0), ],
false,
);
let communities = g.louvain();
let mut assigned_nodes: Vec<NodeId> = Vec::new();
for community in &communities {
assigned_nodes.extend(community);
}
assigned_nodes.sort_unstable();
assert_eq!(assigned_nodes, vec![0, 1, 2, 3, 4]);
let unique_count = assigned_nodes.len();
assigned_nodes.dedup();
assert_eq!(assigned_nodes.len(), unique_count);
}
#[test]
fn test_modularity_bad_partition() {
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 0)], false);
let communities = vec![vec![0], vec![1], vec![2]];
let modularity = g.modularity(&communities);
assert!(modularity < 0.1);
}
#[test]
fn test_closeness_centrality_empty() {
let g = Graph::new(false);
let cc = g.closeness_centrality();
assert!(cc.is_empty());
}
#[test]
fn test_closeness_centrality_star_graph() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3)], false);
let cc = g.closeness_centrality();
assert_eq!(cc.len(), 4);
assert!(cc[0] > cc[1]);
assert!(cc[0] > cc[2]);
assert!(cc[0] > cc[3]);
assert!((cc[1] - cc[2]).abs() < 1e-6);
assert!((cc[2] - cc[3]).abs() < 1e-6);
}
#[test]
fn test_closeness_centrality_path_graph() {
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], false);
let cc = g.closeness_centrality();
assert_eq!(cc.len(), 4);
assert!(cc[1] > cc[0]);
assert!(cc[2] > cc[0]);
assert!(cc[1] > cc[3]);
assert!(cc[2] > cc[3]);
}
#[test]
fn test_eigenvector_centrality_empty() {
let g = Graph::new(false);
let ec = g
.eigenvector_centrality(100, 1e-6)
.expect("eigenvector centrality should succeed on empty graph");
assert!(ec.is_empty());
}
#[test]
fn test_eigenvector_centrality_star_graph() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3)], false);
let ec = g
.eigenvector_centrality(100, 1e-6)
.expect("eigenvector centrality should succeed on star graph");
assert_eq!(ec.len(), 4);
assert!(ec[0] > ec[1]);
assert!(ec[0] > ec[2]);
assert!(ec[0] > ec[3]);
}
#[test]
fn test_eigenvector_centrality_path_graph() {
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], false);
let ec = g
.eigenvector_centrality(100, 1e-6)
.expect("eigenvector centrality should succeed on path graph");
assert_eq!(ec.len(), 4);
assert!(ec[1] > ec[0]);
assert!(ec[2] > ec[3]);
}
#[test]
fn test_eigenvector_centrality_disconnected() {
let g = Graph::from_edges(&[], false);
let ec = g
.eigenvector_centrality(100, 1e-6)
.expect("eigenvector centrality should succeed on graph with no edges");
assert!(ec.is_empty());
}
#[test]
fn test_katz_centrality_empty() {
let g = Graph::new(true);
let kc = g
.katz_centrality(0.1, 100, 1e-6)
.expect("katz centrality should succeed on empty graph");
assert!(kc.is_empty());
}
#[test]
fn test_katz_centrality_invalid_alpha() {
let g = Graph::from_edges(&[(0, 1), (1, 2)], true);
assert!(g.katz_centrality(0.0, 100, 1e-6).is_err());
assert!(g.katz_centrality(1.0, 100, 1e-6).is_err());
assert!(g.katz_centrality(1.5, 100, 1e-6).is_err());
}
#[test]
fn test_katz_centrality_cycle() {
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 0)], true);
let kc = g
.katz_centrality(0.1, 100, 1e-6)
.expect("katz centrality should succeed on cycle graph");
assert_eq!(kc.len(), 3);
assert!((kc[0] - kc[1]).abs() < 1e-3);
assert!((kc[1] - kc[2]).abs() < 1e-3);
}
#[test]
fn test_katz_centrality_star_directed() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3)], true);
let kc = g
.katz_centrality(0.1, 100, 1e-6)
.expect("katz centrality should succeed on directed star graph");
assert_eq!(kc.len(), 4);
assert!(kc[1] > kc[0]);
assert!(kc[2] > kc[0]);
assert!(kc[3] > kc[0]);
}
#[test]
fn test_harmonic_centrality_empty() {
let g = Graph::new(false);
let hc = g.harmonic_centrality();
assert!(hc.is_empty());
}
#[test]
fn test_harmonic_centrality_star_graph() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3)], false);
let hc = g.harmonic_centrality();
assert_eq!(hc.len(), 4);
assert!(hc[0] > hc[1]);
assert!(hc[0] > hc[2]);
assert!(hc[0] > hc[3]);
}
#[test]
fn test_harmonic_centrality_disconnected() {
let g = Graph::from_edges(&[(0, 1), (2, 3)], false);
let hc = g.harmonic_centrality();
assert_eq!(hc.len(), 4);
assert!((hc[0] - hc[1]).abs() < 1e-6);
assert!((hc[2] - hc[3]).abs() < 1e-6);
}
#[test]
fn test_density_empty() {
let g = Graph::new(false);
assert_eq!(g.density(), 0.0);
}
#[test]
fn test_density_single_node() {
let g = Graph::from_edges(&[(0, 0)], false);
assert_eq!(g.density(), 0.0);
}
#[test]
fn test_density_complete_graph() {
let g = Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)], false);
assert!((g.density() - 1.0).abs() < 1e-6);
}
#[test]
fn test_density_path_graph() {
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], false);
assert!((g.density() - 0.5).abs() < 1e-6);
}