use super::measures::BoundedMeasure;
use crate::prelude::*;
use core::marker::Copy;
#[derive(Debug, Clone)]
pub struct Paths<K: BoundedMeasure> {
pub distances: Vec<K>,
pub predecessors: Vec<Option<usize>>,
}
pub fn bellman_ford<'a, G: ?Sized, E, F, K, T: GraphType>(
g: &'a G,
source: usize,
edge_cost: F,
) -> Result<Paths<K>, HypergraphErrors>
where
G: CommonProperties<'a, T, NodeIndex = usize, EdgeIndex = usize>,
F: Fn(usize) -> K,
K: BoundedMeasure + Copy,
{
let (distances, predecessors) = bellman_ford_initialize_relax(g, source, &edge_cost);
for i in 0..g.node_count() {
for (k, nodes) in g.costed_neighbours(i, &edge_cost) {
for j in nodes {
if distances[i] + k < distances[j] {
return Err(HypergraphErrors::NegativeCycle);
}
}
}
}
Ok(Paths {
distances,
predecessors,
})
}
pub fn find_negative_cycle<'a, G, F, T: GraphType, K: BoundedMeasure + Copy>(
g: &'a G,
source: usize,
edge_cost: &F,
) -> Option<Vec<usize>>
where
G: CommonProperties<'a, T, NodeIndex = usize, EdgeIndex = usize>,
F: Fn(usize) -> K,
{
let mut path = Vec::<usize>::new();
let (distance, predecessor) = bellman_ford_initialize_relax(g, source, edge_cost);
'outer: for i in 0..g.node_count() {
for (w, nodes) in g.costed_neighbours(i, edge_cost) {
for j in nodes {
if i != j && distance[i] + w < distance[j] {
let start = j;
let mut node = start;
let mut visited = g.visit_map();
loop {
let ancestor = match predecessor[node] {
Some(predecessor_node) => predecessor_node,
None => node, };
if ancestor == start {
path.push(ancestor);
break;
}
else if visited.contains(ancestor) {
let pos = path
.iter()
.position(|&p| p == ancestor)
.expect("we should always have a position");
path = path[pos..path.len()].to_vec();
break;
}
path.push(ancestor);
visited.insert(ancestor);
node = ancestor;
}
break 'outer;
}
}
}
}
if !path.is_empty() {
path.reverse();
Some(path)
} else {
None
}
}
pub fn find_negative_directed_cycle<'a, G, F>(
g: &'a G,
source: usize,
edge_cost: &F,
) -> Option<Vec<usize>>
where
G: DiGraphProperties<'a, NodeIndex = usize, EdgeIndex = usize>,
F: Fn(usize, <G as GraphBasics<'_>>::EdgeRef) -> usize,
{
let mut path = Vec::<usize>::new();
let (distance, predecessor) = bellman_ford_initialize_relax_directed(g, source, edge_cost);
'outer: for i in 0..g.node_count() {
for edge in g.out_edges(i).unwrap() {
let nb = g.target(edge).unwrap();
let w = edge_cost(edge, g.edge(edge)?);
for j in nb {
if i != j && distance[i] + w < distance[j] {
let start = j;
let mut node = start;
let mut visited = g.visit_map();
loop {
let ancestor = match predecessor[node] {
Some(predecessor_node) => predecessor_node,
None => node, };
if ancestor == start {
path.push(ancestor);
break;
}
else if visited.contains(ancestor) {
let pos = path
.iter()
.position(|&p| p == ancestor)
.expect("we should always have a position");
path = path[pos..path.len()].to_vec();
break;
}
path.push(ancestor);
visited.insert(ancestor);
node = ancestor;
}
break 'outer;
}
}
}
}
if !path.is_empty() {
path.reverse();
Some(path)
} else {
None
}
}
#[inline(always)]
fn bellman_ford_initialize_relax<'a, G: ?Sized, F, K, T: GraphType>(
g: &'a G,
source: usize,
edge_cost: F,
) -> (Vec<K>, Vec<Option<usize>>)
where
G: CommonProperties<'a, T, NodeIndex = usize, EdgeIndex = usize>,
F: Fn(usize) -> K,
K: BoundedMeasure + Copy,
{
let mut predecessor = vec![None; g.node_count()];
let mut distance = vec![K::max(); g.node_count()];
distance[source] = K::default();
for _ in 1..g.node_count() {
let mut did_update = false;
for i in 0..g.node_count() {
for (w, nodes) in g.costed_neighbours(i, &edge_cost) {
for j in nodes {
if distance[i] + w < distance[j] {
distance[j] = distance[i] + w;
predecessor[j] = Some(i);
did_update = true;
}
}
}
}
if !did_update {
break;
}
}
(distance, predecessor)
}
#[inline(always)]
fn bellman_ford_initialize_relax_directed<'a, G, F, K>(
g: &'a G,
source: usize,
mut edge_cost: F,
) -> (Vec<K>, Vec<Option<usize>>)
where
G: DiGraphProperties<'a, NodeIndex = usize, EdgeIndex = usize>,
F: FnMut(usize, <G as GraphBasics<'_>>::EdgeRef) -> K,
K: BoundedMeasure + Copy,
{
let mut predecessor = vec![None; g.node_count()];
let mut distance = vec![K::max(); g.node_count()];
distance[source] = K::default();
for _ in 1..g.node_count() {
let mut did_update = false;
for i in 0..g.node_count() {
for edge_index in g.out_edges(i).unwrap() {
let w = edge_cost(edge_index, g.edge(edge_index).unwrap());
for j in g.target(edge_index).unwrap() {
if distance[i] + w < distance[j] {
distance[j] = distance[i] + w;
predecessor[j] = Some(i);
did_update = true;
}
}
}
}
if !did_update {
break;
}
}
(distance, predecessor)
}