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