use std::iter::zip;
use anyhow::Result;
use sparsetools::csr::CSR;
use spsolve::Solver;
use crate::common::{Lambda, Options};
use crate::math::dot;
use crate::nlp;
use crate::traits::{ObjectiveFunction, ProgressMonitor};
struct QuadraticObjectiveFunction {
c: Vec<f64>,
h_mat: CSR<usize, f64>,
}
impl ObjectiveFunction for QuadraticObjectiveFunction {
fn f(&self, x: &[f64], hessian: bool) -> (f64, Vec<f64>, Option<CSR<usize, f64>>) {
let f = 0.5 * dot(&x, &(&self.h_mat * &x)) + dot(&self.c, &x);
let df = zip(&self.h_mat * &x, &self.c)
.map(|(hx, c)| hx + c)
.collect();
if !hessian {
(f, df, None)
} else {
let d2f = self.h_mat.to_owned();
(f, df, Some(d2f))
}
}
}
pub fn qp<S>(
h_mat: &CSR<usize, f64>,
c: &[f64],
a_mat: &CSR<usize, f64>,
l: &[f64],
u: &[f64],
xmin: &[f64],
xmax: &[f64],
x0: &[f64],
solver: &S,
progress: Option<&dyn ProgressMonitor>,
opt: &Options,
) -> Result<(Vec<f64>, f64, bool, usize, Lambda)>
where
S: Solver<usize, f64>,
{
let qp = QuadraticObjectiveFunction {
c: c.to_owned(),
h_mat: h_mat.to_owned(),
};
nlp(
&qp, x0, a_mat, l, u, xmin, xmax, None, solver, opt, progress,
)
}