Skip to content

Commit faf64e9

Browse files
authored
Merge pull request #44 from purpleprotocol/dijkstra_api
Added Graph::dijkstra() api
2 parents 567a64c + f0b879a commit faf64e9

6 files changed

Lines changed: 198 additions & 59 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ assert_eq!(graph.edge_count(), 0);
3838
In `Cargo.toml`:
3939
```toml
4040
[dependencies]
41-
graphlib = {version = "*", features = ["no_std"]}
41+
graphlib = { version = "*", features = ["no_std"] }
4242
```
4343

4444
### Contributing

src/graph.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2019 Octavian Oncescu
22

33
use crate::edge::Edge;
4-
use crate::iterators::{Bfs, Dfs, Topo, VertexIter};
4+
use crate::iterators::*;
55
use crate::vertex_id::VertexId;
66
use hashbrown::{HashMap, HashSet};
77

@@ -1209,6 +1209,52 @@ impl<T> Graph<T> {
12091209
Topo::new(self)
12101210
}
12111211

1212+
/// Returns an iterator over the shortest path from the source
1213+
/// vertex to the destination vertex. The iterator will yield
1214+
/// `None` if there is no such path or the provided vertex ids
1215+
/// do not belong to any vertices in the graph.
1216+
/// ## Example
1217+
/// ```rust
1218+
/// #[macro_use] extern crate graphlib;
1219+
/// use graphlib::Graph;
1220+
/// use std::collections::HashSet;
1221+
///
1222+
/// let mut graph: Graph<usize> = Graph::new();
1223+
///
1224+
/// let v1 = graph.add_vertex(1);
1225+
/// let v2 = graph.add_vertex(2);
1226+
/// let v3 = graph.add_vertex(3);
1227+
/// let v4 = graph.add_vertex(4);
1228+
/// let v5 = graph.add_vertex(5);
1229+
/// let v6 = graph.add_vertex(6);
1230+
///
1231+
/// graph.add_edge(&v1, &v2).unwrap();
1232+
/// graph.add_edge(&v2, &v3).unwrap();
1233+
/// graph.add_edge(&v3, &v4).unwrap();
1234+
/// graph.add_edge(&v3, &v5).unwrap();
1235+
/// graph.add_edge(&v5, &v6).unwrap();
1236+
/// graph.add_edge(&v6, &v4).unwrap();
1237+
///
1238+
/// let mut dijkstra = graph.dijkstra(&v1, &v4);
1239+
///
1240+
/// assert_eq!(dijkstra.next(), Some(&v1));
1241+
/// assert_eq!(dijkstra.next(), Some(&v2));
1242+
/// assert_eq!(dijkstra.next(), Some(&v3));
1243+
/// assert_eq!(dijkstra.next(), Some(&v4));
1244+
/// assert_eq!(dijkstra.next(), None);
1245+
/// ```
1246+
pub fn dijkstra<'a>(&'a self, src: &'a VertexId, dest: &'a VertexId) -> VertexIter<'a> {
1247+
if let Some(dijkstra) = Dijkstra::new(&self, src).ok() {
1248+
if let Some(iter) = dijkstra.get_path_to(dest).ok() {
1249+
iter
1250+
} else {
1251+
VertexIter(Box::new(iter::empty()))
1252+
}
1253+
} else {
1254+
VertexIter(Box::new(iter::empty()))
1255+
}
1256+
}
1257+
12121258
#[cfg(feature = "dot")]
12131259
/// Creates a file with the dot representation of the graph.
12141260
/// This method requires the `dot` feature.

src/iterators/dijkstra.rs

Lines changed: 58 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@
22

33
use crate::graph::{Graph, GraphErr};
44
use crate::iterators::vertices::VertexIter;
5+
use crate::iterators::owning_iterator::OwningIterator;
56
use crate::vertex_id::VertexId;
67

78
use hashbrown::HashMap;
89
use hashbrown::HashSet;
910

1011
#[cfg(not(feature = "no_std"))]
11-
use std::{cmp::Ordering, collections::BinaryHeap, f32, fmt::Debug, iter};
12+
use std::{cmp::Ordering, collections::{BinaryHeap, VecDeque}, f32, fmt::Debug, iter};
1213

