rust_igraph/algorithms/
independent_set.rs1use crate::core::{Graph, IgraphResult, VertexId};
12
13#[allow(clippy::cast_possible_truncation)] pub fn maximum_independent_set(graph: &Graph) -> IgraphResult<Vec<VertexId>> {
44 let n = graph.vcount();
45 let directed = graph.is_directed();
46
47 if n == 0 {
48 return Ok(Vec::new());
49 }
50
51 if graph.ecount() == 0 {
52 return Ok((0..n).collect());
53 }
54
55 let mut removed = vec![false; n as usize];
56
57 for v in 0..n {
59 let neighbors = all_neighbors(graph, v, directed)?;
60 if neighbors.contains(&v) {
61 removed[v as usize] = true;
62 }
63 }
64
65 let mut result = Vec::new();
66 let mut degrees = vec![0u32; n as usize];
67
68 for v in 0..n {
69 if !removed[v as usize] {
70 degrees[v as usize] = effective_degree(graph, v, &removed, directed)?;
71 }
72 }
73
74 loop {
75 let mut best_v: Option<VertexId> = None;
76 let mut best_deg = u32::MAX;
77
78 for v in 0..n {
79 if removed[v as usize] {
80 continue;
81 }
82 let deg = degrees[v as usize];
83 if deg < best_deg || (deg == best_deg && best_v.is_none_or(|b| v < b)) {
84 best_deg = deg;
85 best_v = Some(v);
86 }
87 }
88
89 let Some(v) = best_v else { break };
90
91 result.push(v);
92 removed[v as usize] = true;
93
94 let neighbors = all_neighbors(graph, v, directed)?;
95 for &w in &neighbors {
96 if !removed[w as usize] {
97 removed[w as usize] = true;
98 }
99 }
100
101 for u in 0..n {
102 if !removed[u as usize] {
103 degrees[u as usize] = effective_degree(graph, u, &removed, directed)?;
104 }
105 }
106 }
107
108 result.sort_unstable();
109 Ok(result)
110}
111
112fn all_neighbors(graph: &Graph, v: VertexId, directed: bool) -> IgraphResult<Vec<VertexId>> {
113 let mut neighbors = graph.neighbors(v)?;
114 if directed {
115 let in_n = graph.in_neighbors_vec(v)?;
116 for w in in_n {
117 if !neighbors.contains(&w) {
118 neighbors.push(w);
119 }
120 }
121 }
122 Ok(neighbors)
123}
124
125fn effective_degree(
126 graph: &Graph,
127 v: VertexId,
128 removed: &[bool],
129 directed: bool,
130) -> IgraphResult<u32> {
131 let neighbors = all_neighbors(graph, v, directed)?;
132 #[allow(clippy::cast_possible_truncation)]
133 let deg = neighbors
134 .iter()
135 .filter(|&&w| w != v && !removed[w as usize])
136 .count() as u32;
137 Ok(deg)
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use crate::algorithms::properties::is_clique::is_independent_vertex_set;
144
145 #[test]
146 fn empty_graph() {
147 let g = Graph::with_vertices(0);
148 let mis = maximum_independent_set(&g).unwrap();
149 assert!(mis.is_empty());
150 }
151
152 #[test]
153 fn no_edges() {
154 let g = Graph::with_vertices(5);
155 let mis = maximum_independent_set(&g).unwrap();
156 assert_eq!(mis.len(), 5);
157 assert!(is_independent_vertex_set(&g, &mis).unwrap());
158 }
159
160 #[test]
161 fn single_edge() {
162 let mut g = Graph::with_vertices(2);
163 g.add_edge(0, 1).unwrap();
164 let mis = maximum_independent_set(&g).unwrap();
165 assert_eq!(mis.len(), 1);
166 assert!(is_independent_vertex_set(&g, &mis).unwrap());
167 }
168
169 #[test]
170 fn path_4() {
171 let mut g = Graph::with_vertices(4);
172 g.add_edge(0, 1).unwrap();
173 g.add_edge(1, 2).unwrap();
174 g.add_edge(2, 3).unwrap();
175 let mis = maximum_independent_set(&g).unwrap();
176 assert!(is_independent_vertex_set(&g, &mis).unwrap());
177 assert!(mis.len() >= 2); }
179
180 #[test]
181 fn triangle() {
182 let mut g = Graph::with_vertices(3);
183 g.add_edge(0, 1).unwrap();
184 g.add_edge(1, 2).unwrap();
185 g.add_edge(2, 0).unwrap();
186 let mis = maximum_independent_set(&g).unwrap();
187 assert!(is_independent_vertex_set(&g, &mis).unwrap());
188 assert_eq!(mis.len(), 1); }
190
191 #[test]
192 fn star_graph() {
193 let mut g = Graph::with_vertices(5);
194 for i in 1..5u32 {
195 g.add_edge(0, i).unwrap();
196 }
197 let mis = maximum_independent_set(&g).unwrap();
198 assert!(is_independent_vertex_set(&g, &mis).unwrap());
199 assert!(mis.len() >= 2);
201 }
202
203 #[test]
204 fn complete_k4() {
205 let mut g = Graph::with_vertices(4);
206 for u in 0..4u32 {
207 for v in (u + 1)..4 {
208 g.add_edge(u, v).unwrap();
209 }
210 }
211 let mis = maximum_independent_set(&g).unwrap();
212 assert!(is_independent_vertex_set(&g, &mis).unwrap());
213 assert_eq!(mis.len(), 1); }
215
216 #[test]
217 fn bipartite_k22() {
218 let mut g = Graph::with_vertices(4);
219 g.add_edge(0, 2).unwrap();
220 g.add_edge(0, 3).unwrap();
221 g.add_edge(1, 2).unwrap();
222 g.add_edge(1, 3).unwrap();
223 let mis = maximum_independent_set(&g).unwrap();
224 assert!(is_independent_vertex_set(&g, &mis).unwrap());
225 assert_eq!(mis.len(), 2); }
227
228 #[test]
229 fn isolated_with_edges() {
230 let mut g = Graph::with_vertices(5);
231 g.add_edge(0, 1).unwrap();
232 g.add_edge(2, 3).unwrap();
233 let mis = maximum_independent_set(&g).unwrap();
235 assert!(is_independent_vertex_set(&g, &mis).unwrap());
236 assert!(mis.contains(&4)); assert!(mis.len() >= 3); }
239
240 #[test]
241 fn directed_graph() {
242 let mut g = Graph::new(3, true).unwrap();
243 g.add_edge(0, 1).unwrap();
244 g.add_edge(1, 2).unwrap();
245 let mis = maximum_independent_set(&g).unwrap();
246 assert!(is_independent_vertex_set(&g, &mis).unwrap());
247 }
248
249 #[test]
250 fn self_loop() {
251 let mut g = Graph::with_vertices(3);
252 g.add_edge(0, 0).unwrap();
253 g.add_edge(1, 2).unwrap();
254 let mis = maximum_independent_set(&g).unwrap();
255 assert!(is_independent_vertex_set(&g, &mis).unwrap());
256 assert!(!mis.contains(&0)); }
258
259 #[test]
260 fn sorted_output() {
261 let mut g = Graph::with_vertices(6);
262 g.add_edge(4, 5).unwrap();
263 g.add_edge(0, 1).unwrap();
264 let mis = maximum_independent_set(&g).unwrap();
265 for i in 1..mis.len() {
266 assert!(mis[i] > mis[i - 1]);
267 }
268 }
269
270 #[test]
271 fn petersen_graph() {
272 let mut g = Graph::with_vertices(10);
274 for i in 0..5u32 {
276 g.add_edge(i, (i + 1) % 5).unwrap();
277 }
278 for i in 0..5u32 {
280 g.add_edge(5 + i, 5 + (i + 2) % 5).unwrap();
281 }
282 for i in 0..5u32 {
284 g.add_edge(i, 5 + i).unwrap();
285 }
286 let mis = maximum_independent_set(&g).unwrap();
287 assert!(is_independent_vertex_set(&g, &mis).unwrap());
288 assert!(mis.len() >= 3); }
290
291 #[test]
292 fn complement_of_vertex_cover() {
293 use crate::algorithms::vertex_cover::minimum_vertex_cover;
295 let mut g = Graph::with_vertices(6);
296 for i in 0..5u32 {
297 g.add_edge(i, i + 1).unwrap();
298 }
299 let cover = minimum_vertex_cover(&g).unwrap();
300 let n = g.vcount();
301 let complement: Vec<VertexId> = (0..n).filter(|v| !cover.contains(v)).collect();
302 assert!(is_independent_vertex_set(&g, &complement).unwrap());
303 }
304}