use super::types::CommunityResult;
use crate::base::{EdgeWeight, Graph, IndexType, Node};
use scirs2_core::random::seq::SliceRandom;
use std::collections::HashMap;
use std::hash::Hash;
#[allow(dead_code)]
fn label_propagation_internal<N, E, Ix>(
graph: &Graph<N, E, Ix>,
max_iterations: usize,
) -> HashMap<N, usize>
where
N: Node + Clone + Hash + Eq + std::fmt::Debug,
E: EdgeWeight,
Ix: IndexType,
{
let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
let n = nodes.len();
if n == 0 {
return HashMap::new();
}
let mut labels: Vec<usize> = (0..n).collect();
let node_to_idx: HashMap<N, usize> = nodes
.iter()
.enumerate()
.map(|(i, n)| (n.clone(), i))
.collect();
let mut rng = scirs2_core::random::rng();
let mut changed = true;
let mut _iterations = 0;
while changed && _iterations < max_iterations {
changed = false;
_iterations += 1;
let mut order: Vec<usize> = (0..n).collect();
order.shuffle(&mut rng);
for &i in &order {
let node = &nodes[i];
let mut label_counts: HashMap<usize, usize> = HashMap::new();
if let Ok(neighbors) = graph.neighbors(node) {
for neighbor in neighbors {
if let Some(&neighbor_idx) = node_to_idx.get(&neighbor) {
let neighbor_label = labels[neighbor_idx];
*label_counts.entry(neighbor_label).or_insert(0) += 1;
}
}
}
if label_counts.is_empty() {
continue;
}
let max_count = *label_counts.values().max().expect("Operation failed");
let best_labels: Vec<usize> = label_counts
.into_iter()
.filter(|(_, count)| *count == max_count)
.map(|(label, _)| label)
.collect();
use scirs2_core::random::{Rng, RngExt};
let new_label = best_labels[rng.random_range(0..best_labels.len())];
if labels[i] != new_label {
labels[i] = new_label;
changed = true;
}
}
}
nodes
.into_iter()
.enumerate()
.map(|(i, node)| (node, labels[i]))
.collect()
}
#[deprecated(note = "Use `label_propagation_result` instead")]
#[allow(dead_code)]
pub fn label_propagation<N, E, Ix>(
graph: &Graph<N, E, Ix>,
max_iterations: usize,
) -> HashMap<N, usize>
where
N: Node + Clone + Hash + Eq + std::fmt::Debug,
E: EdgeWeight,
Ix: IndexType,
{
label_propagation_internal(graph, max_iterations)
}
#[allow(dead_code)]
pub fn label_propagation_result<N, E, Ix>(
graph: &Graph<N, E, Ix>,
max_iterations: usize,
) -> CommunityResult<N>
where
N: Node + Clone + Hash + Eq + std::fmt::Debug,
E: EdgeWeight,
Ix: IndexType,
{
let node_communities = label_propagation_internal(graph, max_iterations);
CommunityResult::from_node_map(node_communities)
}