use super::Constraint;
use crate::matrix_operations;
use crate::FunctionCallResult;
use num::Float;
use std::iter::Sum;
#[derive(Clone, Copy)]
pub struct SecondOrderCone<T = f64> {
alpha: T,
}
impl<T: Float> SecondOrderCone<T> {
pub fn new(alpha: T) -> SecondOrderCone<T> {
assert!(alpha > T::zero()); SecondOrderCone { alpha }
}
}
impl<T> Constraint<T> for SecondOrderCone<T>
where
T: Float + Sum<T>,
{
fn project(&self, x: &mut [T]) -> FunctionCallResult {
let n = x.len();
assert!(n >= 2, "x must be of dimension at least 2");
let z = &x[..n - 1];
let r = x[n - 1];
let norm_z = matrix_operations::norm2(z);
if self.alpha * norm_z <= -r {
x.iter_mut().for_each(|v| *v = T::zero());
} else if norm_z > self.alpha * r {
let beta = (self.alpha * norm_z + r) / (self.alpha.powi(2) + T::one());
x[..n - 1]
.iter_mut()
.for_each(|v| *v = *v * self.alpha * beta / norm_z);
x[n - 1] = beta;
}
Ok(())
}
fn is_convex(&self) -> bool {
true
}
}