use super::Constraint;
use crate::FunctionCallResult;
#[derive(Default)]
pub struct CartesianProduct<'a, T = f64> {
idx: Vec<usize>,
constraints: Vec<Box<dyn Constraint<T> + 'a>>,
}
impl<'a, T> CartesianProduct<'a, T> {
pub fn new() -> Self {
CartesianProduct {
idx: Vec::new(),
constraints: Vec::new(),
}
}
pub fn new_with_capacity(num_sets: usize) -> Self {
CartesianProduct {
idx: Vec::with_capacity(num_sets),
constraints: Vec::with_capacity(num_sets),
}
}
pub fn dimension(&self) -> usize {
*self.idx.last().unwrap_or(&0)
}
#[must_use]
pub fn add_constraint(mut self, ni: usize, constraint: impl Constraint<T> + 'a) -> Self {
assert!(
self.dimension() < ni,
"provided index is smaller than or equal to previous index, or zero"
);
self.idx.push(ni);
self.constraints.push(Box::new(constraint));
self
}
}
impl<'a, T> Constraint<T> for CartesianProduct<'a, T> {
fn project(&self, x: &mut [T]) -> FunctionCallResult {
assert!(x.len() == self.dimension(), "x has wrong size");
let mut j = 0;
for (&i, c) in self.idx.iter().zip(self.constraints.iter()) {
c.project(&mut x[j..i])?;
j = i;
}
Ok(())
}
fn is_convex(&self) -> bool {
self.constraints.iter().fold(true, |mut flag, cnstr| {
flag &= cnstr.is_convex();
flag
})
}
}