use graph::{Digraph, Edge, IndexDigraph, IndexGraph, IndexNetwork, Node};
use shortestpath::binheap::BinHeap;
use shortestpath::heap::Heap;
use EdgeMap;
use num::traits::NumAssign;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
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<Weights>(
&mut self,
weights: Weights,
src: G::Node,
snk: Option<G::Node>,
) -> Vec<(G::Node, G::Edge)>
where
Weights: EdgeMap<'a, G, W>,
{
self.generic(weights, src, snk, |dist, w| dist + w, |g, u| g.neighs(u))
}
pub fn bidirected<Weights>(
&mut self,
weights: Weights,
src: G::Node,
snk: Option<G::Node>,
) -> Vec<(G::Node, G::Edge)>
where
G: IndexNetwork<'a>,
Weights: EdgeMap<'a, G, W>,
{
self.generic(weights, src, snk, |dist, w| dist + w, |g, u| g.neighs(u))
}
pub fn directed<Weights>(&mut self, weights: Weights, src: G::Node, snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where
G: Digraph<'a>,
Weights: EdgeMap<'a, G, W>,
{
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: EdgeMap<'a, G, 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, Ws, W>(
g: &'a G,
weights: Ws,
src: G::Node,
snk: Option<G::Node>,
) -> Vec<(G::Node, G::Edge)>
where
G: IndexGraph<'a>,
G::Node: Hash,
Ws: EdgeMap<'a, G, W>,
W: NumAssign + Ord + Copy,
{
let mut d = Dijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, Ws::Output>, usize>>::new(g);
d.undirected(weights, src, snk)
}
pub fn bidirected<'a, G, Ws, W>(g: &'a G, weights: Ws, src: G::Node, snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where
G: IndexNetwork<'a>,
G::Node: Hash,
Ws: EdgeMap<'a, G, W>,
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, Ws, W>(g: &'a G, weights: Ws, src: G::Node, snk: Option<G::Node>) -> Vec<(G::Node, G::Edge)>
where
G: IndexDigraph<'a>,
G::Node: Hash,
Ws: EdgeMap<'a, G, W>,
W: NumAssign + Ord + Copy,
{
let mut d = Dijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, Ws::Output>, 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: EdgeMap<'a, G, 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)
}
}