rust_igraph/algorithms/properties/
is_cricket_free.rs1use crate::core::{Graph, IgraphResult};
15
16pub fn is_cricket_free(graph: &Graph) -> IgraphResult<bool> {
45 if graph.is_directed() {
46 return Ok(false);
47 }
48
49 let n = graph.vcount();
50 if n < 5 {
51 return Ok(true);
52 }
53
54 let n_usize = n as usize;
55 let mut adj = vec![vec![false; n_usize]; n_usize];
56
57 for v in 0..n {
58 let nbrs = graph.neighbors(v)?;
59 for &w in &nbrs {
60 adj[v as usize][w as usize] = true;
61 }
62 }
63
64 for a in 0..n {
68 let ai = a as usize;
69 for b in (a + 1)..n {
70 let bi = b as usize;
71 if !adj[ai][bi] {
72 continue;
73 }
74 for c in (b + 1)..n {
75 let ci = c as usize;
76 if !adj[ai][ci] || !adj[bi][ci] {
77 continue;
78 }
79
80 if has_cricket_pendants(&adj, n_usize, ai, bi, ci) {
82 return Ok(false);
83 }
84 if has_cricket_pendants(&adj, n_usize, bi, ai, ci) {
85 return Ok(false);
86 }
87 if has_cricket_pendants(&adj, n_usize, ci, ai, bi) {
88 return Ok(false);
89 }
90 }
91 }
92 }
93
94 Ok(true)
95}
96
97fn has_cricket_pendants(adj: &[Vec<bool>], n: usize, hub: usize, t1: usize, t2: usize) -> bool {
101 let row_hub = &adj[hub];
102 let row_t1 = &adj[t1];
103 let row_t2 = &adj[t2];
104
105 let pendants: Vec<usize> = row_hub
106 .iter()
107 .enumerate()
108 .take(n)
109 .filter(|&(d, &is_adj)| {
110 is_adj && d != hub && d != t1 && d != t2 && !row_t1[d] && !row_t2[d]
111 })
112 .map(|(d, _)| d)
113 .collect();
114
115 if pendants.len() < 2 {
116 return false;
117 }
118
119 for (i, &d) in pendants.iter().enumerate() {
120 for &e in &pendants[(i + 1)..] {
121 if !adj[d][e] {
122 return true;
123 }
124 }
125 }
126
127 false
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn empty_graph() {
136 let g = Graph::with_vertices(0);
137 assert!(is_cricket_free(&g).unwrap());
138 }
139
140 #[test]
141 fn small_graphs() {
142 let g = Graph::with_vertices(4);
143 assert!(is_cricket_free(&g).unwrap());
144 }
145
146 #[test]
147 fn triangle() {
148 let mut g = Graph::with_vertices(3);
149 g.add_edge(0, 1).unwrap();
150 g.add_edge(1, 2).unwrap();
151 g.add_edge(2, 0).unwrap();
152 assert!(is_cricket_free(&g).unwrap());
153 }
154
155 #[test]
156 fn cricket() {
157 let mut g = Graph::with_vertices(5);
159 g.add_edge(0, 1).unwrap();
160 g.add_edge(0, 2).unwrap();
161 g.add_edge(1, 2).unwrap();
162 g.add_edge(1, 3).unwrap();
163 g.add_edge(1, 4).unwrap();
164 assert!(!is_cricket_free(&g).unwrap());
165 }
166
167 #[test]
168 fn bull_is_cricket_free() {
169 let mut g = Graph::with_vertices(5);
172 g.add_edge(0, 1).unwrap();
173 g.add_edge(0, 2).unwrap();
174 g.add_edge(1, 2).unwrap();
175 g.add_edge(1, 3).unwrap();
176 g.add_edge(2, 4).unwrap();
177 assert!(is_cricket_free(&g).unwrap());
178 }
179
180 #[test]
181 fn k5_cricket_free() {
182 let mut g = Graph::with_vertices(5);
184 for i in 0..5u32 {
185 for j in (i + 1)..5 {
186 g.add_edge(i, j).unwrap();
187 }
188 }
189 assert!(is_cricket_free(&g).unwrap());
190 }
191
192 #[test]
193 fn paw_cricket_free() {
194 let mut g = Graph::with_vertices(4);
196 g.add_edge(0, 1).unwrap();
197 g.add_edge(1, 2).unwrap();
198 g.add_edge(2, 0).unwrap();
199 g.add_edge(2, 3).unwrap();
200 assert!(is_cricket_free(&g).unwrap());
201 }
202
203 #[test]
204 fn pendants_adjacent_not_cricket() {
205 let mut g = Graph::with_vertices(5);
208 g.add_edge(0, 1).unwrap();
209 g.add_edge(0, 2).unwrap();
210 g.add_edge(1, 2).unwrap();
211 g.add_edge(1, 3).unwrap();
212 g.add_edge(1, 4).unwrap();
213 g.add_edge(3, 4).unwrap();
214 assert!(is_cricket_free(&g).unwrap());
215 }
216
217 #[test]
218 fn pendant_connected_to_triangle_vertex() {
219 let mut g = Graph::with_vertices(5);
225 g.add_edge(0, 1).unwrap();
226 g.add_edge(0, 2).unwrap();
227 g.add_edge(1, 2).unwrap();
228 g.add_edge(1, 3).unwrap();
229 g.add_edge(1, 4).unwrap();
230 g.add_edge(0, 3).unwrap();
231 assert!(is_cricket_free(&g).unwrap());
232 }
233
234 #[test]
235 fn directed_returns_false() {
236 let mut g = Graph::new(3, true).unwrap();
237 g.add_edge(0, 1).unwrap();
238 g.add_edge(1, 2).unwrap();
239 g.add_edge(2, 0).unwrap();
240 assert!(!is_cricket_free(&g).unwrap());
241 }
242
243 #[test]
244 fn star_cricket_free() {
245 let mut g = Graph::with_vertices(6);
247 g.add_edge(0, 1).unwrap();
248 g.add_edge(0, 2).unwrap();
249 g.add_edge(0, 3).unwrap();
250 g.add_edge(0, 4).unwrap();
251 g.add_edge(0, 5).unwrap();
252 assert!(is_cricket_free(&g).unwrap());
253 }
254
255 #[test]
256 fn path_cricket_free() {
257 let mut g = Graph::with_vertices(5);
258 g.add_edge(0, 1).unwrap();
259 g.add_edge(1, 2).unwrap();
260 g.add_edge(2, 3).unwrap();
261 g.add_edge(3, 4).unwrap();
262 assert!(is_cricket_free(&g).unwrap());
263 }
264
265 #[test]
266 fn three_pendants_from_hub() {
267 let mut g = Graph::with_vertices(6);
270 g.add_edge(0, 1).unwrap();
271 g.add_edge(0, 2).unwrap();
272 g.add_edge(1, 2).unwrap();
273 g.add_edge(1, 3).unwrap();
274 g.add_edge(1, 4).unwrap();
275 g.add_edge(1, 5).unwrap();
276 assert!(!is_cricket_free(&g).unwrap());
277 }
278}