rust_igraph/algorithms/properties/
exponential_vertex_indices.rs1#![allow(
14 clippy::cast_possible_truncation,
15 clippy::cast_precision_loss,
16 clippy::many_single_char_names,
17 clippy::needless_range_loop,
18 clippy::too_many_lines
19)]
20
21use crate::core::{Graph, IgraphResult};
22
23pub fn exponential_first_zagreb(graph: &Graph) -> IgraphResult<f64> {
40 let n = graph.vcount() as usize;
41 let mut result = 0.0_f64;
42
43 for v in 0..n {
44 let d = graph.degree(v as u32)? as f64;
45 result += (d * d).exp();
46 }
47
48 Ok(result)
49}
50
51pub fn exponential_forgotten(graph: &Graph) -> IgraphResult<f64> {
68 let n = graph.vcount() as usize;
69 let mut result = 0.0_f64;
70
71 for v in 0..n {
72 let d = graph.degree(v as u32)? as f64;
73 result += (d * d * d).exp();
74 }
75
76 Ok(result)
77}
78
79pub fn exponential_inverse_degree(graph: &Graph) -> IgraphResult<f64> {
95 let n = graph.vcount() as usize;
96 let mut result = 0.0_f64;
97
98 for v in 0..n {
99 let d = graph.degree(v as u32)?;
100 if d == 0 {
101 continue;
102 }
103 result += (1.0 / d as f64).exp();
104 }
105
106 Ok(result)
107}
108
109pub fn exponential_sum_connectivity(graph: &Graph) -> IgraphResult<f64> {
125 let mut result = 0.0_f64;
126
127 for (u, v) in graph.edges() {
128 if u == v {
129 continue;
130 }
131 let du = graph.degree(u)? as f64;
132 let dv = graph.degree(v)? as f64;
133 let s = du + dv;
134 if s > 0.0 {
135 result += (1.0 / s.sqrt()).exp();
136 }
137 }
138
139 Ok(result)
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 fn single_edge() -> Graph {
147 Graph::from_edges(&[(0, 1)], false, Some(2)).unwrap()
148 }
149
150 fn path3() -> Graph {
151 Graph::from_edges(&[(0, 1), (1, 2)], false, Some(3)).unwrap()
152 }
153
154 fn k3() -> Graph {
155 Graph::from_edges(&[(0, 1), (1, 2), (0, 2)], false, Some(3)).unwrap()
156 }
157
158 fn k4() -> Graph {
159 Graph::from_edges(
160 &[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)],
161 false,
162 Some(4),
163 )
164 .unwrap()
165 }
166
167 fn cycle4() -> Graph {
168 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0)], false, Some(4)).unwrap()
169 }
170
171 fn star5() -> Graph {
172 Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (0, 4)], false, Some(5)).unwrap()
173 }
174
175 fn paw() -> Graph {
176 Graph::from_edges(&[(0, 1), (1, 2), (0, 2), (2, 3)], false, Some(4)).unwrap()
177 }
178
179 #[test]
182 fn efz_empty() {
183 let g = Graph::with_vertices(0);
184 assert!(exponential_first_zagreb(&g).unwrap().abs() < 1e-10);
185 }
186
187 #[test]
188 fn efz_isolated() {
189 let g = Graph::with_vertices(5);
191 assert!((exponential_first_zagreb(&g).unwrap() - 5.0).abs() < 1e-10);
192 }
193
194 #[test]
195 fn efz_k3() {
196 assert!((exponential_first_zagreb(&k3()).unwrap() - 3.0 * 4.0_f64.exp()).abs() < 1e-10);
198 }
199
200 #[test]
201 fn efz_k4() {
202 assert!((exponential_first_zagreb(&k4()).unwrap() - 4.0 * 9.0_f64.exp()).abs() < 1e-6);
204 }
205
206 #[test]
207 fn efz_single_edge() {
208 assert!(
210 (exponential_first_zagreb(&single_edge()).unwrap() - 2.0 * 1.0_f64.exp()).abs() < 1e-10
211 );
212 }
213
214 #[test]
215 fn efz_star5() {
216 let expected = 16.0_f64.exp() + 4.0 * 1.0_f64.exp();
218 assert!((exponential_first_zagreb(&star5()).unwrap() - expected).abs() < 1e-6);
219 }
220
221 #[test]
222 fn efz_cycle4() {
223 assert!((exponential_first_zagreb(&cycle4()).unwrap() - 4.0 * 4.0_f64.exp()).abs() < 1e-10);
225 }
226
227 #[test]
230 fn ef_empty() {
231 let g = Graph::with_vertices(0);
232 assert!(exponential_forgotten(&g).unwrap().abs() < 1e-10);
233 }
234
235 #[test]
236 fn ef_isolated() {
237 let g = Graph::with_vertices(5);
238 assert!((exponential_forgotten(&g).unwrap() - 5.0).abs() < 1e-10);
239 }
240
241 #[test]
242 fn ef_k3() {
243 assert!((exponential_forgotten(&k3()).unwrap() - 3.0 * 8.0_f64.exp()).abs() < 1e-6);
245 }
246
247 #[test]
248 fn ef_single_edge() {
249 assert!(
251 (exponential_forgotten(&single_edge()).unwrap() - 2.0 * 1.0_f64.exp()).abs() < 1e-10
252 );
253 }
254
255 #[test]
256 fn ef_star5() {
257 let expected = 64.0_f64.exp() + 4.0 * 1.0_f64.exp();
259 assert!((exponential_forgotten(&star5()).unwrap() - expected).abs() / expected < 1e-10);
260 }
261
262 #[test]
265 fn eid_empty() {
266 let g = Graph::with_vertices(0);
267 assert!(exponential_inverse_degree(&g).unwrap().abs() < 1e-10);
268 }
269
270 #[test]
271 fn eid_isolated() {
272 let g = Graph::with_vertices(5);
273 assert!(exponential_inverse_degree(&g).unwrap().abs() < 1e-10);
274 }
275
276 #[test]
277 fn eid_k3() {
278 assert!((exponential_inverse_degree(&k3()).unwrap() - 3.0 * 0.5_f64.exp()).abs() < 1e-10);
280 }
281
282 #[test]
283 fn eid_single_edge() {
284 assert!(
286 (exponential_inverse_degree(&single_edge()).unwrap() - 2.0 * 1.0_f64.exp()).abs()
287 < 1e-10
288 );
289 }
290
291 #[test]
292 fn eid_star5() {
293 let expected = 0.25_f64.exp() + 4.0 * 1.0_f64.exp();
295 assert!((exponential_inverse_degree(&star5()).unwrap() - expected).abs() < 1e-10);
296 }
297
298 #[test]
299 fn eid_paw() {
300 let expected = 2.0 * 0.5_f64.exp() + (1.0 / 3.0_f64).exp() + 1.0_f64.exp();
302 assert!((exponential_inverse_degree(&paw()).unwrap() - expected).abs() < 1e-10);
303 }
304
305 #[test]
308 fn esc_empty() {
309 let g = Graph::with_vertices(0);
310 assert!(exponential_sum_connectivity(&g).unwrap().abs() < 1e-10);
311 }
312
313 #[test]
314 fn esc_isolated() {
315 let g = Graph::with_vertices(5);
316 assert!(exponential_sum_connectivity(&g).unwrap().abs() < 1e-10);
317 }
318
319 #[test]
320 fn esc_k3() {
321 assert!((exponential_sum_connectivity(&k3()).unwrap() - 3.0 * 0.5_f64.exp()).abs() < 1e-10);
323 }
324
325 #[test]
326 fn esc_single_edge() {
327 let expected = (1.0 / 2.0_f64.sqrt()).exp();
329 assert!((exponential_sum_connectivity(&single_edge()).unwrap() - expected).abs() < 1e-10);
330 }
331
332 #[test]
333 fn esc_k4() {
334 let expected = 6.0 * (1.0 / 6.0_f64.sqrt()).exp();
336 assert!((exponential_sum_connectivity(&k4()).unwrap() - expected).abs() < 1e-10);
337 }
338
339 #[test]
340 fn esc_star5() {
341 let expected = 4.0 * (1.0 / 5.0_f64.sqrt()).exp();
343 assert!((exponential_sum_connectivity(&star5()).unwrap() - expected).abs() < 1e-10);
344 }
345
346 #[test]
347 fn esc_cycle4() {
348 assert!(
350 (exponential_sum_connectivity(&cycle4()).unwrap() - 4.0 * 0.5_f64.exp()).abs() < 1e-10
351 );
352 }
353
354 #[test]
355 fn esc_paw() {
356 let expected = 2.0 * 0.5_f64.exp() + 2.0 * (1.0 / 5.0_f64.sqrt()).exp();
361 assert!((exponential_sum_connectivity(&paw()).unwrap() - expected).abs() < 1e-10);
362 }
363
364 #[test]
367 fn efz_ge_n() {
368 for g in &[single_edge(), path3(), k3(), k4(), star5(), paw()] {
370 assert!(exponential_first_zagreb(g).unwrap() >= f64::from(g.vcount()) - 1e-10);
371 }
372 }
373
374 #[test]
375 fn esc_positive() {
376 for g in &[single_edge(), path3(), k3(), k4(), star5(), paw()] {
377 assert!(exponential_sum_connectivity(g).unwrap() > 0.0);
378 }
379 }
380}