use super::super::*;
use crate::problem::SolveStatus;
use crate::sparse::CscMatrix;
#[test]
fn test_qp001_solve_as_lp_no_numerical_error() {
let q = CscMatrix::from_triplets(&[], &[], &[], 2, 2).unwrap();
let c = vec![-1.0, -1.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[1.0, 1.0], 1, 2).unwrap();
let b = vec![4.0];
let bounds = vec![(0.0f64, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let opts = SolverOptions {
presolve: false,
..SolverOptions::default()
};
let result = solve_qp_with(&problem, &opts);
assert_ne!(result.status, SolveStatus::NumericalError);
}
#[test]
fn test_a2t03_qp_no_deadline_converges() {
let q = CscMatrix::from_triplets(&[0, 1], &[0, 1], &[2.0, 2.0], 2, 2).unwrap();
let c = vec![0.0, 0.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[-1.0, -1.0], 1, 2).unwrap();
let b = vec![-1.0];
let bounds = vec![(f64::NEG_INFINITY, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let opts = SolverOptions {
timeout_secs: None,
..SolverOptions::default()
};
let result = solve_qp_with(&problem, &opts);
assert_eq!(result.status, SolveStatus::Optimal);
}
#[test]
fn test_a3c02_cancel_flag_preset_qp_returns_timeout() {
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
let q = CscMatrix::from_triplets(&[0, 1], &[0, 1], &[2.0, 2.0], 2, 2).unwrap();
let c = vec![0.0, 0.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[-1.0, -1.0], 1, 2).unwrap();
let b = vec![-1.0];
let bounds = vec![(f64::NEG_INFINITY, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let cancel = Arc::new(AtomicBool::new(true));
let opts = SolverOptions {
cancel_flag: Some(Arc::clone(&cancel)),
..SolverOptions::default()
};
let result = solve_qp_with(&problem, &opts);
assert_eq!(result.status, SolveStatus::Timeout);
}
#[test]
fn test_a4p01_presolve_transparency_qp() {
let q = CscMatrix::from_triplets(&[0, 1], &[0, 1], &[2.0, 2.0], 2, 2).unwrap();
let c = vec![0.0, 0.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[-1.0, -1.0], 1, 2).unwrap();
let b = vec![-1.0];
let bounds = vec![(f64::NEG_INFINITY, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let opts_with = SolverOptions {
presolve: true,
..SolverOptions::default()
};
let opts_without = SolverOptions {
presolve: false,
..SolverOptions::default()
};
let result_with = solve_qp_with(&problem, &opts_with);
let result_without = solve_qp_with(&problem, &opts_without);
assert_eq!(result_with.status, SolveStatus::Optimal);
assert_eq!(result_without.status, SolveStatus::Optimal);
assert!((result_with.solution[0] - result_without.solution[0]).abs() < 1e-3);
assert!((result_with.solution[1] - result_without.solution[1]).abs() < 1e-3);
}
#[test]
fn test_a6i03_nonconvex_skip_for_large_n() {
let n = 1001usize;
let mut rows = vec![0usize];
let mut cols = vec![0usize];
let mut vals = vec![-1e-3_f64];
for i in 1..n {
rows.push(i);
cols.push(i);
vals.push(1.0);
}
let q1 = CscMatrix::from_triplets(&rows, &cols, &vals, n, n).unwrap();
assert!(!check_q_positive_semidefinite(&q1));
let mut rows2: Vec<usize> = (0..n).collect();
let mut cols2: Vec<usize> = (0..n).collect();
let mut vals2: Vec<f64> = vec![1.0; n];
rows2.push(0);
cols2.push(1);
vals2.push(-2.0);
let q2 = CscMatrix::from_triplets(&rows2, &cols2, &vals2, n, n).unwrap();
assert!(check_q_positive_semidefinite(&q2));
}
#[cfg(feature = "parallel")]
#[test]
fn test_a7cs02_concurrent_cancel_flag_thread_safety() {
let q = CscMatrix::from_triplets(&[0, 1], &[0, 1], &[2.0, 2.0], 2, 2).unwrap();
let c = vec![0.0, 0.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[-1.0, -1.0], 1, 2).unwrap();
let b = vec![-1.0];
let bounds = vec![(f64::NEG_INFINITY, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
for _ in 0..10 {
let opts = SolverOptions::default();
let result = solve_qp_with(&problem, &opts);
assert_eq!(result.status, SolveStatus::Optimal);
}
}
#[cfg(feature = "parallel")]
#[test]
fn test_a7cs03_concurrent_all_timeout_returns_timeout() {
let q = CscMatrix::from_triplets(&[0, 1], &[0, 1], &[2.0, 2.0], 2, 2).unwrap();
let c = vec![0.0, 0.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[-1.0, -1.0], 1, 2).unwrap();
let b = vec![-1.0];
let bounds = vec![(f64::NEG_INFINITY, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let opts = SolverOptions {
timeout_secs: Some(0.0),
..SolverOptions::default()
};
let result = solve_qp_with(&problem, &opts);
assert_eq!(result.status, SolveStatus::Timeout);
}
#[cfg(feature = "parallel")]
#[test]
fn test_a3c01_cancel_flag_concurrent_returns_timeout() {
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
let q = CscMatrix::from_triplets(&[0, 1], &[0, 1], &[2.0, 2.0], 2, 2).unwrap();
let c = vec![0.0, 0.0];
let a = CscMatrix::from_triplets(&[0, 0], &[0, 1], &[-1.0, -1.0], 1, 2).unwrap();
let b = vec![-1.0];
let bounds = vec![(f64::NEG_INFINITY, f64::INFINITY); 2];
let problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let cancel = Arc::new(AtomicBool::new(true));
let opts = SolverOptions {
cancel_flag: Some(Arc::clone(&cancel)),
..SolverOptions::default()
};
let result = solve_qp_with(&problem, &opts);
assert_eq!(result.status, SolveStatus::Timeout);
}