@@ -81,22 +81,61 @@ where
8181// -----------------------------
8282//
8383
84- /// Full implementation of eigenvector centrality with convergence tolerance.
85- pub fn eigenvector_centrality_impl < A , Ty > (
86- graph : & BaseGraph < A , f64 , Ty > ,
84+ /// Full implementation of eigenvector centrality with convergence tolerance,
85+ /// calculates eigenvector centrality for nodes in a graph iteratively.
86+ ///
87+ /// this function designed for generic edge type,
88+ /// see [`eigenvector_centrality`] and [`eigenvector_centrality_numpy`]
89+ /// for cleaner interaction with `f64` edge graph.
90+ ///
91+ /// # Arguments:
92+ ///
93+ /// * `graph`: the targeted graph.
94+ /// * `max_iter`: The maximum number of iterations that the algorithm will run for.
95+ /// * `tol`: the average tolerance for convergence.
96+ /// * `eval_weight`: callback to evaluate the weight of edges in the graph.
97+ ///
98+ /// # Returns :
99+ ///
100+ /// a vector of `f64` representing eigenvector centralities of each node in the graph.
101+ ///
102+ /// # Example
103+ /// ```rust
104+ /// use graphina::core::types::Graph;
105+ /// use graphina::centrality::algorithms::eigenvector_centrality_impl;
106+ ///
107+ /// let mut g: Graph<i32, (f64, f64)> = Graph::new();
108+ /// // ^^^^^^^^^^
109+ /// // L arbitrary type as edge
110+ /// let nodes = [g.add_node(1), g.add_node(2), g.add_node(3)];
111+ /// g.add_edge(nodes[0], nodes[1], (0.0, 1.0));
112+ /// g.add_edge(nodes[0], nodes[2], (1.0, 0.0));
113+ /// let centrality = eigenvector_centrality_impl(
114+ /// &g,
115+ /// 1000,
116+ /// 1e-6_f64,
117+ /// |w| w.0 * 10.0 + w.1 // <-- custom evaluation for edge weight
118+ /// );
119+ /// println!("{:.5?}", centrality); // [0.70711, 0.07036, 0.70360]
120+ /// ```
121+ pub fn eigenvector_centrality_impl < A , W , Ty > (
122+ graph : & BaseGraph < A , W , Ty > ,
87123 max_iter : usize ,
88124 tol : f64 ,
125+ eval_weight : impl Fn ( & W ) -> f64 ,
89126) -> Vec < f64 >
90127where
91- Ty : GraphConstructor < A , f64 > ,
128+ Ty : GraphConstructor < A , W > ,
92129{
93130 let n = graph. node_count ( ) ;
94131 let mut centrality = vec ! [ 1.0 ; n] ;
132+ let mut next = centrality. clone ( ) ;
95133 for _ in 0 ..max_iter {
96- let mut next = vec ! [ 0.0 ; n] ;
97- for ( node, _) in graph. nodes ( ) {
98- for neighbor in graph. neighbors ( node) {
99- next[ neighbor. index ( ) ] += centrality[ node. index ( ) ] ;
134+ for ( src, dst, w) in graph. edges ( ) {
135+ let w = eval_weight ( w) ;
136+ next[ dst. index ( ) ] += w * centrality[ src. index ( ) ] ;
137+ if !<Ty as GraphConstructor < A , W > >:: is_directed ( ) {
138+ next[ src. index ( ) ] += w * centrality[ dst. index ( ) ] ;
100139 }
101140 }
102141 let norm = next. iter ( ) . map ( |x| x * x) . sum :: < f64 > ( ) . sqrt ( ) ;
@@ -106,11 +145,14 @@ where
106145 }
107146 }
108147 let diff: f64 = centrality
109- . iter ( )
148+ . iter_mut ( )
110149 . zip ( next. iter ( ) )
111- . map ( |( a, b) | ( a - b) . abs ( ) )
150+ . map ( |( a, b) | {
151+ let d = ( * a - b) . abs ( ) ;
152+ * a = * b;
153+ d
154+ } )
112155 . sum ( ) ;
113- centrality = next;
114156 if diff < tol * n as f64 {
115157 break ;
116158 }
@@ -119,23 +161,90 @@ where
119161}
120162
121163/// Wrapper for eigenvector centrality with default tolerance (1e-6).
122- pub fn eigenvector_centrality < A , Ty > ( graph : & BaseGraph < A , f64 , Ty > , max_iter : usize ) -> Vec < f64 >
164+ /// calculates eigenvector centrality for nodes in a graph iteratively.
165+ ///
166+ /// # Arguments:
167+ ///
168+ /// * `graph`: the targeted graph.
169+ /// * `max_iter`: The maximum number of iterations that the algorithm will run for.
170+ /// * `weighted`: whether or not the calculated centrality will be weighed.
171+ ///
172+ /// # Returns :
173+ ///
174+ /// a vector of `f64` representing eigenvector centralities of each node in the graph.
175+ ///
176+ /// # Examples :
177+ /// ```rust
178+ /// use graphina::centrality::algorithms::eigenvector_centrality;
179+ /// use graphina::core::types::Graph;
180+ /// let mut g = Graph::new();
181+ ///
182+ /// let nodes = [g.add_node(1), g.add_node(2), g.add_node(3)];
183+ /// g.add_edge(nodes[0], nodes[1], 1.0);
184+ /// g.add_edge(nodes[0], nodes[2], 2.0);
185+ /// let centrality = eigenvector_centrality(&g, 1000, false);
186+ /// println!("{:.5?}", centrality); // [0.70711, 0.50000, 0.50000]
187+ /// let centrality = eigenvector_centrality(&g, 1000, true);
188+ /// println!("{:.5?}", centrality); // [0.70711, 0.31623, 0.63246]
189+ /// ```
190+ pub fn eigenvector_centrality < A , Ty > (
191+ graph : & BaseGraph < A , f64 , Ty > ,
192+ max_iter : usize ,
193+ weighted : bool ,
194+ ) -> Vec < f64 >
123195where
124196 Ty : GraphConstructor < A , f64 > ,
125197{
126- eigenvector_centrality_impl ( graph, max_iter, 1e-6_f64 )
198+ let eval_weight = if weighted {
199+ |f : & f64 | * f
200+ } else {
201+ |_f : & f64 | 1.0
202+ } ;
203+ eigenvector_centrality_impl ( graph, max_iter, 1e-6_f64 , eval_weight)
127204}
128205
129- /// NumPy–style eigenvector centrality (alias to the above).
206+ /// NumPy–style eigenvector centrality (alias to [`eigenvector_centrality`]).
207+ /// calculates eigenvector centrality for nodes in a graph iteratively.
208+ ///
209+ /// # Arguments:
210+ ///
211+ /// * `graph`: the targeted graph.
212+ /// * `max_iter`: The maximum number of iterations that the algorithm will run for.
213+ /// * `weighted`: whether or not the calculated centrality will be weighed.
214+ ///
215+ /// # Returns :
216+ ///
217+ /// a vector of `f64` representing eigenvector centralities of each node in the graph.
218+ ///
219+ /// # Examples :
220+ /// ```rust
221+ /// use graphina::centrality::algorithms::eigenvector_centrality_numpy;
222+ /// use graphina::core::types::Graph;
223+ /// let mut g = Graph::new();
224+ ///
225+ /// let nodes = [g.add_node(1), g.add_node(2), g.add_node(3)];
226+ /// g.add_edge(nodes[0], nodes[1], 1.0);
227+ /// g.add_edge(nodes[0], nodes[2], 2.0);
228+ /// let centrality = eigenvector_centrality_numpy(&g, 1000, false);
229+ /// println!("{:.5?}", centrality); // [0.70711, 0.50000, 0.50000]
230+ /// let centrality = eigenvector_centrality_numpy(&g, 1000, true);
231+ /// println!("{:.5?}", centrality); // [0.70711, 0.31623, 0.63246]
232+ /// ```
130233pub fn eigenvector_centrality_numpy < A , Ty > (
131234 graph : & BaseGraph < A , f64 , Ty > ,
132235 max_iter : usize ,
133236 tol : f64 ,
237+ weighted : bool ,
134238) -> Vec < f64 >
135239where
136240 Ty : GraphConstructor < A , f64 > ,
137241{
138- eigenvector_centrality_impl ( graph, max_iter, tol)
242+ let eval_weight = if weighted {
243+ |f : & f64 | * f
244+ } else {
245+ |_f : & f64 | 1.0
246+ } ;
247+ eigenvector_centrality_impl ( graph, max_iter, tol, eval_weight)
139248}
140249
141250//
0 commit comments