#![allow(clippy::type_complexity)]
use crate::num::traits::{Bounded, NumAssign};
use crate::traits::{IndexDigraph, IndexGraph};
pub fn undirected<'a, G, W, F>(g: &'a G, weights: F) -> Vec<Vec<Option<(W, G::Node)>>>
where
G: IndexGraph<'a>,
W: NumAssign + Ord + Copy + Bounded,
F: Fn(G::Edge) -> W,
{
let mut dist: Vec<Vec<Option<(W, G::Node)>>> = vec![vec![None; g.num_nodes()]; g.num_nodes()];
for u in g.nodes() {
dist[g.node_id(u)][g.node_id(u)] = Some((W::zero(), u));
}
for e in g.edges() {
let (u, v) = g.enodes(e);
let uid = g.node_id(u);
let vid = g.node_id(v);
let w = weights(e);
if w < dist[uid][vid].map(|x| x.0).unwrap_or_else(W::max_value) {
dist[uid][vid] = Some((w, u));
dist[vid][uid] = Some((w, u));
}
}
for k in 0..g.num_nodes() {
for u in 0..g.num_nodes() {
if u == k {
continue;
}
if let Some(&(dist_uk, _)) = dist[u][k].as_ref() {
for v in 0..g.num_nodes() {
if v == k {
continue;
}
if let Some(&(dist_kv, pred_kv)) = dist[k][v].as_ref() {
if dist[u][v].map(|x| x.0).unwrap_or_else(W::max_value) > dist_uk + dist_kv {
dist[u][v] = Some((dist_uk + dist_kv, pred_kv));
}
}
}
}
}
}
dist
}
pub fn directed<'a, G, W, F>(g: &'a G, weights: F) -> Vec<Vec<Option<(W, G::Node)>>>
where
G: IndexDigraph<'a>,
W: NumAssign + Ord + Copy + Bounded,
F: Fn(G::Edge) -> W,
{
let mut dist: Vec<Vec<Option<(W, G::Node)>>> = vec![vec![None; g.num_nodes()]; g.num_nodes()];
for u in g.nodes() {
dist[g.node_id(u)][g.node_id(u)] = Some((W::zero(), u));
}
for e in g.edges() {
let (u, v) = (g.src(e), g.snk(e));
let uid = g.node_id(u);
let vid = g.node_id(v);
let w = weights(e);
if w < dist[uid][vid].map(|x| x.0).unwrap_or_else(W::max_value) {
dist[uid][vid] = Some((w, u));
}
}
for k in 0..g.num_nodes() {
for u in 0..g.num_nodes() {
if u == k {
continue;
}
if let Some(&(dist_uk, _)) = dist[u][k].as_ref() {
for v in 0..g.num_nodes() {
if v == k {
continue;
}
if let Some(&(dist_kv, pred_kv)) = dist[k][v].as_ref() {
if dist[u][v].map(|x| x.0).unwrap_or_else(W::max_value) > dist_uk + dist_kv {
dist[u][v] = Some((dist_uk + dist_kv, pred_kv));
}
}
}
}
}
}
dist
}