use std::marker::PhantomData;
use crate::{Vertex, Graph};
use crate::algorithms::definitions::Parents;
use crate::error::{GraphError, ErrorKind};
use std::ops::Add;
pub struct Distance<'a, T> {
dist: Vec<Option<T>>,
phantom: PhantomData<&'a T>,
}
impl <'a, T> Distance<'a, T> where T: Copy {
pub fn get_distance(&self, target: &Vertex<T>) -> Option<T> {
self.dist[target.id()]
}
}
pub fn bellman_ford<'a, T>(graph: &'a Graph<T>, from: &'a Vertex<T>) -> Result<(Parents<'a, T>, Distance<'a, T>), GraphError> where T: Default + Copy + PartialOrd + PartialEq + Add<Output = T> {
let mut parents = vec![None; graph.size()];
let mut distances = vec![None; graph.size()];
let from = from.id();
distances[from] = Some(Default::default());
for _ in 0..graph.size() {
let mut any = false;
for idx in 0..graph.size() {
if distances[idx].is_some() {
for edge in &graph.adj[idx].edges {
if distances[edge.to].is_none() {
parents[edge.to] = Some(&graph.adj[idx]);
distances[edge.to] = Some(edge.weight + distances[idx].unwrap());
any = true;
} else if edge.weight + distances[idx].unwrap() < distances[edge.to].unwrap() {
parents[edge.to] = Some(&graph.adj[idx]);
distances[edge.to] = Some(edge.weight + distances[idx].unwrap());
any = true
}
}
}
}
if !any {
return Ok((parents, Distance{dist: distances, phantom: PhantomData}));
}
}
Err(GraphError::Regular(ErrorKind::ExistsCycleNegativeWeight))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bellman_ford(){
use crate::utils;
let mut graph = Graph::new(10);
graph.add_edge(1, 2, 2.0).unwrap();
graph.add_edge(2, 3, 5.0).unwrap();
graph.add_edge(3, 5, 7.0).unwrap();
graph.add_edge(1, 5, 19.0).unwrap();
let start = graph.get_vertex(1).unwrap();
let (parents, distances) = bellman_ford(&graph, start).unwrap();
let target = graph.get_vertex(5).unwrap();
let path = utils::find_path(&graph, &target, &parents).unwrap().unwrap();
assert_eq!(path.iter().map(|vertex|vertex.id()).collect::<Vec<usize>>(), vec![1, 2, 3, 5]);
assert_eq!(distances.get_distance(target).unwrap(), 14.0);
let target = graph.get_vertex(3).unwrap();
let path = utils::find_path(&graph, &target, &parents).unwrap().unwrap();
assert_eq!(path.iter().map(|vertex|vertex.id()).collect::<Vec<usize>>(), vec![1, 2, 3]);
let target = graph.get_vertex(7).unwrap();
assert_eq!(distances.get_distance(target), None);
}
#[test]
#[should_panic]
fn test_bellman_ford_exists_cycle(){
let mut graph = Graph::new(4);
graph.add_edge(1, 2, 2.0).unwrap();
graph.add_edge(2, 3, -2.0).unwrap();
graph.add_edge(3, 4, -2.0).unwrap();
graph.add_edge(4, 2, -2.0).unwrap();
let start = graph.get_vertex(1).unwrap();
bellman_ford(&graph, start).unwrap();
}
}