rust_igraph/algorithms/properties/
is_diamond_free.rs1use crate::core::{Graph, IgraphResult};
10
11pub fn is_diamond_free(graph: &Graph) -> IgraphResult<bool> {
41 if graph.is_directed() {
42 return Ok(false);
43 }
44
45 let n = graph.vcount();
46 if n <= 3 {
47 return Ok(true);
48 }
49
50 let n_usize = n as usize;
52 let mut adj = vec![vec![false; n_usize]; n_usize];
53 for v in 0..n {
54 let nbrs = graph.neighbors(v)?;
55 for &w in &nbrs {
56 adj[v as usize][w as usize] = true;
57 }
58 }
59
60 for u in 0..n {
68 let nbrs_u = graph.neighbors(u)?;
69 for &v in &nbrs_u {
70 if v <= u {
71 continue;
72 }
73
74 let common: Vec<u32> = nbrs_u
76 .iter()
77 .filter(|&&w| w != v && adj[v as usize][w as usize])
78 .copied()
79 .collect();
80
81 for i in 0..common.len() {
83 for j in (i + 1)..common.len() {
84 if !adj[common[i] as usize][common[j] as usize] {
85 return Ok(false);
86 }
87 }
88 }
89 }
90 }
91
92 Ok(true)
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn empty_graph() {
101 let g = Graph::with_vertices(0);
102 assert!(is_diamond_free(&g).unwrap());
103 }
104
105 #[test]
106 fn single_vertex() {
107 let g = Graph::with_vertices(1);
108 assert!(is_diamond_free(&g).unwrap());
109 }
110
111 #[test]
112 fn single_edge() {
113 let mut g = Graph::with_vertices(2);
114 g.add_edge(0, 1).unwrap();
115 assert!(is_diamond_free(&g).unwrap());
116 }
117
118 #[test]
119 fn triangle() {
120 let mut g = Graph::with_vertices(3);
121 g.add_edge(0, 1).unwrap();
122 g.add_edge(1, 2).unwrap();
123 g.add_edge(2, 0).unwrap();
124 assert!(is_diamond_free(&g).unwrap());
125 }
126
127 #[test]
128 fn diamond() {
129 let mut g = Graph::with_vertices(4);
131 g.add_edge(0, 1).unwrap();
132 g.add_edge(0, 2).unwrap();
133 g.add_edge(0, 3).unwrap();
134 g.add_edge(1, 2).unwrap();
135 g.add_edge(1, 3).unwrap();
136 assert!(!is_diamond_free(&g).unwrap());
137 }
138
139 #[test]
140 fn k4_is_diamond_free() {
141 let mut g = Graph::with_vertices(4);
144 g.add_edge(0, 1).unwrap();
145 g.add_edge(0, 2).unwrap();
146 g.add_edge(0, 3).unwrap();
147 g.add_edge(1, 2).unwrap();
148 g.add_edge(1, 3).unwrap();
149 g.add_edge(2, 3).unwrap();
150 assert!(is_diamond_free(&g).unwrap());
151 }
152
153 #[test]
154 fn path_diamond_free() {
155 let mut g = Graph::with_vertices(5);
156 g.add_edge(0, 1).unwrap();
157 g.add_edge(1, 2).unwrap();
158 g.add_edge(2, 3).unwrap();
159 g.add_edge(3, 4).unwrap();
160 assert!(is_diamond_free(&g).unwrap());
161 }
162
163 #[test]
164 fn cycle_c5_diamond_free() {
165 let mut g = Graph::with_vertices(5);
166 g.add_edge(0, 1).unwrap();
167 g.add_edge(1, 2).unwrap();
168 g.add_edge(2, 3).unwrap();
169 g.add_edge(3, 4).unwrap();
170 g.add_edge(4, 0).unwrap();
171 assert!(is_diamond_free(&g).unwrap());
172 }
173
174 #[test]
175 fn star_diamond_free() {
176 let mut g = Graph::with_vertices(5);
177 g.add_edge(0, 1).unwrap();
178 g.add_edge(0, 2).unwrap();
179 g.add_edge(0, 3).unwrap();
180 g.add_edge(0, 4).unwrap();
181 assert!(is_diamond_free(&g).unwrap());
182 }
183
184 #[test]
185 fn two_triangles_sharing_vertex() {
186 let mut g = Graph::with_vertices(5);
188 g.add_edge(0, 1).unwrap();
189 g.add_edge(1, 2).unwrap();
190 g.add_edge(2, 0).unwrap();
191 g.add_edge(0, 3).unwrap();
192 g.add_edge(3, 4).unwrap();
193 g.add_edge(4, 0).unwrap();
194 assert!(is_diamond_free(&g).unwrap());
197 }
198
199 #[test]
200 fn two_triangles_sharing_edge() {
201 let mut g = Graph::with_vertices(4);
203 g.add_edge(0, 1).unwrap();
204 g.add_edge(1, 2).unwrap();
205 g.add_edge(2, 0).unwrap();
206 g.add_edge(0, 3).unwrap();
207 g.add_edge(1, 3).unwrap();
208 assert!(!is_diamond_free(&g).unwrap());
211 }
212
213 #[test]
214 fn directed_returns_false() {
215 let mut g = Graph::new(3, true).unwrap();
216 g.add_edge(0, 1).unwrap();
217 g.add_edge(1, 2).unwrap();
218 g.add_edge(2, 0).unwrap();
219 assert!(!is_diamond_free(&g).unwrap());
220 }
221
222 #[test]
223 fn isolated_vertices() {
224 let g = Graph::with_vertices(10);
225 assert!(is_diamond_free(&g).unwrap());
226 }
227
228 #[test]
229 fn wheel_w5_not_diamond_free() {
230 let mut g = Graph::with_vertices(6);
232 g.add_edge(0, 1).unwrap();
233 g.add_edge(0, 2).unwrap();
234 g.add_edge(0, 3).unwrap();
235 g.add_edge(0, 4).unwrap();
236 g.add_edge(0, 5).unwrap();
237 g.add_edge(1, 2).unwrap();
238 g.add_edge(2, 3).unwrap();
239 g.add_edge(3, 4).unwrap();
240 g.add_edge(4, 5).unwrap();
241 g.add_edge(5, 1).unwrap();
242 assert!(!is_diamond_free(&g).unwrap());
244 }
245}