rust_igraph/algorithms/connectivity/
is_biconnected.rs1use crate::core::{Graph, IgraphResult};
25
26pub fn is_biconnected(graph: &Graph) -> IgraphResult<bool> {
50 let n = graph.vcount();
51 if n < 2 {
54 return Ok(false);
55 }
56 if n == 2 {
60 let nbrs = graph.neighbors(0)?;
61 return Ok(nbrs.contains(&1));
62 }
63 let cc = super::components::connected_components(graph)?;
65 if cc.count != 1 {
66 return Ok(false);
67 }
68 let aps = super::articulation::articulation_points(graph)?;
69 Ok(aps.is_empty())
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn empty_graph_is_not_biconnected() {
78 let g = Graph::with_vertices(0);
79 assert!(!is_biconnected(&g).unwrap());
80 }
81
82 #[test]
83 fn singleton_is_not_biconnected() {
84 let g = Graph::with_vertices(1);
85 assert!(!is_biconnected(&g).unwrap());
86 }
87
88 #[test]
89 fn two_vertices_no_edge_is_not_biconnected() {
90 let g = Graph::with_vertices(2);
91 assert!(!is_biconnected(&g).unwrap());
92 }
93
94 #[test]
95 fn two_vertices_one_edge_is_biconnected() {
96 let mut g = Graph::with_vertices(2);
97 g.add_edge(0, 1).unwrap();
98 assert!(is_biconnected(&g).unwrap());
99 }
100
101 #[test]
102 fn triangle_is_biconnected() {
103 let mut g = Graph::with_vertices(3);
104 g.add_edge(0, 1).unwrap();
105 g.add_edge(1, 2).unwrap();
106 g.add_edge(2, 0).unwrap();
107 assert!(is_biconnected(&g).unwrap());
108 }
109
110 #[test]
111 fn path_3_is_not_biconnected() {
112 let mut g = Graph::with_vertices(3);
114 g.add_edge(0, 1).unwrap();
115 g.add_edge(1, 2).unwrap();
116 assert!(!is_biconnected(&g).unwrap());
117 }
118
119 #[test]
120 fn cycle_4_is_biconnected() {
121 let mut g = Graph::with_vertices(4);
122 for i in 0..4u32 {
123 g.add_edge(i, (i + 1) % 4).unwrap();
124 }
125 assert!(is_biconnected(&g).unwrap());
126 }
127
128 #[test]
129 fn k4_complete_is_biconnected() {
130 let mut g = Graph::with_vertices(4);
131 for u in 0..4u32 {
132 for v in (u + 1)..4 {
133 g.add_edge(u, v).unwrap();
134 }
135 }
136 assert!(is_biconnected(&g).unwrap());
137 }
138
139 #[test]
140 fn disconnected_graph_is_not_biconnected() {
141 let mut g = Graph::with_vertices(4);
142 g.add_edge(0, 1).unwrap();
143 g.add_edge(2, 3).unwrap();
144 assert!(!is_biconnected(&g).unwrap());
145 }
146
147 #[test]
148 fn star_is_not_biconnected() {
149 let mut g = Graph::with_vertices(4);
151 for v in 1..4 {
152 g.add_edge(0, v).unwrap();
153 }
154 assert!(!is_biconnected(&g).unwrap());
155 }
156
157 #[test]
158 fn cycle_with_pendant_is_not_biconnected() {
159 let mut g = Graph::with_vertices(4);
161 g.add_edge(0, 1).unwrap();
162 g.add_edge(1, 2).unwrap();
163 g.add_edge(2, 0).unwrap();
164 g.add_edge(2, 3).unwrap();
165 assert!(!is_biconnected(&g).unwrap());
166 }
167
168 #[test]
169 fn isolated_extra_vertex_breaks_biconnected() {
170 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, 0).unwrap();
175 assert!(!is_biconnected(&g).unwrap());
176 }
177}