use crate::algo::GraphProjection;
use crate::algo::algorithms::{Algorithm, dijkstra_distances};
use rayon::prelude::*;
use uni_common::core::id::Vid;
pub struct HarmonicCentrality;
#[derive(Debug, Clone, Default)]
pub struct HarmonicCentralityConfig {}
pub struct HarmonicCentralityResult {
pub scores: Vec<(Vid, f64)>,
}
impl Algorithm for HarmonicCentrality {
type Config = HarmonicCentralityConfig;
type Result = HarmonicCentralityResult;
fn name() -> &'static str {
"harmonic_centrality"
}
fn run(graph: &GraphProjection, _config: Self::Config) -> Self::Result {
let n = graph.vertex_count();
if n == 0 {
return HarmonicCentralityResult { scores: Vec::new() };
}
let scores: Vec<(Vid, f64)> = (0..n)
.into_par_iter()
.map(|i| {
let score = compute_harmonic_score(graph, i as u32);
(graph.to_vid(i as u32), score)
})
.collect();
HarmonicCentralityResult { scores }
}
}
fn compute_harmonic_score(graph: &GraphProjection, start: u32) -> f64 {
let dist = dijkstra_distances(graph, start);
dist.into_iter()
.filter(|d| d.is_finite() && *d > 0.0)
.map(|d| 1.0 / d)
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::algo::test_utils::build_test_graph;
#[test]
fn test_harmonic_centrality_simple() {
let vids = vec![Vid::from(0), Vid::from(1), Vid::from(2)];
let edges = vec![(Vid::from(0), Vid::from(1)), (Vid::from(1), Vid::from(2))];
let graph = build_test_graph(vids, edges);
let result = HarmonicCentrality::run(&graph, HarmonicCentralityConfig::default());
let map: std::collections::HashMap<_, _> = result.scores.into_iter().collect();
assert!((map[&Vid::from(0)] - 1.5).abs() < 1e-6);
assert!((map[&Vid::from(1)] - 1.0).abs() < 1e-6);
assert!((map[&Vid::from(2)] - 0.0).abs() < 1e-6);
}
}