@@ -81,22 +81,61 @@ where
81
81
// -----------------------------
82
82
//
83
83
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 > ,
87
123
max_iter : usize ,
88
124
tol : f64 ,
125
+ eval_weight : impl Fn ( & W ) -> f64 ,
89
126
) -> Vec < f64 >
90
127
where
91
- Ty : GraphConstructor < A , f64 > ,
128
+ Ty : GraphConstructor < A , W > ,
92
129
{
93
130
let n = graph. node_count ( ) ;
94
131
let mut centrality = vec ! [ 1.0 ; n] ;
132
+ let mut next = centrality. clone ( ) ;
95
133
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 ( ) ] ;
100
139
}
101
140
}
102
141
let norm = next. iter ( ) . map ( |x| x * x) . sum :: < f64 > ( ) . sqrt ( ) ;
@@ -106,11 +145,14 @@ where
106
145
}
107
146
}
108
147
let diff: f64 = centrality
109
- . iter ( )
148
+ . iter_mut ( )
110
149
. 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
+ } )
112
155
. sum ( ) ;
113
- centrality = next;
114
156
if diff < tol * n as f64 {
115
157
break ;
116
158
}
@@ -119,23 +161,90 @@ where
119
161
}
120
162
121
163
/// 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 >
123
195
where
124
196
Ty : GraphConstructor < A , f64 > ,
125
197
{
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)
127
204
}
128
205
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
+ /// ```
130
233
pub fn eigenvector_centrality_numpy < A , Ty > (
131
234
graph : & BaseGraph < A , f64 , Ty > ,
132
235
max_iter : usize ,
133
236
tol : f64 ,
237
+ weighted : bool ,
134
238
) -> Vec < f64 >
135
239
where
136
240
Ty : GraphConstructor < A , f64 > ,
137
241
{
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)
139
248
}
140
249
141
250
//
0 commit comments