1use std::collections::VecDeque;
11
12use crate::core::{Graph, IgraphResult, VertexId};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct BfsTree {
18 pub order: Vec<VertexId>,
20 pub distances: Vec<Option<u32>>,
23 pub parents: Vec<Option<VertexId>>,
26}
27
28pub fn bfs_tree(graph: &Graph, root: VertexId) -> IgraphResult<BfsTree> {
59 graph.neighbors(root)?; let n = graph.vcount();
62 let n_us = n as usize;
63 let mut distances: Vec<Option<u32>> = vec![None; n_us];
64 let mut parents: Vec<Option<VertexId>> = vec![None; n_us];
65 let mut order: Vec<VertexId> = Vec::with_capacity(n_us);
66 let mut queue: VecDeque<VertexId> = VecDeque::new();
67
68 distances[root as usize] = Some(0);
69 order.push(root);
70 queue.push_back(root);
71
72 while let Some(v) = queue.pop_front() {
73 let v_dist = distances[v as usize].expect("dequeued vertex is visited");
74 let next_dist = v_dist
75 .checked_add(1)
76 .ok_or(crate::core::IgraphError::Internal(
77 "BFS distance overflow (graph diameter exceeds u32::MAX)",
78 ))?;
79 for w in graph.neighbors(v)? {
80 if distances[w as usize].is_none() {
81 distances[w as usize] = Some(next_dist);
82 parents[w as usize] = Some(v);
83 order.push(w);
84 queue.push_back(w);
85 }
86 }
87 }
88
89 Ok(BfsTree {
90 order,
91 distances,
92 parents,
93 })
94}
95
96pub fn bfs(graph: &Graph, root: VertexId) -> IgraphResult<Vec<VertexId>> {
118 graph.neighbors(root)?;
120
121 let n = graph.vcount();
122 let mut visited = vec![false; n as usize];
123 let mut order: Vec<VertexId> = Vec::with_capacity(n as usize);
124 let mut queue: VecDeque<VertexId> = VecDeque::new();
125
126 visited[root as usize] = true;
127 order.push(root);
128 queue.push_back(root);
129
130 while let Some(v) = queue.pop_front() {
131 for w in graph.neighbors(v)? {
134 if !visited[w as usize] {
135 visited[w as usize] = true;
136 order.push(w);
137 queue.push_back(w);
138 }
139 }
140 }
141
142 Ok(order)
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147pub enum BfsMode {
148 Out,
150 In,
152 All,
154}
155
156#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct BfsSimple {
159 pub order: Vec<VertexId>,
161 pub layers: Vec<usize>,
165 pub parents: Vec<Option<VertexId>>,
170}
171
172pub fn bfs_simple(graph: &Graph, root: VertexId, mode: BfsMode) -> IgraphResult<BfsSimple> {
199 graph.neighbors(root)?; let n = graph.vcount() as usize;
202 let use_mode = if graph.is_directed() {
203 mode
204 } else {
205 BfsMode::All
206 };
207
208 let mut visited = vec![false; n];
209 let mut parents: Vec<Option<VertexId>> = vec![None; n];
210 let mut order: Vec<VertexId> = Vec::with_capacity(n);
211 let mut layers: Vec<usize> = Vec::new();
212
213 let mut queue: VecDeque<(VertexId, u32)> = VecDeque::new();
215 let mut last_layer: Option<u32> = None;
216
217 visited[root as usize] = true;
218 order.push(root);
219 layers.push(0); queue.push_back((root, 0));
221
222 while let Some((v, dist)) = queue.pop_front() {
223 let neis = match use_mode {
224 BfsMode::Out => graph.out_neighbors_vec(v)?,
225 BfsMode::In => graph.in_neighbors_vec(v)?,
226 BfsMode::All => {
227 if graph.is_directed() {
228 let mut combined = graph.out_neighbors_vec(v)?;
229 combined.extend(graph.in_neighbors_vec(v)?);
230 combined
231 } else {
232 graph.neighbors(v)?
233 }
234 }
235 };
236 let next_dist = dist
237 .checked_add(1)
238 .ok_or(crate::core::IgraphError::Internal(
239 "BFS distance overflow (graph diameter exceeds u32::MAX)",
240 ))?;
241 for w in neis {
242 if !visited[w as usize] {
243 visited[w as usize] = true;
244 parents[w as usize] = Some(v);
245 queue.push_back((w, next_dist));
246 if last_layer != Some(next_dist) {
247 layers.push(order.len());
248 last_layer = Some(next_dist);
249 }
250 order.push(w);
251 }
252 }
253 }
254
255 layers.push(order.len());
257
258 Ok(BfsSimple {
259 order,
260 layers,
261 parents,
262 })
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 fn path_graph(n: u32) -> Graph {
270 let mut g = Graph::with_vertices(n);
271 for i in 0..n.saturating_sub(1) {
272 g.add_edge(i, i + 1).unwrap();
273 }
274 g
275 }
276
277 #[test]
278 fn empty_graph_errors_on_any_root() {
279 let g = Graph::with_vertices(0);
280 let err = bfs(&g, 0).unwrap_err();
281 assert!(matches!(
282 err,
283 crate::core::IgraphError::VertexOutOfRange { id: 0, n: 0 }
284 ));
285 }
286
287 #[test]
288 fn single_vertex_visits_self() {
289 let g = Graph::with_vertices(1);
290 assert_eq!(bfs(&g, 0).unwrap(), vec![0]);
291 }
292
293 #[test]
294 fn path_visits_in_order() {
295 let g = path_graph(5);
296 assert_eq!(bfs(&g, 0).unwrap(), vec![0, 1, 2, 3, 4]);
297 }
298
299 #[test]
300 fn bfs_layers_breadth_first_not_depth_first() {
301 let mut g = Graph::with_vertices(4);
305 g.add_edge(0, 1).unwrap();
306 g.add_edge(0, 2).unwrap();
307 g.add_edge(1, 3).unwrap();
308 let order = bfs(&g, 0).unwrap();
310 assert_eq!(order[0], 0);
311 let pos_3 = order.iter().position(|&x| x == 3).unwrap();
312 let pos_1 = order.iter().position(|&x| x == 1).unwrap();
313 let pos_2 = order.iter().position(|&x| x == 2).unwrap();
314 assert!(pos_3 > pos_1 && pos_3 > pos_2);
315 }
316
317 #[test]
318 fn unreachable_vertex_excluded() {
319 let mut g = Graph::with_vertices(3);
320 g.add_edge(0, 1).unwrap();
321 let order = bfs(&g, 0).unwrap();
323 assert_eq!(order, vec![0, 1]);
324 }
325
326 #[test]
327 fn invalid_root_errors() {
328 let g = Graph::with_vertices(2);
329 let err = bfs(&g, 5).unwrap_err();
330 match err {
331 crate::core::IgraphError::VertexOutOfRange { id, n } => {
332 assert_eq!(id, 5);
333 assert_eq!(n, 2);
334 }
335 other => panic!("unexpected error: {other:?}"),
336 }
337 }
338
339 #[test]
340 fn bfs_tree_returns_full_state_for_a_tree() {
341 let mut g = Graph::with_vertices(4);
343 g.add_edge(0, 1).unwrap();
344 g.add_edge(0, 2).unwrap();
345 g.add_edge(0, 3).unwrap();
346 let r = bfs_tree(&g, 0).unwrap();
347 assert_eq!(r.order, vec![0, 1, 2, 3]);
348 assert_eq!(r.distances, vec![Some(0), Some(1), Some(1), Some(1)]);
349 assert_eq!(r.parents, vec![None, Some(0), Some(0), Some(0)]);
350 }
351
352 #[test]
353 fn bfs_tree_path_5_is_chain() {
354 let g = path_graph(5);
355 let r = bfs_tree(&g, 0).unwrap();
356 assert_eq!(r.order, vec![0, 1, 2, 3, 4]);
357 assert_eq!(
358 r.distances,
359 vec![Some(0), Some(1), Some(2), Some(3), Some(4)]
360 );
361 assert_eq!(r.parents, vec![None, Some(0), Some(1), Some(2), Some(3)]);
362 }
363
364 #[test]
365 fn bfs_tree_unreachable_vertices_have_none() {
366 let mut g = Graph::with_vertices(4);
367 g.add_edge(0, 1).unwrap();
368 let r = bfs_tree(&g, 0).unwrap();
370 assert_eq!(r.order, vec![0, 1]);
371 assert_eq!(r.distances, vec![Some(0), Some(1), None, None]);
372 assert_eq!(r.parents, vec![None, Some(0), None, None]);
373 }
374
375 #[test]
376 fn bfs_tree_invalid_root_errors() {
377 let g = Graph::with_vertices(3);
378 assert!(bfs_tree(&g, 7).is_err());
379 }
380
381 #[test]
382 fn bfs_tree_directed_uses_out_edges() {
383 let mut g = Graph::new(4, true).unwrap();
385 g.add_edge(0, 1).unwrap();
386 g.add_edge(1, 2).unwrap();
387 g.add_edge(1, 3).unwrap();
388 let r = bfs_tree(&g, 0).unwrap();
389 assert_eq!(r.distances, vec![Some(0), Some(1), Some(2), Some(2)]);
390 assert_eq!(r.parents[0], None);
391 assert_eq!(r.parents[1], Some(0));
392 assert_eq!(r.parents[2], Some(1));
393 assert_eq!(r.parents[3], Some(1));
394 let r2 = bfs_tree(&g, 2).unwrap();
396 assert_eq!(r2.order, vec![2]);
397 }
398
399 #[test]
402 fn bfs_simple_undirected_tree() {
403 let mut g = Graph::with_vertices(4);
409 g.add_edge(0, 1).unwrap();
410 g.add_edge(0, 2).unwrap();
411 g.add_edge(1, 3).unwrap();
412
413 let r = bfs_simple(&g, 0, BfsMode::Out).unwrap();
414 assert_eq!(r.order, vec![0, 1, 2, 3]);
415 assert_eq!(r.layers, vec![0, 1, 3, 4]);
416 assert_eq!(r.parents[0], None);
417 assert_eq!(r.parents[1], Some(0));
418 assert_eq!(r.parents[2], Some(0));
419 assert_eq!(r.parents[3], Some(1));
420 }
421
422 #[test]
423 fn bfs_simple_single_vertex() {
424 let g = Graph::with_vertices(1);
425 let r = bfs_simple(&g, 0, BfsMode::All).unwrap();
426 assert_eq!(r.order, vec![0]);
427 assert_eq!(r.layers, vec![0, 1]);
428 assert_eq!(r.parents, vec![None]);
429 }
430
431 #[test]
432 fn bfs_simple_invalid_root() {
433 let g = Graph::with_vertices(2);
434 assert!(bfs_simple(&g, 5, BfsMode::Out).is_err());
435 }
436
437 #[test]
438 fn bfs_simple_directed_out() {
439 let mut g = Graph::new(4, true).unwrap();
441 g.add_edge(0, 1).unwrap();
442 g.add_edge(1, 2).unwrap();
443 g.add_edge(0, 3).unwrap();
444
445 let r = bfs_simple(&g, 0, BfsMode::Out).unwrap();
446 assert_eq!(r.order, vec![0, 1, 3, 2]);
447 assert_eq!(r.layers, vec![0, 1, 3, 4]);
448 assert_eq!(r.parents[1], Some(0));
449 assert_eq!(r.parents[2], Some(1));
450 assert_eq!(r.parents[3], Some(0));
451 }
452
453 #[test]
454 fn bfs_simple_directed_in() {
455 let mut g = Graph::new(4, true).unwrap();
457 g.add_edge(1, 0).unwrap();
458 g.add_edge(2, 1).unwrap();
459 g.add_edge(3, 0).unwrap();
460
461 let r = bfs_simple(&g, 0, BfsMode::In).unwrap();
462 assert_eq!(r.order, vec![0, 1, 3, 2]);
463 assert_eq!(r.layers, vec![0, 1, 3, 4]);
464 assert_eq!(r.parents[1], Some(0));
465 assert_eq!(r.parents[3], Some(0));
466 assert_eq!(r.parents[2], Some(1));
467 }
468
469 #[test]
470 fn bfs_simple_directed_all() {
471 let mut g = Graph::new(3, true).unwrap();
473 g.add_edge(0, 1).unwrap();
474 g.add_edge(2, 0).unwrap();
475
476 let r = bfs_simple(&g, 0, BfsMode::All).unwrap();
477 assert_eq!(r.order.len(), 3);
478 assert_eq!(r.order[0], 0);
479 assert_eq!(r.layers, vec![0, 1, 3]);
481 }
482
483 #[test]
484 fn bfs_simple_unreachable_vertices() {
485 let mut g = Graph::with_vertices(4);
486 g.add_edge(0, 1).unwrap();
487 let r = bfs_simple(&g, 0, BfsMode::All).unwrap();
489 assert_eq!(r.order, vec![0, 1]);
490 assert_eq!(r.layers, vec![0, 1, 2]);
491 assert_eq!(r.parents[2], None);
492 assert_eq!(r.parents[3], None);
493 }
494
495 #[test]
496 fn bfs_simple_mode_ignored_for_undirected() {
497 let mut g = Graph::with_vertices(3);
498 g.add_edge(0, 1).unwrap();
499 g.add_edge(1, 2).unwrap();
500 let r = bfs_simple(&g, 0, BfsMode::In).unwrap();
502 assert_eq!(r.order, vec![0, 1, 2]);
503 }
504
505 #[test]
506 fn bfs_simple_layers_match_distances() {
507 let g = path_graph(6);
508 let r = bfs_simple(&g, 0, BfsMode::Out).unwrap();
509 assert_eq!(r.layers, vec![0, 1, 2, 3, 4, 5, 6]);
511 for d in 0..6 {
512 let layer_verts = &r.order[r.layers[d]..r.layers[d + 1]];
513 assert_eq!(layer_verts.len(), 1);
514 }
515 }
516}