use crate::graph::{processing::TopologicalSort, EdgeWeightedDigraph, FlowNetwork, Weight};
use std::cmp::Ordering;
use std::collections::BinaryHeap;
#[derive(Eq, PartialEq)]
struct CurrentNode<T>
where
T: std::hash::Hash,
{
vertex: usize,
distance: T,
}
impl<T: Ord + std::hash::Hash> Ord for CurrentNode<T> {
fn cmp(&self, other: &Self) -> Ordering {
other
.distance
.cmp(&self.distance)
.then_with(|| self.vertex.cmp(&other.vertex))
}
}
impl<T: Ord + std::hash::Hash> PartialOrd for CurrentNode<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub fn dijkstra<T: Weight + std::hash::Hash>(
graph: &EdgeWeightedDigraph<T>,
source: usize,
edge_to: &mut Vec<usize>,
dist_to: &mut Vec<T>,
) {
let nb = graph.nb_vertices();
assert_eq!(edge_to.len(), dist_to.len());
assert_eq!(nb, edge_to.len());
let mut priority_queue = BinaryHeap::new();
dist_to[source] = Weight::zero();
priority_queue.push(CurrentNode {
vertex: source,
distance: Weight::zero(),
});
while let Some(CurrentNode { vertex, distance }) = priority_queue.pop() {
let neighbors = graph.vertex_edges(&vertex);
for (neighbor, dist) in neighbors {
let node = CurrentNode {
vertex: *neighbor,
distance: distance + *dist,
};
if dist_to[*neighbor] > node.distance {
relax(dist_to, edge_to, vertex, *neighbor, *dist);
{
priority_queue.push(node);
}
}
}
}
}
fn relax<T: Weight + std::hash::Hash>(
dist_to: &mut [T],
edge_to: &mut [usize],
origin: usize,
destination: usize,
dist: T,
) {
dist_to[destination] = dist_to[origin] + dist;
edge_to[destination] = origin;
}
pub fn shortest_path_ewdag<T: Weight + std::hash::Hash>(
graph: &EdgeWeightedDigraph<T>,
source: usize,
edge_to: &mut Vec<usize>,
dist_to: &mut Vec<T>,
) {
let nb = graph.nb_vertices();
assert_eq!(edge_to.len(), dist_to.len());
assert_eq!(nb, edge_to.len());
let mut topo = TopologicalSort::init(nb);
topo.depth_first_order(graph);
dist_to[source] = Weight::zero();
let mut flag_source = false;
for vertex in topo.order() {
if *vertex == source {
flag_source = true;
}
if flag_source {
let neighbors = graph.vertex_edges(vertex);
for (neighbor, dist) in neighbors {
if dist_to[*neighbor] > dist_to[*vertex] + *dist {
relax(dist_to, edge_to, *vertex, *neighbor, *dist);
}
}
}
}
}
pub fn bellman_ford<T: Weight + std::hash::Hash>(
graph: &EdgeWeightedDigraph<T>,
source: usize,
edge_to: &mut [usize],
dist_to: &mut [T],
) {
dist_to[source] = Weight::zero();
let nb = graph.nb_edges();
for vertex in 0..nb {
let adj_v = graph.vertex_edges(&vertex);
for (u, w) in adj_v {
if dist_to[*u] > dist_to[vertex] + *w {
relax(dist_to, edge_to, vertex, *u, *w);
}
}
}
}