rust_igraph/algorithms/properties/
is_strongly_regular.rs1use crate::algorithms::properties::is_simple::is_simple;
16use crate::core::{Graph, IgraphResult};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct StronglyRegularParams {
21 pub n: u32,
23 pub k: u32,
25 pub lambda: u32,
27 pub mu: u32,
29}
30
31pub fn is_strongly_regular(graph: &Graph) -> IgraphResult<Option<StronglyRegularParams>> {
80 if graph.is_directed() {
81 return Ok(None);
82 }
83
84 let n = graph.vcount();
85 if n == 0 {
86 return Ok(Some(StronglyRegularParams {
87 n: 0,
88 k: 0,
89 lambda: 0,
90 mu: 0,
91 }));
92 }
93
94 if !is_simple(graph)? {
95 return Ok(None);
96 }
97
98 let deg0 = graph.neighbors(0)?.len();
100 for v in 1..n {
101 let dv = graph.neighbors(v)?.len();
102 if dv != deg0 {
103 return Ok(None);
104 }
105 }
106 let k = u32::try_from(deg0).unwrap_or(u32::MAX);
107
108 if k == 0 {
110 return Ok(Some(StronglyRegularParams {
112 n,
113 k: 0,
114 lambda: 0,
115 mu: 0,
116 }));
117 }
118 if k == n.saturating_sub(1) {
119 return Ok(Some(StronglyRegularParams {
121 n,
122 k,
123 lambda: n.saturating_sub(2),
124 mu: 0,
125 }));
126 }
127
128 let n_usize = n as usize;
130 let mut adj = vec![vec![false; n_usize]; n_usize];
131 for v in 0..n {
132 let nbrs = graph.neighbors(v)?;
133 for w in nbrs {
134 adj[v as usize][w as usize] = true;
135 }
136 }
137
138 let mut lambda: Option<u32> = None;
140 let mut mu: Option<u32> = None;
141
142 for u in 0..n {
143 for v in (u + 1)..n {
144 let common = count_common_neighbors(&adj, u as usize, v as usize, n_usize);
145
146 if adj[u as usize][v as usize] {
147 match lambda {
149 None => lambda = Some(common),
150 Some(l) if l != common => return Ok(None),
151 _ => {}
152 }
153 } else {
154 match mu {
156 None => mu = Some(common),
157 Some(m) if m != common => return Ok(None),
158 _ => {}
159 }
160 }
161 }
162 }
163
164 Ok(Some(StronglyRegularParams {
165 n,
166 k,
167 lambda: lambda.unwrap_or(0),
168 mu: mu.unwrap_or(0),
169 }))
170}
171
172fn count_common_neighbors(adj: &[Vec<bool>], u: usize, v: usize, n: usize) -> u32 {
173 let mut count = 0u32;
174 for (au, av) in adj[u][..n].iter().zip(adj[v][..n].iter()) {
175 if *au && *av {
176 count = count.saturating_add(1);
177 }
178 }
179 count
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn empty_graph() {
188 let g = Graph::with_vertices(0);
189 let params = is_strongly_regular(&g).unwrap().unwrap();
190 assert_eq!(params.n, 0);
191 }
192
193 #[test]
194 fn single_vertex() {
195 let g = Graph::with_vertices(1);
196 let params = is_strongly_regular(&g).unwrap().unwrap();
197 assert_eq!(params.n, 1);
198 assert_eq!(params.k, 0);
199 }
200
201 #[test]
202 fn single_edge() {
203 let mut g = Graph::with_vertices(2);
204 g.add_edge(0, 1).unwrap();
205 let params = is_strongly_regular(&g).unwrap().unwrap();
206 assert_eq!(params.n, 2);
207 assert_eq!(params.k, 1);
208 }
209
210 #[test]
211 fn triangle() {
212 let mut g = Graph::with_vertices(3);
213 g.add_edge(0, 1).unwrap();
214 g.add_edge(1, 2).unwrap();
215 g.add_edge(2, 0).unwrap();
216 let params = is_strongly_regular(&g).unwrap().unwrap();
217 assert_eq!(params.n, 3);
218 assert_eq!(params.k, 2);
219 assert_eq!(params.lambda, 1);
220 }
221
222 #[test]
223 fn k4() {
224 let mut g = Graph::with_vertices(4);
225 for u in 0..4u32 {
226 for v in (u + 1)..4 {
227 g.add_edge(u, v).unwrap();
228 }
229 }
230 let params = is_strongly_regular(&g).unwrap().unwrap();
231 assert_eq!(params.n, 4);
232 assert_eq!(params.k, 3);
233 assert_eq!(params.lambda, 2);
234 }
235
236 #[test]
237 fn edgeless() {
238 let g = Graph::with_vertices(5);
239 let params = is_strongly_regular(&g).unwrap().unwrap();
240 assert_eq!(params.n, 5);
241 assert_eq!(params.k, 0);
242 }
243
244 #[test]
245 fn path_not_sr() {
246 let mut g = Graph::with_vertices(4);
247 g.add_edge(0, 1).unwrap();
248 g.add_edge(1, 2).unwrap();
249 g.add_edge(2, 3).unwrap();
250 assert!(is_strongly_regular(&g).unwrap().is_none());
251 }
252
253 #[test]
254 fn c5_is_sr() {
255 let mut g = Graph::with_vertices(5);
257 g.add_edge(0, 1).unwrap();
258 g.add_edge(1, 2).unwrap();
259 g.add_edge(2, 3).unwrap();
260 g.add_edge(3, 4).unwrap();
261 g.add_edge(4, 0).unwrap();
262 let params = is_strongly_regular(&g).unwrap().unwrap();
263 assert_eq!(params.n, 5);
264 assert_eq!(params.k, 2);
265 assert_eq!(params.lambda, 0);
266 assert_eq!(params.mu, 1);
267 }
268
269 #[test]
270 fn c4_not_sr() {
271 let mut g = Graph::with_vertices(4);
280 g.add_edge(0, 1).unwrap();
281 g.add_edge(1, 2).unwrap();
282 g.add_edge(2, 3).unwrap();
283 g.add_edge(3, 0).unwrap();
284 let params = is_strongly_regular(&g).unwrap().unwrap();
285 assert_eq!(params.n, 4);
286 assert_eq!(params.k, 2);
287 assert_eq!(params.lambda, 0);
288 assert_eq!(params.mu, 2);
289 }
290
291 #[test]
292 fn petersen() {
293 let mut g = Graph::with_vertices(10);
294 g.add_edge(0, 1).unwrap();
295 g.add_edge(1, 2).unwrap();
296 g.add_edge(2, 3).unwrap();
297 g.add_edge(3, 4).unwrap();
298 g.add_edge(4, 0).unwrap();
299 g.add_edge(5, 7).unwrap();
300 g.add_edge(7, 9).unwrap();
301 g.add_edge(9, 6).unwrap();
302 g.add_edge(6, 8).unwrap();
303 g.add_edge(8, 5).unwrap();
304 g.add_edge(0, 5).unwrap();
305 g.add_edge(1, 6).unwrap();
306 g.add_edge(2, 7).unwrap();
307 g.add_edge(3, 8).unwrap();
308 g.add_edge(4, 9).unwrap();
309 let params = is_strongly_regular(&g).unwrap().unwrap();
310 assert_eq!(params.n, 10);
311 assert_eq!(params.k, 3);
312 assert_eq!(params.lambda, 0);
313 assert_eq!(params.mu, 1);
314 }
315
316 #[test]
317 fn star_not_sr() {
318 let mut g = Graph::with_vertices(5);
319 for i in 1..5u32 {
320 g.add_edge(0, i).unwrap();
321 }
322 assert!(is_strongly_regular(&g).unwrap().is_none());
323 }
324
325 #[test]
326 fn c6_not_sr() {
327 let mut g = Graph::with_vertices(6);
333 g.add_edge(0, 1).unwrap();
334 g.add_edge(1, 2).unwrap();
335 g.add_edge(2, 3).unwrap();
336 g.add_edge(3, 4).unwrap();
337 g.add_edge(4, 5).unwrap();
338 g.add_edge(5, 0).unwrap();
339 assert!(is_strongly_regular(&g).unwrap().is_none());
340 }
341
342 #[test]
343 fn directed_returns_none() {
344 let mut g = Graph::new(3, true).unwrap();
345 g.add_edge(0, 1).unwrap();
346 g.add_edge(1, 2).unwrap();
347 g.add_edge(2, 0).unwrap();
348 assert!(is_strongly_regular(&g).unwrap().is_none());
349 }
350
351 #[test]
352 fn paley5_is_sr() {
353 let mut g = Graph::with_vertices(10);
357 g.add_edge(0, 1).unwrap();
358 g.add_edge(1, 2).unwrap();
359 g.add_edge(2, 3).unwrap();
360 g.add_edge(3, 4).unwrap();
361 g.add_edge(4, 0).unwrap();
362 g.add_edge(5, 7).unwrap();
363 g.add_edge(7, 9).unwrap();
364 g.add_edge(9, 6).unwrap();
365 g.add_edge(6, 8).unwrap();
366 g.add_edge(8, 5).unwrap();
367 g.add_edge(0, 5).unwrap();
368 g.add_edge(1, 6).unwrap();
369 g.add_edge(2, 7).unwrap();
370 g.add_edge(3, 8).unwrap();
371 g.add_edge(4, 9).unwrap();
372 let comp = crate::algorithms::operators::complementer::complementer(&g, false).unwrap();
373 let params = is_strongly_regular(&comp).unwrap().unwrap();
374 assert_eq!(params.n, 10);
375 assert_eq!(params.k, 6);
376 assert_eq!(params.lambda, 3);
377 assert_eq!(params.mu, 4);
378 }
379
380 #[test]
381 fn two_k3_is_sr() {
382 let mut g = Graph::with_vertices(6);
385 g.add_edge(0, 1).unwrap();
386 g.add_edge(1, 2).unwrap();
387 g.add_edge(2, 0).unwrap();
388 g.add_edge(3, 4).unwrap();
389 g.add_edge(4, 5).unwrap();
390 g.add_edge(5, 3).unwrap();
391 let params = is_strongly_regular(&g).unwrap().unwrap();
392 assert_eq!(params.n, 6);
393 assert_eq!(params.k, 2);
394 assert_eq!(params.lambda, 1);
395 assert_eq!(params.mu, 0);
396 }
397
398 #[test]
399 fn cube_not_sr() {
400 let mut g = Graph::with_vertices(8);
407 g.add_edge(0, 1).unwrap();
408 g.add_edge(1, 2).unwrap();
409 g.add_edge(2, 3).unwrap();
410 g.add_edge(3, 0).unwrap();
411 g.add_edge(4, 5).unwrap();
412 g.add_edge(5, 6).unwrap();
413 g.add_edge(6, 7).unwrap();
414 g.add_edge(7, 4).unwrap();
415 g.add_edge(0, 4).unwrap();
416 g.add_edge(1, 5).unwrap();
417 g.add_edge(2, 6).unwrap();
418 g.add_edge(3, 7).unwrap();
419 assert!(is_strongly_regular(&g).unwrap().is_none());
420 }
421}