rust_igraph/algorithms/paths/
distances_all.rs1use std::collections::VecDeque;
10
11use crate::core::{Graph, IgraphError, IgraphResult, VertexId};
12
13pub fn distances_all(graph: &Graph) -> IgraphResult<Vec<Option<u32>>> {
45 let n = graph.vcount();
46 let n_us = n as usize;
47
48 if n == 0 {
49 return Ok(Vec::new());
50 }
51
52 let mut result = vec![
53 None;
54 n_us.checked_mul(n_us).ok_or_else(|| {
55 IgraphError::InvalidArgument("distances_all: n*n overflows usize".into())
56 })?
57 ];
58
59 if graph.is_directed() {
60 let adj = build_out_adj(graph, n_us)?;
61 for src in 0..n {
62 bfs_distances_with_adj(&adj, src, n_us, &mut result);
63 }
64 } else {
65 for src in 0..n {
66 bfs_distances_undirected(graph, src, n_us, &mut result)?;
67 }
68 }
69
70 Ok(result)
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum DistancesMode {
76 Out,
78 In,
80 All,
82}
83
84pub fn distances_all_with_mode(
104 graph: &Graph,
105 mode: DistancesMode,
106) -> IgraphResult<Vec<Option<u32>>> {
107 let n = graph.vcount();
108 let n_us = n as usize;
109
110 if n == 0 {
111 return Ok(Vec::new());
112 }
113
114 let mut result = vec![
115 None;
116 n_us.checked_mul(n_us).ok_or_else(|| {
117 IgraphError::InvalidArgument("distances_all_with_mode: n*n overflows usize".into())
118 })?
119 ];
120
121 if !graph.is_directed() {
122 for src in 0..n {
123 bfs_distances_undirected(graph, src, n_us, &mut result)?;
124 }
125 return Ok(result);
126 }
127
128 let adj = match mode {
129 DistancesMode::Out => build_out_adj(graph, n_us)?,
130 DistancesMode::In => build_in_adj(graph, n_us)?,
131 DistancesMode::All => build_all_adj(graph, n_us)?,
132 };
133
134 for src in 0..n {
135 bfs_distances_with_adj(&adj, src, n_us, &mut result);
136 }
137
138 Ok(result)
139}
140
141fn bfs_distances_undirected(
143 graph: &Graph,
144 source: VertexId,
145 n_us: usize,
146 result: &mut [Option<u32>],
147) -> IgraphResult<()> {
148 let src_us = source as usize;
149 let row_offset = src_us * n_us;
150
151 let mut visited = vec![false; n_us];
152 let mut queue = VecDeque::new();
153
154 visited[src_us] = true;
155 result[row_offset + src_us] = Some(0);
156 queue.push_back((source, 0u32));
157
158 while let Some((cur, dist)) = queue.pop_front() {
159 let next_dist = dist + 1;
160 for nb in graph.neighbors_iter(cur)? {
161 let nb_idx = nb as usize;
162 if !visited[nb_idx] {
163 visited[nb_idx] = true;
164 result[row_offset + nb_idx] = Some(next_dist);
165 queue.push_back((nb, next_dist));
166 }
167 }
168 }
169
170 Ok(())
171}
172
173fn bfs_distances_with_adj(
175 adj: &[Vec<VertexId>],
176 source: VertexId,
177 n_us: usize,
178 result: &mut [Option<u32>],
179) {
180 let src_us = source as usize;
181 let row_offset = src_us * n_us;
182
183 let mut visited = vec![false; n_us];
184 let mut queue = VecDeque::new();
185
186 visited[src_us] = true;
187 result[row_offset + src_us] = Some(0);
188 queue.push_back((source, 0u32));
189
190 while let Some((cur, dist)) = queue.pop_front() {
191 let next_dist = dist + 1;
192 for &nb in &adj[cur as usize] {
193 let nb_idx = nb as usize;
194 if !visited[nb_idx] {
195 visited[nb_idx] = true;
196 result[row_offset + nb_idx] = Some(next_dist);
197 queue.push_back((nb, next_dist));
198 }
199 }
200 }
201}
202
203fn build_out_adj(graph: &Graph, n_us: usize) -> IgraphResult<Vec<Vec<VertexId>>> {
204 let m =
205 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
206 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
207 for eid in 0..m {
208 let (from, to) = graph.edge(eid)?;
209 adj[from as usize].push(to);
210 }
211 Ok(adj)
212}
213
214fn build_in_adj(graph: &Graph, n_us: usize) -> IgraphResult<Vec<Vec<VertexId>>> {
215 let m =
216 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
217 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
218 for eid in 0..m {
219 let (from, to) = graph.edge(eid)?;
220 adj[to as usize].push(from);
221 }
222 Ok(adj)
223}
224
225fn build_all_adj(graph: &Graph, n_us: usize) -> IgraphResult<Vec<Vec<VertexId>>> {
226 let m =
227 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
228 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
229 for eid in 0..m {
230 let (from, to) = graph.edge(eid)?;
231 adj[from as usize].push(to);
232 if from != to {
233 adj[to as usize].push(from);
234 }
235 }
236 Ok(adj)
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn empty_graph() {
245 let g = Graph::with_vertices(0);
246 let d = distances_all(&g).unwrap();
247 assert!(d.is_empty());
248 }
249
250 #[test]
251 fn singleton() {
252 let g = Graph::with_vertices(1);
253 let d = distances_all(&g).unwrap();
254 assert_eq!(d, vec![Some(0)]);
255 }
256
257 #[test]
258 fn path_graph() {
259 let mut g = Graph::with_vertices(4);
260 g.add_edge(0, 1).unwrap();
261 g.add_edge(1, 2).unwrap();
262 g.add_edge(2, 3).unwrap();
263 let d = distances_all(&g).unwrap();
264 let n = 4usize;
265 assert_eq!(d[0], Some(0)); assert_eq!(d[1], Some(1)); assert_eq!(d[2], Some(2)); assert_eq!(d[3], Some(3)); assert_eq!(d[3 * n], Some(3)); assert_eq!(d[n + 3], Some(2)); }
272
273 #[test]
274 fn triangle() {
275 let mut g = Graph::with_vertices(3);
276 g.add_edge(0, 1).unwrap();
277 g.add_edge(1, 2).unwrap();
278 g.add_edge(2, 0).unwrap();
279 let d = distances_all(&g).unwrap();
280 let n = 3;
281 for i in 0..n {
282 assert_eq!(d[i * n + i], Some(0));
283 for j in 0..n {
284 if i != j {
285 assert_eq!(d[i * n + j], Some(1));
286 }
287 }
288 }
289 }
290
291 #[test]
292 fn two_components() {
293 let mut g = Graph::with_vertices(4);
294 g.add_edge(0, 1).unwrap();
295 g.add_edge(2, 3).unwrap();
296 let d = distances_all(&g).unwrap();
297 let n = 4usize;
298 assert_eq!(d[1], Some(1)); assert_eq!(d[2 * n + 3], Some(1));
300 assert_eq!(d[2], None); assert_eq!(d[n + 3], None); }
303
304 #[test]
305 fn cycle_5() {
306 let mut g = Graph::with_vertices(5);
307 g.add_edge(0, 1).unwrap();
308 g.add_edge(1, 2).unwrap();
309 g.add_edge(2, 3).unwrap();
310 g.add_edge(3, 4).unwrap();
311 g.add_edge(4, 0).unwrap();
312 let d = distances_all(&g).unwrap();
313 assert_eq!(d[0], Some(0));
315 assert_eq!(d[1], Some(1));
316 assert_eq!(d[2], Some(2));
317 assert_eq!(d[3], Some(2));
318 assert_eq!(d[4], Some(1));
319 }
320
321 #[test]
322 fn directed_out() {
323 let mut g = Graph::new(3, true).unwrap();
324 g.add_edge(0, 1).unwrap();
325 g.add_edge(1, 2).unwrap();
326 let d = distances_all(&g).unwrap();
327 let n = 3usize;
328 assert_eq!(d[2], Some(2)); assert_eq!(d[2 * n], None); assert_eq!(d[n], None); }
332
333 #[test]
334 fn directed_in_mode() {
335 let mut g = Graph::new(3, true).unwrap();
336 g.add_edge(0, 1).unwrap();
337 g.add_edge(1, 2).unwrap();
338 let d = distances_all_with_mode(&g, DistancesMode::In).unwrap();
339 let n = 3usize;
340 assert_eq!(d[2 * n + 1], Some(1));
342 assert_eq!(d[2 * n], Some(2)); assert_eq!(d[1], None); }
345
346 #[test]
347 fn directed_all_mode() {
348 let mut g = Graph::new(3, true).unwrap();
349 g.add_edge(0, 1).unwrap();
350 g.add_edge(1, 2).unwrap();
351 let d = distances_all_with_mode(&g, DistancesMode::All).unwrap();
352 let n = 3;
353 assert_eq!(d[2], Some(2));
355 assert_eq!(d[2 * n], Some(2));
356 }
357
358 #[test]
359 fn symmetric_undirected() {
360 let mut g = Graph::with_vertices(5);
361 g.add_edge(0, 1).unwrap();
362 g.add_edge(1, 2).unwrap();
363 g.add_edge(2, 3).unwrap();
364 g.add_edge(3, 4).unwrap();
365 let d = distances_all(&g).unwrap();
366 let n = 5;
367 for i in 0..n {
368 for j in 0..n {
369 assert_eq!(d[i * n + j], d[j * n + i], "not symmetric at ({i},{j})");
370 }
371 }
372 }
373
374 #[test]
375 fn isolated_vertices() {
376 let g = Graph::with_vertices(3);
377 let d = distances_all(&g).unwrap();
378 let n = 3;
379 for i in 0..n {
380 assert_eq!(d[i * n + i], Some(0));
381 for j in 0..n {
382 if i != j {
383 assert_eq!(d[i * n + j], None);
384 }
385 }
386 }
387 }
388
389 #[test]
390 fn oracle_star() {
391 let mut g = Graph::with_vertices(4);
394 g.add_edge(0, 1).unwrap();
395 g.add_edge(0, 2).unwrap();
396 g.add_edge(0, 3).unwrap();
397 let d = distances_all(&g).unwrap();
398 let n = 4;
399 for item in d.iter().take(4).skip(1) {
401 assert_eq!(*item, Some(1));
402 }
403 assert_eq!(d[n + 2], Some(2));
405 assert_eq!(d[n + 3], Some(2));
406 assert_eq!(d[2 * n + 3], Some(2));
407 }
408}