rust_igraph/algorithms/properties/
is_dart_free.rs1use crate::core::{Graph, IgraphResult};
14
15pub fn is_dart_free(graph: &Graph) -> IgraphResult<bool> {
47 if graph.is_directed() {
48 return Ok(false);
49 }
50
51 let n = graph.vcount();
52 if n < 5 {
53 return Ok(true);
54 }
55
56 let n_usize = n as usize;
57 let mut adj = vec![vec![false; n_usize]; n_usize];
58 let mut nbrs_list: Vec<Vec<u32>> = Vec::with_capacity(n_usize);
59
60 for v in 0..n {
61 let nbrs = graph.neighbors(v)?;
62 for &w in &nbrs {
63 adj[v as usize][w as usize] = true;
64 }
65 nbrs_list.push(nbrs);
66 }
67
68 for a in 0..n {
79 let ai = a as usize;
80 for &b in &nbrs_list[ai] {
81 if b <= a {
82 continue;
83 }
84 let bi = b as usize;
85 let common: Vec<usize> = nbrs_list[ai]
87 .iter()
88 .filter(|&&w| w != b && adj[bi][w as usize])
89 .map(|&w| w as usize)
90 .collect();
91
92 if common.len() < 2 {
93 continue;
94 }
95
96 for (i, &ci) in common.iter().enumerate() {
97 for &di in &common[(i + 1)..] {
98 if adj[ci][di] {
99 continue;
100 }
101 if has_dart_pendant(&adj, &nbrs_list, ci, ai, bi, di) {
104 return Ok(false);
105 }
106 if has_dart_pendant(&adj, &nbrs_list, di, ai, bi, ci) {
108 return Ok(false);
109 }
110 }
111 }
112 }
113 }
114
115 Ok(true)
116}
117
118fn has_dart_pendant(
121 adj: &[Vec<bool>],
122 nbrs_list: &[Vec<u32>],
123 wing: usize,
124 s1: usize,
125 s2: usize,
126 other_wing: usize,
127) -> bool {
128 for &e_u32 in &nbrs_list[wing] {
129 let e = e_u32 as usize;
130 if e == s1 || e == s2 || e == other_wing {
131 continue;
132 }
133 if !adj[s1][e] && !adj[s2][e] && !adj[other_wing][e] {
134 return true;
135 }
136 }
137 false
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn empty_graph() {
146 let g = Graph::with_vertices(0);
147 assert!(is_dart_free(&g).unwrap());
148 }
149
150 #[test]
151 fn small_graphs() {
152 let g = Graph::with_vertices(4);
153 assert!(is_dart_free(&g).unwrap());
154 }
155
156 #[test]
157 fn triangle() {
158 let mut g = Graph::with_vertices(3);
159 g.add_edge(0, 1).unwrap();
160 g.add_edge(1, 2).unwrap();
161 g.add_edge(2, 0).unwrap();
162 assert!(is_dart_free(&g).unwrap());
163 }
164
165 #[test]
166 fn diamond_dart_free() {
167 let mut g = Graph::with_vertices(4);
168 g.add_edge(0, 1).unwrap();
169 g.add_edge(0, 2).unwrap();
170 g.add_edge(0, 3).unwrap();
171 g.add_edge(1, 2).unwrap();
172 g.add_edge(1, 3).unwrap();
173 assert!(is_dart_free(&g).unwrap());
174 }
175
176 #[test]
177 fn dart() {
178 let mut g = Graph::with_vertices(5);
181 g.add_edge(0, 1).unwrap();
182 g.add_edge(0, 2).unwrap();
183 g.add_edge(0, 3).unwrap();
184 g.add_edge(1, 2).unwrap();
185 g.add_edge(1, 3).unwrap();
186 g.add_edge(2, 4).unwrap();
187 assert!(!is_dart_free(&g).unwrap());
188 }
189
190 #[test]
191 fn dart_pendant_from_other_wing() {
192 let mut g = Graph::with_vertices(5);
194 g.add_edge(0, 1).unwrap();
195 g.add_edge(0, 2).unwrap();
196 g.add_edge(0, 3).unwrap();
197 g.add_edge(1, 2).unwrap();
198 g.add_edge(1, 3).unwrap();
199 g.add_edge(3, 4).unwrap();
200 assert!(!is_dart_free(&g).unwrap());
201 }
202
203 #[test]
204 fn k5_dart_free() {
205 let mut g = Graph::with_vertices(5);
207 for i in 0..5u32 {
208 for j in (i + 1)..5 {
209 g.add_edge(i, j).unwrap();
210 }
211 }
212 assert!(is_dart_free(&g).unwrap());
213 }
214
215 #[test]
216 fn pendant_from_spine_not_dart() {
217 let mut g = Graph::with_vertices(5);
231 g.add_edge(0, 1).unwrap();
232 g.add_edge(0, 2).unwrap();
233 g.add_edge(0, 3).unwrap();
234 g.add_edge(1, 2).unwrap();
235 g.add_edge(1, 3).unwrap();
236 g.add_edge(0, 4).unwrap();
237 assert!(is_dart_free(&g).unwrap());
238 }
239
240 #[test]
241 fn pendant_connected_to_other_wing_not_dart() {
242 let mut g = Graph::with_vertices(5);
245 g.add_edge(0, 1).unwrap();
246 g.add_edge(0, 2).unwrap();
247 g.add_edge(0, 3).unwrap();
248 g.add_edge(1, 2).unwrap();
249 g.add_edge(1, 3).unwrap();
250 g.add_edge(2, 4).unwrap();
251 g.add_edge(3, 4).unwrap();
252 assert!(is_dart_free(&g).unwrap());
253 }
254
255 #[test]
256 fn path_dart_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_dart_free(&g).unwrap());
263 }
264
265 #[test]
266 fn star_dart_free() {
267 let mut g = Graph::with_vertices(6);
268 g.add_edge(0, 1).unwrap();
269 g.add_edge(0, 2).unwrap();
270 g.add_edge(0, 3).unwrap();
271 g.add_edge(0, 4).unwrap();
272 g.add_edge(0, 5).unwrap();
273 assert!(is_dart_free(&g).unwrap());
274 }
275
276 #[test]
277 fn directed_returns_false() {
278 let mut g = Graph::new(3, true).unwrap();
279 g.add_edge(0, 1).unwrap();
280 g.add_edge(1, 2).unwrap();
281 g.add_edge(2, 0).unwrap();
282 assert!(!is_dart_free(&g).unwrap());
283 }
284
285 #[test]
286 fn c4_dart_free() {
287 let mut g = Graph::with_vertices(4);
289 g.add_edge(0, 1).unwrap();
290 g.add_edge(1, 2).unwrap();
291 g.add_edge(2, 3).unwrap();
292 g.add_edge(3, 0).unwrap();
293 assert!(is_dart_free(&g).unwrap());
294 }
295
296 #[test]
297 fn c5_dart_free() {
298 let mut g = Graph::with_vertices(5);
299 g.add_edge(0, 1).unwrap();
300 g.add_edge(1, 2).unwrap();
301 g.add_edge(2, 3).unwrap();
302 g.add_edge(3, 4).unwrap();
303 g.add_edge(4, 0).unwrap();
304 assert!(is_dart_free(&g).unwrap());
305 }
306}