rust_igraph/algorithms/properties/
is_banner_free.rs1use crate::core::{Graph, IgraphResult};
11
12pub fn is_banner_free(graph: &Graph) -> IgraphResult<bool> {
41 if graph.is_directed() {
42 return Ok(false);
43 }
44
45 let n = graph.vcount();
46 if n < 5 {
47 return Ok(true);
48 }
49
50 let n_usize = n as usize;
51 let mut adj = vec![vec![false; n_usize]; n_usize];
52 let mut nbrs_list: Vec<Vec<u32>> = Vec::with_capacity(n_usize);
53
54 for v in 0..n {
55 let nbrs = graph.neighbors(v)?;
56 for &w in &nbrs {
57 adj[v as usize][w as usize] = true;
58 }
59 nbrs_list.push(nbrs);
60 }
61
62 for a in 0..n {
70 let ai = a as usize;
71 for &b in &nbrs_list[ai] {
72 if b <= a {
73 continue;
74 }
75 let bi = b as usize;
76 for &c in &nbrs_list[bi] {
77 if c == a {
78 continue;
79 }
80 let ci = c as usize;
81 if adj[ai][ci] {
82 continue;
83 }
84 for &d in &nbrs_list[ci] {
86 if d == b || d == a {
87 continue;
88 }
89 let di = d as usize;
90 if !adj[ai][di] || adj[bi][di] {
91 continue;
92 }
93 if has_pendant(&adj, &nbrs_list, ai, bi, ci, di) {
96 return Ok(false);
97 }
98 if has_pendant(&adj, &nbrs_list, bi, ai, ci, di) {
99 return Ok(false);
100 }
101 if has_pendant(&adj, &nbrs_list, ci, ai, bi, di) {
102 return Ok(false);
103 }
104 if has_pendant(&adj, &nbrs_list, di, ai, bi, ci) {
105 return Ok(false);
106 }
107 }
108 }
109 }
110 }
111
112 Ok(true)
113}
114
115fn has_pendant(
118 adj: &[Vec<bool>],
119 nbrs_list: &[Vec<u32>],
120 v: usize,
121 o1: usize,
122 o2: usize,
123 o3: usize,
124) -> bool {
125 for &e_u32 in &nbrs_list[v] {
126 let e = e_u32 as usize;
127 if e == o1 || e == o2 || e == o3 {
128 continue;
129 }
130 if !adj[o1][e] && !adj[o2][e] && !adj[o3][e] {
131 return true;
132 }
133 }
134 false
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn empty_graph() {
143 let g = Graph::with_vertices(0);
144 assert!(is_banner_free(&g).unwrap());
145 }
146
147 #[test]
148 fn small_graphs() {
149 let g = Graph::with_vertices(4);
150 assert!(is_banner_free(&g).unwrap());
151 }
152
153 #[test]
154 fn triangle() {
155 let mut g = Graph::with_vertices(3);
156 g.add_edge(0, 1).unwrap();
157 g.add_edge(1, 2).unwrap();
158 g.add_edge(2, 0).unwrap();
159 assert!(is_banner_free(&g).unwrap());
160 }
161
162 #[test]
163 fn c4_banner_free() {
164 let mut g = Graph::with_vertices(4);
165 g.add_edge(0, 1).unwrap();
166 g.add_edge(1, 2).unwrap();
167 g.add_edge(2, 3).unwrap();
168 g.add_edge(3, 0).unwrap();
169 assert!(is_banner_free(&g).unwrap());
170 }
171
172 #[test]
173 fn banner() {
174 let mut g = Graph::with_vertices(5);
176 g.add_edge(0, 1).unwrap();
177 g.add_edge(1, 2).unwrap();
178 g.add_edge(2, 3).unwrap();
179 g.add_edge(3, 0).unwrap();
180 g.add_edge(0, 4).unwrap();
181 assert!(!is_banner_free(&g).unwrap());
182 }
183
184 #[test]
185 fn k5_banner_free() {
186 let mut g = Graph::with_vertices(5);
188 for i in 0..5u32 {
189 for j in (i + 1)..5 {
190 g.add_edge(i, j).unwrap();
191 }
192 }
193 assert!(is_banner_free(&g).unwrap());
194 }
195
196 #[test]
197 fn path_banner_free() {
198 let mut g = Graph::with_vertices(5);
199 g.add_edge(0, 1).unwrap();
200 g.add_edge(1, 2).unwrap();
201 g.add_edge(2, 3).unwrap();
202 g.add_edge(3, 4).unwrap();
203 assert!(is_banner_free(&g).unwrap());
204 }
205
206 #[test]
207 fn star_banner_free() {
208 let mut g = Graph::with_vertices(6);
209 g.add_edge(0, 1).unwrap();
210 g.add_edge(0, 2).unwrap();
211 g.add_edge(0, 3).unwrap();
212 g.add_edge(0, 4).unwrap();
213 g.add_edge(0, 5).unwrap();
214 assert!(is_banner_free(&g).unwrap());
215 }
216
217 #[test]
218 fn c5_banner_free() {
219 let mut g = Graph::with_vertices(5);
221 g.add_edge(0, 1).unwrap();
222 g.add_edge(1, 2).unwrap();
223 g.add_edge(2, 3).unwrap();
224 g.add_edge(3, 4).unwrap();
225 g.add_edge(4, 0).unwrap();
226 assert!(is_banner_free(&g).unwrap());
227 }
228
229 #[test]
230 fn directed_returns_false() {
231 let mut g = Graph::new(3, true).unwrap();
232 g.add_edge(0, 1).unwrap();
233 g.add_edge(1, 2).unwrap();
234 g.add_edge(2, 0).unwrap();
235 assert!(!is_banner_free(&g).unwrap());
236 }
237
238 #[test]
239 fn pendant_connected_to_non_cycle_vertex() {
240 let mut g = Graph::with_vertices(5);
243 g.add_edge(0, 1).unwrap();
244 g.add_edge(1, 2).unwrap();
245 g.add_edge(2, 3).unwrap();
246 g.add_edge(3, 0).unwrap();
247 g.add_edge(0, 4).unwrap();
248 g.add_edge(1, 4).unwrap();
249 assert!(is_banner_free(&g).unwrap());
250 }
251
252 #[test]
253 fn cube_not_banner_free() {
254 let mut g = Graph::with_vertices(8);
257 g.add_edge(0, 1).unwrap();
258 g.add_edge(0, 2).unwrap();
259 g.add_edge(0, 4).unwrap();
260 g.add_edge(1, 3).unwrap();
261 g.add_edge(1, 5).unwrap();
262 g.add_edge(2, 3).unwrap();
263 g.add_edge(2, 6).unwrap();
264 g.add_edge(3, 7).unwrap();
265 g.add_edge(4, 5).unwrap();
266 g.add_edge(4, 6).unwrap();
267 g.add_edge(5, 7).unwrap();
268 g.add_edge(6, 7).unwrap();
269 assert!(!is_banner_free(&g).unwrap());
270 }
271
272 #[test]
273 fn k33_banner_free() {
274 let mut g = Graph::with_vertices(6);
277 for i in 0..3u32 {
278 for j in 3..6u32 {
279 g.add_edge(i, j).unwrap();
280 }
281 }
282 assert!(is_banner_free(&g).unwrap());
283 }
284
285 #[test]
286 fn c4_with_isolated_pendant_not_banner_free() {
287 let mut g = Graph::with_vertices(5);
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 g.add_edge(3, 4).unwrap();
294 assert!(!is_banner_free(&g).unwrap());
295 }
296}