@@ -581,19 +581,54 @@ where
581
581
///
582
582
/// Closeness = (n - 1) / (sum of shortest-path distances).
583
583
///
584
+ /// where n is number of reachable nodes.
585
+ ///
584
586
/// # Arguments
585
587
///
586
588
/// * `graph`: the targeted graph.
587
589
/// * `eval_cost`: callback to evaluate the cost of edges in the graph, returning
588
590
/// - `Some(f64)` for cost
589
591
/// - `None` for impassable
592
+ /// * `wf_improved`: whether or not to scale the result by reachability ratio.
590
593
///
591
594
/// # Returns
592
595
///
593
596
/// a vector of `f64` representing closeness centralities of each node in the graph.
597
+ ///
598
+ /// # Example
599
+ /// ```rust
600
+ /// use graphina::core::types::Graph;
601
+ ///
602
+ /// use graphina::centrality::algorithms::closeness_centrality_impl;
603
+ ///
604
+ /// let mut graph: Graph<i32, (String, f64)> = Graph::new();
605
+ ///
606
+ /// let ids = (0..5).map(|i| graph.add_node(i)).collect::<Vec<_>>();
607
+ ///
608
+ /// let edges = [
609
+ /// (0, 1, ("friend".to_string(), 0.9)),
610
+ /// (0, 2, ("family".to_string(), 0.8)),
611
+ /// (1, 3, ("friend".to_string(), 0.7)),
612
+ /// (2, 4, ("enemy".to_string(), 0.1)),
613
+ /// ];
614
+ /// for (s, d, w) in edges {
615
+ /// graph.add_edge(ids[s], ids[d], w);
616
+ /// }
617
+ ///
618
+ /// let eval_cost = |(s, f): &(String, f64)| match s.as_str() {
619
+ /// "friend" => Some(1.0 / *f / 2.0),
620
+ /// "family" => Some(1.0 / *f / 4.0),
621
+ /// "enemy" => None,
622
+ /// _ => Some(1.0 / *f),
623
+ /// };
624
+ ///
625
+ /// let centrality = closeness_centrality_impl(&graph, eval_cost, true).unwrap();
626
+ /// println!("{:.5?}", centrality); // [1.05244, 1.05244, 0.81436, 0.63088, 0.00000]
627
+ /// ```
594
628
pub fn closeness_centrality_impl < A , W , Ty > (
595
629
graph : & BaseGraph < A , W , Ty > ,
596
630
eval_cost : impl Fn ( & W ) -> Option < f64 > ,
631
+ wf_improved : bool ,
597
632
) -> Result < Vec < f64 > , GraphinaException >
598
633
where
599
634
A : Debug ,
@@ -605,32 +640,60 @@ where
605
640
let mut closeness = vec ! [ 0.0 ; n] ;
606
641
for ( node, _) in graph. nodes ( ) {
607
642
let ( distances, _) = dijkstra_path_impl ( graph, node, None , & eval_cost) ?;
643
+ let reachable = distances. iter ( ) . filter ( |d| d. is_some ( ) ) . count ( ) as f64 ;
608
644
let sum: f64 = distances. iter ( ) . filter_map ( |d| d. to_owned ( ) ) . sum ( ) ;
609
645
if sum > 0.0 {
610
- closeness[ node. index ( ) ] = ( n as f64 - 1.0 ) / sum;
646
+ closeness[ node. index ( ) ] = ( reachable - 1.0 ) / sum;
647
+ }
648
+ if wf_improved {
649
+ closeness[ node. index ( ) ] *= ( reachable - 1.0 ) / ( n as f64 - 1.0 ) ;
611
650
}
612
651
}
613
652
Ok ( closeness)
614
653
}
615
654
616
655
/// Compute closeness centrality using Dijkstra’s algorithm.
656
+ ///
617
657
/// Closeness = (n - 1) / (sum of shortest-path distances).
658
+ ///
659
+ /// where n is number of reachable nodes.
660
+ ///
661
+ /// # Arguments
662
+ ///
663
+ /// * `graph`: the targeted graph.
664
+ /// * `wf_improved`: whether or not to scale the result by reachability ratio.
665
+ ///
666
+ /// # Returns
667
+ ///
668
+ /// a vector of `f64` representing closeness centralities of each node in the graph.
669
+ ///
670
+ /// # Example
671
+ /// ```rust
672
+ /// use graphina::core::types::Graph;
673
+ ///
674
+ /// use graphina::centrality::algorithms::closeness_centrality;
675
+ ///
676
+ /// let mut graph = Graph::new();
677
+ /// let ids = (0..5).map(|i| graph.add_node(i)).collect::<Vec<_>>();
678
+ /// let edges = [(0, 1, 1.0), (0, 2, 1.0), (1, 3, 1.0)];
679
+ /// for (s, d, w) in edges {
680
+ /// graph.add_edge(ids[s], ids[d], w);
681
+ /// }
682
+ ///
683
+ /// let centrality = closeness_centrality(&graph, false).unwrap();
684
+ /// println!("{:.5?}", centrality); // [0.75000, 0.75000, 0.50000, 0.50000, 0.00000]
685
+ /// ```
618
686
pub fn closeness_centrality < A , Ty > (
619
- graph : & BaseGraph < A , ordered_float:: OrderedFloat < f64 > , Ty > ,
687
+ graph : & BaseGraph < A , f64 , Ty > ,
688
+ wf_improved : bool ,
620
689
) -> Result < Vec < f64 > , GraphinaException >
621
690
where
622
- Ty : GraphConstructor < A , ordered_float:: OrderedFloat < f64 > > ,
691
+ A : Debug ,
692
+ Ty : GraphConstructor < A , f64 > ,
693
+ BaseGraph < A , f64 , Ty > : GraphinaGraph < A , f64 > ,
623
694
{
624
- let n = graph. node_count ( ) ;
625
- let mut closeness = vec ! [ 0.0 ; n] ;
626
- for ( node, _) in graph. nodes ( ) {
627
- let distances = dijkstra ( graph, node) ?;
628
- let sum: f64 = distances. iter ( ) . filter_map ( |d| d. map ( |od| od. 0 ) ) . sum ( ) ;
629
- if sum > 0.0 {
630
- closeness[ node. index ( ) ] = ( n as f64 - 1.0 ) / sum;
631
- }
632
- }
633
- Ok ( closeness)
695
+ let eval_cost = |f : & f64 | Some ( * f) ;
696
+ closeness_centrality_impl ( graph, eval_cost, wf_improved)
634
697
}
635
698
636
699
//
0 commit comments