rust_igraph/algorithms/properties/
reformulated_zagreb.rs1#![allow(
15 clippy::cast_possible_truncation,
16 clippy::cast_precision_loss,
17 clippy::many_single_char_names,
18 clippy::needless_range_loop,
19 clippy::too_many_lines
20)]
21
22use crate::core::{Graph, IgraphResult};
23
24pub fn first_reformulated_zagreb(graph: &Graph) -> IgraphResult<u64> {
40 let mut em1: u64 = 0;
41
42 for (u, v) in graph.edges() {
43 if u == v {
44 continue;
45 }
46 let du = graph.degree(u)? as u64;
47 let dv = graph.degree(v)? as u64;
48 let eps = du + dv - 2;
49 em1 = em1.saturating_add(eps.saturating_mul(eps));
50 }
51
52 Ok(em1)
53}
54
55pub fn second_reformulated_zagreb(graph: &Graph) -> IgraphResult<u64> {
74 let n = graph.vcount() as usize;
75 let ecount = graph.ecount();
76
77 if ecount == 0 {
78 return Ok(0);
79 }
80
81 let edges: Vec<(u32, u32)> = graph.edges().collect();
82 let mut deg = vec![0_usize; n];
83 for v in 0..n as u32 {
84 deg[v as usize] = graph.degree(v)?;
85 }
86
87 let mut edge_deg = Vec::with_capacity(ecount);
88 for &(u, v) in &edges {
89 if u == v {
90 edge_deg.push(0_u64);
91 continue;
92 }
93 edge_deg.push((deg[u as usize] + deg[v as usize] - 2) as u64);
94 }
95
96 let mut incident: Vec<Vec<usize>> = vec![Vec::new(); n];
97 for (idx, &(u, v)) in edges.iter().enumerate() {
98 if u == v {
99 continue;
100 }
101 incident[u as usize].push(idx);
102 incident[v as usize].push(idx);
103 }
104
105 let mut em2: u64 = 0;
106 for v in 0..n {
107 let inc = &incident[v];
108 let k = inc.len();
109 for i in 0..k {
110 for j in (i + 1)..k {
111 em2 = em2.saturating_add(edge_deg[inc[i]].saturating_mul(edge_deg[inc[j]]));
112 }
113 }
114 }
115
116 Ok(em2)
117}
118
119pub fn third_zagreb_index(graph: &Graph) -> IgraphResult<u64> {
136 let mut m3: u64 = 0;
137
138 for (u, v) in graph.edges() {
139 if u == v {
140 continue;
141 }
142 let du = graph.degree(u)?;
143 let dv = graph.degree(v)?;
144 m3 = m3.saturating_add(du.abs_diff(dv) as u64);
145 }
146
147 Ok(m3)
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 fn single_edge() -> Graph {
155 Graph::from_edges(&[(0, 1)], false, Some(2)).unwrap()
156 }
157
158 fn path3() -> Graph {
159 Graph::from_edges(&[(0, 1), (1, 2)], false, Some(3)).unwrap()
160 }
161
162 fn path4() -> Graph {
163 Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], false, Some(4)).unwrap()
164 }
165
166 fn k3() -> Graph {
167 Graph::from_edges(&[(0, 1), (1, 2), (0, 2)], false, Some(3)).unwrap()
168 }
169
170 fn k4() -> Graph {
171 Graph::from_edges(
172 &[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)],
173 false,
174 Some(4),
175 )
176 .unwrap()
177 }
178
179 fn cycle4() -> Graph {
180 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0)], false, Some(4)).unwrap()
181 }
182
183 fn cycle5() -> Graph {
184 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)], false, Some(5)).unwrap()
185 }
186
187 fn star5() -> Graph {
188 Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (0, 4)], false, Some(5)).unwrap()
189 }
190
191 fn paw() -> Graph {
192 Graph::from_edges(&[(0, 1), (1, 2), (0, 2), (2, 3)], false, Some(4)).unwrap()
193 }
194
195 #[test]
198 fn em1_empty() {
199 let g = Graph::with_vertices(0);
200 assert_eq!(first_reformulated_zagreb(&g).unwrap(), 0);
201 }
202
203 #[test]
204 fn em1_single_vertex() {
205 let g = Graph::with_vertices(1);
206 assert_eq!(first_reformulated_zagreb(&g).unwrap(), 0);
207 }
208
209 #[test]
210 fn em1_single_edge() {
211 assert_eq!(first_reformulated_zagreb(&single_edge()).unwrap(), 0);
213 }
214
215 #[test]
216 fn em1_path3() {
217 assert_eq!(first_reformulated_zagreb(&path3()).unwrap(), 2);
220 }
221
222 #[test]
223 fn em1_path4() {
224 assert_eq!(first_reformulated_zagreb(&path4()).unwrap(), 6);
227 }
228
229 #[test]
230 fn em1_k3() {
231 assert_eq!(first_reformulated_zagreb(&k3()).unwrap(), 12);
234 }
235
236 #[test]
237 fn em1_k4() {
238 assert_eq!(first_reformulated_zagreb(&k4()).unwrap(), 96);
241 }
242
243 #[test]
244 fn em1_cycle4() {
245 assert_eq!(first_reformulated_zagreb(&cycle4()).unwrap(), 16);
248 }
249
250 #[test]
251 fn em1_cycle5() {
252 assert_eq!(first_reformulated_zagreb(&cycle5()).unwrap(), 20);
255 }
256
257 #[test]
258 fn em1_star5() {
259 assert_eq!(first_reformulated_zagreb(&star5()).unwrap(), 36);
262 }
263
264 #[test]
265 fn em1_paw() {
266 assert_eq!(first_reformulated_zagreb(&paw()).unwrap(), 26);
270 }
271
272 #[test]
273 fn em1_regular_formula() {
274 for g in &[k3(), k4(), cycle4(), cycle5()] {
276 let m = g.ecount() as u64;
277 let r = g.degree(0).unwrap() as u64;
278 let eps = 2 * r - 2;
279 assert_eq!(first_reformulated_zagreb(g).unwrap(), m * eps * eps);
280 }
281 }
282
283 #[test]
286 fn em2_empty() {
287 let g = Graph::with_vertices(0);
288 assert_eq!(second_reformulated_zagreb(&g).unwrap(), 0);
289 }
290
291 #[test]
292 fn em2_single_edge() {
293 assert_eq!(second_reformulated_zagreb(&single_edge()).unwrap(), 0);
295 }
296
297 #[test]
298 fn em2_path3() {
299 assert_eq!(second_reformulated_zagreb(&path3()).unwrap(), 1);
302 }
303
304 #[test]
305 fn em2_path4() {
306 assert_eq!(second_reformulated_zagreb(&path4()).unwrap(), 4);
310 }
311
312 #[test]
313 fn em2_k3() {
314 assert_eq!(second_reformulated_zagreb(&k3()).unwrap(), 12);
319 }
320
321 #[test]
322 fn em2_k4() {
323 assert_eq!(second_reformulated_zagreb(&k4()).unwrap(), 192);
326 }
327
328 #[test]
329 fn em2_cycle4() {
330 assert_eq!(second_reformulated_zagreb(&cycle4()).unwrap(), 16);
333 }
334
335 #[test]
336 fn em2_cycle5() {
337 assert_eq!(second_reformulated_zagreb(&cycle5()).unwrap(), 20);
340 }
341
342 #[test]
343 fn em2_star5() {
344 assert_eq!(second_reformulated_zagreb(&star5()).unwrap(), 54);
347 }
348
349 #[test]
350 fn em2_paw() {
351 assert_eq!(second_reformulated_zagreb(&paw()).unwrap(), 33);
358 }
359
360 #[test]
361 fn em2_regular_formula() {
362 for g in &[k3(), k4(), cycle4(), cycle5()] {
367 let n = u64::from(g.vcount());
368 let r = g.degree(0).unwrap() as u64;
369 let eps = 2 * r - 2;
370 let pairs = n * r * (r - 1) / 2;
371 assert_eq!(second_reformulated_zagreb(g).unwrap(), pairs * eps * eps);
372 }
373 }
374
375 #[test]
378 fn m3_empty() {
379 let g = Graph::with_vertices(0);
380 assert_eq!(third_zagreb_index(&g).unwrap(), 0);
381 }
382
383 #[test]
384 fn m3_single_edge() {
385 assert_eq!(third_zagreb_index(&single_edge()).unwrap(), 0);
387 }
388
389 #[test]
390 fn m3_path3() {
391 assert_eq!(third_zagreb_index(&path3()).unwrap(), 2);
393 }
394
395 #[test]
396 fn m3_path4() {
397 assert_eq!(third_zagreb_index(&path4()).unwrap(), 2);
399 }
400
401 #[test]
402 fn m3_k3() {
403 assert_eq!(third_zagreb_index(&k3()).unwrap(), 0);
405 }
406
407 #[test]
408 fn m3_k4() {
409 assert_eq!(third_zagreb_index(&k4()).unwrap(), 0);
410 }
411
412 #[test]
413 fn m3_cycle4() {
414 assert_eq!(third_zagreb_index(&cycle4()).unwrap(), 0);
415 }
416
417 #[test]
418 fn m3_star5() {
419 assert_eq!(third_zagreb_index(&star5()).unwrap(), 12);
421 }
422
423 #[test]
424 fn m3_paw() {
425 assert_eq!(third_zagreb_index(&paw()).unwrap(), 4);
427 }
428
429 #[test]
430 fn m3_zero_for_regular() {
431 for g in &[k3(), k4(), cycle4(), cycle5()] {
432 assert_eq!(third_zagreb_index(g).unwrap(), 0);
433 }
434 }
435
436 #[test]
439 fn all_compute_ok() {
440 for g in &[single_edge(), path3(), k3(), k4(), cycle4(), star5(), paw()] {
441 first_reformulated_zagreb(g).unwrap();
442 second_reformulated_zagreb(g).unwrap();
443 third_zagreb_index(g).unwrap();
444 }
445 }
446
447 #[test]
448 fn em1_zero_iff_matching() {
449 assert_eq!(first_reformulated_zagreb(&single_edge()).unwrap(), 0);
452 let matching = Graph::from_edges(&[(0, 1), (2, 3)], false, Some(4)).unwrap();
453 assert_eq!(first_reformulated_zagreb(&matching).unwrap(), 0);
454 }
455}