use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, U1}; use rand::{Rng, RngCore}; use crate::binary_string::BinaryString; pub trait Bounded { type Item; fn is_in_bounds(&self, obj: &Self::Item) -> bool; fn bound(&self, obj: Self::Item) -> Self::Item; fn next_random(&self, size: D, rand: &mut dyn RngCore) -> Self::Item; } pub struct BoundedBinaryString where D: Dim, DefaultAllocator: Allocator { min: Option>, max: Option>, } impl BoundedBinaryString where D: Dim, DefaultAllocator: Allocator { pub fn unbounded() -> Self { Self { min: None, max: None, } } } impl Bounded for BoundedBinaryString where D: Dim, DefaultAllocator: Allocator { type Item = BinaryString; fn is_in_bounds(&self, obj: &Self::Item) -> bool { if let Some(min) = &self.min { if obj < min { return false; } } if let Some(max) = &self.max { if obj > max { return false; } } return true; } fn bound(&self, obj: Self::Item) -> Self::Item { if let Some(min) = &self.min { if &obj < min { return min.clone(); } } if let Some(max) = &self.max { if &obj > max { return max.clone(); } } obj } fn next_random(&self, size: D, rand: &mut dyn RngCore) -> Self::Item { // TODO... this is very suboptimal, favoring the max, min. self.bound( BinaryString::from_ovector( OVector::::from_fn_generic(size, U1, |_, _| rand.random_range(0..=1)) )) } } pub struct BoundedOVector where D: Dim, DefaultAllocator: Allocator { min_max: OVector<(f64, f64), D> } impl BoundedOVector where D: Dim, DefaultAllocator: Allocator { pub fn new(min: OVector, max: OVector) -> Self { Self { min_max: min.zip_map(&max, |min, max| (min, max)) } } } impl Bounded for BoundedOVector where D: Dim, DefaultAllocator: Allocator { type Item = OVector; fn is_in_bounds(&self, obj: &Self::Item) -> bool { obj.iter() .zip(self.min_max.iter()) .all(|(&c, &(min, max))| c <= max && c >= min) } fn bound(&self, mut obj: Self::Item) -> Self::Item { obj .zip_apply(&self.min_max, |c, (min, max)| *c = c.clamp(min, max)); obj } fn next_random(&self, _: D, rand: &mut dyn RngCore) -> Self::Item { self.min_max.map(|(min, max)| rand.random_range(min..=max)) } }