rust_igraph/algorithms/
vertex_cover.rs1use crate::core::{Graph, IgraphResult, VertexId};
13
14pub fn is_vertex_cover(graph: &Graph, cover: &[VertexId]) -> bool {
33 let n = graph.vcount() as usize;
34 let mut in_cover = vec![false; n];
35 for &v in cover {
36 if (v as usize) < n {
37 in_cover[v as usize] = true;
38 }
39 }
40
41 let ecount = graph.ecount();
42 #[allow(clippy::cast_possible_truncation)] for eid in 0..ecount as u32 {
44 if let Ok((u, v)) = graph.edge(eid) {
45 if !in_cover[u as usize] && !in_cover[v as usize] {
46 return false;
47 }
48 }
49 }
50 true
51}
52
53#[allow(clippy::cast_possible_truncation)] pub fn minimum_vertex_cover(graph: &Graph) -> IgraphResult<Vec<VertexId>> {
83 let n = graph.vcount();
84 let ecount = graph.ecount();
85
86 if ecount == 0 {
87 return Ok(Vec::new());
88 }
89
90 let mut in_cover = vec![false; n as usize];
91 let mut covered = vec![false; ecount];
92
93 for eid in 0..ecount {
94 if covered[eid] {
95 continue;
96 }
97
98 let (u, v) = graph.edge(eid as u32)?;
99 if in_cover[u as usize] || in_cover[v as usize] {
100 covered[eid] = true;
101 continue;
102 }
103
104 in_cover[u as usize] = true;
105 in_cover[v as usize] = true;
106
107 mark_incident_covered(graph, u, &mut covered);
108 mark_incident_covered(graph, v, &mut covered);
109 }
110
111 let mut result: Vec<VertexId> = (0..n).filter(|&v| in_cover[v as usize]).collect();
112 result.sort_unstable();
113 Ok(result)
114}
115
116fn mark_incident_covered(graph: &Graph, v: VertexId, covered: &mut [bool]) {
117 if let Ok(edges) = graph.incident(v) {
118 for &eid in &edges {
119 covered[eid as usize] = true;
120 }
121 }
122 if graph.is_directed() {
123 if let Ok(edges) = graph.incident_in(v) {
124 for &eid in &edges {
125 covered[eid as usize] = true;
126 }
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn empty_graph() {
137 let g = Graph::with_vertices(0);
138 let cover = minimum_vertex_cover(&g).unwrap();
139 assert!(cover.is_empty());
140 }
141
142 #[test]
143 fn no_edges() {
144 let g = Graph::with_vertices(5);
145 let cover = minimum_vertex_cover(&g).unwrap();
146 assert!(cover.is_empty());
147 }
148
149 #[test]
150 fn single_edge() {
151 let mut g = Graph::with_vertices(2);
152 g.add_edge(0, 1).unwrap();
153 let cover = minimum_vertex_cover(&g).unwrap();
154 assert_eq!(cover.len(), 2);
155 assert!(is_vertex_cover(&g, &cover));
156 }
157
158 #[test]
159 fn path_3() {
160 let mut g = Graph::with_vertices(3);
161 g.add_edge(0, 1).unwrap();
162 g.add_edge(1, 2).unwrap();
163 let cover = minimum_vertex_cover(&g).unwrap();
164 assert!(is_vertex_cover(&g, &cover));
165 assert!(cover.len() <= 4); }
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 let cover = minimum_vertex_cover(&g).unwrap();
175 assert!(is_vertex_cover(&g, &cover));
176 assert!(cover.len() >= 2); assert!(cover.len() <= 4); }
179
180 #[test]
181 fn star_graph() {
182 let mut g = Graph::with_vertices(5);
183 for i in 1..5u32 {
184 g.add_edge(0, i).unwrap();
185 }
186 let cover = minimum_vertex_cover(&g).unwrap();
187 assert!(is_vertex_cover(&g, &cover));
188 assert!(cover.len() <= 2);
190 }
191
192 #[test]
193 fn complete_k4() {
194 let mut g = Graph::with_vertices(4);
195 for u in 0..4u32 {
196 for v in (u + 1)..4 {
197 g.add_edge(u, v).unwrap();
198 }
199 }
200 let cover = minimum_vertex_cover(&g).unwrap();
201 assert!(is_vertex_cover(&g, &cover));
202 assert!(cover.len() >= 3); }
204
205 #[test]
206 fn bipartite_matching_example() {
207 let mut g = Graph::with_vertices(4);
209 g.add_edge(0, 2).unwrap();
210 g.add_edge(0, 3).unwrap();
211 g.add_edge(1, 2).unwrap();
212 g.add_edge(1, 3).unwrap();
213 let cover = minimum_vertex_cover(&g).unwrap();
214 assert!(is_vertex_cover(&g, &cover));
215 assert!(cover.len() >= 2); assert!(cover.len() <= 4); }
218
219 #[test]
220 fn directed_graph() {
221 let mut g = Graph::new(3, true).unwrap();
222 g.add_edge(0, 1).unwrap();
223 g.add_edge(1, 2).unwrap();
224 let cover = minimum_vertex_cover(&g).unwrap();
225 assert!(is_vertex_cover(&g, &cover));
226 }
227
228 #[test]
229 fn self_loop() {
230 let mut g = Graph::with_vertices(3);
231 g.add_edge(0, 0).unwrap();
232 g.add_edge(1, 2).unwrap();
233 let cover = minimum_vertex_cover(&g).unwrap();
234 assert!(is_vertex_cover(&g, &cover));
235 assert!(cover.contains(&0)); }
237
238 #[test]
239 fn isolated_with_edges() {
240 let mut g = Graph::with_vertices(5);
241 g.add_edge(0, 1).unwrap();
242 g.add_edge(2, 3).unwrap();
243 let cover = minimum_vertex_cover(&g).unwrap();
245 assert!(is_vertex_cover(&g, &cover));
246 assert!(!cover.contains(&4));
247 }
248
249 #[test]
250 fn two_approx_guarantee() {
251 let mut g = Graph::with_vertices(6);
257 for i in 0..5u32 {
258 g.add_edge(i, i + 1).unwrap();
259 }
260 let cover = minimum_vertex_cover(&g).unwrap();
261 assert!(is_vertex_cover(&g, &cover));
262 assert!(cover.len() <= 6); }
264
265 #[test]
266 fn is_cover_validator_positive() {
267 let mut g = Graph::with_vertices(3);
268 g.add_edge(0, 1).unwrap();
269 g.add_edge(1, 2).unwrap();
270 assert!(is_vertex_cover(&g, &[1]));
271 assert!(is_vertex_cover(&g, &[0, 2]));
272 assert!(is_vertex_cover(&g, &[0, 1, 2]));
273 }
274
275 #[test]
276 fn is_cover_validator_negative() {
277 let mut g = Graph::with_vertices(4);
278 g.add_edge(0, 1).unwrap();
279 g.add_edge(1, 2).unwrap();
280 g.add_edge(2, 3).unwrap();
281 assert!(!is_vertex_cover(&g, &[]));
282 assert!(!is_vertex_cover(&g, &[0]));
283 assert!(!is_vertex_cover(&g, &[0, 3]));
284 }
285
286 #[test]
287 fn sorted_output() {
288 let mut g = Graph::with_vertices(6);
289 g.add_edge(4, 5).unwrap();
290 g.add_edge(0, 1).unwrap();
291 g.add_edge(2, 3).unwrap();
292 let cover = minimum_vertex_cover(&g).unwrap();
293 for i in 1..cover.len() {
294 assert!(cover[i] > cover[i - 1]);
295 }
296 }
297
298 #[test]
299 fn parallel_edges() {
300 let mut g = Graph::with_vertices(2);
301 g.add_edge(0, 1).unwrap();
302 g.add_edge(0, 1).unwrap();
303 g.add_edge(0, 1).unwrap();
304 let cover = minimum_vertex_cover(&g).unwrap();
305 assert!(is_vertex_cover(&g, &cover));
306 assert_eq!(cover.len(), 2);
307 }
308}