use super::Constraint;
#[derive(Default)]
pub struct CartesianProduct<'a> {
idx: Vec<usize>,
constraints: Vec<Box<dyn Constraint + 'a>>,
}
impl<'a> CartesianProduct<'a> {
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::new(),
}
}
pub fn dimension(&self) -> usize {
*self.idx.last().unwrap_or(&0)
}
pub fn add_constraint(mut self, ni: usize, constraint: impl Constraint + '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> Constraint for CartesianProduct<'a> {
fn project(&self, x: &mut [f64]) {
assert!(x.len() == self.dimension(), "x has wrong size");
let mut j = 0;
self.idx
.iter()
.zip(self.constraints.iter())
.for_each(|(&i, c)| {
c.project(&mut x[j..i]);
j = i;
});
}
fn is_convex(&self) -> bool {
self.constraints.iter().fold(true, |mut flag, cnstr| {
flag &= cnstr.is_convex();
flag
})
}
}