use super::ContainerResultExt;
use crate::containers::maps::MapTrait;
use crate::graph::{GraphWithEdgeValues, NodeIndex};
use super::AlgorithmError;
pub fn dijkstra<G, NI, V, VIS, M>(
graph: &G,
source: NI,
mut visited: VIS,
mut distance_map: M,
) -> Result<M, AlgorithmError<NI>>
where
G: GraphWithEdgeValues<NI, V>,
NI: NodeIndex,
VIS: MapTrait<NI, bool>,
M: MapTrait<NI, Option<V>>,
V: PartialOrd + Copy + core::ops::Add<Output = V> + Default,
AlgorithmError<NI>: From<G::Error>,
{
distance_map
.insert(source, Some(V::default()))
.capacity_error()?;
for node in graph.iter_nodes()? {
if node != source {
distance_map.insert(node, None).capacity_error()?;
}
}
for node in graph.iter_nodes()? {
visited.insert(node, false).capacity_error()?;
}
let node_count = graph.iter_nodes()?.count();
for _ in 0..node_count {
let mut min_distance = None;
let mut min_node = None;
for node in graph.iter_nodes()? {
if let (Some(is_visited), Some(dist_opt)) =
(visited.get(&node), distance_map.get(&node))
{
if !*is_visited {
if let Some(dist) = dist_opt {
if let Some(current_min) = min_distance {
if *dist < current_min {
min_distance = Some(*dist);
min_node = Some(node);
}
} else {
min_distance = Some(*dist);
min_node = Some(node);
}
}
}
}
}
let u = match min_node {
Some(node) => node,
None => break,
};
visited.insert(u, true).capacity_error()?;
for (dst, weight_opt) in graph.outgoing_edge_values(u)? {
if let Some(weight) = weight_opt {
if !*visited.get(&dst).unwrap_or(&false) {
if let Some(Some(u_dist)) = distance_map.get(&u) {
let new_distance = *u_dist + *weight;
if let Some(dst_dist_opt) = distance_map.get(&dst) {
if dst_dist_opt.is_none_or(|old| new_distance < old) {
distance_map
.insert(dst, Some(new_distance))
.capacity_error()?;
}
}
}
}
}
}
}
Ok(distance_map)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::containers::maps::staticdict::Dictionary;
use crate::edgelist::edge_list::EdgeList;
use crate::edges::EdgeValueStruct;
#[test]
fn test_dijkstra_simple() {
let edge_data = EdgeValueStruct([
('A', 'B', 1),
('A', 'C', 4),
('B', 'C', 2),
('B', 'D', 5),
('C', 'D', 1),
]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let distance_map = Dictionary::<char, Option<i32>, 16>::new();
let visited = Dictionary::<char, bool, 16>::new();
let result = dijkstra(&graph, 'A', visited, distance_map).unwrap();
assert_eq!(result.get(&'A'), Some(&Some(0)));
assert_eq!(result.get(&'B'), Some(&Some(1)));
assert_eq!(result.get(&'C'), Some(&Some(3))); assert_eq!(result.get(&'D'), Some(&Some(4))); }
#[test]
fn test_dijkstra_disconnected() {
let edge_data = EdgeValueStruct([(0usize, 1usize, 2i32)]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let distance_map = Dictionary::<usize, Option<i32>, 16>::new();
let visited = Dictionary::<usize, bool, 16>::new();
let result = dijkstra(&graph, 0, visited, distance_map).unwrap();
assert_eq!(result.get(&0), Some(&Some(0)));
assert_eq!(result.get(&1), Some(&Some(2)));
}
}