use crate::partitioning::graph_traits::PartitionableGraph;
use hashbrown::HashMap;
use rayon::prelude::*;
#[derive(Debug, Clone)]
pub struct ClusterCounters {
pub m_edges: u64,
pub vol: Vec<u64>,
pub e_ij: HashMap<(u32, u32), u64>,
pub e_cc: Vec<u64>,
}
pub fn compute_counters<G>(g: &G, clusters: &[u32]) -> ClusterCounters
where
G: PartitionableGraph<VertexId = usize>,
{
let verts: Vec<usize> = g.vertices().collect();
assert_eq!(verts.len(), clusters.len(), "clusters length mismatch");
let idx_map: HashMap<usize, usize> = verts
.iter()
.copied()
.enumerate()
.map(|(i, v)| (v, i))
.collect();
let m_edges = g.edges().count() as u64;
let n_clusters = clusters.iter().max().map(|c| *c as usize + 1).unwrap_or(0);
let mut vol = vec![0u64; n_clusters];
let mut e_cc = vec![0u64; n_clusters];
let mut e_ij: HashMap<(u32, u32), u64> = HashMap::new();
for &u in &verts {
let ui = idx_map[&u];
let cid = clusters[ui];
vol[cid as usize] += g.degree(u) as u64;
}
for (u, v) in g.edges().collect::<Vec<_>>() {
let ui = idx_map[&u];
let vi = idx_map[&v];
let cu = clusters[ui];
let cv = clusters[vi];
if cu == cv {
e_cc[cu as usize] += 1;
} else {
let key = (cu.min(cv), cu.max(cv));
*e_ij.entry(key).or_insert(0) += 1;
}
}
ClusterCounters {
m_edges,
vol,
e_ij,
e_cc,
}
}