use crate::core::error::Result;
use crate::core::paths::dijkstra_path_f64;
use crate::core::types::{BaseGraph, GraphConstructor, GraphinaGraph, NodeMap};
use std::fmt::Debug;
pub fn harmonic_centrality<A, Ty>(graph: &BaseGraph<A, f64, Ty>) -> Result<NodeMap<f64>>
where
A: Debug,
Ty: GraphConstructor<A, f64>,
BaseGraph<A, f64, Ty>: GraphinaGraph<A, f64>,
{
let mut centrality = NodeMap::default();
for (node, _) in graph.nodes() {
let (distances, _) = dijkstra_path_f64(graph, node, None)?;
let sum: f64 = distances
.into_iter()
.filter(|(other, _)| *other != node)
.filter_map(|(_, d)| d.map(|dist| 1.0 / dist))
.sum();
centrality.insert(node, sum);
}
Ok(centrality)
}
#[cfg(test)]
mod tests {
#[test]
fn test_harmonic_centrality_excludes_source() {
use crate::centrality::harmonic::harmonic_centrality;
use crate::core::types::Graph;
let mut g = Graph::<i32, f64>::new();
let n0 = g.add_node(0);
let n1 = g.add_node(1);
let n2 = g.add_node(2);
g.add_edge(n0, n1, 1.0);
g.add_edge(n1, n2, 1.0);
g.add_edge(n2, n0, 1.0);
let hc = harmonic_centrality(&g).expect("harmonic should succeed");
for n in [n0, n1, n2] {
assert!(hc[&n].is_finite(), "harmonic centrality must be finite");
assert!((hc[&n] - 2.0).abs() < 1e-9, "expected 2.0, got {}", hc[&n]);
}
}
}