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 neighbors = graph.neighbors(cur)?;
160 let next_dist = dist + 1;
161 for &nb in &neighbors {
162 let nb_idx = nb as usize;
163 if !visited[nb_idx] {
164 visited[nb_idx] = true;
165 result[row_offset + nb_idx] = Some(next_dist);
166 queue.push_back((nb, next_dist));
167 }
168 }
169 }
170
171 Ok(())
172}
173
174fn bfs_distances_with_adj(
176 adj: &[Vec<VertexId>],
177 source: VertexId,
178 n_us: usize,
179 result: &mut [Option<u32>],
180) {
181 let src_us = source as usize;
182 let row_offset = src_us * n_us;
183
184 let mut visited = vec![false; n_us];
185 let mut queue = VecDeque::new();
186
187 visited[src_us] = true;
188 result[row_offset + src_us] = Some(0);
189 queue.push_back((source, 0u32));
190
191 while let Some((cur, dist)) = queue.pop_front() {
192 let next_dist = dist + 1;
193 for &nb in &adj[cur as usize] {
194 let nb_idx = nb as usize;
195 if !visited[nb_idx] {
196 visited[nb_idx] = true;
197 result[row_offset + nb_idx] = Some(next_dist);
198 queue.push_back((nb, next_dist));
199 }
200 }
201 }
202}
203
204fn build_out_adj(graph: &Graph, n_us: usize) -> IgraphResult<Vec<Vec<VertexId>>> {
205 let m =
206 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
207 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
208 for eid in 0..m {
209 let (from, to) = graph.edge(eid)?;
210 adj[from as usize].push(to);
211 }
212 Ok(adj)
213}
214
215fn build_in_adj(graph: &Graph, n_us: usize) -> IgraphResult<Vec<Vec<VertexId>>> {
216 let m =
217 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
218 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
219 for eid in 0..m {
220 let (from, to) = graph.edge(eid)?;
221 adj[to as usize].push(from);
222 }
223 Ok(adj)
224}
225
226fn build_all_adj(graph: &Graph, n_us: usize) -> IgraphResult<Vec<Vec<VertexId>>> {
227 let m =
228 u32::try_from(graph.ecount()).map_err(|_| IgraphError::Internal("ecount overflows u32"))?;
229 let mut adj: Vec<Vec<VertexId>> = vec![Vec::new(); n_us];
230 for eid in 0..m {
231 let (from, to) = graph.edge(eid)?;
232 adj[from as usize].push(to);
233 if from != to {
234 adj[to as usize].push(from);
235 }
236 }
237 Ok(adj)
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn empty_graph() {
246 let g = Graph::with_vertices(0);
247 let d = distances_all(&g).unwrap();
248 assert!(d.is_empty());
249 }
250
251 #[test]
252 fn singleton() {
253 let g = Graph::with_vertices(1);
254 let d = distances_all(&g).unwrap();
255 assert_eq!(d, vec![Some(0)]);
256 }
257
258 #[test]
259 fn path_graph() {
260 let mut g = Graph::with_vertices(4);
261 g.add_edge(0, 1).unwrap();
262 g.add_edge(1, 2).unwrap();
263 g.add_edge(2, 3).unwrap();
264 let d = distances_all(&g).unwrap();
265 let n = 4usize;
266 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)); }
273
274 #[test]
275 fn triangle() {
276 let mut g = Graph::with_vertices(3);
277 g.add_edge(0, 1).unwrap();
278 g.add_edge(1, 2).unwrap();
279 g.add_edge(2, 0).unwrap();
280 let d = distances_all(&g).unwrap();
281 let n = 3;
282 for i in 0..n {
283 assert_eq!(d[i * n + i], Some(0));
284 for j in 0..n {
285 if i != j {
286 assert_eq!(d[i * n + j], Some(1));
287 }
288 }
289 }
290 }
291
292 #[test]
293 fn two_components() {
294 let mut g = Graph::with_vertices(4);
295 g.add_edge(0, 1).unwrap();
296 g.add_edge(2, 3).unwrap();
297 let d = distances_all(&g).unwrap();
298 let n = 4usize;
299 assert_eq!(d[1], Some(1)); assert_eq!(d[2 * n + 3], Some(1));
301 assert_eq!(d[2], None); assert_eq!(d[n + 3], None); }
304
305 #[test]
306 fn cycle_5() {
307 let mut g = Graph::with_vertices(5);
308 g.add_edge(0, 1).unwrap();
309 g.add_edge(1, 2).unwrap();
310 g.add_edge(2, 3).unwrap();
311 g.add_edge(3, 4).unwrap();
312 g.add_edge(4, 0).unwrap();
313 let d = distances_all(&g).unwrap();
314 assert_eq!(d[0], Some(0));
316 assert_eq!(d[1], Some(1));
317 assert_eq!(d[2], Some(2));
318 assert_eq!(d[3], Some(2));
319 assert_eq!(d[4], Some(1));
320 }
321
322 #[test]
323 fn directed_out() {
324 let mut g = Graph::new(3, true).unwrap();
325 g.add_edge(0, 1).unwrap();
326 g.add_edge(1, 2).unwrap();
327 let d = distances_all(&g).unwrap();
328 let n = 3usize;
329 assert_eq!(d[2], Some(2)); assert_eq!(d[2 * n], None); assert_eq!(d[n], None); }
333
334 #[test]
335 fn directed_in_mode() {
336 let mut g = Graph::new(3, true).unwrap();
337 g.add_edge(0, 1).unwrap();
338 g.add_edge(1, 2).unwrap();
339 let d = distances_all_with_mode(&g, DistancesMode::In).unwrap();
340 let n = 3usize;
341 assert_eq!(d[2 * n + 1], Some(1));
343 assert_eq!(d[2 * n], Some(2)); assert_eq!(d[1], None); }
346
347 #[test]
348 fn directed_all_mode() {
349 let mut g = Graph::new(3, true).unwrap();
350 g.add_edge(0, 1).unwrap();
351 g.add_edge(1, 2).unwrap();
352 let d = distances_all_with_mode(&g, DistancesMode::All).unwrap();
353 let n = 3;
354 assert_eq!(d[2], Some(2));
356 assert_eq!(d[2 * n], Some(2));
357 }
358
359 #[test]
360 fn symmetric_undirected() {
361 let mut g = Graph::with_vertices(5);
362 g.add_edge(0, 1).unwrap();
363 g.add_edge(1, 2).unwrap();
364 g.add_edge(2, 3).unwrap();
365 g.add_edge(3, 4).unwrap();
366 let d = distances_all(&g).unwrap();
367 let n = 5;
368 for i in 0..n {
369 for j in 0..n {
370 assert_eq!(d[i * n + j], d[j * n + i], "not symmetric at ({i},{j})");
371 }
372 }
373 }
374
375 #[test]
376 fn isolated_vertices() {
377 let g = Graph::with_vertices(3);
378 let d = distances_all(&g).unwrap();
379 let n = 3;
380 for i in 0..n {
381 assert_eq!(d[i * n + i], Some(0));
382 for j in 0..n {
383 if i != j {
384 assert_eq!(d[i * n + j], None);
385 }
386 }
387 }
388 }
389
390 #[test]
391 fn oracle_star() {
392 let mut g = Graph::with_vertices(4);
395 g.add_edge(0, 1).unwrap();
396 g.add_edge(0, 2).unwrap();
397 g.add_edge(0, 3).unwrap();
398 let d = distances_all(&g).unwrap();
399 let n = 4;
400 for item in d.iter().take(4).skip(1) {
402 assert_eq!(*item, Some(1));
403 }
404 assert_eq!(d[n + 2], Some(2));
406 assert_eq!(d[n + 3], Some(2));
407 assert_eq!(d[2 * n + 3], Some(2));
408 }
409}