use graph::{Node, Edge, Digraph, IndexGraph, IndexDigraph, IndexNetwork};
use vec::{EdgeSlice, BiEdgeSlice};
use shortestpath::binheap::BinHeap;
use shortestpath::heap::Heap;
use num::traits::NumAssign;
use std::collections::HashMap;
use std::hash::Hash;
use std::cmp::Ordering;
use std::ops::Index;
pub struct Dijkstra<'a, G, W, N, E, H = BinHeap<NodeItem<N, E, W>, usize>>
where G: 'a + IndexGraph<'a, Node=N, Edge=E>,
N: 'a + Node + Hash,
E: 'a + Edge,
W: NumAssign + Ord + Copy,
H: Heap<Key=NodeItem<G::Node, G::Edge, W>, Item=usize>,
{
g: &'a G,
items: HashMap<G::Node, usize>,
heap: H,
}
impl<'a, G, W, N, E, H> Dijkstra<'a, G, W, N, E, H>
where G: 'a + IndexGraph<'a, Node=N, Edge=E>,
N: 'a + Node + Hash,
E: 'a + Edge,
W: NumAssign + Ord + Copy,
H: Heap<Key=NodeItem<G::Node, G::Edge, W>, Item=usize>,
{
pub fn new(g: &'a G) -> Self {
Dijkstra {
g: g,
items: HashMap::new(),
heap: H::new(),
}
}
pub fn undirected<'b>(&mut self,
weights: &EdgeSlice<'a,'b,G,W>,
src: G::Node,
snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
{
self.generic(weights, src, snk,
|dist, w| dist + w,
|g, u| g.neighs(u))
}
pub fn bidirected<'b>(&mut self,
weights: &BiEdgeSlice<'a,'b,G,W>,
src: G::Node,
snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where G: IndexNetwork<'a>,
{
self.generic(weights, src, snk,
|dist, w| dist + w,
|g, u| g.neighs(u))
}
pub fn directed<'b>(&mut self,
weights: &EdgeSlice<'a,'b,G,W>,
src: G::Node,
snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where G: Digraph<'a>,
{
self.generic(weights, src, snk,
|dist, w| dist + w,
|g, u| g.outedges(u))
}
pub fn generic<Weights, F, Neighs, It>(&mut self,
weights: &Weights,
src: G::Node,
snk: Option<G::Node>,
accum: F,
neighs: Neighs) -> Vec<(G::Node, G::Edge)>
where Weights: Index<G::Edge, Output=W>,
F: Fn(W, W) -> W,
Neighs: Fn(&'a G, G::Node) -> It,
It: Iterator<Item=(G::Edge, G::Node)>,
{
self.items.clear();
self.heap.clear();
let mut preds = vec![];
self.items.insert(src, self.heap.insert(NodeItem::<_, G::Edge, _> {
node: src,
pred: None,
weight: W::zero(),
}));
while let Some(uitem) = self.heap.pop_min() {
let u = uitem.node;
let dist = uitem.weight;
if let Some(e) = uitem.pred {
preds.push((u, e));
}
if Some(u) == snk {
break
}
self.items.insert(u, usize::max_value());
for (e, v) in neighs(self.g, u) {
match self.items.get(&v) {
None => {
let newd = accum(dist, weights[e]);
self.items.insert(v, self.heap.insert(NodeItem {
node: v,
weight: newd,
pred: Some(e),
}));
},
Some(&vitem) if vitem < usize::max_value() => {
let newd = accum(dist, weights[e]);
if newd < self.heap.key(vitem).weight {
self.heap.key(vitem).weight = newd;
self.heap.key(vitem).pred = Some(e);
self.heap.decrease(vitem);
}
},
_ => (),
}
}
}
preds
}
}
pub fn undirected<'a, 'b, G, W>(g: &'a G,
weights: &EdgeSlice<'a,'b,G,W>,
src: G::Node,
snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where G: IndexGraph<'a>,
G::Node: Hash,
W: NumAssign + Ord + Copy,
{
let mut d = Dijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.undirected(weights, src, snk)
}
pub fn bidirected<'a, 'b, G, W>(g: &'a G,
weights: &BiEdgeSlice<'a,'b,G,W>,
src: G::Node,
snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where G: IndexNetwork<'a>,
G::Node: Hash,
W: NumAssign + Ord + Copy,
{
let mut d = Dijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.bidirected(weights, src, snk)
}
pub fn directed<'a, 'b, G, W>(g: &'a G,
weights: &EdgeSlice<'a,'b,G,W>,
src: G::Node,
snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where G: IndexDigraph<'a>,
G::Node: Hash,
W: NumAssign + Ord + Copy,
{
let mut d = Dijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.directed(weights, src, snk)
}
pub fn generic<'a, G, W, Weights, F, Neighs, It, H>(g: &'a G,
weights: &Weights,
src: G::Node,
snk: Option<G::Node>,
f: F,
neighs: Neighs) -> Vec<(G::Node, G::Edge)>
where G: IndexGraph<'a>,
G::Node: Hash,
W: NumAssign + Ord + Copy,
Weights: Index<G::Edge, Output=W>,
F: Fn(W, W) -> W,
Neighs: Fn(&'a G, G::Node) -> It,
It: Iterator<Item=(G::Edge, G::Node)>,
H: Heap<Key=NodeItem<G::Node, G::Edge, W>, Item=usize>,
{
let mut d = Dijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.generic(weights, src, snk, f, neighs)
}
#[derive(Clone, Copy)]
pub struct NodeItem<Node: Copy, Edge: Copy, W: Copy + PartialOrd> {
node: Node,
pred: Option<Edge>,
weight: W,
}
impl<Node: Copy, Edge: Copy, W: PartialOrd + Copy> PartialEq
for NodeItem<Node, Edge, W>
{
fn eq(&self, other: &Self) -> bool {
self.weight.eq(&other.weight)
}
}
impl<Node: Copy, Edge: Copy, W: PartialOrd + Copy> PartialOrd for
NodeItem<Node, Edge, W>
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.weight.partial_cmp(&other.weight)
}
}