rust_igraph/algorithms/properties/
is_complete.rs1use std::collections::HashSet;
28
29use crate::core::Graph;
30use crate::core::IgraphResult;
31use crate::core::graph::VertexId;
32
33use super::is_simple::{SimpleMode, is_simple_with_mode};
34
35pub fn is_complete(graph: &Graph) -> IgraphResult<bool> {
68 let n = graph.vcount();
69 if n <= 1 {
70 return Ok(true);
71 }
72
73 let n64 = u64::from(n);
74 let m64 = graph.ecount() as u64;
75 let directed = graph.is_directed();
76
77 let Some(target_undir_x2) = n64.checked_mul(n64 - 1) else {
79 return Ok(false);
80 };
81 let target = if directed {
82 target_undir_x2
83 } else {
84 target_undir_x2 / 2
85 };
86
87 if m64 < target {
88 return Ok(false);
89 }
90
91 if is_simple_with_mode(graph, SimpleMode::DirectedAsDirected)? {
93 return Ok(m64 == target);
94 }
95
96 let n_us = n as usize;
102 let mut seen: HashSet<VertexId> = HashSet::with_capacity(n_us);
103 for v in 0..n {
104 seen.clear();
105 if directed {
106 let eids = graph.incident(v)?;
107 for eid in eids {
108 let nei = graph.edge_other(eid, v)?;
109 if nei != v {
110 seen.insert(nei);
111 }
112 }
113 } else {
114 let neis = graph.neighbors(v)?;
115 for nei in neis {
116 if nei != v {
117 seen.insert(nei);
118 }
119 }
120 }
121 if seen.len() + 1 < n_us {
123 return Ok(false);
124 }
125 }
126
127 Ok(true)
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::core::Graph;
134
135 #[test]
136 fn null_graph_is_complete() {
137 let g = Graph::with_vertices(0);
138 assert!(is_complete(&g).unwrap());
139 }
140
141 #[test]
142 fn null_directed_is_complete() {
143 let g = Graph::new(0, true).unwrap();
144 assert!(is_complete(&g).unwrap());
145 }
146
147 #[test]
148 fn singleton_undirected_is_complete() {
149 let g = Graph::with_vertices(1);
150 assert!(is_complete(&g).unwrap());
151 }
152
153 #[test]
154 fn singleton_directed_is_complete() {
155 let g = Graph::new(1, true).unwrap();
156 assert!(is_complete(&g).unwrap());
157 }
158
159 #[test]
160 fn singleton_with_self_loop_is_complete() {
161 let mut g = Graph::with_vertices(1);
163 g.add_edge(0, 0).unwrap();
164 assert!(is_complete(&g).unwrap());
165 }
166
167 #[test]
168 fn k2_undirected_is_complete() {
169 let mut g = Graph::with_vertices(2);
170 g.add_edge(0, 1).unwrap();
171 assert!(is_complete(&g).unwrap());
172 }
173
174 #[test]
175 fn k3_undirected_is_complete() {
176 let mut g = Graph::with_vertices(3);
177 g.add_edges(vec![(0u32, 1u32), (0, 2), (1, 2)]).unwrap();
178 assert!(is_complete(&g).unwrap());
179 }
180
181 #[test]
182 fn k4_undirected_is_complete() {
183 let mut g = Graph::with_vertices(4);
184 g.add_edges(vec![(0u32, 1u32), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)])
185 .unwrap();
186 assert!(is_complete(&g).unwrap());
187 }
188
189 #[test]
190 fn path_is_not_complete() {
191 let mut g = Graph::with_vertices(3);
193 g.add_edges(vec![(0u32, 1u32), (1, 2)]).unwrap();
194 assert!(!is_complete(&g).unwrap());
195 }
196
197 #[test]
198 fn missing_one_edge_is_not_complete() {
199 let mut g = Graph::with_vertices(4);
201 g.add_edges(vec![(0u32, 1u32), (0, 2), (0, 3), (1, 2), (1, 3)])
202 .unwrap();
203 assert!(!is_complete(&g).unwrap());
204 }
205
206 #[test]
207 fn k3_directed_needs_both_directions() {
208 let mut g = Graph::new(3, true).unwrap();
212 g.add_edges(vec![(0u32, 1u32), (1, 2), (2, 0)]).unwrap();
213 assert!(!is_complete(&g).unwrap());
214 }
215
216 #[test]
217 fn k3_directed_complete() {
218 let mut g = Graph::new(3, true).unwrap();
220 g.add_edges(vec![(0u32, 1u32), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1)])
221 .unwrap();
222 assert!(is_complete(&g).unwrap());
223 }
224
225 #[test]
226 fn k2_directed_not_complete_with_only_one_arc() {
227 let mut g = Graph::new(2, true).unwrap();
228 g.add_edge(0, 1).unwrap();
229 assert!(!is_complete(&g).unwrap());
230 }
231
232 #[test]
233 fn k2_directed_complete_with_both_arcs() {
234 let mut g = Graph::new(2, true).unwrap();
235 g.add_edges(vec![(0u32, 1u32), (1, 0)]).unwrap();
236 assert!(is_complete(&g).unwrap());
237 }
238
239 #[test]
240 fn complete_with_extra_self_loops_still_complete() {
241 let mut g = Graph::with_vertices(3);
244 g.add_edges(vec![(0u32, 1u32), (0, 2), (1, 2), (0, 0)])
245 .unwrap();
246 assert!(is_complete(&g).unwrap());
247 }
248
249 #[test]
250 fn complete_with_parallel_edges_still_complete() {
251 let mut g = Graph::with_vertices(3);
254 g.add_edges(vec![(0u32, 1u32), (0, 2), (1, 2), (0, 1)])
255 .unwrap();
256 assert!(is_complete(&g).unwrap());
257 }
258
259 #[test]
260 fn parallel_edges_padding_does_not_help_missing_pair() {
261 let mut g = Graph::with_vertices(4);
265 g.add_edges(vec![(0u32, 1u32), (0, 2), (0, 3), (1, 2), (1, 2), (1, 2)])
266 .unwrap();
267 assert!(!is_complete(&g).unwrap());
268 }
269
270 #[test]
271 fn ecount_too_low_short_circuit() {
272 let mut g = Graph::with_vertices(10);
274 g.add_edge(0, 1).unwrap();
275 assert!(!is_complete(&g).unwrap());
276 }
277
278 #[test]
279 fn empty_n2_is_not_complete() {
280 let g = Graph::with_vertices(2);
282 assert!(!is_complete(&g).unwrap());
283 }
284
285 #[test]
286 fn multi_edge_padding_to_target_but_missing_pair() {
287 let mut g = Graph::with_vertices(3);
290 g.add_edges(vec![(0u32, 1u32), (0, 1), (0, 1)]).unwrap();
291 assert!(!is_complete(&g).unwrap());
292 }
293}