use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use crate::network::{Edge, Graph};
#[derive(Copy, Clone)]
struct CostNode {
pub idx: usize,
pub cost: u32,
}
impl Ord for CostNode {
fn cmp(&self, other: &CostNode) -> Ordering {
other
.cost
.cmp(&self.cost)
.then_with(|| other.idx.cmp(&self.idx))
}
}
impl PartialOrd for CostNode {
fn partial_cmp(&self, other: &CostNode) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for CostNode {}
impl PartialEq for CostNode {
fn eq(&self, other: &CostNode) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[derive(Clone)]
pub struct Path<'a> {
pub cost: Vec<u32>,
pub predecessors: Vec<Option<&'a Edge>>,
}
pub struct Dijkstra<'a> {
pub graph: &'a Graph,
pub path: Path<'a>,
}
impl<'a> Dijkstra<'a> {
pub fn new(graph: &'a Graph) -> Dijkstra {
Dijkstra {
graph,
path: Path {
cost: vec![std::u32::MAX; graph.node_count()],
predecessors: vec![None; graph.node_count()],
},
}
}
}
impl<'a> Dijkstra<'a> {
pub fn compute_shortest_path(&mut self, src_idx: usize, dst_idx: usize) -> Cow<Path> {
self.path.cost = vec![std::u32::MAX; self.graph.node_count()];
self.path.predecessors = vec![None; self.graph.node_count()];
let mut queue = BinaryHeap::new();
queue.push(CostNode {
idx: src_idx,
cost: 0,
});
self.path.cost[src_idx] = 0;
while let Some(CostNode { idx, cost }) = queue.pop() {
if idx == dst_idx {
break;
}
if cost > self.path.cost[idx] {
continue;
}
if let Some(leaving_edges) = self.graph.leaving_edges(idx) {
for edge in leaving_edges {
let new_cost = cost + edge.meters();
if new_cost < self.path.cost[edge.dst_idx()] {
self.path.predecessors[edge.dst_idx()] = Some(&edge);
self.path.cost[edge.dst_idx()] = new_cost;
queue.push(CostNode {
idx: edge.dst_idx(),
cost: new_cost,
});
}
}
}
}
Cow::Borrowed(&self.path)
}
}