use shortestpath::binheap::BinHeap;
use shortestpath::heap::Heap;
use EdgeMap;
use {Digraph, Edge, IndexDigraph, IndexGraph, IndexNetwork, Node};
use num::traits::NumAssign;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Index;
pub struct BiDijkstra<'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,
srcitms: HashMap<G::Node, NodeState<W>>,
srcheap: H,
pred: Vec<(G::Node, (G::Node, G::Edge))>,
snkitms: HashMap<G::Node, NodeState<W>>,
snkheap: H,
succ: Vec<(G::Node, (G::Node, G::Edge))>,
}
impl<'a, G, W, N, E, H> BiDijkstra<'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 {
BiDijkstra {
g: g,
srcitms: HashMap::new(),
srcheap: H::new(),
pred: vec![],
snkitms: HashMap::new(),
snkheap: H::new(),
succ: vec![],
}
}
pub fn undirected<Ws>(&mut self, weights: Ws, src: G::Node, snk: G::Node) -> Vec<G::Edge>
where
Ws: EdgeMap<'a, G, W>,
{
self.generic(weights, src, snk, |g, u| g.neighs(u), |g, u| g.neighs(u))
}
pub fn bidirected<Ws>(&mut self, weights: Ws, src: G::Node, snk: G::Node) -> Vec<G::Edge>
where
G: IndexNetwork<'a>,
Ws: EdgeMap<'a, G, W>,
{
self.generic(weights, src, snk, |g, u| g.neighs(u), |g, u| g.neighs(u))
}
pub fn directed<Ws>(&mut self, weights: Ws, src: G::Node, snk: G::Node) -> Vec<G::Edge>
where
G: Digraph<'a>,
Ws: EdgeMap<'a, G, W>,
{
self.generic(weights, src, snk, |g, u| g.outedges(u), |g, u| g.inedges(u))
}
pub fn generic<Weights, Out, OutIt, In, InIt>(
&mut self,
weights: Weights,
src: G::Node,
snk: G::Node,
outedges: Out,
inedges: In,
) -> Vec<G::Edge>
where
Weights: Index<G::Edge, Output = W>,
Out: Fn(&'a G, G::Node) -> OutIt,
OutIt: Iterator<Item = (G::Edge, G::Node)>,
In: Fn(&'a G, G::Node) -> InIt,
InIt: Iterator<Item = (G::Edge, G::Node)>,
{
for e in self.g.edges() {
assert!(weights[e] >= W::zero(), "Weights must be non-negative");
}
self.srcheap.clear();
self.srcitms.clear();
self.pred.clear();
self.srcitms.insert(
src,
NodeState::Seen(self.srcheap.insert(NodeItem {
node: src,
weight: W::zero(),
pred: None,
})),
);
self.snkheap.clear();
self.snkitms.clear();
self.succ.clear();
self.snkitms.insert(
snk,
NodeState::Seen(self.snkheap.insert(NodeItem {
node: snk,
weight: W::zero(),
pred: None,
})),
);
let mut midnode = None;
while !self.srcheap.is_empty() && !self.snkheap.is_empty() {
let udata = self.srcheap.pop_min().unwrap();
let u = udata.node;
let d = udata.weight;
if let Some(e) = udata.pred {
self.pred.push((u, e));
}
if let Some(&NodeState::Finished(dsnk)) = self.snkitms.get(&u) {
let mut u = u;
let mut d = d + dsnk;
for (v, vst) in &self.srcitms {
if let NodeState::Finished(dsrc) = *vst {
if let Some(&NodeState::Finished(dsnk)) = self.snkitms.get(v) {
if dsrc + dsnk < d {
d = dsrc + dsnk;
u = *v;
}
}
}
}
midnode = Some(u);
break;
}
self.srcitms.insert(u, NodeState::Finished(d));
for (e, v) in outedges(self.g, u) {
match self.srcitms.get(&v) {
None => {
let newd = d + weights[e];
self.srcitms.insert(
v,
NodeState::Seen(self.srcheap.insert(NodeItem {
node: v,
weight: newd,
pred: Some((u, e)),
})),
);
}
Some(&NodeState::Seen(itm)) => {
let newd = d + weights[e];
if newd < self.srcheap.key(itm).weight {
{
let data = self.srcheap.key(itm);
data.weight = newd;
data.pred = Some((u, e));
}
self.srcheap.decrease(itm);
}
}
_ => (),
}
}
let vdata = self.snkheap.pop_min().unwrap();
let v = vdata.node;
let d = vdata.weight;
if let Some(e) = vdata.pred {
self.succ.push((v, e));
}
if let Some(&NodeState::Finished(dsrc)) = self.srcitms.get(&v) {
let mut v = v;
let mut d = d + dsrc;
for (w, wst) in &self.snkitms {
if let NodeState::Finished(dsnk) = *wst {
if let Some(&NodeState::Finished(dsrc)) = self.srcitms.get(w) {
if dsrc + dsnk < d {
d = dsrc + dsnk;
v = *w;
}
}
}
}
midnode = Some(v);
break;
}
self.snkitms.insert(v, NodeState::Finished(d));
for (e, u) in inedges(self.g, v) {
match self.snkitms.get(&u) {
None => {
let newd = d + weights[e];
self.snkitms.insert(
u,
NodeState::Seen(self.snkheap.insert(NodeItem {
node: u,
weight: newd,
pred: Some((v, e)),
})),
);
}
Some(&NodeState::Seen(itm)) => {
let newd = d + weights[e];
if newd < self.snkheap.key(itm).weight {
{
let data = self.snkheap.key(itm);
data.weight = newd;
data.pred = Some((v, e));
}
self.snkheap.decrease(itm);
}
}
_ => (),
}
}
}
if let Some(midnode) = midnode {
let mut path = vec![];
let mut y = midnode;
for &(v, (u, e)) in self.pred.iter().rev() {
if v == y {
path.push(e);
y = u;
}
}
path.reverse();
let mut x = midnode;
for &(u, (v, e)) in self.succ.iter().rev() {
if u == x {
path.push(e);
x = v;
}
}
path
} else {
vec![]
}
}
}
pub fn undirected<'a, G, Ws, W>(g: &'a G, weights: Ws, src: G::Node, snk: G::Node) -> Vec<G::Edge>
where
G: IndexGraph<'a>,
G::Node: Hash,
Ws: EdgeMap<'a, G, W>,
W: NumAssign + Ord + Copy,
{
let mut d = BiDijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.undirected(weights, src, snk)
}
pub fn bidirected<'a, G, Ws, W>(g: &'a G, weights: Ws, src: G::Node, snk: G::Node) -> Vec<G::Edge>
where
G: IndexNetwork<'a>,
G::Node: Hash,
Ws: EdgeMap<'a, G, W>,
W: NumAssign + Ord + Copy,
{
let mut d = BiDijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.bidirected(weights, src, snk)
}
pub fn directed<'a, G, Ws, W>(g: &'a G, weights: Ws, src: G::Node, snk: G::Node) -> Vec<G::Edge>
where
G: IndexDigraph<'a>,
G::Node: Hash,
Ws: EdgeMap<'a, G, W>,
W: NumAssign + Ord + Copy,
{
let mut d = BiDijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.directed(weights, src, snk)
}
pub fn generic<'a, G, W, Weights, Out, OutIt, In, InIt, H>(
g: &'a G,
weights: Weights,
src: G::Node,
snk: G::Node,
outedges: Out,
inedges: In,
) -> Vec<G::Edge>
where
G: IndexGraph<'a>,
G::Node: Hash,
W: NumAssign + Ord + Copy,
Weights: Index<G::Edge, Output = W>,
Out: Fn(&'a G, G::Node) -> OutIt,
OutIt: Iterator<Item = (G::Edge, G::Node)>,
In: Fn(&'a G, G::Node) -> InIt,
InIt: Iterator<Item = (G::Edge, G::Node)>,
H: Heap<Key = NodeItem<G::Node, G::Edge, W>, Item = usize>,
{
let mut d = BiDijkstra::<_, _, _, _, BinHeap<NodeItem<_, _, W>, usize>>::new(g);
d.generic(weights, src, snk, outedges, inedges)
}
#[derive(Clone, Copy)]
pub struct NodeItem<Node: Copy, Edge: Copy, W: Copy + PartialOrd> {
node: Node,
pred: Option<(Node, 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)
}
}
#[derive(Clone, Copy)]
enum NodeState<T> {
Seen(usize),
Finished(T),
}