use crate::factor_solve;
use num_traits::{Float, PrimInt, ToPrimitive};
const TESTS_TOL: f64 = 1e-4;
#[test]
fn basic() {
let a_n = 10;
let a_p = vec![0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 17];
let a_i = vec![0, 1, 1, 2, 3, 4, 1, 5, 0, 6, 3, 7, 6, 8, 1, 2, 9];
let a_x = vec![
1.0, 0.460641, -0.121189, 0.417928, 0.177828, 0.1, -0.0290058, -1.0, 0.350321, -0.441092,
-0.0845395, -0.316228, 0.178663, -0.299077, 0.182452, -1.56506, -0.1,
];
let mut b = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let xsol = vec![
10.2171, 3.9416, -5.69096, 9.28661, 50.0, -6.11433, -26.3104, -27.7809, -45.8099, -3.74178,
];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL,
"Solve accuracy failed"
);
}
#[test]
fn basic_f32_i64() {
let a_n = 10;
let a_p = vec![0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 17];
let a_i = vec![0, 1, 1, 2, 3, 4, 1, 5, 0, 6, 3, 7, 6, 8, 1, 2, 9];
let a_x = vec![
1.0, 0.460641, -0.121189, 0.417928, 0.177828, 0.1, -0.0290058, -1.0, 0.350321, -0.441092,
-0.0845395, -0.316228, 0.178663, -0.299077, 0.182452, -1.56506, -0.1,
];
let mut b = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let xsol = vec![
10.2171, 3.9416, -5.69096, 9.28661, 50.0, -6.11433, -26.3104, -27.7809, -45.8099, -3.74178,
];
let status = factor_solve::<f32, i64>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL as f32,
"Solve accuracy failed"
);
}
#[test]
fn identity() {
let a_p = vec![0, 1, 2, 3, 4];
let a_i = vec![0, 1, 2, 3];
let a_x = vec![1.0, 1.0, 1.0, 1.0];
let a_n = 4;
let mut b = vec![2.0, 2.0, 2.0, 2.0];
let xsol = vec![2.0, 2.0, 2.0, 2.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL,
"Solve accuracy failed"
);
}
#[test]
fn osqp_kkt() {
let a_p = vec![0, 1, 2, 5, 6, 7, 8, 12];
let a_i = vec![0, 1, 2, 1, 0, 3, 4, 5, 5, 6, 4, 3];
let a_x = vec![
-0.25, -0.25, 1.0, 0.513578, 0.529142, -0.25, -0.25, 1.10274, 0.15538, 1.25883, 0.13458,
0.621134,
];
let a_n = 7;
let mut b = vec![
-0.595598, -0.0193715, -0.576156, -0.168746, 0.61543, 0.419073, 1.31087,
];
let xsol = vec![
1.13141, -1.1367, -0.591044, 1.68867, -2.24209, 0.32254, 0.407998,
];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL,
"Solve accuracy failed"
);
}
#[test]
fn rank_deficient() {
let a_p = vec![0, 1, 3];
let a_i = vec![0, 0, 1];
let a_x = vec![1.0, 1.0, 1.0];
let a_n = 2;
let mut b = vec![1.0, 1.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_err(), "Rank deficiency not detected");
}
#[test]
fn singleton() {
let a_p = vec![0, 1];
let a_i = vec![0];
let a_x = vec![0.2];
let a_n = 1;
let mut b = vec![2.0];
let xsol = vec![10.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL,
"Solve accuracy failed"
);
}
#[test]
fn sym_structure() {
let a_p = vec![0, 2, 4];
let a_i = vec![0, 1, 0, 1];
let a_x = vec![5.0, 1.0, 1.0, 5.0];
let a_n = 2;
let mut b = vec![1.0, 1.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_err(), "Fully symmetric input not detected");
}
#[test]
fn tril_structure() {
let a_p = vec![0, 2, 3];
let a_i = vec![0, 1, 1];
let a_x = vec![5.0, 1.0, 5.0];
let a_n = 2;
let mut b = vec![1.0, 1.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_err(), "Tril input not detected");
}
#[test]
fn two_by_two() {
let a_p = vec![0, 1, 3];
let a_i = vec![0, 0, 1];
let a_x = vec![1.0, 1.0, -1.0];
let a_n = 2;
let mut b = vec![2.0, 4.0];
let xsol = vec![3.0, -1.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL,
"Solve accuracy failed"
);
}
#[test]
fn zero_on_diag() {
let a_p = vec![0, 1, 2, 5];
let a_i = vec![0, 0, 0, 1, 2];
let a_x = vec![4.0, 1.0, 2.0, 1.0, -3.0];
let a_n = 3;
let mut b = vec![6.0, 9.0, 12.0];
let xsol = vec![17.0, -46.0, -8.0];
let status = factor_solve::<f64, usize>(a_n, &a_p, &a_i, &a_x, &mut b);
assert!(status.is_ok(), "Factorisation failed");
assert!(
vec_diff_norm(&b, &xsol, a_n) < TESTS_TOL,
"Solve accuracy failed"
);
}
fn vec_diff_norm<S: Float, I: PrimInt + ToPrimitive>(x: &[S], y: &[S], len: I) -> S {
let mut max_diff = S::zero();
for i in 0..len.to_usize().unwrap() {
let el_diff = x[i] - y[i];
max_diff = if el_diff > max_diff {
el_diff
} else {
if -el_diff > max_diff {
-el_diff
} else {
max_diff
}
};
}
max_diff
}