Skip to main content

rust_igraph/algorithms/properties/
is_complete_bipartite.rs

1//! Complete bipartite graph predicate (ALGO-PR-122).
2//!
3//! A graph is complete bipartite (`K_{m,n}`) if its vertices can be
4//! partitioned into two non-empty independent sets such that every
5//! vertex in one set is adjacent to every vertex in the other.
6//!
7//! Every star `K_{1,n}` is complete bipartite. Every single edge is
8//! `K_{1,1}`. The empty graph and edgeless graphs with more than one
9//! component (or a single part) are not complete bipartite.
10//!
11//! Directed graphs are treated as undirected.
12
13use crate::algorithms::properties::is_bipartite::{BipartiteResult, is_bipartite};
14use crate::core::{Graph, IgraphResult};
15
16/// Check whether a graph is complete bipartite.
17///
18/// Returns `true` if the graph is isomorphic to `K_{m,n}` for some
19/// `m, n ≥ 1`. Uses the bipartite check to find the two parts, then
20/// verifies that the edge count equals `m * n`.
21///
22/// Directed graphs are treated as undirected.
23///
24/// # Examples
25///
26/// ```
27/// use rust_igraph::{Graph, is_complete_bipartite};
28///
29/// // `K_{2,3}`: 2 vertices connected to 3 vertices
30/// let mut g = Graph::with_vertices(5);
31/// for i in 0..2u32 {
32///     for j in 2..5u32 {
33///         g.add_edge(i, j).unwrap();
34///     }
35/// }
36/// assert!(is_complete_bipartite(&g).unwrap());
37///
38/// // `C_6`: bipartite but not complete bipartite
39/// let mut g = Graph::with_vertices(6);
40/// for i in 0..6u32 {
41///     g.add_edge(i, (i + 1) % 6).unwrap();
42/// }
43/// assert!(!is_complete_bipartite(&g).unwrap());
44/// ```
45pub fn is_complete_bipartite(graph: &Graph) -> IgraphResult<bool> {
46    let n = graph.vcount();
47
48    if n < 2 {
49        return Ok(false);
50    }
51
52    let bip: BipartiteResult = is_bipartite(graph)?;
53    if !bip.is_bipartite {
54        return Ok(false);
55    }
56
57    let part_a = bip.types.iter().filter(|&&t| t).count();
58    let part_b = bip.types.iter().filter(|&&t| !t).count();
59
60    if part_a == 0 || part_b == 0 {
61        return Ok(false);
62    }
63
64    let expected_edges = part_a.saturating_mul(part_b);
65    Ok(graph.ecount() == expected_edges)
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn empty_graph() {
74        let g = Graph::with_vertices(0);
75        assert!(!is_complete_bipartite(&g).unwrap());
76    }
77
78    #[test]
79    fn single_vertex() {
80        let g = Graph::with_vertices(1);
81        assert!(!is_complete_bipartite(&g).unwrap());
82    }
83
84    #[test]
85    fn single_edge_k11() {
86        let mut g = Graph::with_vertices(2);
87        g.add_edge(0, 1).unwrap();
88        assert!(is_complete_bipartite(&g).unwrap());
89    }
90
91    #[test]
92    fn k12_star() {
93        let mut g = Graph::with_vertices(3);
94        g.add_edge(0, 1).unwrap();
95        g.add_edge(0, 2).unwrap();
96        assert!(is_complete_bipartite(&g).unwrap());
97    }
98
99    #[test]
100    fn k22() {
101        // K_{2,2} = C_4 with all cross edges
102        let mut g = Graph::with_vertices(4);
103        g.add_edge(0, 2).unwrap();
104        g.add_edge(0, 3).unwrap();
105        g.add_edge(1, 2).unwrap();
106        g.add_edge(1, 3).unwrap();
107        assert!(is_complete_bipartite(&g).unwrap());
108    }
109
110    #[test]
111    fn k23() {
112        let mut g = Graph::with_vertices(5);
113        for i in 0..2u32 {
114            for j in 2..5u32 {
115                g.add_edge(i, j).unwrap();
116            }
117        }
118        assert!(is_complete_bipartite(&g).unwrap());
119    }
120
121    #[test]
122    fn k33() {
123        let mut g = Graph::with_vertices(6);
124        for i in 0..3u32 {
125            for j in 3..6u32 {
126                g.add_edge(i, j).unwrap();
127            }
128        }
129        assert!(is_complete_bipartite(&g).unwrap());
130    }
131
132    #[test]
133    fn c4_is_k22() {
134        // C_4 = K_{2,2}: parts {0,2} and {1,3}, all 4 cross edges present
135        let mut g = Graph::with_vertices(4);
136        g.add_edge(0, 1).unwrap();
137        g.add_edge(1, 2).unwrap();
138        g.add_edge(2, 3).unwrap();
139        g.add_edge(3, 0).unwrap();
140        assert!(is_complete_bipartite(&g).unwrap());
141    }
142
143    #[test]
144    fn c6_not_complete_bipartite() {
145        let mut g = Graph::with_vertices(6);
146        for i in 0..6u32 {
147            g.add_edge(i, (i + 1) % 6).unwrap();
148        }
149        assert!(!is_complete_bipartite(&g).unwrap());
150    }
151
152    #[test]
153    fn triangle_not_bipartite() {
154        let mut g = Graph::with_vertices(3);
155        g.add_edge(0, 1).unwrap();
156        g.add_edge(1, 2).unwrap();
157        g.add_edge(2, 0).unwrap();
158        assert!(!is_complete_bipartite(&g).unwrap());
159    }
160
161    #[test]
162    fn k4_not_bipartite() {
163        let mut g = Graph::with_vertices(4);
164        for i in 0..4u32 {
165            for j in (i + 1)..4 {
166                g.add_edge(i, j).unwrap();
167            }
168        }
169        assert!(!is_complete_bipartite(&g).unwrap());
170    }
171
172    #[test]
173    fn edgeless() {
174        let g = Graph::with_vertices(4);
175        assert!(!is_complete_bipartite(&g).unwrap());
176    }
177
178    #[test]
179    fn two_components_not_complete_bipartite() {
180        // Two K_{1,1} components
181        let mut g = Graph::with_vertices(4);
182        g.add_edge(0, 1).unwrap();
183        g.add_edge(2, 3).unwrap();
184        assert!(!is_complete_bipartite(&g).unwrap());
185    }
186
187    #[test]
188    fn path_p3_is_k12() {
189        // P_3 = K_{1,2}: part {1} connects to both {0,2}
190        let mut g = Graph::with_vertices(3);
191        g.add_edge(0, 1).unwrap();
192        g.add_edge(1, 2).unwrap();
193        assert!(is_complete_bipartite(&g).unwrap());
194    }
195
196    #[test]
197    fn directed_treated_as_undirected() {
198        // K_{1,2} as directed
199        let mut g = Graph::new(3, true).unwrap();
200        g.add_edge(0, 1).unwrap();
201        g.add_edge(0, 2).unwrap();
202        assert!(is_complete_bipartite(&g).unwrap());
203    }
204}