rust_igraph/algorithms/properties/
hyper_zagreb.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_hyper_zagreb(graph: &Graph) -> IgraphResult<u64> {
36 let mut hm1 = 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 let s = du + dv;
45 hm1 = hm1.saturating_add(s.saturating_mul(s));
46 }
47
48 Ok(hm1)
49}
50
51pub fn second_hyper_zagreb(graph: &Graph) -> IgraphResult<u64> {
67 let mut hm2 = 0_u64;
68
69 for (u, v) in graph.edges() {
70 if u == v {
71 continue;
72 }
73 let du = graph.degree(u)? as u64;
74 let dv = graph.degree(v)? as u64;
75 let p = du.saturating_mul(dv);
76 hm2 = hm2.saturating_add(p.saturating_mul(p));
77 }
78
79 Ok(hm2)
80}
81
82pub fn first_redefined_zagreb(graph: &Graph) -> IgraphResult<f64> {
98 let mut rezg1 = 0.0_f64;
99
100 for (u, v) in graph.edges() {
101 if u == v {
102 continue;
103 }
104 let du = graph.degree(u)? as f64;
105 let dv = graph.degree(v)? as f64;
106 let prod = du * dv;
107 if prod > 0.0 {
108 rezg1 += (du + dv) / prod;
109 }
110 }
111
112 Ok(rezg1)
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 fn single_edge() -> Graph {
120 Graph::from_edges(&[(0, 1)], false, Some(2)).unwrap()
121 }
122
123 fn path3() -> Graph {
124 Graph::from_edges(&[(0, 1), (1, 2)], false, Some(3)).unwrap()
125 }
126
127 fn path4() -> Graph {
128 Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], false, Some(4)).unwrap()
129 }
130
131 fn k3() -> Graph {
132 Graph::from_edges(&[(0, 1), (1, 2), (0, 2)], false, Some(3)).unwrap()
133 }
134
135 fn k4() -> Graph {
136 Graph::from_edges(
137 &[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)],
138 false,
139 Some(4),
140 )
141 .unwrap()
142 }
143
144 fn cycle4() -> Graph {
145 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0)], false, Some(4)).unwrap()
146 }
147
148 fn cycle5() -> Graph {
149 Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)], false, Some(5)).unwrap()
150 }
151
152 fn star5() -> Graph {
153 Graph::from_edges(&[(0, 1), (0, 2), (0, 3), (0, 4)], false, Some(5)).unwrap()
154 }
155
156 fn paw() -> Graph {
157 Graph::from_edges(&[(0, 1), (1, 2), (0, 2), (2, 3)], false, Some(4)).unwrap()
158 }
159
160 #[test]
163 fn hm1_empty() {
164 let g = Graph::with_vertices(0);
165 assert_eq!(first_hyper_zagreb(&g).unwrap(), 0);
166 }
167
168 #[test]
169 fn hm1_isolated() {
170 let g = Graph::with_vertices(5);
171 assert_eq!(first_hyper_zagreb(&g).unwrap(), 0);
172 }
173
174 #[test]
175 fn hm1_single_edge() {
176 assert_eq!(first_hyper_zagreb(&single_edge()).unwrap(), 4);
178 }
179
180 #[test]
181 fn hm1_path3() {
182 assert_eq!(first_hyper_zagreb(&path3()).unwrap(), 18);
184 }
185
186 #[test]
187 fn hm1_path4() {
188 assert_eq!(first_hyper_zagreb(&path4()).unwrap(), 34);
190 }
191
192 #[test]
193 fn hm1_k3() {
194 assert_eq!(first_hyper_zagreb(&k3()).unwrap(), 48);
196 }
197
198 #[test]
199 fn hm1_k4() {
200 assert_eq!(first_hyper_zagreb(&k4()).unwrap(), 216);
202 }
203
204 #[test]
205 fn hm1_cycle4() {
206 assert_eq!(first_hyper_zagreb(&cycle4()).unwrap(), 64);
208 }
209
210 #[test]
211 fn hm1_cycle5() {
212 assert_eq!(first_hyper_zagreb(&cycle5()).unwrap(), 80);
214 }
215
216 #[test]
217 fn hm1_star5() {
218 assert_eq!(first_hyper_zagreb(&star5()).unwrap(), 100);
220 }
221
222 #[test]
223 fn hm1_paw() {
224 assert_eq!(first_hyper_zagreb(&paw()).unwrap(), 82);
228 }
229
230 #[test]
231 fn hm1_regular_formula() {
232 for g in &[k3(), k4(), cycle4(), cycle5()] {
234 let m = g.ecount() as u64;
235 let r = g.degree(0).unwrap() as u64;
236 assert_eq!(first_hyper_zagreb(g).unwrap(), 4 * r * r * m);
237 }
238 }
239
240 #[test]
243 fn hm2_empty() {
244 let g = Graph::with_vertices(0);
245 assert_eq!(second_hyper_zagreb(&g).unwrap(), 0);
246 }
247
248 #[test]
249 fn hm2_single_edge() {
250 assert_eq!(second_hyper_zagreb(&single_edge()).unwrap(), 1);
252 }
253
254 #[test]
255 fn hm2_path3() {
256 assert_eq!(second_hyper_zagreb(&path3()).unwrap(), 8);
258 }
259
260 #[test]
261 fn hm2_path4() {
262 assert_eq!(second_hyper_zagreb(&path4()).unwrap(), 24);
264 }
265
266 #[test]
267 fn hm2_k3() {
268 assert_eq!(second_hyper_zagreb(&k3()).unwrap(), 48);
270 }
271
272 #[test]
273 fn hm2_k4() {
274 assert_eq!(second_hyper_zagreb(&k4()).unwrap(), 486);
276 }
277
278 #[test]
279 fn hm2_cycle4() {
280 assert_eq!(second_hyper_zagreb(&cycle4()).unwrap(), 64);
282 }
283
284 #[test]
285 fn hm2_cycle5() {
286 assert_eq!(second_hyper_zagreb(&cycle5()).unwrap(), 80);
288 }
289
290 #[test]
291 fn hm2_star5() {
292 assert_eq!(second_hyper_zagreb(&star5()).unwrap(), 64);
294 }
295
296 #[test]
297 fn hm2_paw() {
298 assert_eq!(second_hyper_zagreb(&paw()).unwrap(), 97);
301 }
302
303 #[test]
304 fn hm2_regular_formula() {
305 for g in &[k3(), k4(), cycle4(), cycle5()] {
307 let m = g.ecount() as u64;
308 let r = g.degree(0).unwrap() as u64;
309 assert_eq!(second_hyper_zagreb(g).unwrap(), m * r * r * r * r);
310 }
311 }
312
313 #[test]
314 fn hm1_k3_eq_hm2_k3() {
315 assert_eq!(
317 first_hyper_zagreb(&k3()).unwrap(),
318 second_hyper_zagreb(&k3()).unwrap()
319 );
320 }
321
322 #[test]
325 fn rezg1_empty() {
326 let g = Graph::with_vertices(0);
327 assert!((first_redefined_zagreb(&g).unwrap()).abs() < 1e-10);
328 }
329
330 #[test]
331 fn rezg1_single_edge() {
332 assert!((first_redefined_zagreb(&single_edge()).unwrap() - 2.0).abs() < 1e-10);
334 }
335
336 #[test]
337 fn rezg1_path3() {
338 assert!((first_redefined_zagreb(&path3()).unwrap() - 3.0).abs() < 1e-10);
340 }
341
342 #[test]
343 fn rezg1_path4() {
344 assert!((first_redefined_zagreb(&path4()).unwrap() - 4.0).abs() < 1e-10);
346 }
347
348 #[test]
349 fn rezg1_k3() {
350 assert!((first_redefined_zagreb(&k3()).unwrap() - 3.0).abs() < 1e-10);
352 }
353
354 #[test]
355 fn rezg1_k4() {
356 assert!((first_redefined_zagreb(&k4()).unwrap() - 4.0).abs() < 1e-10);
358 }
359
360 #[test]
361 fn rezg1_cycle4() {
362 assert!((first_redefined_zagreb(&cycle4()).unwrap() - 4.0).abs() < 1e-10);
364 }
365
366 #[test]
367 fn rezg1_cycle5() {
368 assert!((first_redefined_zagreb(&cycle5()).unwrap() - 5.0).abs() < 1e-10);
370 }
371
372 #[test]
373 fn rezg1_star5() {
374 assert!((first_redefined_zagreb(&star5()).unwrap() - 5.0).abs() < 1e-10);
376 }
377
378 #[test]
379 fn rezg1_paw() {
380 assert!((first_redefined_zagreb(&paw()).unwrap() - 4.0).abs() < 1e-10);
383 }
384
385 #[test]
386 fn rezg1_regular_formula() {
387 for g in &[k3(), k4(), cycle4(), cycle5()] {
389 let m = g.ecount() as f64;
390 let r = g.degree(0).unwrap() as f64;
391 let expected = m * 2.0 / r;
392 assert!((first_redefined_zagreb(g).unwrap() - expected).abs() < 1e-8);
393 }
394 }
395
396 #[test]
399 fn hm1_geq_hm2_for_bipartite() {
400 for g in &[single_edge(), path3(), path4(), star5()] {
402 let _ = first_hyper_zagreb(g).unwrap();
403 let _ = second_hyper_zagreb(g).unwrap();
404 }
405 }
406
407 #[test]
408 fn rezg1_positive() {
409 for g in &[single_edge(), path3(), k3(), k4(), cycle4(), star5(), paw()] {
410 assert!(first_redefined_zagreb(g).unwrap() > 0.0);
411 }
412 }
413
414 #[test]
415 fn rezg1_identity() {
416 for g in &[path3(), k3(), k4(), cycle4(), cycle5(), star5(), paw()] {
427 let n_nonisolated = (0..g.vcount())
428 .filter(|&v| g.degree(v).unwrap() > 0)
429 .count() as f64;
430 assert!((first_redefined_zagreb(g).unwrap() - n_nonisolated).abs() < 1e-8);
431 }
432 }
433}