use crate::ipopt_cq::{IpoptCalculatedQuantities, IpoptCqHandle};
use crate::ipopt_data::{IpoptData, IpoptDataHandle};
use crate::ipopt_nlp::{IpoptNlp, Nlp};
use crate::iterates_vector::IteratesVector;
use pounce_common::types::{Index, Number};
use pounce_linalg::dense_vector::{DenseVector, DenseVectorSpace};
use pounce_linalg::expansion_matrix::{ExpansionMatrix, ExpansionMatrixSpace};
use pounce_linalg::triplet::{GenTMatrix, GenTMatrixSpace};
use pounce_linalg::{Matrix, SymMatrix, Vector};
use std::cell::RefCell;
use std::rc::Rc;
fn dvec(values: &[Number]) -> DenseVector {
let space = DenseVectorSpace::new(values.len() as Index);
let mut v = space.make_new_dense();
v.values_mut().copy_from_slice(values);
v
}
fn rcv(values: &[Number]) -> Rc<dyn Vector> {
Rc::new(dvec(values))
}
struct MuMockNlp {
x_l: DenseVector,
x_u: DenseVector,
d_l: DenseVector,
d_u: DenseVector,
px_l: Rc<dyn Matrix>,
px_u: Rc<dyn Matrix>,
pd_l: Rc<dyn Matrix>,
pd_u: Rc<dyn Matrix>,
}
impl MuMockNlp {
fn new() -> Self {
Self {
x_l: dvec(&[0.0]),
x_u: dvec(&[5.0]),
d_l: dvec(&[1.0]),
d_u: dvec(&[]),
px_l: Rc::new(ExpansionMatrix::new(ExpansionMatrixSpace::new(
2,
1,
&[0],
0,
))),
px_u: Rc::new(ExpansionMatrix::new(ExpansionMatrixSpace::new(
2,
1,
&[1],
0,
))),
pd_l: Rc::new(ExpansionMatrix::new(ExpansionMatrixSpace::new(
1,
1,
&[0],
0,
))),
pd_u: Rc::new(ExpansionMatrix::new(ExpansionMatrixSpace::new(
1,
0,
&[],
0,
))),
}
}
}
impl Nlp for MuMockNlp {
fn n(&self) -> Index {
2
}
fn m_eq(&self) -> Index {
1
}
fn m_ineq(&self) -> Index {
1
}
fn eval_f(&mut self, x: &dyn Vector) -> Number {
let xx = x.as_any().downcast_ref::<DenseVector>().unwrap();
xx.values()[0] * xx.values()[0] + xx.values()[1] * xx.values()[1]
}
fn eval_grad_f(&mut self, x: &dyn Vector, g: &mut dyn Vector) {
let xx = x.as_any().downcast_ref::<DenseVector>().unwrap();
let gg = g.as_any_mut().downcast_mut::<DenseVector>().unwrap();
gg.values_mut()[0] = 2.0 * xx.values()[0];
gg.values_mut()[1] = 2.0 * xx.values()[1];
}
fn eval_c(&mut self, x: &dyn Vector, c: &mut dyn Vector) {
let xx = x.as_any().downcast_ref::<DenseVector>().unwrap();
let cc = c.as_any_mut().downcast_mut::<DenseVector>().unwrap();
cc.values_mut()[0] = xx.values()[0] + xx.values()[1] - 1.0;
}
fn eval_d(&mut self, x: &dyn Vector, d: &mut dyn Vector) {
let xx = x.as_any().downcast_ref::<DenseVector>().unwrap();
let dd = d.as_any_mut().downcast_mut::<DenseVector>().unwrap();
dd.values_mut()[0] = xx.values()[0];
}
fn eval_jac_c(&mut self, _x: &dyn Vector) -> Rc<dyn Matrix> {
let space = GenTMatrixSpace::new(1, 2, vec![1, 1], vec![1, 2]);
let mut jac = GenTMatrix::new(space);
jac.set_values(&[1.0, 1.0]);
Rc::new(jac)
}
fn eval_jac_d(&mut self, _x: &dyn Vector) -> Rc<dyn Matrix> {
let space = GenTMatrixSpace::new(1, 2, vec![1], vec![1]);
let mut jac = GenTMatrix::new(space);
jac.set_values(&[1.0]);
Rc::new(jac)
}
fn eval_h(
&mut self,
_x: &dyn Vector,
_obj_factor: Number,
_y_c: &dyn Vector,
_y_d: &dyn Vector,
) -> Rc<dyn SymMatrix> {
unimplemented!("the μ path never asks for the Hessian")
}
}
impl IpoptNlp for MuMockNlp {
fn x_l(&self) -> &dyn Vector {
&self.x_l
}
fn x_u(&self) -> &dyn Vector {
&self.x_u
}
fn d_l(&self) -> &dyn Vector {
&self.d_l
}
fn d_u(&self) -> &dyn Vector {
&self.d_u
}
fn px_l(&self) -> Rc<dyn Matrix> {
self.px_l.clone()
}
fn px_u(&self) -> Rc<dyn Matrix> {
self.px_u.clone()
}
fn pd_l(&self) -> Rc<dyn Matrix> {
self.pd_l.clone()
}
fn pd_u(&self) -> Rc<dyn Matrix> {
self.pd_u.clone()
}
}
pub(crate) fn fixture(mu: Number) -> (IpoptDataHandle, IpoptCqHandle) {
let (x, s, z) = ([2.0, 3.0], 4.0, 0.5);
let mut data = IpoptData::new();
data.curr_mu = mu;
data.curr_tau = 0.99;
data.set_curr(IteratesVector::new(
rcv(&x),
rcv(&[s]),
rcv(&[1.0]),
rcv(&[1.0]),
rcv(&[z]),
rcv(&[z]),
rcv(&[z]),
rcv(&[]),
));
let data_handle: IpoptDataHandle = Rc::new(RefCell::new(data));
let nlp: Rc<RefCell<dyn IpoptNlp>> = Rc::new(RefCell::new(MuMockNlp::new()));
let cq = IpoptCalculatedQuantities::new(data_handle.clone(), nlp);
(data_handle, Rc::new(RefCell::new(cq)))
}