use super::ContainerResultExt;
use crate::containers::maps::MapTrait;
use crate::graph::{GraphWithEdgeValues, NodeIndex};
use super::AlgorithmError;
pub fn bellman_ford<G, NI, V, M>(
graph: &G,
source: NI,
distance_map: M,
) -> Result<M, AlgorithmError<NI>>
where
G: GraphWithEdgeValues<NI, V>,
NI: NodeIndex,
M: MapTrait<NI, Option<V>>,
V: PartialOrd + Copy + core::ops::Add<Output = V> + Default,
AlgorithmError<NI>: From<G::Error>,
{
let node_count = graph.iter_nodes()?.count();
let max_iterations = if node_count > 0 { node_count - 1 } else { 0 };
bellman_ford_bounded(graph, source, distance_map, max_iterations)
}
pub fn bellman_ford_bounded<G, NI, V, M>(
graph: &G,
source: NI,
mut distance_map: M,
max_iterations: usize,
) -> Result<M, AlgorithmError<NI>>
where
G: GraphWithEdgeValues<NI, V>,
NI: NodeIndex,
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 _ in 0..max_iterations {
let mut changed = false;
for (src, dst, weight_opt) in graph.iter_edge_values()? {
if let Some(weight) = weight_opt {
if let Some(Some(src_dist)) = distance_map.get(&src) {
let new_distance = *src_dist + *weight;
if let Some(dst_dist_opt) = distance_map.get(&dst) {
if dst_dist_opt.is_none() || new_distance < dst_dist_opt.unwrap() {
distance_map
.insert(dst, Some(new_distance))
.capacity_error()?;
changed = true;
}
}
}
}
}
if !changed {
break;
}
}
for (src, dst, weight_opt) in graph.iter_edge_values()? {
if let Some(weight) = weight_opt {
if let Some(Some(src_dist)) = distance_map.get(&src) {
if let Some(Some(dst_dist)) = distance_map.get(&dst) {
let new_distance = *src_dist + *weight;
if new_distance < *dst_dist {
return Err(AlgorithmError::CycleDetected);
}
}
}
}
}
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_bellman_ford_simple() {
let edge_data = EdgeValueStruct([(0usize, 1usize, 5i32), (1, 2, 3)]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let distance_map = Dictionary::<usize, Option<i32>, 16>::new();
let result = bellman_ford(&graph, 0, distance_map).unwrap();
assert_eq!(result.get(&0), Some(&Some(0)));
assert_eq!(result.get(&1), Some(&Some(5)));
assert_eq!(result.get(&2), Some(&Some(8)));
}
#[test]
fn test_bellman_ford_negative_cycle() {
let edge_data = EdgeValueStruct([(0usize, 1usize, -1i32), (1, 0, -1)]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let distance_map = Dictionary::<usize, Option<i32>, 16>::new();
let result = bellman_ford_bounded(&graph, 0, distance_map, 1);
assert!(matches!(result, Err(AlgorithmError::CycleDetected)));
}
#[test]
fn test_bellman_ford_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 result = bellman_ford(&graph, 0, distance_map).unwrap();
assert_eq!(result.get(&0), Some(&Some(0)));
assert_eq!(result.get(&1), Some(&Some(2)));
}
}