rust_igraph/algorithms/paths/
distances.rs1use std::collections::VecDeque;
18
19use crate::core::{Graph, IgraphResult, VertexId};
20
21pub fn distances(graph: &Graph, source: VertexId) -> IgraphResult<Vec<Option<u32>>> {
48 let n = graph.vcount();
49 if n == 0 {
50 return Ok(Vec::new());
51 }
52 graph.neighbors_iter(source)?; let n_us = n as usize;
55 let mut dist: Vec<Option<u32>> = vec![None; n_us];
56 let mut queue: VecDeque<VertexId> = VecDeque::new();
57
58 dist[source as usize] = Some(0);
59 queue.push_back(source);
60
61 while let Some(v) = queue.pop_front() {
62 let next = dist[v as usize]
63 .ok_or(crate::core::IgraphError::Internal(
64 "dequeued vertex has no distance",
65 ))?
66 .checked_add(1)
67 .ok_or(crate::core::IgraphError::Internal(
68 "distance overflow (graph diameter exceeds u32::MAX)",
69 ))?;
70 for w in graph.neighbors_iter(v)? {
71 if dist[w as usize].is_none() {
72 dist[w as usize] = Some(next);
73 queue.push_back(w);
74 }
75 }
76 }
77
78 Ok(dist)
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn empty_graph_yields_empty_distances() {
87 let g = Graph::with_vertices(0);
88 let d = distances(&g, 0);
89 assert_eq!(d.unwrap(), Vec::<Option<u32>>::new());
93 }
94
95 #[test]
96 fn single_vertex_distance_to_self_is_zero() {
97 let g = Graph::with_vertices(1);
98 let d = distances(&g, 0).unwrap();
99 assert_eq!(d, vec![Some(0)]);
100 }
101
102 #[test]
103 fn invalid_source_errors() {
104 let g = Graph::with_vertices(3);
105 let err = distances(&g, 5);
106 assert!(err.is_err(), "expected error for source >= vcount");
107 }
108
109 #[test]
110 fn path_distances_increase_by_one() {
111 let mut g = Graph::with_vertices(5);
113 for i in 0..4 {
114 g.add_edge(i, i + 1).unwrap();
115 }
116 let d = distances(&g, 0).unwrap();
117 assert_eq!(d, vec![Some(0), Some(1), Some(2), Some(3), Some(4)]);
118 }
119
120 #[test]
121 fn isolated_components_are_unreachable() {
122 let mut g = Graph::with_vertices(5);
124 g.add_edge(0, 1).unwrap();
125 g.add_edge(1, 2).unwrap();
126 g.add_edge(3, 4).unwrap();
127 let d = distances(&g, 0).unwrap();
128 assert_eq!(d, vec![Some(0), Some(1), Some(2), None, None]);
129 }
130
131 #[test]
132 fn self_loop_does_not_affect_distance() {
133 let mut g = Graph::with_vertices(2);
135 g.add_edge(0, 0).unwrap();
136 g.add_edge(0, 1).unwrap();
137 let d = distances(&g, 0).unwrap();
138 assert_eq!(d, vec![Some(0), Some(1)]);
139 }
140
141 #[test]
142 fn parallel_edges_do_not_affect_distance() {
143 let mut g = Graph::with_vertices(2);
145 g.add_edge(0, 1).unwrap();
146 g.add_edge(0, 1).unwrap();
147 g.add_edge(0, 1).unwrap();
148 let d = distances(&g, 0).unwrap();
149 assert_eq!(d, vec![Some(0), Some(1)]);
150 }
151
152 #[test]
153 fn directed_graph_uses_out_edges() {
154 let mut g = Graph::new(3, true).unwrap();
156 g.add_edge(0, 1).unwrap();
157 g.add_edge(1, 2).unwrap();
158 let d_from_zero = distances(&g, 0).unwrap();
159 assert_eq!(d_from_zero, vec![Some(0), Some(1), Some(2)]);
160 let d_from_two = distances(&g, 2).unwrap();
161 assert_eq!(d_from_two, vec![None, None, Some(0)]);
162 }
163
164 #[test]
165 fn cycle_distances_are_minimum_of_two_directions() {
166 let mut g = Graph::with_vertices(6);
169 for i in 0..5 {
170 g.add_edge(i, i + 1).unwrap();
171 }
172 g.add_edge(5, 0).unwrap();
173 let d = distances(&g, 0).unwrap();
174 assert_eq!(
175 d,
176 vec![Some(0), Some(1), Some(2), Some(3), Some(2), Some(1)]
177 );
178 }
179}