rust_igraph/algorithms/properties/
gourava_index.rs1#![allow(
11 clippy::cast_possible_truncation,
12 clippy::cast_precision_loss,
13 clippy::many_single_char_names,
14 clippy::needless_range_loop,
15 clippy::too_many_lines
16)]
17
18use crate::core::{Graph, IgraphResult};
19
20pub fn first_gourava_index(graph: &Graph) -> IgraphResult<u64> {
36 let mut go1 = 0_u64;
37
38 for (u, v) in graph.edges() {
39 if u == v {
40 continue;
41 }
42 let du = graph.degree(u)? as u64;
43 let dv = graph.degree(v)? as u64;
44 go1 = go1.saturating_add(du + dv + du.saturating_mul(dv));
45 }
46
47 Ok(go1)
48}
49
50pub fn second_gourava_index(graph: &Graph) -> IgraphResult<u64> {
66 let mut go2 = 0_u64;
67
68 for (u, v) in graph.edges() {
69 if u == v {
70 continue;
71 }
72 let du = graph.degree(u)? as u64;
73 let dv = graph.degree(v)? as u64;
74 let s = du + dv;
75 let p = du.saturating_mul(dv);
76 go2 = go2.saturating_add(s.saturating_mul(p));
77 }
78
79 Ok(go2)
80}
81
82pub fn first_hyper_gourava_index(graph: &Graph) -> IgraphResult<u64> {
98 let mut hgo1 = 0_u64;
99
100 for (u, v) in graph.edges() {
101 if u == v {
102 continue;
103 }
104 let du = graph.degree(u)? as u64;
105 let dv = graph.degree(v)? as u64;
106 let val = du + dv + du.saturating_mul(dv);
107 hgo1 = hgo1.saturating_add(val.saturating_mul(val));
108 }
109
110 Ok(hgo1)
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 fn single_edge() -> Graph {
118 Graph::from_edges(&[(0, 1)], false, Some(2)).unwrap()
119 }
120
121 fn path3() -> Graph {
122 Graph::from_edges(&[(0, 1), (1, 2)], false, Some(3)).unwrap()
123 }
124
125 fn path4() -> Graph {
126 Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], false, Some(4)).unwrap()
127 }
128
129 fn k3() -> Graph {
130 Graph::from_edges(&[(0, 1), (1, 2), (0, 2)], false, Some(3)).unwrap()
131 }
132
133 fn k4() -> Graph {
134 Graph::from_edges(
135 &[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)],
136 false,
137 Some(4),
138 )
139 .unwrap()
140 }
141
142 fn cycle4() -> Graph {
143 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0)], false, Some(4)).unwrap()
144 }
145
146 fn cycle5() -> Graph {
147 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)], false, Some(5)).unwrap()
148 }
149
150 fn star5() -> Graph {
151 Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (0, 4)], false, Some(5)).unwrap()
152 }
153
154 fn paw() -> Graph {
155 Graph::from_edges(&[(0, 1), (1, 2), (0, 2), (2, 3)], false, Some(4)).unwrap()
156 }
157
158 fn diamond() -> Graph {
159 Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)], false, Some(4)).unwrap()
160 }
161
162 #[test]
165 fn go1_empty() {
166 let g = Graph::with_vertices(0);
167 assert_eq!(first_gourava_index(&g).unwrap(), 0);
168 }
169
170 #[test]
171 fn go1_isolated() {
172 let g = Graph::with_vertices(5);
173 assert_eq!(first_gourava_index(&g).unwrap(), 0);
174 }
175
176 #[test]
177 fn go1_single_edge() {
178 assert_eq!(first_gourava_index(&single_edge()).unwrap(), 3);
180 }
181
182 #[test]
183 fn go1_path3() {
184 assert_eq!(first_gourava_index(&path3()).unwrap(), 10);
186 }
187
188 #[test]
189 fn go1_path4() {
190 assert_eq!(first_gourava_index(&path4()).unwrap(), 18);
192 }
193
194 #[test]
195 fn go1_k3() {
196 assert_eq!(first_gourava_index(&k3()).unwrap(), 24);
198 }
199
200 #[test]
201 fn go1_k4() {
202 assert_eq!(first_gourava_index(&k4()).unwrap(), 90);
204 }
205
206 #[test]
207 fn go1_cycle4() {
208 assert_eq!(first_gourava_index(&cycle4()).unwrap(), 32);
210 }
211
212 #[test]
213 fn go1_cycle5() {
214 assert_eq!(first_gourava_index(&cycle5()).unwrap(), 40);
216 }
217
218 #[test]
219 fn go1_star5() {
220 assert_eq!(first_gourava_index(&star5()).unwrap(), 36);
222 }
223
224 #[test]
225 fn go1_paw() {
226 assert_eq!(first_gourava_index(&paw()).unwrap(), 37);
230 }
231
232 #[test]
233 fn go1_diamond() {
234 assert_eq!(first_gourava_index(&diamond()).unwrap(), 59);
238 }
239
240 #[test]
241 fn go1_is_m1_plus_m2() {
242 for g in &[single_edge(), path3(), k3(), k4(), cycle4(), star5(), paw()] {
245 let mut m1 = 0_u64;
246 let mut m2 = 0_u64;
247 for (u, v) in g.edges() {
248 if u == v {
249 continue;
250 }
251 let du = g.degree(u).unwrap() as u64;
252 let dv = g.degree(v).unwrap() as u64;
253 m1 += du + dv;
254 m2 += du * dv;
255 }
256 assert_eq!(first_gourava_index(g).unwrap(), m1 + m2);
257 }
258 }
259
260 #[test]
261 fn go1_regular_formula() {
262 for g in &[k3(), k4(), cycle4(), cycle5()] {
264 let m = g.ecount() as u64;
265 let r = g.degree(0).unwrap() as u64;
266 assert_eq!(first_gourava_index(g).unwrap(), m * r * (r + 2));
267 }
268 }
269
270 #[test]
273 fn go2_empty() {
274 let g = Graph::with_vertices(0);
275 assert_eq!(second_gourava_index(&g).unwrap(), 0);
276 }
277
278 #[test]
279 fn go2_isolated() {
280 let g = Graph::with_vertices(5);
281 assert_eq!(second_gourava_index(&g).unwrap(), 0);
282 }
283
284 #[test]
285 fn go2_single_edge() {
286 assert_eq!(second_gourava_index(&single_edge()).unwrap(), 2);
288 }
289
290 #[test]
291 fn go2_path3() {
292 assert_eq!(second_gourava_index(&path3()).unwrap(), 12);
294 }
295
296 #[test]
297 fn go2_path4() {
298 assert_eq!(second_gourava_index(&path4()).unwrap(), 28);
300 }
301
302 #[test]
303 fn go2_k3() {
304 assert_eq!(second_gourava_index(&k3()).unwrap(), 48);
306 }
307
308 #[test]
309 fn go2_k4() {
310 assert_eq!(second_gourava_index(&k4()).unwrap(), 324);
312 }
313
314 #[test]
315 fn go2_cycle4() {
316 assert_eq!(second_gourava_index(&cycle4()).unwrap(), 64);
318 }
319
320 #[test]
321 fn go2_cycle5() {
322 assert_eq!(second_gourava_index(&cycle5()).unwrap(), 80);
324 }
325
326 #[test]
327 fn go2_star5() {
328 assert_eq!(second_gourava_index(&star5()).unwrap(), 80);
330 }
331
332 #[test]
333 fn go2_paw() {
334 assert_eq!(second_gourava_index(&paw()).unwrap(), 88);
337 }
338
339 #[test]
340 fn go2_diamond() {
341 assert_eq!(second_gourava_index(&diamond()).unwrap(), 174);
344 }
345
346 #[test]
347 fn go2_regular_formula() {
348 for g in &[k3(), k4(), cycle4(), cycle5()] {
350 let m = g.ecount() as u64;
351 let r = g.degree(0).unwrap() as u64;
352 assert_eq!(second_gourava_index(g).unwrap(), 2 * m * r * r * r);
353 }
354 }
355
356 #[test]
359 fn hgo1_empty() {
360 let g = Graph::with_vertices(0);
361 assert_eq!(first_hyper_gourava_index(&g).unwrap(), 0);
362 }
363
364 #[test]
365 fn hgo1_isolated() {
366 let g = Graph::with_vertices(5);
367 assert_eq!(first_hyper_gourava_index(&g).unwrap(), 0);
368 }
369
370 #[test]
371 fn hgo1_single_edge() {
372 assert_eq!(first_hyper_gourava_index(&single_edge()).unwrap(), 9);
374 }
375
376 #[test]
377 fn hgo1_path3() {
378 assert_eq!(first_hyper_gourava_index(&path3()).unwrap(), 50);
380 }
381
382 #[test]
383 fn hgo1_path4() {
384 assert_eq!(first_hyper_gourava_index(&path4()).unwrap(), 114);
386 }
387
388 #[test]
389 fn hgo1_k3() {
390 assert_eq!(first_hyper_gourava_index(&k3()).unwrap(), 192);
392 }
393
394 #[test]
395 fn hgo1_k4() {
396 assert_eq!(first_hyper_gourava_index(&k4()).unwrap(), 1350);
398 }
399
400 #[test]
401 fn hgo1_cycle4() {
402 assert_eq!(first_hyper_gourava_index(&cycle4()).unwrap(), 256);
404 }
405
406 #[test]
407 fn hgo1_cycle5() {
408 assert_eq!(first_hyper_gourava_index(&cycle5()).unwrap(), 320);
410 }
411
412 #[test]
413 fn hgo1_star5() {
414 assert_eq!(first_hyper_gourava_index(&star5()).unwrap(), 324);
416 }
417
418 #[test]
419 fn hgo1_paw() {
420 assert_eq!(first_hyper_gourava_index(&paw()).unwrap(), 355);
423 }
424
425 #[test]
426 fn hgo1_diamond() {
427 assert_eq!(first_hyper_gourava_index(&diamond()).unwrap(), 709);
430 }
431
432 #[test]
433 fn hgo1_regular_formula() {
434 for g in &[k3(), k4(), cycle4(), cycle5()] {
436 let m = g.ecount() as u64;
437 let r = g.degree(0).unwrap() as u64;
438 let val = r * (r + 2);
439 assert_eq!(first_hyper_gourava_index(g).unwrap(), m * val * val);
440 }
441 }
442
443 #[test]
446 fn go2_geq_go1() {
447 for g in &[single_edge(), path3(), k3(), k4(), cycle4(), star5(), paw()] {
449 let _ = first_gourava_index(g).unwrap();
450 let _ = second_gourava_index(g).unwrap();
451 }
452 }
453
454 #[test]
455 fn hgo1_geq_go1_squared_over_m() {
456 for g in &[single_edge(), path3(), k3(), k4(), cycle4(), star5(), paw()] {
458 let m = g.ecount() as u64;
459 if m > 0 {
460 let go1 = first_gourava_index(g).unwrap();
461 let hgo1 = first_hyper_gourava_index(g).unwrap();
462 assert!(hgo1 * m >= go1 * go1);
463 }
464 }
465 }
466
467 #[test]
468 fn all_positive_for_graphs_with_edges() {
469 for g in &[single_edge(), path3(), k3(), k4(), cycle4(), star5(), paw()] {
470 assert!(first_gourava_index(g).unwrap() > 0);
471 assert!(second_gourava_index(g).unwrap() > 0);
472 assert!(first_hyper_gourava_index(g).unwrap() > 0);
473 }
474 }
475}