use crate::{
ArcsWeighted,
DistanceMatrix,
Order,
Vertices,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FloydWarshall<'a, D> {
digraph: &'a D,
dist: DistanceMatrix<isize>,
}
impl<'a, D> FloydWarshall<'a, D> {
#[must_use]
pub fn new(digraph: &'a D) -> Self
where
D: Order,
{
Self {
digraph,
dist: DistanceMatrix::<isize>::new(digraph.order(), isize::MAX),
}
}
#[doc(alias = "apsp")]
#[must_use]
pub fn distances(&mut self) -> &DistanceMatrix<isize>
where
D: ArcsWeighted<Weight = isize> + Order + Vertices,
{
let dist_ptr = self.dist.dist.as_mut_ptr();
let order = self.digraph.order();
for (u, v, &w) in self.digraph.arcs_weighted() {
unsafe {
*dist_ptr.add(u * order + v) = w;
}
}
for i in 0..self.digraph.order() {
unsafe {
*dist_ptr.add(i * order + i) = 0;
}
}
for i in self.digraph.vertices() {
for j in self.digraph.vertices() {
let a = unsafe { *dist_ptr.add(j * order + i) };
if a == isize::MAX {
continue;
}
for k in self.digraph.vertices() {
let b = unsafe { *dist_ptr.add(i * order + k) };
if b == isize::MAX {
continue;
}
let s = a + b;
if s < unsafe { *dist_ptr.add(j * order + k) } {
unsafe {
*dist_ptr.add(j * order + k) = s;
}
}
}
}
}
&self.dist
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::{
AddArcWeighted,
AdjacencyListWeighted,
Empty,
repr::adjacency_list_weighted::fixture::{
bang_jensen_94_isize,
bang_jensen_96_isize,
bang_jensen_99,
kattis_bryr_1_isize,
kattis_bryr_2_isize,
kattis_bryr_3_isize,
kattis_crosscountry_isize,
kattis_shortestpath1_isize,
},
},
};
#[test]
fn distances_doctest() {
let mut digraph = AdjacencyListWeighted::empty(4);
digraph.add_arc_weighted(0, 2, -2);
digraph.add_arc_weighted(1, 0, 4);
digraph.add_arc_weighted(1, 2, 3);
digraph.add_arc_weighted(2, 3, 2);
digraph.add_arc_weighted(3, 1, -1);
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], -1);
assert_eq!(dist[(0, 2)], -2);
assert_eq!(dist[(0, 3)], 0);
assert_eq!(dist[(1, 0)], 4);
assert_eq!(dist[(1, 1)], 0);
assert_eq!(dist[(1, 2)], 2);
assert_eq!(dist[(1, 3)], 4);
assert_eq!(dist[(2, 0)], 5);
assert_eq!(dist[(2, 1)], 1);
assert_eq!(dist[(2, 2)], 0);
assert_eq!(dist[(2, 3)], 2);
assert_eq!(dist[(3, 0)], 3);
assert_eq!(dist[(3, 1)], -1);
assert_eq!(dist[(3, 2)], 1);
assert_eq!(dist[(3, 3)], 0);
}
#[test]
fn distances_trivial() {
let digraph = AdjacencyListWeighted::<isize>::trivial();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
}
#[test]
fn distances_bang_jensen_94_weighted() {
let digraph = bang_jensen_94_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 1);
assert_eq!(dist[(0, 2)], 1);
assert_eq!(dist[(0, 3)], 2);
assert_eq!(dist[(0, 4)], 2);
assert_eq!(dist[(0, 5)], 2);
assert_eq!(dist[(0, 6)], 3);
}
#[test]
fn distances_bang_jensen_96() {
let digraph = bang_jensen_96_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 5);
assert_eq!(dist[(0, 2)], 3);
assert_eq!(dist[(0, 3)], 6);
assert_eq!(dist[(0, 4)], 4);
assert_eq!(dist[(0, 5)], 7);
}
#[test]
fn distances_bang_jensen_99() {
let digraph = bang_jensen_99();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 8);
assert_eq!(dist[(0, 2)], 3);
assert_eq!(dist[(0, 3)], 1);
assert_eq!(dist[(0, 4)], -4);
assert_eq!(dist[(0, 5)], -1);
}
#[test]
fn distances_kattis_bryr_1() {
let digraph = kattis_bryr_1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 1);
assert_eq!(dist[(0, 2)], 1);
}
#[test]
fn distances_kattis_bryr_2() {
let digraph = kattis_bryr_2_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 1);
assert_eq!(dist[(0, 2)], 2);
assert_eq!(dist[(0, 3)], 1);
assert_eq!(dist[(0, 4)], 2);
assert_eq!(dist[(0, 5)], 3);
}
#[test]
fn distances_kattis_bryr_3() {
let digraph = kattis_bryr_3_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 0);
assert_eq!(dist[(0, 2)], 1);
assert_eq!(dist[(0, 3)], 0);
assert_eq!(dist[(0, 4)], 0);
assert_eq!(dist[(0, 5)], 0);
assert_eq!(dist[(0, 6)], 1);
assert_eq!(dist[(0, 7)], 0);
assert_eq!(dist[(0, 8)], 0);
assert_eq!(dist[(0, 9)], 1);
}
#[test]
fn distances_kattis_crosscountry() {
let digraph = kattis_crosscountry_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 1);
assert_eq!(dist[(0, 2)], 3);
assert_eq!(dist[(0, 3)], 10);
}
#[test]
fn distances_kattis_shortestpath1() {
let digraph = kattis_shortestpath1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist[(0, 0)], 0);
assert_eq!(dist[(0, 1)], 2);
assert_eq!(dist[(0, 2)], 4);
assert_eq!(dist[(0, 3)], dist.infinity);
}
}