rust_igraph/algorithms/properties/
is_house_free.rs1use crate::core::{Graph, IgraphResult};
13
14pub fn is_house_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 let mut nbrs_list: Vec<Vec<u32>> = Vec::with_capacity(n_usize);
57
58 for v in 0..n {
59 let nbrs = graph.neighbors(v)?;
60 for &w in &nbrs {
61 adj[v as usize][w as usize] = true;
62 }
63 nbrs_list.push(nbrs);
64 }
65
66 for a in 0..n {
74 let ai = a as usize;
75 for b in (a + 1)..n {
76 let bi = b as usize;
77 if !adj[ai][bi] {
78 continue;
79 }
80 for c in (b + 1)..n {
81 let ci = c as usize;
82 if !adj[ai][ci] || !adj[bi][ci] {
83 continue;
84 }
85
86 if check_house_roof(&adj, &nbrs_list, ai, bi, ci) {
91 return Ok(false);
92 }
93 if check_house_roof(&adj, &nbrs_list, bi, ai, ci) {
95 return Ok(false);
96 }
97 if check_house_roof(&adj, &nbrs_list, ai, ci, bi) {
99 return Ok(false);
100 }
101 if check_house_roof(&adj, &nbrs_list, ci, ai, bi) {
102 return Ok(false);
103 }
104 if check_house_roof(&adj, &nbrs_list, bi, ci, ai) {
106 return Ok(false);
107 }
108 if check_house_roof(&adj, &nbrs_list, ci, bi, ai) {
109 return Ok(false);
110 }
111 }
112 }
113 }
114
115 Ok(true)
116}
117
118fn check_house_roof(
123 adj: &[Vec<bool>],
124 nbrs_list: &[Vec<u32>],
125 base1: usize,
126 base2: usize,
127 top: usize,
128) -> bool {
129 for &d_u32 in &nbrs_list[top] {
131 let d = d_u32 as usize;
132 if d == base1 || d == base2 {
133 continue;
134 }
135 if adj[base1][d] || adj[base2][d] {
136 continue;
137 }
138 for &e_u32 in &nbrs_list[d] {
140 let e = e_u32 as usize;
141 if e == top || e == base1 || e == base2 || e == d {
142 continue;
143 }
144 if adj[base1][e] && !adj[base2][e] && !adj[top][e] {
145 return true;
146 }
147 }
148 }
149 false
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn empty_graph() {
158 let g = Graph::with_vertices(0);
159 assert!(is_house_free(&g).unwrap());
160 }
161
162 #[test]
163 fn small_graphs() {
164 let g = Graph::with_vertices(4);
165 assert!(is_house_free(&g).unwrap());
166 }
167
168 #[test]
169 fn triangle() {
170 let mut g = Graph::with_vertices(3);
171 g.add_edge(0, 1).unwrap();
172 g.add_edge(1, 2).unwrap();
173 g.add_edge(2, 0).unwrap();
174 assert!(is_house_free(&g).unwrap());
175 }
176
177 #[test]
178 fn house() {
179 let mut g = Graph::with_vertices(5);
181 g.add_edge(0, 1).unwrap();
182 g.add_edge(1, 2).unwrap();
183 g.add_edge(2, 0).unwrap();
184 g.add_edge(2, 3).unwrap();
185 g.add_edge(3, 4).unwrap();
186 g.add_edge(4, 0).unwrap();
187 assert!(!is_house_free(&g).unwrap());
188 }
189
190 #[test]
191 fn c5_not_house() {
192 let mut g = Graph::with_vertices(5);
194 g.add_edge(0, 1).unwrap();
195 g.add_edge(1, 2).unwrap();
196 g.add_edge(2, 3).unwrap();
197 g.add_edge(3, 4).unwrap();
198 g.add_edge(4, 0).unwrap();
199 assert!(is_house_free(&g).unwrap());
200 }
201
202 #[test]
203 fn k5_house_free() {
204 let mut g = Graph::with_vertices(5);
206 for i in 0..5u32 {
207 for j in (i + 1)..5 {
208 g.add_edge(i, j).unwrap();
209 }
210 }
211 assert!(is_house_free(&g).unwrap());
212 }
213
214 #[test]
215 fn c4_house_free() {
216 let mut g = Graph::with_vertices(4);
217 g.add_edge(0, 1).unwrap();
218 g.add_edge(1, 2).unwrap();
219 g.add_edge(2, 3).unwrap();
220 g.add_edge(3, 0).unwrap();
221 assert!(is_house_free(&g).unwrap());
222 }
223
224 #[test]
225 fn diamond_house_free() {
226 let mut g = Graph::with_vertices(4);
227 g.add_edge(0, 1).unwrap();
228 g.add_edge(0, 2).unwrap();
229 g.add_edge(0, 3).unwrap();
230 g.add_edge(1, 2).unwrap();
231 g.add_edge(1, 3).unwrap();
232 assert!(is_house_free(&g).unwrap());
233 }
234
235 #[test]
236 fn path_house_free() {
237 let mut g = Graph::with_vertices(5);
238 g.add_edge(0, 1).unwrap();
239 g.add_edge(1, 2).unwrap();
240 g.add_edge(2, 3).unwrap();
241 g.add_edge(3, 4).unwrap();
242 assert!(is_house_free(&g).unwrap());
243 }
244
245 #[test]
246 fn star_house_free() {
247 let mut g = Graph::with_vertices(6);
248 g.add_edge(0, 1).unwrap();
249 g.add_edge(0, 2).unwrap();
250 g.add_edge(0, 3).unwrap();
251 g.add_edge(0, 4).unwrap();
252 g.add_edge(0, 5).unwrap();
253 assert!(is_house_free(&g).unwrap());
254 }
255
256 #[test]
257 fn directed_returns_false() {
258 let mut g = Graph::new(3, true).unwrap();
259 g.add_edge(0, 1).unwrap();
260 g.add_edge(1, 2).unwrap();
261 g.add_edge(2, 0).unwrap();
262 assert!(!is_house_free(&g).unwrap());
263 }
264
265 #[test]
266 fn house_with_extra_chord_not_house() {
267 let mut g = Graph::with_vertices(5);
270 g.add_edge(0, 1).unwrap();
271 g.add_edge(1, 2).unwrap();
272 g.add_edge(2, 0).unwrap();
273 g.add_edge(2, 3).unwrap();
274 g.add_edge(3, 4).unwrap();
275 g.add_edge(4, 0).unwrap();
276 g.add_edge(1, 3).unwrap();
277 assert!(is_house_free(&g).unwrap());
278 }
279
280 #[test]
281 fn gem_not_house() {
282 let mut g = Graph::with_vertices(5);
285 g.add_edge(0, 1).unwrap();
286 g.add_edge(0, 2).unwrap();
287 g.add_edge(0, 3).unwrap();
288 g.add_edge(0, 4).unwrap();
289 g.add_edge(1, 2).unwrap();
290 g.add_edge(2, 3).unwrap();
291 g.add_edge(3, 4).unwrap();
292 assert!(is_house_free(&g).unwrap());
298 }
299
300 #[test]
301 fn petersen_not_house_free() {
302 let mut g = Graph::with_vertices(10);
307 g.add_edge(0, 1).unwrap();
308 g.add_edge(1, 2).unwrap();
309 g.add_edge(2, 3).unwrap();
310 g.add_edge(3, 4).unwrap();
311 g.add_edge(4, 0).unwrap();
312 g.add_edge(5, 7).unwrap();
313 g.add_edge(7, 9).unwrap();
314 g.add_edge(9, 6).unwrap();
315 g.add_edge(6, 8).unwrap();
316 g.add_edge(8, 5).unwrap();
317 g.add_edge(0, 5).unwrap();
318 g.add_edge(1, 6).unwrap();
319 g.add_edge(2, 7).unwrap();
320 g.add_edge(3, 8).unwrap();
321 g.add_edge(4, 9).unwrap();
322 assert!(is_house_free(&g).unwrap());
323 }
324}