use super::super::*;
use crate::problem::SolveStatus;
use crate::qp::problem::QcqpMatrix;
use crate::sparse::CscMatrix;
fn make_qp_with_qcqp_constraints(n_qcqp_nnz: usize) -> QpProblem {
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 mut problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
let mut qc = QcqpMatrix::new(2);
for i in 0..n_qcqp_nnz {
qc.triplets.push((i % 2, i % 2, 1.0));
}
problem.quadratic_constraints = vec![qc];
problem
}
#[test]
fn qcqp_rejected_with_not_supported() {
let problem = make_qp_with_qcqp_constraints(1);
let result = solve_qp(&problem);
assert!(
matches!(result.status, SolveStatus::NotSupported(_)),
"expected NotSupported for QCQP, got {:?}",
result.status
);
assert!(result.solution.is_empty());
assert_eq!(result.objective, f64::INFINITY);
}
#[test]
fn qcqp_rejected_multiple_triplets() {
let problem = make_qp_with_qcqp_constraints(3);
let result = solve_qp(&problem);
assert!(
matches!(result.status, SolveStatus::NotSupported(_)),
"expected NotSupported, got {:?}",
result.status
);
}
#[test]
fn plain_qp_not_rejected() {
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 result = solve_qp(&problem);
assert_eq!(
result.status,
SolveStatus::Optimal,
"plain QP should solve normally"
);
}
#[test]
fn empty_qcqp_matrices_not_rejected() {
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 mut problem = QpProblem::new_all_le(q, c, a, b, bounds).unwrap();
problem.quadratic_constraints = vec![QcqpMatrix::new(2)];
let result = solve_qp(&problem);
assert_eq!(
result.status,
SolveStatus::Optimal,
"QpProblem with all-empty QcqpMatrix entries should solve normally"
);
}