use crate::adj_matrix::unweighted;
use nalgebra::base::{dimension::Dyn, DMatrix, Scalar};
use nalgebra::{ClosedAddAssign, ClosedMulAssign};
use num_traits::identities::{One, Zero};
use petgraph::visit::{IntoEdges, IntoNodeIdentifiers, NodeCount, NodeIndexable};
use std::ops::Sub;
pub fn seidel<G>(graph: G) -> Vec<Vec<u32>>
where
G: IntoEdges + IntoNodeIdentifiers + NodeCount + NodeIndexable,
{
apd(unweighted(graph, 1u32, 0u32))
.row_iter()
.map(|row| row.into_iter().copied().collect())
.collect()
}
#[allow(non_snake_case)]
pub fn apd<K>(A: DMatrix<K>) -> DMatrix<K>
where
K: Scalar
+ Copy
+ ClosedAddAssign
+ ClosedMulAssign
+ Zero
+ One
+ PartialOrd
+ Sub<K, Output = K>,
{
let n = A.nrows();
let nrows = Dyn(n);
let ncols = Dyn(n);
if (0..n).all(|i| (0..n).all(|j| i == j || A[(i, j)] != K::zero())) {
return A;
}
unsafe {
let mut Z = DMatrix::uninit(nrows, ncols).assume_init();
A.mul_to(&A, &mut Z);
let mut B = DMatrix::uninit(nrows, ncols).assume_init();
for i in 0..n {
for j in 0..n {
if i != j && (A[(i, j)] == K::one() || Z[(i, j)] > K::zero()) {
B[(i, j)] = K::one();
} else {
B[(i, j)] = K::zero();
}
}
}
let T = apd(B);
let mut X = DMatrix::uninit(nrows, ncols).assume_init();
T.mul_to(&A, &mut X);
let degree = A.row_iter().map(|row| row.sum()).collect::<Vec<K>>();
let mut D = DMatrix::uninit(nrows, ncols).assume_init();
for i in 0..n {
for j in 0..n {
if X[(i, j)] >= T[(i, j)] * degree[j] {
D[(i, j)] = T[(i, j)] + T[(i, j)];
} else {
D[(i, j)] = T[(i, j)] + T[(i, j)] - K::one();
}
}
}
D
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generate::random_ungraph;
use crate::shortest_path::floyd_warshall;
use petgraph::graph::Graph;
use petgraph::Directed;
use rand::Rng;
fn graph1() -> Graph<(), f32> {
let mut graph = Graph::<(), f32>::new();
let n0 = graph.add_node(());
let n1 = graph.add_node(());
let n2 = graph.add_node(());
let n3 = graph.add_node(());
let n4 = graph.add_node(());
graph.add_edge(n0, n1, 40.0);
graph.add_edge(n0, n4, 18.0);
graph.add_edge(n1, n0, 40.0);
graph.add_edge(n1, n4, 15.0);
graph.add_edge(n1, n2, 22.0);
graph.add_edge(n1, n3, 6.0);
graph.add_edge(n2, n1, 22.0);
graph.add_edge(n2, n3, 14.0);
graph.add_edge(n3, n4, 20.0);
graph.add_edge(n3, n1, 6.0);
graph.add_edge(n3, n2, 14.0);
graph.add_edge(n4, n0, 18.0);
graph.add_edge(n4, n1, 15.0);
graph.add_edge(n4, n3, 20.0);
graph
}
fn graph2() -> Graph<(), ()> {
let mut graph = Graph::<(), ()>::new();
let n0 = graph.add_node(());
let n1 = graph.add_node(());
let n2 = graph.add_node(());
let n3 = graph.add_node(());
graph.add_edge(n0, n1, ());
graph.add_edge(n1, n0, ());
graph.add_edge(n1, n2, ());
graph.add_edge(n2, n1, ());
graph.add_edge(n1, n3, ());
graph.add_edge(n3, n1, ());
graph.add_edge(n2, n3, ());
graph.add_edge(n3, n2, ());
graph
}
fn graph3() -> Graph<(), f64> {
let mut graph = Graph::<(), f64>::new();
let n0 = graph.add_node(());
let n1 = graph.add_node(());
graph.add_edge(n0, n1, 10.0);
graph.add_edge(n1, n0, 5.0);
graph
}
fn graph4() -> Graph<(), f32> {
Graph::<(), f32>::new()
}
#[test]
fn test_apd() {
assert_eq!(
apd(unweighted(&graph1(), 1u8, 0u8))
.row_iter()
.map(|row| row.into_iter().copied().collect::<Vec<u8>>())
.collect::<Vec<Vec<u8>>>(),
vec![
vec![0, 1, 2, 2, 1],
vec![1, 0, 1, 1, 1],
vec![2, 1, 0, 1, 2],
vec![2, 1, 1, 0, 1],
vec![1, 1, 2, 1, 0]
]
);
assert_eq!(
apd(unweighted(&graph2(), 1usize, 0usize))
.row_iter()
.map(|row| row.into_iter().copied().collect::<Vec<usize>>())
.collect::<Vec<Vec<usize>>>(),
vec![
vec![0, 1, 2, 2],
vec![1, 0, 1, 1],
vec![2, 1, 0, 1],
vec![2, 1, 1, 0],
]
);
assert_eq!(
apd(unweighted(&graph3(), 1f64, 0.0))
.row_iter()
.map(|row| row.into_iter().copied().collect::<Vec<f64>>())
.collect::<Vec<Vec<f64>>>(),
vec![vec![0.0, 1.0], vec![1.0, 0.0]]
);
assert_eq!(
apd(unweighted(&graph4(), 1f32, 0.0))
.row_iter()
.map(|row| row.into_iter().copied().collect::<Vec<f32>>())
.collect::<Vec<Vec<f32>>>(),
Vec::<Vec<f32>>::new()
);
let mut rng = rand::thread_rng();
for n in 2..=50 {
let graph = Graph::<(), f32, Directed, usize>::from_edges(
random_ungraph(
n,
rng.gen_range((n - 1) * (n - 2) / 2 + 1..=n * (n - 1) / 2),
)
.unwrap()
.into_iter()
.map(|edge| (edge.0, edge.1, 1.0)),
);
assert_eq!(
apd(unweighted(&graph, 1f32, 0.0))
.row_iter()
.map(|row| row.into_iter().copied().collect::<Vec<f32>>())
.collect::<Vec<Vec<f32>>>(),
floyd_warshall(&graph, |edge| *edge.weight()).unwrap()
);
}
}
#[test]
fn test_seidel() {
assert_eq!(
seidel(&graph1()),
vec![
vec![0, 1, 2, 2, 1],
vec![1, 0, 1, 1, 1],
vec![2, 1, 0, 1, 2],
vec![2, 1, 1, 0, 1],
vec![1, 1, 2, 1, 0]
]
);
assert_eq!(
seidel(&graph2()),
vec![
vec![0, 1, 2, 2],
vec![1, 0, 1, 1],
vec![2, 1, 0, 1],
vec![2, 1, 1, 0],
]
);
assert_eq!(seidel(&graph3()), vec![vec![0, 1], vec![1, 0]]);
assert_eq!(seidel(&graph4()), Vec::<Vec<u32>>::new());
let mut rng = rand::thread_rng();
for n in 2..=50 {
let graph = Graph::<(), f32, Directed, usize>::from_edges(
random_ungraph(
n,
rng.gen_range((n - 1) * (n - 2) / 2 + 1..=n * (n - 1) / 2),
)
.unwrap()
.into_iter()
.map(|edge| (edge.0, edge.1, 1.0)),
);
assert_eq!(
seidel(&graph)
.into_iter()
.map(|row| row.into_iter().map(|d| d as f32).collect::<Vec<f32>>())
.collect::<Vec<Vec<f32>>>(),
floyd_warshall(&graph, |edge| *edge.weight()).unwrap()
);
}
}
}