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"
);
}
}