use crate::graph::GraphDataBuilder;
use crate::leiden::{Leiden, LeidenConfig};
fn leiden_from_edgelist_core(edges: &[(usize, usize, f64)], num_nodes: usize, seed: u64) -> Vec<usize> {
let mut builder = GraphDataBuilder::new(num_nodes);
for &(u, v, w) in edges {
if builder.add_edge(u, v, w).is_err() {
return (0..num_nodes).collect();
}
}
let graph_data = match builder.build() {
Ok(g) => g,
Err(_) => return (0..num_nodes).collect(),
};
let config = LeidenConfig {
seed: Some(seed),
..Default::default()
};
match Leiden::new(config).run(&graph_data) {
Ok(result) => (0..num_nodes)
.map(|i| result.partition.community_of(i))
.collect(),
Err(_) => (0..num_nodes).collect(),
}
}
#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
pub fn leiden_from_edgelist(edges: &[f64], num_nodes: usize, seed: Option<u64>) -> Vec<usize> {
let edge_tuples: Vec<_> = edges
.chunks_exact(3)
.map(|chunk| (chunk[0] as usize, chunk[1] as usize, chunk[2]))
.collect();
let seed = seed.unwrap_or(0);
leiden_from_edgelist_core(&edge_tuples, num_nodes, seed)
}
#[cfg(test)]
mod tests {
use super::leiden_from_edgelist_core;
use std::collections::HashSet;
#[test]
fn leiden_from_edgelist_core_triangle_graph() {
let edges = [(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0)];
let result = leiden_from_edgelist_core(&edges, 3, 42);
assert_eq!(result.len(), 3);
let comms: HashSet<usize> = result.iter().copied().collect();
assert!(comms.len() >= 1, "expected at least 1 community, got {}", comms.len());
}
#[test]
fn leiden_from_edgelist_core_empty_edge_list() {
let edges: [(usize, usize, f64); 0] = [];
let result = leiden_from_edgelist_core(&edges, 3, 42);
assert_eq!(result.len(), 3);
let comms: HashSet<usize> = result.iter().copied().collect();
assert_eq!(comms.len(), 3, "each node should be in its own community");
}
#[test]
fn leiden_from_edgelist_core_single_edge() {
let edges = [(0, 1, 1.0)];
let result = leiden_from_edgelist_core(&edges, 2, 42);
assert_eq!(result.len(), 2);
assert_eq!(
result[0], result[1],
"both nodes should be in the same community"
);
}
#[test]
fn leiden_from_edgelist_core_disconnected() {
let edges = [(0, 1, 1.0), (2, 3, 1.0)];
let result = leiden_from_edgelist_core(&edges, 4, 42);
assert_eq!(result.len(), 4);
assert_eq!(result[0], result[1], "nodes 0,1 should be together");
assert_eq!(result[2], result[3], "nodes 2,3 should be together");
assert_ne!(result[0], result[2], "the two components should be in different communities");
}
}