rust_igraph/algorithms/properties/
is_geodetic.rs1use std::collections::VecDeque;
14
15use crate::core::{Graph, IgraphResult};
16
17pub fn is_geodetic(graph: &Graph) -> IgraphResult<bool> {
50 let n = graph.vcount();
51 if n <= 2 {
52 return Ok(true);
53 }
54
55 let n_usize = n as usize;
56 let mut dist = vec![u32::MAX; n_usize];
57 let mut nrgeo = vec![0u32; n_usize];
58 let mut queue: VecDeque<u32> = VecDeque::new();
59
60 for source in 0..n {
61 dist.fill(u32::MAX);
62 nrgeo.fill(0);
63
64 dist[source as usize] = 0;
65 nrgeo[source as usize] = 1;
66 queue.clear();
67 queue.push_back(source);
68
69 while let Some(v) = queue.pop_front() {
70 let next_dist = dist[v as usize].saturating_add(1);
71 let neighbors = graph.neighbors(v)?;
72
73 for w in neighbors {
74 let w_idx = w as usize;
75 if dist[w_idx] == u32::MAX {
76 dist[w_idx] = next_dist;
77 nrgeo[w_idx] = 1;
78 queue.push_back(w);
79 } else if dist[w_idx] == next_dist {
80 nrgeo[w_idx] = nrgeo[w_idx].saturating_add(1);
81 if nrgeo[w_idx] > 1 {
82 return Ok(false);
83 }
84 }
85 }
86 }
87 }
88
89 Ok(true)
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn empty_graph() {
98 let g = Graph::with_vertices(0);
99 assert!(is_geodetic(&g).unwrap());
100 }
101
102 #[test]
103 fn single_vertex() {
104 let g = Graph::with_vertices(1);
105 assert!(is_geodetic(&g).unwrap());
106 }
107
108 #[test]
109 fn single_edge() {
110 let mut g = Graph::with_vertices(2);
111 g.add_edge(0, 1).unwrap();
112 assert!(is_geodetic(&g).unwrap());
113 }
114
115 #[test]
116 fn path_is_geodetic() {
117 let mut g = Graph::with_vertices(5);
118 g.add_edge(0, 1).unwrap();
119 g.add_edge(1, 2).unwrap();
120 g.add_edge(2, 3).unwrap();
121 g.add_edge(3, 4).unwrap();
122 assert!(is_geodetic(&g).unwrap());
123 }
124
125 #[test]
126 fn tree_is_geodetic() {
127 let mut g = Graph::with_vertices(7);
128 g.add_edge(0, 1).unwrap();
129 g.add_edge(0, 2).unwrap();
130 g.add_edge(1, 3).unwrap();
131 g.add_edge(1, 4).unwrap();
132 g.add_edge(2, 5).unwrap();
133 g.add_edge(2, 6).unwrap();
134 assert!(is_geodetic(&g).unwrap());
135 }
136
137 #[test]
138 fn triangle_is_geodetic() {
139 let mut g = Graph::with_vertices(3);
141 g.add_edge(0, 1).unwrap();
142 g.add_edge(1, 2).unwrap();
143 g.add_edge(2, 0).unwrap();
144 assert!(is_geodetic(&g).unwrap());
145 }
146
147 #[test]
148 fn k4_is_geodetic() {
149 let mut g = Graph::with_vertices(4);
151 for u in 0..4u32 {
152 for v in (u + 1)..4 {
153 g.add_edge(u, v).unwrap();
154 }
155 }
156 assert!(is_geodetic(&g).unwrap());
157 }
158
159 #[test]
160 fn cycle_4_not_geodetic() {
161 let mut g = Graph::with_vertices(4);
163 g.add_edge(0, 1).unwrap();
164 g.add_edge(1, 2).unwrap();
165 g.add_edge(2, 3).unwrap();
166 g.add_edge(3, 0).unwrap();
167 assert!(!is_geodetic(&g).unwrap());
168 }
169
170 #[test]
171 fn cycle_5_is_geodetic() {
172 let mut g = Graph::with_vertices(5);
175 g.add_edge(0, 1).unwrap();
176 g.add_edge(1, 2).unwrap();
177 g.add_edge(2, 3).unwrap();
178 g.add_edge(3, 4).unwrap();
179 g.add_edge(4, 0).unwrap();
180 assert!(is_geodetic(&g).unwrap());
181 }
182
183 #[test]
184 fn cycle_6_not_geodetic() {
185 let mut g = Graph::with_vertices(6);
187 g.add_edge(0, 1).unwrap();
188 g.add_edge(1, 2).unwrap();
189 g.add_edge(2, 3).unwrap();
190 g.add_edge(3, 4).unwrap();
191 g.add_edge(4, 5).unwrap();
192 g.add_edge(5, 0).unwrap();
193 assert!(!is_geodetic(&g).unwrap());
194 }
195
196 #[test]
197 fn cycle_3_is_geodetic() {
198 let mut g = Graph::with_vertices(3);
200 g.add_edge(0, 1).unwrap();
201 g.add_edge(1, 2).unwrap();
202 g.add_edge(2, 0).unwrap();
203 assert!(is_geodetic(&g).unwrap());
204 }
205
206 #[test]
207 fn star_is_geodetic() {
208 let mut g = Graph::with_vertices(5);
209 for i in 1..5u32 {
210 g.add_edge(0, i).unwrap();
211 }
212 assert!(is_geodetic(&g).unwrap());
213 }
214
215 #[test]
216 fn two_triangles_sharing_vertex_is_geodetic() {
217 let mut g = Graph::with_vertices(5);
219 g.add_edge(0, 1).unwrap();
220 g.add_edge(1, 2).unwrap();
221 g.add_edge(2, 0).unwrap();
222 g.add_edge(2, 3).unwrap();
223 g.add_edge(3, 4).unwrap();
224 g.add_edge(4, 2).unwrap();
225 assert!(is_geodetic(&g).unwrap());
226 }
227
228 #[test]
229 fn disconnected_trees_geodetic() {
230 let mut g = Graph::with_vertices(6);
231 g.add_edge(0, 1).unwrap();
232 g.add_edge(1, 2).unwrap();
233 g.add_edge(3, 4).unwrap();
234 g.add_edge(4, 5).unwrap();
235 assert!(is_geodetic(&g).unwrap());
236 }
237
238 #[test]
239 fn edgeless_is_geodetic() {
240 let g = Graph::with_vertices(5);
241 assert!(is_geodetic(&g).unwrap());
242 }
243
244 #[test]
245 fn directed_path_geodetic() {
246 let mut g = Graph::new(4, true).unwrap();
247 g.add_edge(0, 1).unwrap();
248 g.add_edge(1, 2).unwrap();
249 g.add_edge(2, 3).unwrap();
250 assert!(is_geodetic(&g).unwrap());
251 }
252
253 #[test]
254 fn directed_diamond_not_geodetic() {
255 let mut g = Graph::new(4, true).unwrap();
257 g.add_edge(0, 1).unwrap();
258 g.add_edge(0, 2).unwrap();
259 g.add_edge(1, 3).unwrap();
260 g.add_edge(2, 3).unwrap();
261 assert!(!is_geodetic(&g).unwrap());
262 }
263
264 #[test]
265 fn k4_minus_edge_not_geodetic() {
266 let mut g = Graph::with_vertices(4);
269 g.add_edge(0, 1).unwrap();
270 g.add_edge(0, 2).unwrap();
271 g.add_edge(0, 3).unwrap();
272 g.add_edge(1, 2).unwrap();
273 g.add_edge(1, 3).unwrap();
274 assert!(!is_geodetic(&g).unwrap());
275 }
276}