use crate::Graph;
pub fn coreness(graph: &Graph) -> Vec<usize> {
let node_count = graph.node_count();
let max_degree = graph.max_degree();
let mut core_table = vec![0; node_count];
let mut nodes = vec![0_usize; node_count];
let mut position = vec![0_usize; node_count];
let mut degree_hist = vec![0; max_degree + 1];
for (node, degree) in core_table.iter_mut().enumerate() {
*degree = graph.degree(node);
degree_hist[*degree] += 1;
}
let mut offset = 0;
for count in degree_hist.iter_mut() {
let temp = *count;
*count = offset;
offset += temp;
}
for node in 0..node_count {
let degree = graph.degree(node);
position[node] = degree_hist[degree];
nodes[position[node]] = node;
degree_hist[degree] += 1;
}
for degree in (1..=max_degree).rev() {
degree_hist[degree] = degree_hist[degree - 1];
}
degree_hist[0] = 0;
for i in 0..node_count {
let u = nodes[i];
for &v in graph.neighbors(u) {
if core_table[v] > core_table[u] {
let degree_v = core_table[v];
let position_v = position[v];
let position_w = degree_hist[degree_v];
let w = nodes[position_w];
if v != w {
position[v] = position_w;
position[w] = position_v;
nodes[position_v] = w;
nodes[position_w] = v;
}
degree_hist[degree_v] += 1;
core_table[v] -= 1;
}
}
}
core_table
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::GdlGraph;
use trim_margin::MarginTrimmable;
#[test]
fn test_coreness() {
let graph = "
|(n0:L0)
|(n1:L0)
|(n2:L0)
|(n3:L0)
|(n4:L0)
|(n0)-->(n1)
|(n1)-->(n2)
|(n1)-->(n3)
|(n2)-->(n4)
|(n3)-->(n4)
|(n4)-->(n1)
|(n4)-->(n2)
|"
.trim_margin()
.unwrap()
.parse::<GdlGraph>()
.unwrap();
let core_table = coreness(&graph);
assert_eq!(core_table, vec![1, 2, 2, 2, 2])
}
}