short_paths/
lib.rs

1// Enumerate shortest s-t paths in a graph, following the algorithm in
2// http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=7BB56B2ABC7C9113C121413A62AF3974?doi=10.1.1.30.3705&rep=rep1&type=pdf
3// For sake of simplicity, when enumerating the paths we simply do
4// a Dijkstra-esque walk with an auxilliary heap, so the i'th path
5// is generated in O(log i), rather than constant time. This also means
6// that no explicit path count or length bound needs to be given, and
7// paths are generated in increasing order of length.
8extern crate petgraph;
9
10mod scored;
11
12#[cfg(test)]
13mod tests;
14
15use petgraph::{Direction, Graph};
16use petgraph::graph::{EdgeIndex, NodeIndex};
17use petgraph::algo::Measure;
18use petgraph::visit::{EdgeRef, IntoEdgesDirected, IntoNodeReferences, NodeRef, Visitable, VisitMap};
19use std::collections::{BinaryHeap, HashMap, VecDeque};
20use std::collections::hash_map::Entry;
21use std::hash::Hash;
22use std::ops::Sub;
23
24use scored::{MinScored, Scored};
25
26#[derive(Debug)]
27pub struct ShortPathsIterator<'a, N: 'a, E: 'a, K>
28    where
29    K: PartialOrd
30{
31    graph: &'a Graph<N, E>,
32    source: NodeIndex,
33    spt: HashMap<NodeIndex, (K, Option<EdgeIndex>)>,
34    path_graph: Graph<PathNode, (PathEdge, K)>,
35    path_graph_root: NodeIndex,
36    generated_paths: Vec<PathData>,
37    visit_queue: BinaryHeap<MinScored<K, PathData>>,
38}
39
40#[derive(Clone, Debug)]
41pub enum PathData {
42    Empty,
43    Augment(usize, EdgeIndex),
44}
45
46// Compute the shortest path tree toward the target. Returns it as a map
47// mapping node IDs to the distance from the target and the outgoing edge
48// in the SPT.
49//
50// The code is similar to that of the `dijkstra` function in petgraph, but
51// the main Dijkstra loop is structured slightly differently.
52fn build_shortest_path_tree<G, F, K>(graph: G, target: G::NodeId, mut edge_cost: F)
53    -> HashMap<G::NodeId, (K, Option<G::EdgeId>)> 
54    where
55    G: IntoEdgesDirected + Visitable,
56    G::NodeId: Eq + Hash,
57    F: FnMut(G::EdgeRef) -> K,
58    K: Measure + Copy,
59{
60    let mut visited = graph.visit_map();
61    let mut tree = HashMap::new();
62    let mut visit_next = BinaryHeap::new();
63    let zero_score = K::default();
64
65    tree.insert(target, (zero_score, None));
66    visit_next.push(MinScored(zero_score, target));
67
68    while let Some(MinScored(node_score, node)) = visit_next.pop() {
69        if visited.is_visited(&node) {
70            continue
71        }
72
73        visited.visit(node);
74
75        for e in graph.edges_directed(node, Direction::Incoming) {
76            let next = e.source();
77            if visited.is_visited(&next) {
78                continue
79            }
80
81            visited.visit(node);
82
83            let next_score = node_score + edge_cost(e);
84            match tree.entry(next) {
85                Entry::Occupied(ent) => {
86                    let (previous_score, _) = *ent.get();
87                    if next_score < previous_score {
88                        *ent.into_mut() = (next_score, Some(e.id()));
89                    } else {
90                        continue
91                    }
92                },
93                Entry::Vacant(ent) => {
94                    ent.insert((next_score, Some(e.id())));
95                },
96            }
97
98            visit_next.push(MinScored(next_score, next));
99        }
100    }
101
102    tree
103}
104
105// Compute the graph denoted D(G) in the source paper, and the mapping
106// V(G) -> V(D(G))
107// A vertex can be missing from this mapping if the only outgoing paths
108// toward the sink are in the shortest path tree.
109fn build_heap_graph<N, E, K, F>(
110    graph: &Graph<N, E>,
111    target: NodeIndex,
112    spt: &HashMap<NodeIndex, (K, Option<EdgeIndex>)>,
113    mut edge_cost: F,
114) -> (Graph<(EdgeIndex, K), ()>, HashMap<NodeIndex, NodeIndex>)
115    where
116    E: Copy,
117    F: FnMut(E) -> K,
118    K: Measure + Sub<Output=K> + Copy,
119{
120    let mut result_graph = Graph::<(EdgeIndex, K), ()>::new();
121    let mut heap_roots = HashMap::new();
122
123    let mut inverse_spt: HashMap<NodeIndex, Vec<NodeIndex>> = HashMap::new();
124    for (&node, &(_, successor)) in spt.iter() {
125        if let Some(successor_edge) = successor {
126            let successor_node = graph.edge_endpoints(successor_edge).unwrap().1;
127            inverse_spt.entry(successor_node).or_insert_with(Vec::new).push(node);
128        }
129    }
130
131    let mut edge_sidetrack_cost = |e: EdgeIndex| -> K {
132        let (edge_source, edge_target) = match graph.edge_endpoints(e) {
133            Some(endpoints) => endpoints,
134            None => return K::default(),
135        };
136        let source_distance = match spt.get(&edge_source) {
137            Some(&(dist, _)) => dist,
138            None => return K::default(),
139        };
140        let target_distance = match spt.get(&edge_target) {
141            Some(&(dist, _)) => dist,
142            None => return K::default(),
143        };
144        edge_cost(graph[e]) + target_distance - source_distance
145    };
146
147    let mut visit_order = VecDeque::new();
148    visit_order.push_back(target);
149
150    while let Some(node) = visit_order.pop_front() {
151        let (_, successor) = spt[&node];
152        match successor {
153            Some(successor_edge_id) => {
154                let successor_target = graph.edge_endpoints(successor_edge_id).unwrap().1;
155
156                match heap_roots.get(&successor_target) {
157                    Some(&successor_heap_root) => {
158                        let mut outgoing_edges: Vec<EdgeIndex> = Vec::new();
159                        for e in graph.edges(node) {
160                            let e_id = e.id();
161                            if e_id == successor_edge_id {
162                                continue
163                            }
164                            outgoing_edges.push(e_id);
165                        }
166
167                        let new_root = merge_and_embed(&mut result_graph, outgoing_edges, successor_heap_root, &mut edge_sidetrack_cost);
168                        heap_roots.insert(node, new_root);
169                    },
170                    None => {
171                        // The target heap is empty, so we simply embed the appropriate heap
172                        let mut scored_edges: Vec<Scored<K, EdgeIndex>> = Vec::new();
173                        for e in graph.edges(node) {
174                            let e_id = e.id();
175                            if e_id == successor_edge_id {
176                                continue
177                            }
178                            scored_edges.push(Scored(edge_sidetrack_cost(e_id), e_id));
179                        }
180
181                        if scored_edges.len() > 0 {
182                            min_heapify(&mut scored_edges);
183
184                            let mut heap_nodes = Vec::new();
185                            for &Scored(e_cost, e_id) in scored_edges.iter() {
186                                let new_node = result_graph.add_node((e_id, e_cost));
187                                heap_nodes.push(new_node);
188                            }
189                            for (i, &node) in heap_nodes.iter().enumerate() {
190                                if 2*i + 1 < heap_nodes.len() {
191                                    let child_node = heap_nodes[2*i+1];
192                                    result_graph.add_edge(node, child_node, ());
193                                }
194                                if 2*i + 2 < heap_nodes.len() {
195                                    let child_node = heap_nodes[2*i+2];
196                                    result_graph.add_edge(node, child_node, ());
197                                }
198                            }
199                            heap_roots.insert(node, heap_nodes[0]);
200                        }
201                    },
202                }
203            },
204            None => {
205                // This is the target vertex, so we simply embed a heap of all
206                // outgoing edges.
207                let mut scored_edges: Vec<Scored<K, EdgeIndex>> = Vec::new();
208                for e in graph.edges(node) {
209                    let e_id = e.id();
210                    scored_edges.push(Scored(edge_sidetrack_cost(e_id), e_id));
211                }
212                if scored_edges.len() > 0 {
213                    min_heapify(&mut scored_edges);
214
215                    let mut heap_nodes = Vec::new();
216                    for &Scored(e_cost, e_id) in scored_edges.iter() {
217                        let new_node = result_graph.add_node((e_id, e_cost));
218                        heap_nodes.push(new_node);
219                    }
220                    for (i, &node) in heap_nodes.iter().enumerate() {
221                        if 2*i + 1 < heap_nodes.len() {
222                            let child_node = heap_nodes[2*i+1];
223                            result_graph.add_edge(node, child_node, ());
224                        }
225                        if 2*i + 2 < heap_nodes.len() {
226                            let child_node = heap_nodes[2*i+2];
227                            result_graph.add_edge(node, child_node, ());
228                        }
229                    }
230                    heap_roots.insert(node, heap_nodes[0]);
231                }
232            },
233        }
234        if let Some(predecessors) = inverse_spt.get(&node) {
235            for &pred in predecessors.iter() {
236                visit_order.push_back(pred);
237            }
238        }
239    }
240
241    (result_graph, heap_roots)
242}
243
244#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
245pub enum PathNode {
246    Root,
247    Heap(EdgeIndex),
248}
249
250#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
251pub enum PathEdge {
252    Heap,
253    Cross,
254    Initial,
255}
256
257fn build_path_graph<N, E, K>(
258    graph: &Graph<N, E>,
259    source: NodeIndex,
260    spt: &HashMap<NodeIndex, (K, Option<EdgeIndex>)>,
261    heap_graph: &Graph<(EdgeIndex, K), ()>,
262    heap_roots: &HashMap<NodeIndex, NodeIndex>,
263) -> (Graph<PathNode, (PathEdge, K)>, NodeIndex)
264    where
265    E: Copy,
266    K: Measure + Sub<Output=K> + Copy,
267{
268    let mut result_graph = Graph::<PathNode, (PathEdge, K)>::new();
269    // Map from heap graph `dg` nodes to result graph's nodes.
270    let mut node_map: HashMap<NodeIndex, NodeIndex> = HashMap::new();
271
272    let root_node = result_graph.add_node(PathNode::Root);
273
274    for n in heap_graph.node_references() {
275        let &(e_id, _) = n.weight();
276        let new_node = result_graph.add_node(PathNode::Heap(e_id));
277
278        node_map.insert(n.id(), new_node);
279    }
280
281    // Create heap edges
282    for e in heap_graph.edge_references() {
283        let s = e.source();
284        let t = e.target();
285        let &(_, source_edge_sidetrack) = heap_graph.node_weight(s).unwrap();
286        let &(_, target_edge_sidetrack) = heap_graph.node_weight(t).unwrap();
287
288        let s_node = node_map[&s];
289        let t_node = node_map[&t];
290        result_graph.add_edge(s_node, t_node, (PathEdge::Heap, target_edge_sidetrack - source_edge_sidetrack));
291    }
292
293    // Create cross edges
294    for n in heap_graph.node_references() {
295        let &(e_id, _) = n.weight();
296        let (e_source, e_target) = graph.edge_endpoints(e_id).unwrap();
297        if let Some(&(_, Some(spt_edge_id))) = spt.get(&e_source) {
298            if e_id == spt_edge_id {
299                continue
300            }
301        }
302        let new_source = node_map[&n.id()];
303        if let Some(&root_node) = heap_roots.get(&e_target) {
304            let &(_, root_edge_sidetrack) = heap_graph.node_weight(root_node).unwrap();
305            let new_target = node_map[&root_node];
306            result_graph.add_edge(new_source, new_target, (PathEdge::Cross, root_edge_sidetrack));
307        }
308    }
309
310    // Create initial edge
311    let initial_root = heap_roots[&source];
312    let &(_, initial_root_sidetrack) = heap_graph.node_weight(initial_root).unwrap();
313    let initial_target = node_map[&initial_root];
314    result_graph.add_edge(root_node, initial_target, (PathEdge::Initial, initial_root_sidetrack));
315
316    (result_graph, root_node)
317}
318
319// Creates a heap out of the given values, merges it with the existing heap
320// at target_root, and returns the root of the new merged heap. The existing
321// heap should be untouched.
322fn merge_and_embed<N, K, F>(graph: &mut Graph<(N, K), ()>, values: Vec<N>, target_root: NodeIndex, mut cost: F) -> NodeIndex
323    where
324    N: Copy,
325    F: FnMut(N) -> K,
326    K: PartialOrd + Copy,
327{
328    // If there is nothing to merge, we can just use the existing heap root.
329    if values.len() == 0 {
330        return target_root
331    }
332
333    let mut scored_values = Vec::new();
334    for v in values {
335        scored_values.push(Scored(cost(v), v));
336    }
337    min_heapify(&mut scored_values);
338
339    // Create a new 3-heap where the root has out-degree 1, including
340    // the root of the 2-heap and the entire 3-heap.
341    let new_root = make_root(graph, scored_values[0].1, target_root, cost);
342
343    // Create nodes for the remaining nodes of the 2-heap and link them together.
344    let mut heap_nodes = Vec::new();
345    heap_nodes.push(new_root);
346
347    for &Scored(v_cost, v) in scored_values.iter().skip(1) {
348        let new_node = graph.add_node((v, v_cost));
349        heap_nodes.push(new_node);
350    }
351
352    for (i, &node) in heap_nodes.iter().enumerate() {
353        if 2*i + 1 < heap_nodes.len() {
354            let child_node = heap_nodes[2*i + 1];
355            graph.add_edge(node, child_node, ());
356        }
357        if 2*i + 2 < heap_nodes.len() {
358            let child_node = heap_nodes[2*i + 2];
359            graph.add_edge(node, child_node, ());
360        }
361    }
362
363    new_root
364}
365
366// Conceptually create a node linking to the given root and sift down,
367// but avoid making any unnecessary nodes. Returns the index of the new root,
368// which will have out-degree 1 (so that it can be linked to two other nodes).
369fn make_root<N, F, K>(graph: &mut Graph<(N, K), ()>, new_value: N, target_root: NodeIndex, mut cost: F) -> NodeIndex
370    where
371    N: Copy,
372    F: FnMut(N) -> K,
373    K: PartialOrd + Copy,
374{
375    let value_cost = cost(new_value);
376    let root_cost = graph[target_root].1;
377    if value_cost <= root_cost {
378        let new_root = graph.add_node((new_value, value_cost));
379        graph.add_edge(new_root, target_root, ());
380        return new_root;
381    }
382    let mut least_child_edge = None;
383    for e in graph.edges(target_root) {
384        match least_child_edge {
385            None => {
386                let child_node = e.target();
387                let child_cost = graph[child_node].1;
388                least_child_edge = Some((child_cost, e.id()));
389            },
390            Some((old_child_cost, _)) => {
391                let child_node = e.target();
392                let child_cost = graph[child_node].1;
393                if child_cost < old_child_cost {
394                    least_child_edge = Some((child_cost, e.id()));
395                }
396            },
397        }
398    }
399    match least_child_edge {
400        Some((_, e_id)) => {
401            let least_child_node = graph.edge_endpoints(e_id).unwrap().1;
402            // Put the new value into the least child's subtree, which will
403            // result in a root no larger than the smallest child.
404            let new_child = make_root(graph, new_value, least_child_node, cost);
405            // Link the resulting root to the other children of the old root.
406            let mut targets = Vec::new();
407            for e in graph.edges(target_root) {
408                if e.id() == e_id {
409                    continue
410                }
411                targets.push(e.target());
412            }
413            for t in targets {
414                graph.add_edge(new_child, t, ());
415            }
416            // Create a new root with the value of the old root, and link it
417            // to the child created above.
418            let target_root_value = graph[target_root];
419            let new_root = graph.add_node(target_root_value);
420            graph.add_edge(new_root, new_child, ());
421
422            new_root
423        },
424        None => {
425            // The target root doesn't have any children, so we just link
426            // the new nodes in reverse order.
427            let new_child = graph.add_node((new_value, cost(new_value)));
428            let (target_root_value, target_root_cost) = graph[target_root];
429            let new_root = graph.add_node((target_root_value, target_root_cost));
430            graph.add_edge(new_root, new_child, ());
431
432            new_root
433        },
434    }
435}
436
437fn min_heapify<T: PartialOrd>(vec: &mut [T]) {
438    let mut n = vec.len() / 2;
439    while n > 0 {
440        n -= 1;
441        sift_down(vec, n);
442    }
443}
444
445#[test]
446fn test_heapify() {
447    let mut vec = vec![3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3];
448    min_heapify(&mut vec);
449
450    for (i, &v) in vec.iter().enumerate() {
451        if 2*i + 1 < vec.len() {
452            assert!(v <= vec[2*i + 1]);
453        }
454        if 2*i + 2 < vec.len() {
455            assert!(v <= vec[2*i + 2]);
456        }
457    }
458}
459
460fn sift_down<T: PartialOrd>(vec: &mut [T], mut pos: usize) {
461    loop {
462        let mut child = 2 * pos + 1;
463        if child >= vec.len() {
464            return
465        }
466        let right = child + 1;
467        // Find smaller child
468        if right < vec.len() && vec[right] < vec[child] {
469            child = right;
470        }
471        // If we're in order, do nothing.
472        if vec[pos] < vec[child] {
473            return
474        }
475        // Otherwise, swap down and continue
476        vec.swap(pos, child);
477        pos = child;
478    }
479}
480
481impl<'a, N, E, K> ShortPathsIterator<'a, N, E, K>
482    where
483    N: 'a + Eq + Copy,
484    E: 'a + Copy,
485    K: PartialOrd + Measure + Sub<Output=K> + Copy,
486{
487    pub fn new<F>(graph: &'a Graph<N, E>, source: NodeIndex, target: NodeIndex, mut edge_cost: F) -> Self
488        where
489        F: FnMut(E) -> K,
490    {
491        let spt = build_shortest_path_tree(graph, target, |e_ref| { edge_cost(*e_ref.weight()) });
492        let (heap_graph, heap_roots) = build_heap_graph(graph, target, &spt, edge_cost);
493        let (path_graph, path_graph_root) = build_path_graph(graph, source, &spt, &heap_graph, &heap_roots);
494
495        let generated_paths = Vec::new();
496        let mut visit_queue = BinaryHeap::new();
497        visit_queue.push(MinScored(K::default(), PathData::Empty));
498
499        ShortPathsIterator {
500            graph,
501            source,
502            spt,
503            path_graph,
504            path_graph_root,
505            generated_paths,
506            visit_queue,
507        }
508    }
509
510    // Returns the final node of the path graph for the given path data.
511    fn path_end(&self, path_data: &PathData) -> NodeIndex {
512        match path_data {
513            &PathData::Empty => {
514                self.path_graph_root
515            },
516            &PathData::Augment(_, edge_idx) => {
517                self.path_graph.edge_endpoints(edge_idx).unwrap().1
518            }
519        }
520    }
521
522    fn unwind_path_graph_path(&self, path_data: &PathData) -> Vec<EdgeIndex> {
523        match path_data {
524            &PathData::Empty => {
525                Vec::new()
526            },
527            &PathData::Augment(parent_idx, edge_idx) => {
528                let mut path = self.unwind_path_graph_path(&self.generated_paths[parent_idx]);
529                path.push(edge_idx);
530                path
531            },
532        }
533    }
534
535    fn expand_path(&self, path_graph_path: &[EdgeIndex]) -> Vec<EdgeIndex> {
536        let mut path = Vec::new();
537        let mut current_vertex = self.source;
538        let mut final_node = self.path_graph_root;
539
540        // Follow the shortest path tree to each cross edge
541        for &e_id in path_graph_path.iter() {
542            let (e_source, e_target) = self.path_graph.edge_endpoints(e_id).unwrap();
543            final_node = e_target;
544            if let Some(&(PathEdge::Cross, _)) = self.path_graph.edge_weight(e_id) {
545                if let Some(&PathNode::Heap(non_spt_edge)) = self.path_graph.node_weight(e_source) {
546                    let (non_spt_source, non_spt_target) = self.graph.edge_endpoints(non_spt_edge).unwrap();
547                    while current_vertex != non_spt_source {
548                        match self.spt.get(&current_vertex) {
549                            Some(&(_, Some(spt_edge))) => {
550                                let (_, spt_edge_target) = self.graph.edge_endpoints(spt_edge).unwrap();
551                                path.push(spt_edge);
552                                current_vertex = spt_edge_target;
553                            },
554                            _ => {
555                                panic!("Reached a vertex with no outgoing shortest path tree edge!")
556                            },
557                        }
558                    }
559                    path.push(non_spt_edge);
560                    current_vertex = non_spt_target;
561                } else {
562                    panic!("Cross edge doesn't correspond to a heap edge?")
563                }
564            }
565        }
566
567        // Use one more non-SPT edge defined by the ending node of the path graph path
568        if let Some(&PathNode::Heap(non_spt_edge)) = self.path_graph.node_weight(final_node) {
569            let (non_spt_source, non_spt_target) = self.graph.edge_endpoints(non_spt_edge).unwrap();
570            while current_vertex != non_spt_source {
571                match self.spt.get(&current_vertex) {
572                    Some(&(_, Some(spt_edge))) => {
573                        let (_, spt_edge_target) = self.graph.edge_endpoints(spt_edge).unwrap();
574                        path.push(spt_edge);
575                        current_vertex = spt_edge_target;
576                    },
577                    _ => panic!("Reached a vertex with no outgoing shortest path tree edge!"),
578                }
579            }
580            path.push(non_spt_edge);
581            current_vertex = non_spt_target;
582        }
583
584        // Finish the path via the shortest path tree
585        while let Some(&(_, Some(spt_edge))) = self.spt.get(&current_vertex) {
586            let (_, spt_edge_target) = self.graph.edge_endpoints(spt_edge).unwrap();
587            path.push(spt_edge);
588            current_vertex = spt_edge_target;
589        }
590
591        path
592    }
593}
594
595impl<'a, N, E, K> Iterator for ShortPathsIterator<'a, N, E, K>
596    where
597    N: 'a + Eq + Copy,
598    E: 'a + Copy,
599    K: PartialOrd + Measure + Sub<Output=K> + Copy,
600{
601    type Item=Vec<EdgeIndex>;
602
603    fn next(&mut self) -> Option<Self::Item> {
604        let front = self.visit_queue.pop();
605        match front {
606            Some(MinScored(path_score, path_data)) => {
607                let path_graph_path = self.unwind_path_graph_path(&path_data);
608                let path_to_return = self.expand_path(&path_graph_path);
609
610                let final_node = self.path_end(&path_data);
611
612                let path_index = self.generated_paths.len();
613                self.generated_paths.push(path_data);
614
615                for edge in self.path_graph.edges(final_node) {
616                    let &(_, edge_cost) = edge.weight();
617                    let new_path_cost = path_score + edge_cost;
618                    let new_path_data = PathData::Augment(path_index, edge.id());
619
620                    self.visit_queue.push(MinScored(new_path_cost, new_path_data));
621                }
622
623                Some(path_to_return)
624            },
625            None => {
626                None
627            },
628        }
629    }
630}