use crate::solver::{Cone, SliceMut, SliceLike};
use crate::LinAlgEx;
use num_traits::{Float, cast, ToPrimitive, Zero, One};
pub struct ConePSD<'a, L: LinAlgEx>
{
work: SliceMut<'a, L::Sl>,
eps_zero: L::F,
}
impl<'a, L: LinAlgEx> ConePSD<'a, L>
{
pub fn query_worklen(nvars: usize) -> usize
{
let n = (cast::<usize, L::F>(8 * nvars + 1).unwrap().sqrt().to_usize().unwrap() - 1) / 2;
assert_eq!(n * (n + 1) / 2, nvars);
L::map_eig_worklen(n)
}
pub fn new(work: &'a mut[L::F], eps_zero: L::F) -> Self
{
ConePSD {
work: L::Sl::new_mut(work),
eps_zero,
}
}
}
impl<'a, L: LinAlgEx> Cone<L> for ConePSD<'a, L>
{
fn proj(&mut self, _dual_cone: bool, x: &mut L::Sl) -> Result<(), ()>
{
if self.work.len() < Self::query_worklen(x.len()) {
log::error!("work shortage: {} given < {} required", self.work.len(), Self::query_worklen(x.len()));
return Err(());
}
let f0 = L::F::zero();
let f1 = L::F::one();
let fsqrt2 = (f1 + f1).sqrt();
L::map_eig(x, Some(fsqrt2), self.eps_zero, &mut self.work, |e| {
if e > f0 {
Some(e)
}
else {
None
}
});
Ok(())
}
fn product_group<G: Fn(&mut L::Sl) + Copy>(&self, dp_tau: &mut L::Sl, group: G)
{
group(dp_tau);
}
}
#[test]
fn test_cone_psd1()
{
use float_eq::assert_float_eq;
use crate::FloatGeneric;
type L = FloatGeneric<f64>;
let ref_x = &[ 5.,
0., 0.,
];
let x = &mut[ 5.,
0., -5.,
];
assert!(ConePSD::<L>::query_worklen(x.len()) <= 10);
let w = &mut[0.; 10];
let mut c = ConePSD::<L>::new(w, 1e-12);
c.proj(false, x).unwrap();
assert_float_eq!(ref_x, x, abs_all <= 1e-6);
}