use super::super::*;
use crate::options::{IpmOptions, SolverOptions, Tolerance};
use crate::problem::SolveStatus;
use crate::sparse::CscMatrix;
fn make_trivial_qp() -> QpProblem {
let q = CscMatrix::from_triplets(&[0], &[0], &[1.0], 1, 1).unwrap();
let c = vec![0.0];
let a = CscMatrix::from_triplets(&[0], &[0], &[1.0], 1, 1).unwrap();
let b = vec![5.0];
let bounds = vec![(0.0, f64::INFINITY)];
QpProblem::new_all_le(q, c, a, b, bounds).unwrap()
}
fn make_trivial_lp_as_qp() -> QpProblem {
let q = CscMatrix::from_triplets(&[], &[], &[], 1, 1).unwrap();
let c = vec![1.0];
let a = CscMatrix::from_triplets(&[0], &[0], &[1.0], 1, 1).unwrap();
let b = vec![5.0];
let bounds = vec![(0.0, f64::INFINITY)];
QpProblem::new_all_le(q, c, a, b, bounds).unwrap()
}
#[test]
fn invalid_options_rejected_at_qp_entry() {
let qp = make_trivial_qp();
let cases: &[(&str, SolverOptions)] = &[
("nan primal_tol", SolverOptions { primal_tol: f64::NAN, ..Default::default() }),
("zero primal_tol", SolverOptions { primal_tol: 0.0, ..Default::default() }),
("neg dual_tol", SolverOptions { dual_tol: -1e-6, ..Default::default() }),
("inf timeout_secs", SolverOptions { timeout_secs: Some(f64::INFINITY), ..Default::default() }),
("neg timeout_secs", SolverOptions { timeout_secs: Some(-1.0), ..Default::default() }),
("zero threads", SolverOptions { threads: 0, ..Default::default() }),
("custom tol nan", SolverOptions { tolerance: Some(Tolerance::Custom(f64::NAN)), ..Default::default() }),
("ipm eps nan", SolverOptions {
ipm: IpmOptions { eps: f64::NAN, ..Default::default() },
..Default::default()
}),
];
for (label, opts) in cases {
let result = solve_qp_with(&qp, opts);
assert_eq!(
result.status,
SolveStatus::NumericalError,
"solve_qp_with with {label} must return NumericalError"
);
}
}
#[test]
fn invalid_options_rejected_at_qp_entry_lp_path() {
let lp_as_qp = make_trivial_lp_as_qp();
let cases: &[(&str, SolverOptions)] = &[
("zero threads lp path", SolverOptions { threads: 0, ..Default::default() }),
("nan primal_tol lp path", SolverOptions { primal_tol: f64::NAN, ..Default::default() }),
("neg timeout lp path", SolverOptions { timeout_secs: Some(-0.1), ..Default::default() }),
];
for (label, opts) in cases {
let result = solve_qp_with(&lp_as_qp, opts);
assert_eq!(
result.status,
SolveStatus::NumericalError,
"solve_qp_with (LP path) with {label} must return NumericalError"
);
}
}