1314
#[cfg(feature = "no_std")]
1415
extern crate alloc;
1516
#[cfg(feature = "no_std")]
16-
use alloc::collections::binary_heap::BinaryHeap;
17+
use alloc::collections::binary_heap::{BinaryHeap, VecDeque};
1718

1819
#[cfg(feature = "no_std")]
1920
use core::{cmp::Ordering, f32, fmt::Debug, iter};
@@ -38,12 +39,12 @@ impl Ord for VertexMeta {
3839
}
3940
}
4041

41-
#[derive(Debug)]
42+
#[derive(Clone, Debug)]
4243
/// Dijkstra Single-source Shortest Path Iterator
4344
pub struct Dijkstra<'a, T> {
4445
source: &'a VertexId,
4546
iterable: &'a Graph<T>,
46-
iterator: Vec<VertexId>,
47+
iterator: VecDeque<VertexId>,
4748
distances: HashMap<VertexId, f32>,
4849
previous: HashMap<VertexId, Option<VertexId>>,
4950
}
@@ -65,7 +66,7 @@ impl<'a, T> Dijkstra<'a, T> {
6566
let mut instance = Dijkstra {
6667
source: src,
6768
iterable: graph,
68-
iterator: Vec::with_capacity(graph.vertex_count()),
69+
iterator: VecDeque::with_capacity(graph.vertex_count()),
6970
distances: HashMap::with_capacity(graph.vertex_count()),
7071
previous: HashMap::with_capacity(graph.vertex_count()),
7172
};
@@ -88,25 +89,25 @@ impl<'a, T> Dijkstra<'a, T> {
8889
Ok(())
8990
}
9091

91-
pub fn get_path_to(&mut self, vert: &'a VertexId) -> Result<VertexIter, GraphErr> {
92+
pub fn get_path_to(mut self, vert: &'a VertexId) -> Result<VertexIter, GraphErr> {
9293
if self.iterable.fetch(vert).is_none() {
9394
return Err(GraphErr::NoSuchVertex);
9495
}
9596

9697
if self.previous.contains_key(vert) {
97-
let mut curr_vert = Some(vert);
98+
let mut cur_vert = Some(vert);
9899
self.iterator.clear();
99100

100-
while curr_vert.is_some() {
101-
self.iterator.push(*curr_vert.unwrap());
101+
while cur_vert.is_some() {
102+
self.iterator.push_front(*cur_vert.unwrap());
102103

103-
match self.previous.get(curr_vert.unwrap()) {
104-
Some(v) => curr_vert = v.as_ref(),
105-
None => curr_vert = None,
104+
match self.previous.get(cur_vert.unwrap()) {
105+
Some(v) => cur_vert = v.as_ref(),
106+
None => cur_vert = None,
106107
}
107108
}
108109

109-
return Ok(VertexIter(Box::new(self.iterator.iter())));
110+
return Ok(VertexIter(Box::new(OwningIterator::new(self.iterator))));
110111
}
111112

112113
Ok(VertexIter(Box::new(iter::empty())))
@@ -146,20 +147,20 @@ impl<'a, T> Dijkstra<'a, T> {
146147
continue;
147148
}
148149

149-
for neighbour in self.iterable.out_neighbors(&vert_meta.id) {
150-
if !visited.contains(&neighbour) {
150+
for neighbor in self.iterable.out_neighbors(&vert_meta.id) {
151+
if !visited.contains(&neighbor) {
151152
let mut alt_dist = *self.distances.get(&vert_meta.id).unwrap();
152153

153-
if let Some(w) = self.iterable.weight(&vert_meta.id, &neighbour) {
154+
if let Some(w) = self.iterable.weight(&vert_meta.id, &neighbor) {
154155
alt_dist += w;
155156
}
156157

157-
if alt_dist < *self.distances.get(&neighbour).unwrap() {
158-
self.distances.insert(*neighbour, alt_dist);
159-
self.previous.insert(*neighbour, Some(vert_meta.id));
158+
if alt_dist < *self.distances.get(&neighbor).unwrap() {
159+
self.distances.insert(*neighbor, alt_dist);
160+
self.previous.insert(*neighbor, Some(vert_meta.id));
160161

161162
vertex_pq.push(VertexMeta {
162-
id: *neighbour,
163+
id: *neighbor,
163164
distance: alt_dist,
164165
});
165166
}
@@ -269,12 +270,12 @@ mod tests {
269270
let v_e = graph.add_vertex(5);
270271
let v_f = graph.add_vertex(6);
271272

272-
graph.add_edge_with_weight(&v_a, &v_b, 0.1);
273-
graph.add_edge_with_weight(&v_b, &v_d, 0.2);
274-
graph.add_edge_with_weight(&v_c, &v_b, 0.5);
275-
graph.add_edge_with_weight(&v_c, &v_d, 0.1);
276-
graph.add_edge_with_weight(&v_c, &v_e, 0.5);
277-
graph.add_edge_with_weight(&v_d, &v_f, 0.8);
273+
graph.add_edge_with_weight(&v_a, &v_b, 0.1).unwrap();
274+
graph.add_edge_with_weight(&v_b, &v_d, 0.2).unwrap();
275+
graph.add_edge_with_weight(&v_c, &v_b, 0.5).unwrap();
276+
graph.add_edge_with_weight(&v_c, &v_d, 0.1).unwrap();
277+
graph.add_edge_with_weight(&v_c, &v_e, 0.5).unwrap();
278+
graph.add_edge_with_weight(&v_d, &v_f, 0.8).unwrap();
278279

279280
{
280281
let mut iterator = Dijkstra::new(&graph, &v_a).unwrap();
@@ -287,12 +288,12 @@ mod tests {
287288
assert_eq!(iterator.get_distance(&v_f).unwrap(), 1.1);
288289
}
289290

290-
graph.add_edge_with_weight(&v_b, &v_a, 0.1);
291-
graph.add_edge_with_weight(&v_d, &v_b, 0.2);
292-
graph.add_edge_with_weight(&v_b, &v_c, 0.5);
293-
graph.add_edge_with_weight(&v_d, &v_c, 0.1);
294-
graph.add_edge_with_weight(&v_e, &v_c, 0.5);
295-
graph.add_edge_with_weight(&v_f, &v_d, 0.8);
291+
graph.add_edge_with_weight(&v_b, &v_a, 0.1).unwrap();
292+
graph.add_edge_with_weight(&v_d, &v_b, 0.2).unwrap();
293+
graph.add_edge_with_weight(&v_b, &v_c, 0.5).unwrap();
294+
graph.add_edge_with_weight(&v_d, &v_c, 0.1).unwrap();
295+
graph.add_edge_with_weight(&v_e, &v_c, 0.5).unwrap();
296+
graph.add_edge_with_weight(&v_f, &v_d, 0.8).unwrap();
296297

297298
let mut iterator = Dijkstra::new(&graph, &v_a).unwrap();
298299

@@ -313,12 +314,12 @@ mod tests {
313314
assert_eq!(iterator.get_distance(&v_f).unwrap(), 0.900_000_04);
314315
// Ugh! I wish there was something like `assert_approx_eq!()`. Too lazy to write on my own.
315316

316-
assert_eq!(iterator.get_path_to(&v_a).unwrap().count(), 4);
317-
assert_eq!(iterator.get_path_to(&v_b).unwrap().count(), 3);
318-
assert_eq!(iterator.get_path_to(&v_c).unwrap().count(), 1);
319-
assert_eq!(iterator.get_path_to(&v_d).unwrap().count(), 2);
320-
assert_eq!(iterator.get_path_to(&v_e).unwrap().count(), 2);
321-
assert_eq!(iterator.get_path_to(&v_f).unwrap().count(), 3);
317+
assert_eq!(iterator.clone().get_path_to(&v_a).unwrap().count(), 4);
318+
assert_eq!(iterator.clone().get_path_to(&v_b).unwrap().count(), 3);
319+
assert_eq!(iterator.clone().get_path_to(&v_c).unwrap().count(), 1);
320+
assert_eq!(iterator.clone().get_path_to(&v_d).unwrap().count(), 2);
321+
assert_eq!(iterator.clone().get_path_to(&v_e).unwrap().count(), 2);
322+
assert_eq!(iterator.clone().get_path_to(&v_f).unwrap().count(), 3);
322323

323324
/*
324325
// To run these tests, uncomment and use `-- --nocapture` flag in `cargo test`
@@ -347,12 +348,12 @@ mod tests {
347348
let v_e = graph.add_vertex(5);
348349
let v_f = graph.add_vertex(6);
349350

350-
graph.add_edge(&v_a, &v_b);
351-
graph.add_edge(&v_b, &v_d);
352-
graph.add_edge(&v_c, &v_b);
353-
graph.add_edge(&v_c, &v_d);
354-
graph.add_edge(&v_c, &v_e);
355-
graph.add_edge(&v_d, &v_f);
351+
graph.add_edge(&v_a, &v_b).unwrap();
352+
graph.add_edge(&v_b, &v_d).unwrap();
353+
graph.add_edge(&v_c, &v_b).unwrap();
354+
graph.add_edge(&v_c, &v_d).unwrap();
355+
graph.add_edge(&v_c, &v_e).unwrap();
356+
graph.add_edge(&v_d, &v_f).unwrap();
356357

357358
let mut iterator = Dijkstra::new(&graph, &v_a).unwrap();
358359

@@ -363,14 +364,14 @@ mod tests {
363364
assert_eq!(iterator.get_distance(&v_e).unwrap(), infinity);
364365
assert_eq!(iterator.get_distance(&v_f).unwrap(), 0.0);
365366

366-
assert_eq!(iterator.get_path_to(&v_a).unwrap().count(), 1);
367-
assert_eq!(iterator.get_path_to(&v_b).unwrap().count(), 2);
368-
assert_eq!(iterator.get_path_to(&v_c).unwrap().count(), 0);
369-
assert_eq!(iterator.get_path_to(&v_d).unwrap().count(), 3);
370-
assert_eq!(iterator.get_path_to(&v_e).unwrap().count(), 0);
371-
assert_eq!(iterator.get_path_to(&v_f).unwrap().count(), 4);
367+
assert_eq!(iterator.clone().get_path_to(&v_a).unwrap().count(), 1);
368+
assert_eq!(iterator.clone().get_path_to(&v_b).unwrap().count(), 2);
369+
assert_eq!(iterator.clone().get_path_to(&v_c).unwrap().count(), 0);
370+
assert_eq!(iterator.clone().get_path_to(&v_d).unwrap().count(), 3);
371+
assert_eq!(iterator.clone().get_path_to(&v_e).unwrap().count(), 0);
372+
assert_eq!(iterator.clone().get_path_to(&v_f).unwrap().count(), 4);
372373

373-
iterator.set_source(&v_c);
374+
iterator.set_source(&v_c).unwrap();
374375

375376
assert_eq!(iterator.get_distance(&v_a).unwrap(), infinity);
376377
assert_eq!(iterator.get_distance(&v_b).unwrap(), 0.0);
@@ -379,12 +380,12 @@ mod tests {
379380
assert_eq!(iterator.get_distance(&v_e).unwrap(), 0.0);
380381
assert_eq!(iterator.get_distance(&v_f).unwrap(), 0.0);
381382

382-
assert_eq!(iterator.get_path_to(&v_a).unwrap().count(), 0);
383-
assert_eq!(iterator.get_path_to(&v_b).unwrap().count(), 2);
384-
assert_eq!(iterator.get_path_to(&v_c).unwrap().count(), 1);
385-
assert_eq!(iterator.get_path_to(&v_d).unwrap().count(), 2);
386-
assert_eq!(iterator.get_path_to(&v_e).unwrap().count(), 2);
387-
assert_eq!(iterator.get_path_to(&v_f).unwrap().count(), 3);
383+
assert_eq!(iterator.clone().get_path_to(&v_a).unwrap().count(), 0);
384+
assert_eq!(iterator.clone().get_path_to(&v_b).unwrap().count(), 2);
385+
assert_eq!(iterator.clone().get_path_to(&v_c).unwrap().count(), 1);
386+
assert_eq!(iterator.clone().get_path_to(&v_d).unwrap().count(), 2);
387+
assert_eq!(iterator.clone().get_path_to(&v_e).unwrap().count(), 2);
388+
assert_eq!(iterator.clone().get_path_to(&v_f).unwrap().count(), 3);
388389

389390
/*
390391
// To run these tests, uncomment and use `-- --nocapture` flag in `cargo test`

src/iterators/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod dfs;
55
mod dijkstra;
66
mod topo;
77
mod vertices;
8+
mod owning_iterator;
89

910
pub use bfs::*;
1011
pub use dfs::*;

src/iterators/owning_iterator.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2019 Octavian Oncescu
2+
3+
use crate::vertex_id::VertexId;
4+
5+
#[cfg(feature = "no_std")]
6+
extern crate alloc;
7+
8+
#[cfg(feature = "no_std")]
9+
use alloc::boxed::Box;
10+
11+
#[cfg(not(feature = "no_std"))]
12+
use std::fmt::Debug;
13+
14+
#[cfg(not(feature = "no_std"))]
15+
use std::marker::PhantomData;
16+
17+
#[cfg(feature = "no_std")]
18+
use alloc::marker::PhantomData;
19+
20+
#[cfg(feature = "no_std")]
21+
use alloc::mem;
22+
23+
#[cfg(not(feature = "no_std"))]
24+
use std::mem;
25+
26+
#[cfg(not(feature = "no_std"))]
27+
use std::collections::VecDeque;
28+
29+
#[cfg(feature = "no_std")]
30+
use alloc::collections::VecDeque;
31+
32+
/// Iterator that owns the data.
33+
#[derive(Debug)]
34+
pub(crate) struct OwningIterator<'a> {
35+
iterable: VecDeque<VertexId>,
36+
cur_idx: usize, // Quite the hack, but it works
37+
phantom: PhantomData<&'a u8>,
38+
}
39+
40+
impl<'a> OwningIterator<'a> {
41+
pub fn new(iterable: VecDeque<VertexId>) -> Self {
42+
OwningIterator {
43+
iterable,
44+
cur_idx: 0,
45+
phantom: PhantomData,
46+
}
47+
}
48+
}
49+
50+
impl<'a> Iterator for OwningIterator<'a> {
51+
type Item = &'a VertexId;
52+
53+
#[inline]
54+
fn next(&mut self) -> Option<Self::Item> {
55+
if self.cur_idx == self.iterable.len() {
56+
None
57+
} else {
58+
let last_idx = self.cur_idx;
59+
self.cur_idx += 1;
60+
61+
// Since we cannot annotate the lifetime 'a to &mut self
62+
// because of the Iterator trait's signature, this seems
63+
// the only way to make the compiler happy.
64+
//
65+
// TODO: If you can make this work with safe Rust, please do.
66+
unsafe {
67+
let ptr = &self.iterable[last_idx] as *const VertexId;
68+
let transmuted = mem::transmute::<*const VertexId, &VertexId>(ptr);
69+
Some(transmuted)
70+
}
71+
}
72+
}
73+
}
74+
75+
#[cfg(test)]
76+
mod tests {
77+
use super::*;
78+
79+
#[test]
80+
fn it_yields_correct_vertex_ids() {
81+
let ids: VecDeque<VertexId> = vec![VertexId::random(), VertexId::random(), VertexId::random()].iter().cloned().collect();
82+
let mut iter = OwningIterator::new(ids.clone());
83+
84+
assert_eq!(iter.next(), Some(&ids[0]));
85+
assert_eq!(iter.next(), Some(&ids[1]));
86+
assert_eq!(iter.next(), Some(&ids[2]));
87+
assert_eq!(iter.next(), None);
88+
}
89+
}

0 commit comments

Comments
 (0)