use netoptim_rs::min_cycle_ratio::min_cycle_ratio;
use netoptim_rs::neg_cycle::NegCycleFinder;
use netoptim_rs::parametric::{MaxParametricSolver, ParametricAPI};
use num::rational::Ratio;
use petgraph::graph::{DiGraph, EdgeReference};
#[test]
fn test_xval_neg_cycle_cpp_neg() {
let d =
DiGraph::<(), i32>::from_edges([(0, 1, -5), (1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 0, 1)]);
let mut n = NegCycleFinder::new(&d);
assert!(n.howard(&mut [0; 5], |e| *e.weight()).is_some());
}
#[test]
fn test_xval_neg_cycle_cpp_no_neg() {
let d = DiGraph::<(), i32>::from_edges([(0, 1, 2), (1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 0, 1)]);
let mut n = NegCycleFinder::new(&d);
assert!(n.howard(&mut [0; 5], |e| *e.weight()).is_none());
}
#[test]
fn test_xval_neg_cycle_cpp_timing() {
let d = DiGraph::<(), i32>::from_edges([
(0, 1, 3),
(1, 0, -4),
(1, 2, 2),
(2, 1, 0),
(2, 0, -2),
(0, 2, 1),
]);
let mut n = NegCycleFinder::new(&d);
assert!(n.howard(&mut [0; 3], |e| *e.weight()).is_some());
}
#[test]
fn test_xval_neg_cycle_cpp_raw() {
let d = DiGraph::<(), i32>::from_edges([
(0, 1, 7),
(0, 2, 5),
(1, 0, 0),
(1, 2, 3),
(2, 1, 1),
(2, 0, 2),
]);
let mut n = NegCycleFinder::new(&d);
assert!(n.howard(&mut [0; 3], |e| *e.weight()).is_none());
}
#[test]
fn test_xval_net_oracle_neg_cycle_found() {
let d = DiGraph::<(), f64>::from_edges([(0, 1, 1.0), (1, 2, 1.0), (2, 0, -3.0)]);
let mut n = NegCycleFinder::new(&d);
let r = n.howard(&mut [0.0; 3], |e| *e.weight());
assert!(r.is_some());
let s: f64 = r.unwrap().iter().map(|e| *e.weight()).sum();
assert!((s - (-1.0)).abs() < 1e-10);
}
#[test]
fn test_xval_net_oracle_no_cycle() {
let d = DiGraph::<(), f64>::from_edges([(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0)]);
let mut n = NegCycleFinder::new(&d);
assert!(n.howard(&mut [0.0; 3], |e| *e.weight()).is_none());
}
#[test]
fn test_xval_net_oracle_complex() {
let d = DiGraph::<(), f64>::from_edges([
(0, 1, 1.0),
(1, 2, 1.0),
(2, 3, 1.0),
(3, 0, -4.0),
(0, 2, 0.5),
]);
let mut n = NegCycleFinder::new(&d);
let r = n.howard(&mut [0.0; 4], |e| *e.weight());
assert!(r.is_some());
assert!(r.unwrap().iter().map(|e| *e.weight()).sum::<f64>() < 0.0);
}
#[test]
fn test_xval_min_cycle_ratio_5node() {
let d = DiGraph::<(), Ratio<i32>>::from_edges([
(0, 1, Ratio::new(5, 1)),
(1, 2, Ratio::new(1, 1)),
(2, 3, Ratio::new(1, 1)),
(3, 4, Ratio::new(1, 1)),
(4, 0, Ratio::new(1, 1)),
]);
let mut dist = [Ratio::new(0, 1); 5];
let mut r0 = Ratio::new(5, 1);
let c = min_cycle_ratio(
&d,
&mut r0,
|e| *e.weight(),
|_| Ratio::new(1, 1),
&mut dist,
);
assert_eq!(c.len(), 5);
assert_eq!(r0, Ratio::new(9, 5));
}
struct CPP;
impl ParametricAPI<(), Ratio<i32>> for CPP {
fn distance(&self, r: &Ratio<i32>, e: &EdgeReference<Ratio<i32>>) -> Ratio<i32> {
*e.weight() - *r
}
fn zero_cancel(&self, c: &[EdgeReference<Ratio<i32>>]) -> Ratio<i32> {
c.iter().map(|e| *e.weight()).sum::<Ratio<i32>>() / Ratio::new(c.len() as i32, 1)
}
}
#[test]
fn test_xval_max_parametric_no_neg() {
let d = DiGraph::<(), Ratio<i32>>::from_edges([
(0, 1, Ratio::new(2, 1)),
(1, 2, Ratio::new(1, 1)),
(2, 3, Ratio::new(1, 1)),
(3, 4, Ratio::new(1, 1)),
(4, 0, Ratio::new(1, 1)),
]);
let mut s = MaxParametricSolver::new(&d, CPP);
let mut dist = [Ratio::new(0, 1); 5];
let mut r = Ratio::new(0, 1);
assert!(s.run(&mut dist, &mut r).is_empty());
assert_eq!(r, Ratio::new(0, 1));
}
#[test]
fn test_xval_max_parametric_disjoint() {
let d = DiGraph::<(), Ratio<i32>>::from_edges([
(0, 1, Ratio::new(-1, 1)),
(1, 2, Ratio::new(-1, 1)),
(2, 0, Ratio::new(-1, 1)),
]);
let mut s = MaxParametricSolver::new(&d, CPP);
let mut dist = [Ratio::new(0, 1); 3];
let mut r = Ratio::new(0, 1);
assert!(!s.run(&mut dist, &mut r).is_empty());
assert!(r < Ratio::new(0, 1));
}