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 target_undir_x2 = n64.checked_mul(n64 - 1).expect("u64 mul fits");
79 let target = if directed {
80 target_undir_x2
81 } else {
82 target_undir_x2 / 2
83 };
84
85 if m64 < target {
86 return Ok(false);
87 }
88
89 if is_simple_with_mode(graph, SimpleMode::DirectedAsDirected)? {
91 return Ok(m64 == target);
92 }
93
94 let n_us = n as usize;
100 let mut seen: HashSet<VertexId> = HashSet::with_capacity(n_us);
101 for v in 0..n {
102 seen.clear();
103 if directed {
104 let eids = graph.incident(v).expect("incident on valid vertex");
105 for eid in eids {
106 let nei = graph.edge_other(eid, v).expect("edge_other on valid edge");
107 if nei != v {
108 seen.insert(nei);
109 }
110 }
111 } else {
112 let neis = graph.neighbors(v).expect("neighbors on valid vertex");
113 for nei in neis {
114 if nei != v {
115 seen.insert(nei);
116 }
117 }
118 }
119 if seen.len() + 1 < n_us {
121 return Ok(false);
122 }
123 }
124
125 Ok(true)
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::core::Graph;
132
133 #[test]
134 fn null_graph_is_complete() {
135 let g = Graph::with_vertices(0);
136 assert!(is_complete(&g).unwrap());
137 }
138
139 #[test]
140 fn null_directed_is_complete() {
141 let g = Graph::new(0, true).unwrap();
142 assert!(is_complete(&g).unwrap());
143 }
144
145 #[test]
146 fn singleton_undirected_is_complete() {
147 let g = Graph::with_vertices(1);
148 assert!(is_complete(&g).unwrap());
149 }
150
151 #[test]
152 fn singleton_directed_is_complete() {
153 let g = Graph::new(1, true).unwrap();
154 assert!(is_complete(&g).unwrap());
155 }
156
157 #[test]
158 fn singleton_with_self_loop_is_complete() {
159 let mut g = Graph::with_vertices(1);
161 g.add_edge(0, 0).unwrap();
162 assert!(is_complete(&g).unwrap());
163 }
164
165 #[test]
166 fn k2_undirected_is_complete() {
167 let mut g = Graph::with_vertices(2);
168 g.add_edge(0, 1).unwrap();
169 assert!(is_complete(&g).unwrap());
170 }
171
172 #[test]
173 fn k3_undirected_is_complete() {
174 let mut g = Graph::with_vertices(3);
175 g.add_edges(vec![(0u32, 1u32), (0, 2), (1, 2)]).unwrap();
176 assert!(is_complete(&g).unwrap());
177 }
178
179 #[test]
180 fn k4_undirected_is_complete() {
181 let mut g = Graph::with_vertices(4);
182 g.add_edges(vec![(0u32, 1u32), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)])
183 .unwrap();
184 assert!(is_complete(&g).unwrap());
185 }
186
187 #[test]
188 fn path_is_not_complete() {
189 let mut g = Graph::with_vertices(3);
191 g.add_edges(vec![(0u32, 1u32), (1, 2)]).unwrap();
192 assert!(!is_complete(&g).unwrap());
193 }
194
195 #[test]
196 fn missing_one_edge_is_not_complete() {
197 let mut g = Graph::with_vertices(4);
199 g.add_edges(vec![(0u32, 1u32), (0, 2), (0, 3), (1, 2), (1, 3)])
200 .unwrap();
201 assert!(!is_complete(&g).unwrap());
202 }
203
204 #[test]
205 fn k3_directed_needs_both_directions() {
206 let mut g = Graph::new(3, true).unwrap();
210 g.add_edges(vec![(0u32, 1u32), (1, 2), (2, 0)]).unwrap();
211 assert!(!is_complete(&g).unwrap());
212 }
213
214 #[test]
215 fn k3_directed_complete() {
216 let mut g = Graph::new(3, true).unwrap();
218 g.add_edges(vec![(0u32, 1u32), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1)])
219 .unwrap();
220 assert!(is_complete(&g).unwrap());
221 }
222
223 #[test]
224 fn k2_directed_not_complete_with_only_one_arc() {
225 let mut g = Graph::new(2, true).unwrap();
226 g.add_edge(0, 1).unwrap();
227 assert!(!is_complete(&g).unwrap());
228 }
229
230 #[test]
231 fn k2_directed_complete_with_both_arcs() {
232 let mut g = Graph::new(2, true).unwrap();
233 g.add_edges(vec![(0u32, 1u32), (1, 0)]).unwrap();
234 assert!(is_complete(&g).unwrap());
235 }
236
237 #[test]
238 fn complete_with_extra_self_loops_still_complete() {
239 let mut g = Graph::with_vertices(3);
242 g.add_edges(vec![(0u32, 1u32), (0, 2), (1, 2), (0, 0)])
243 .unwrap();
244 assert!(is_complete(&g).unwrap());
245 }
246
247 #[test]
248 fn complete_with_parallel_edges_still_complete() {
249 let mut g = Graph::with_vertices(3);
252 g.add_edges(vec![(0u32, 1u32), (0, 2), (1, 2), (0, 1)])
253 .unwrap();
254 assert!(is_complete(&g).unwrap());
255 }
256
257 #[test]
258 fn parallel_edges_padding_does_not_help_missing_pair() {
259 let mut g = Graph::with_vertices(4);
263 g.add_edges(vec![(0u32, 1u32), (0, 2), (0, 3), (1, 2), (1, 2), (1, 2)])
264 .unwrap();
265 assert!(!is_complete(&g).unwrap());
266 }
267
268 #[test]
269 fn ecount_too_low_short_circuit() {
270 let mut g = Graph::with_vertices(10);
272 g.add_edge(0, 1).unwrap();
273 assert!(!is_complete(&g).unwrap());
274 }
275
276 #[test]
277 fn empty_n2_is_not_complete() {
278 let g = Graph::with_vertices(2);
280 assert!(!is_complete(&g).unwrap());
281 }
282
283 #[test]
284 fn multi_edge_padding_to_target_but_missing_pair() {
285 let mut g = Graph::with_vertices(3);
288 g.add_edges(vec![(0u32, 1u32), (0, 1), (0, 1)]).unwrap();
289 assert!(!is_complete(&g).unwrap());
290 }
291}