use crate::core::{Graph, IgraphResult};
pub fn is_biconnected(graph: &Graph) -> IgraphResult<bool> {
let n = graph.vcount();
if n < 2 {
return Ok(false);
}
if n == 2 {
let nbrs = graph.neighbors(0)?;
return Ok(nbrs.contains(&1));
}
let cc = super::components::connected_components(graph)?;
if cc.count != 1 {
return Ok(false);
}
let aps = super::articulation::articulation_points(graph)?;
Ok(aps.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_graph_is_not_biconnected() {
let g = Graph::with_vertices(0);
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn singleton_is_not_biconnected() {
let g = Graph::with_vertices(1);
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn two_vertices_no_edge_is_not_biconnected() {
let g = Graph::with_vertices(2);
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn two_vertices_one_edge_is_biconnected() {
let mut g = Graph::with_vertices(2);
g.add_edge(0, 1).unwrap();
assert!(is_biconnected(&g).unwrap());
}
#[test]
fn triangle_is_biconnected() {
let mut g = Graph::with_vertices(3);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 0).unwrap();
assert!(is_biconnected(&g).unwrap());
}
#[test]
fn path_3_is_not_biconnected() {
let mut g = Graph::with_vertices(3);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn cycle_4_is_biconnected() {
let mut g = Graph::with_vertices(4);
for i in 0..4u32 {
g.add_edge(i, (i + 1) % 4).unwrap();
}
assert!(is_biconnected(&g).unwrap());
}
#[test]
fn k4_complete_is_biconnected() {
let mut g = Graph::with_vertices(4);
for u in 0..4u32 {
for v in (u + 1)..4 {
g.add_edge(u, v).unwrap();
}
}
assert!(is_biconnected(&g).unwrap());
}
#[test]
fn disconnected_graph_is_not_biconnected() {
let mut g = Graph::with_vertices(4);
g.add_edge(0, 1).unwrap();
g.add_edge(2, 3).unwrap();
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn star_is_not_biconnected() {
let mut g = Graph::with_vertices(4);
for v in 1..4 {
g.add_edge(0, v).unwrap();
}
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn cycle_with_pendant_is_not_biconnected() {
let mut g = Graph::with_vertices(4);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 0).unwrap();
g.add_edge(2, 3).unwrap();
assert!(!is_biconnected(&g).unwrap());
}
#[test]
fn isolated_extra_vertex_breaks_biconnected() {
let mut g = Graph::with_vertices(4);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 0).unwrap();
assert!(!is_biconnected(&g).unwrap());
}
}