use std::{
cmp::Ordering::{
Equal,
Greater,
Less,
},
ops::{
Index,
IndexMut,
Range,
RangeFull,
},
ptr::write,
};
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub struct DistanceMatrix<W> {
pub dist: Vec<W>,
pub infinity: W,
pub order: usize,
}
impl<W> DistanceMatrix<W> {
#[must_use]
pub fn new(order: usize, infinity: W) -> Self
where
W: Copy,
{
assert!(order > 0, "a distance matrix has at least one vertex");
let size = order
.checked_mul(order)
.expect("a matrix has at most `usize::MAX` elements");
let mut dist = Vec::with_capacity(size);
let dist_ptr: *mut W = dist.as_mut_ptr();
unsafe {
dist.set_len(size);
for i in 0..size {
write(dist_ptr.add(i), infinity);
}
}
Self {
dist,
infinity,
order,
}
}
#[doc(alias = "centre")]
#[doc(alias = "jordan_center")]
#[doc(alias = "jordan_centre")]
#[must_use]
pub fn center(&self) -> Vec<usize>
where
W: Copy + Ord,
{
let ecc = self.eccentricities();
let mut center = Vec::new();
let mut min = self.infinity;
for (i, &e) in ecc.enumerate() {
match e.cmp(&min) {
Less => {
center.clear();
center.push(i);
min = e;
}
Equal => center.push(i),
Greater => (),
}
}
center
}
#[must_use]
pub fn diameter(&self) -> &W
where
W: Copy + Ord,
{
self.eccentricities().max().unwrap_or(&self.infinity)
}
pub fn eccentricities(&self) -> impl Iterator<Item = &'_ W>
where
W: Ord,
{
self.dist
.chunks(self.order)
.map(|row| row.iter().max().unwrap_or(&self.infinity))
}
#[must_use]
pub fn is_connected(&self) -> bool
where
W: Ord,
{
self.eccentricities().all(|e| e != &self.infinity)
}
pub fn periphery(&self) -> impl Iterator<Item = usize>
where
W: Copy + Ord,
{
let ecc = self.eccentricities();
let diameter = self.diameter();
ecc.enumerate()
.filter_map(move |(i, e)| (e == diameter).then_some(i))
}
}
impl<W> Index<usize> for DistanceMatrix<W> {
type Output = W;
fn index(&self, index: usize) -> &Self::Output {
&self.dist[index]
}
}
impl<W> IndexMut<usize> for DistanceMatrix<W> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.dist[index]
}
}
impl<W> Index<(usize, usize)> for DistanceMatrix<W> {
type Output = W;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.dist[index.0 * self.order + index.1]
}
}
impl<W> IndexMut<(usize, usize)> for DistanceMatrix<W> {
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
&mut self.dist[index.0 * self.order + index.1]
}
}
impl<W> Index<RangeFull> for DistanceMatrix<W> {
type Output = [W];
fn index(&self, _: RangeFull) -> &Self::Output {
&self.dist
}
}
impl<W> IndexMut<RangeFull> for DistanceMatrix<W> {
fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
&mut self.dist
}
}
impl<W> Index<Range<usize>> for DistanceMatrix<W> {
type Output = [W];
fn index(&self, index: Range<usize>) -> &Self::Output {
&self.dist[index]
}
}
impl<W> IndexMut<Range<usize>> for DistanceMatrix<W> {
fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
&mut self.dist[index]
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::{
AdjacencyListWeighted,
Empty,
FloydWarshall,
RemoveArc,
repr::adjacency_list_weighted::fixture::{
kattis_bryr_1_isize,
kattis_bryr_2_isize,
kattis_bryr_3_isize,
kattis_crosscountry_isize,
},
},
};
#[test]
fn center_kattis_bryr_1() {
let digraph = kattis_bryr_1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.center().iter().eq(&[0, 1, 2]));
}
#[test]
fn center_kattis_bryr_2() {
let digraph = kattis_bryr_2_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.center().iter().eq(&[3]));
}
#[test]
fn center_kattis_bryr_3() {
let digraph = kattis_bryr_3_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.center().iter().eq(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
}
#[test]
fn center_kattis_crosscountry() {
let digraph = kattis_crosscountry_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.center().iter().eq(&[3]));
}
#[test]
fn center_trivial() {
let digraph = AdjacencyListWeighted::<isize>::trivial();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.center().iter().eq(&[0]));
}
#[test]
fn diameter_kattis_bryr_1() {
let digraph = kattis_bryr_1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist.diameter(), &1);
}
#[test]
fn diameter_kattis_bryr_2() {
let digraph = kattis_bryr_2_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist.diameter(), &4);
}
#[test]
fn diameter_kattis_bryr_3() {
let digraph = kattis_bryr_3_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist.diameter(), &1);
}
#[test]
fn diameter_kattis_crosscountry() {
let digraph = kattis_crosscountry_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist.diameter(), &11);
}
#[test]
fn diameter_trivial() {
let digraph = AdjacencyListWeighted::<isize>::trivial();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert_eq!(dist.diameter(), &0);
}
#[test]
fn eccentricities_kattis_bryr_1() {
let digraph = kattis_bryr_1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.eccentricities().eq(&[1, 1, 1]));
}
#[test]
fn eccentricities_kattis_bryr_2() {
let digraph = kattis_bryr_2_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.eccentricities().eq(&[3, 4, 3, 2, 3, 4]));
}
#[test]
fn eccentricities_kattis_bryr_3() {
let digraph = kattis_bryr_3_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.eccentricities().eq(&[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]));
}
#[test]
fn eccentricities_kattis_crosscountry() {
let digraph = kattis_crosscountry_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.eccentricities().eq(&[10, 11, 7, 6]));
}
#[test]
fn eccentricities_trivial() {
let digraph = AdjacencyListWeighted::<isize>::trivial();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.eccentricities().eq(&[0]));
}
#[test]
fn index_usize() {
let dist = DistanceMatrix::new(4, isize::MAX);
assert_eq!(dist[0], isize::MAX);
assert_eq!(dist[1], isize::MAX);
assert_eq!(dist[2], isize::MAX);
assert_eq!(dist[3], isize::MAX);
}
#[test]
fn index_mut_usize() {
let mut dist = DistanceMatrix::new(4, isize::MAX);
dist[0] = 1;
dist[1] = 2;
dist[2] = 3;
dist[3] = 4;
assert!(dist[0..4].iter().eq(&[1, 2, 3, 4]));
}
#[test]
fn index_tuple() {
let dist = DistanceMatrix::new(4, isize::MAX);
assert_eq!(dist[(0, 0)], isize::MAX);
assert_eq!(dist[(0, 1)], isize::MAX);
assert_eq!(dist[(0, 2)], isize::MAX);
assert_eq!(dist[(0, 3)], isize::MAX);
assert_eq!(dist[(1, 0)], isize::MAX);
assert_eq!(dist[(1, 1)], isize::MAX);
assert_eq!(dist[(1, 2)], isize::MAX);
assert_eq!(dist[(1, 3)], isize::MAX);
assert_eq!(dist[(2, 0)], isize::MAX);
assert_eq!(dist[(2, 1)], isize::MAX);
assert_eq!(dist[(2, 2)], isize::MAX);
assert_eq!(dist[(2, 3)], isize::MAX);
assert_eq!(dist[(3, 0)], isize::MAX);
assert_eq!(dist[(3, 1)], isize::MAX);
assert_eq!(dist[(3, 2)], isize::MAX);
assert_eq!(dist[(3, 3)], isize::MAX);
}
#[test]
fn index_mut_tuple() {
let mut dist = DistanceMatrix::new(4, isize::MAX);
dist[(0, 0)] = 1;
dist[(0, 1)] = 2;
dist[(0, 2)] = 3;
dist[(0, 3)] = 4;
dist[(1, 0)] = 5;
dist[(1, 1)] = 6;
dist[(1, 2)] = 7;
dist[(1, 3)] = 8;
dist[(2, 0)] = 9;
dist[(2, 1)] = 10;
dist[(2, 2)] = 11;
dist[(2, 3)] = 12;
dist[(3, 0)] = 13;
dist[(3, 1)] = 14;
dist[(3, 2)] = 15;
dist[(3, 3)] = 16;
assert!(dist[0..4].iter().eq(&[1, 2, 3, 4]));
assert!(dist[4..8].iter().eq(&[5, 6, 7, 8]));
assert!(dist[8..12].iter().eq(&[9, 10, 11, 12]));
assert!(dist[12..16].iter().eq(&[13, 14, 15, 16]));
}
#[test]
fn index_range_full() {
let dist = DistanceMatrix::new(4, isize::MAX);
assert!(dist[..].iter().eq(&[isize::MAX; 16]));
}
#[test]
fn index_mut_range_full() {
let mut dist = DistanceMatrix::new(4, isize::MAX);
dist[..].iter_mut().for_each(|d| *d = 1);
assert!(dist[0..4].iter().eq(&[1; 4]));
assert!(dist[4..8].iter().eq(&[1; 4]));
assert!(dist[8..12].iter().eq(&[1; 4]));
assert!(dist[12..16].iter().eq(&[1; 4]));
}
#[test]
fn index_range() {
let dist = DistanceMatrix::new(4, isize::MAX);
assert!(dist[0..4].iter().eq(&[isize::MAX; 4]));
assert!(dist[4..8].iter().eq(&[isize::MAX; 4]));
assert!(dist[8..12].iter().eq(&[isize::MAX; 4]));
assert!(dist[12..16].iter().eq(&[isize::MAX; 4]));
}
#[test]
fn index_mut_range() {
let mut dist = DistanceMatrix::new(4, isize::MAX);
dist[0..4].iter_mut().for_each(|d| *d = 1);
dist[4..8].iter_mut().for_each(|d| *d = 2);
dist[8..12].iter_mut().for_each(|d| *d = 3);
dist[12..16].iter_mut().for_each(|d| *d = 4);
assert!(dist[0..4].iter().eq(&[1; 4]));
assert!(dist[4..8].iter().eq(&[2; 4]));
assert!(dist[8..12].iter().eq(&[3; 4]));
assert!(dist[12..16].iter().eq(&[4; 4]));
}
#[test]
fn is_connected_kattis_bryr_1() {
let mut digraph = kattis_bryr_1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.is_connected());
assert!(digraph.remove_arc(1, 0));
assert!(digraph.remove_arc(2, 0));
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(!dist.is_connected());
}
#[test]
fn is_connected_kattis_bryr_2() {
let mut digraph = kattis_bryr_2_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.is_connected());
assert!(digraph.remove_arc(3, 4));
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(!dist.is_connected());
}
#[test]
fn is_connected_kattis_bryr_3() {
let mut digraph = kattis_bryr_3_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.is_connected());
assert!(digraph.remove_arc(0, 3));
assert!(digraph.remove_arc(3, 0));
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(!dist.is_connected());
}
#[test]
fn is_connected_kattis_crosscountry() {
let mut digraph = kattis_crosscountry_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.is_connected());
assert!(digraph.remove_arc(0, 1));
assert!(digraph.remove_arc(2, 1));
assert!(digraph.remove_arc(3, 1));
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(!dist.is_connected());
}
#[test]
fn is_connected_trivial() {
let digraph = AdjacencyListWeighted::<isize>::trivial();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.is_connected());
}
#[test]
fn new() {
let dist = DistanceMatrix::new(4, isize::MAX);
assert_eq!(dist.infinity, isize::MAX);
assert!(dist[0..4].iter().eq(&[isize::MAX; 4]));
assert!(dist[4..8].iter().eq(&[isize::MAX; 4]));
assert!(dist[8..12].iter().eq(&[isize::MAX; 4]));
assert!(dist[12..16].iter().eq(&[isize::MAX; 4]));
}
#[test]
#[should_panic(expected = "a distance matrix has at least one vertex")]
fn new_0() {
drop(DistanceMatrix::new(0, isize::MAX));
}
#[test]
fn periphery_kattis_bryr_1() {
let digraph = kattis_bryr_1_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.periphery().eq([0, 1, 2]));
}
#[test]
fn periphery_kattis_bryr_2() {
let digraph = kattis_bryr_2_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.periphery().eq([1, 5]));
}
#[test]
fn periphery_kattis_bryr_3() {
let digraph = kattis_bryr_3_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.periphery().eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
}
#[test]
fn periphery_kattis_crosscountry() {
let digraph = kattis_crosscountry_isize();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.periphery().eq([1]));
}
#[test]
fn periphery_trivial() {
let digraph = AdjacencyListWeighted::<isize>::trivial();
let mut floyd_warshall = FloydWarshall::new(&digraph);
let dist = floyd_warshall.distances();
assert!(dist.periphery().eq([0]));
}
}