M env/src/binary_string.rs => env/src/binary_string.rs +24 -1
@@ 3,7 3,7 @@ use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, DimName, Dyn, OVecto
use rand::{Rng, RngCore};
use thiserror::Error;
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinaryString<D>
where
D: Dim,
@@ 12,6 12,17 @@ where
pub vec: OVector<i8, D>
}
+impl<D> PartialOrd for BinaryString<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ // TODO: implement more efficient ordering by iteration...
+ self.to_real_single(0.0, 100.0).partial_cmp(&other.to_real_single(0.0, 100.0))
+ }
+}
+
#[derive(Error, Debug, Clone, PartialEq)]
pub enum BinaryStringConversionError {
#[error("The dimension of the bounds does not divide the length of the binary string.")]
@@ 20,6 31,18 @@ pub enum BinaryStringConversionError {
impl<D> BinaryString<D>
where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn from_ovector(vec: OVector<i8, D>) -> Self {
+ Self {
+ vec
+ }
+ }
+}
+
+impl<D> BinaryString<D>
+where
D: DimName,
DefaultAllocator: Allocator<D>
{
A env/src/bounded.rs => env/src/bounded.rs +126 -0
@@ 0,0 1,126 @@
+use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, U1};
+use rand::{Rng, RngCore};
+
+use crate::binary_string::BinaryString;
+
+pub trait Bounded<D> {
+ 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<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ min: Option<BinaryString<D>>,
+ max: Option<BinaryString<D>>,
+}
+
+impl<D> BoundedBinaryString<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn unbounded() -> Self {
+ Self {
+ min: None,
+ max: None,
+ }
+ }
+}
+
+impl<D> Bounded<D> for BoundedBinaryString<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ type Item = BinaryString<D>;
+
+ 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::<i8, D>::from_fn_generic(size, U1, |_, _| rand.random_range(0..=1))
+ ))
+ }
+}
+
+pub struct BoundedOVector<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ min_max: OVector<(f64, f64), D>
+}
+
+impl<D> BoundedOVector<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn new(min: OVector<f64, D>, max: OVector<f64, D>) -> Self {
+ Self {
+ min_max: min.zip_map(&max, |min, max| (min, max))
+ }
+ }
+}
+
+impl<D> Bounded<D> for BoundedOVector<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ type Item = OVector<f64, D>;
+
+ 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))
+ }
+}
A env/src/initializer/mod.rs => env/src/initializer/mod.rs +93 -0
@@ 0,0 1,93 @@
+use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, Scalar, U1};
+use rand::{rng, RngCore};
+
+use crate::{binary_string::BinaryString, bounded::{Bounded, BoundedBinaryString}};
+
+pub trait Initializer<D: Dim, T> {
+ fn initialize_single(&mut self, size: D) -> T;
+ fn initialize(&mut self, size: D, count: usize) -> impl Iterator<Item = T> {
+ let size = size;
+ (0..count).map(move |_| self.initialize_single(size))
+ }
+}
+
+// Always initializes with zeros
+pub struct ZeroInitializer;
+
+impl ZeroInitializer {
+ pub fn new() -> Self {
+ Self {
+ }
+ }
+}
+
+impl<D> Initializer<D, BinaryString<D>> for ZeroInitializer
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ fn initialize_single(&mut self, size: D) -> BinaryString<D> {
+ BinaryString::<D>::from_ovector(
+ <Self as Initializer<D, OVector<i8, D>>>::initialize_single(self, size)
+ )
+ }
+}
+
+impl<D, T> Initializer<D, OVector<T, D>> for ZeroInitializer
+where
+ T: Scalar + Default,
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ fn initialize_single(&mut self, size: D) -> OVector<T, D> {
+ OVector::<T, D>::from_element_generic(size, U1, Default::default())
+ }
+}
+
+pub struct RandomInitializer<D: Dim, T> {
+ rng: Box<dyn RngCore>,
+ bounded: Box<dyn Bounded<D, Item = T>>
+}
+
+impl<T, D: Dim> RandomInitializer<D, T> {
+ pub fn new(bounded: Box<dyn Bounded<D, Item = T>>) -> Self {
+ Self {
+ rng: Box::new(rand::rng()),
+ bounded
+ }
+ }
+}
+
+impl<D: Dim> RandomInitializer<D, BinaryString<D>>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn new_binary() -> Self {
+ Self {
+ rng: Box::new(rand::rng()),
+ bounded: Box::new(BoundedBinaryString::unbounded())
+ }
+ }
+}
+
+impl<D> Initializer<D, BinaryString<D>> for RandomInitializer<D, BinaryString<D>>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ fn initialize_single(&mut self, size: D) -> BinaryString<D> {
+ self.bounded.next_random(size, &mut self.rng)
+ }
+}
+
+impl<D, T> Initializer<D, OVector<T, D>> for RandomInitializer<D, OVector<T, D>>
+where
+ T: Scalar + Default,
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ fn initialize_single(&mut self, size: D) -> OVector<T, D> {
+ self.bounded.next_random(size, &mut self.rng)
+ }
+}
M env/src/main.rs => env/src/main.rs +3 -0
@@ 1,4 1,7 @@
pub mod fitness;
+pub mod crossover;
+pub mod bounded;
+pub mod initializer;
pub mod terminating;
pub mod perturbation;
pub mod comparison;