rust_igraph/algorithms/properties/
is_co_bipartite.rs1use crate::core::{Graph, IgraphResult};
10
11pub fn is_co_bipartite(graph: &Graph) -> IgraphResult<bool> {
40 if graph.is_directed() {
41 return Ok(false);
42 }
43
44 let n = graph.vcount();
45 if n <= 2 {
46 return Ok(true);
47 }
48
49 let n_usize = n as usize;
50 let mut adj = vec![vec![false; n_usize]; n_usize];
51 for v in 0..n {
52 let nbrs = graph.neighbors(v)?;
53 for &w in &nbrs {
54 adj[v as usize][w as usize] = true;
55 }
56 }
57
58 let mut color: Vec<i8> = vec![-1; n_usize];
61
62 for start in 0..n_usize {
63 if color[start] != -1 {
64 continue;
65 }
66 color[start] = 0;
67 let mut queue = std::collections::VecDeque::new();
68 queue.push_back(start);
69
70 while let Some(u) = queue.pop_front() {
71 let u_color = color[u];
72 let next_color = 1 - u_color;
73 for (v, c) in color.iter_mut().enumerate() {
74 if v == u || adj[u][v] {
75 continue;
76 }
77 if *c == -1 {
78 *c = next_color;
79 queue.push_back(v);
80 } else if *c == u_color {
81 return Ok(false);
82 }
83 }
84 }
85 }
86
87 Ok(true)
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn empty_graph() {
96 let g = Graph::with_vertices(0);
97 assert!(is_co_bipartite(&g).unwrap());
98 }
99
100 #[test]
101 fn single_vertex() {
102 let g = Graph::with_vertices(1);
103 assert!(is_co_bipartite(&g).unwrap());
104 }
105
106 #[test]
107 fn two_vertices_no_edge() {
108 let g = Graph::with_vertices(2);
110 assert!(is_co_bipartite(&g).unwrap());
111 }
112
113 #[test]
114 fn two_vertices_with_edge() {
115 let mut g = Graph::with_vertices(2);
116 g.add_edge(0, 1).unwrap();
117 assert!(is_co_bipartite(&g).unwrap());
118 }
119
120 #[test]
121 fn triangle() {
122 let mut g = Graph::with_vertices(3);
124 g.add_edge(0, 1).unwrap();
125 g.add_edge(1, 2).unwrap();
126 g.add_edge(2, 0).unwrap();
127 assert!(is_co_bipartite(&g).unwrap());
128 }
129
130 #[test]
131 fn two_cliques() {
132 let mut g = Graph::with_vertices(5);
134 g.add_edge(0, 1).unwrap();
135 g.add_edge(2, 3).unwrap();
136 g.add_edge(3, 4).unwrap();
137 g.add_edge(2, 4).unwrap();
138 assert!(is_co_bipartite(&g).unwrap());
139 }
140
141 #[test]
142 fn complete_graph() {
143 let mut g = Graph::with_vertices(5);
145 for i in 0..5u32 {
146 for j in (i + 1)..5 {
147 g.add_edge(i, j).unwrap();
148 }
149 }
150 assert!(is_co_bipartite(&g).unwrap());
151 }
152
153 #[test]
154 fn c4_co_bipartite() {
155 let mut g = Graph::with_vertices(4);
158 g.add_edge(0, 1).unwrap();
159 g.add_edge(1, 2).unwrap();
160 g.add_edge(2, 3).unwrap();
161 g.add_edge(3, 0).unwrap();
162 assert!(is_co_bipartite(&g).unwrap());
163 }
164
165 #[test]
166 fn c5_not_co_bipartite() {
167 let mut g = Graph::with_vertices(5);
170 g.add_edge(0, 1).unwrap();
171 g.add_edge(1, 2).unwrap();
172 g.add_edge(2, 3).unwrap();
173 g.add_edge(3, 4).unwrap();
174 g.add_edge(4, 0).unwrap();
175 assert!(!is_co_bipartite(&g).unwrap());
176 }
177
178 #[test]
179 fn path_p3_co_bipartite() {
180 let mut g = Graph::with_vertices(3);
182 g.add_edge(0, 1).unwrap();
183 g.add_edge(1, 2).unwrap();
184 assert!(is_co_bipartite(&g).unwrap());
185 }
186
187 #[test]
188 fn independent_set_3() {
189 let g = Graph::with_vertices(3);
193 assert!(!is_co_bipartite(&g).unwrap());
194 }
195
196 #[test]
197 fn directed_returns_false() {
198 let mut g = Graph::new(3, true).unwrap();
199 g.add_edge(0, 1).unwrap();
200 g.add_edge(1, 2).unwrap();
201 g.add_edge(2, 0).unwrap();
202 assert!(!is_co_bipartite(&g).unwrap());
203 }
204
205 #[test]
206 fn star_not_co_bipartite() {
207 let mut g = Graph::with_vertices(5);
210 g.add_edge(0, 1).unwrap();
211 g.add_edge(0, 2).unwrap();
212 g.add_edge(0, 3).unwrap();
213 g.add_edge(0, 4).unwrap();
214 assert!(!is_co_bipartite(&g).unwrap());
215 }
216
217 #[test]
218 fn complete_bipartite_k22() {
219 let mut g = Graph::with_vertices(4);
221 g.add_edge(0, 2).unwrap();
222 g.add_edge(0, 3).unwrap();
223 g.add_edge(1, 2).unwrap();
224 g.add_edge(1, 3).unwrap();
225 assert!(is_co_bipartite(&g).unwrap());
226 }
227}