M env/src/binary_string.rs => env/src/binary_string.rs +41 -30
@@ 1,4 1,5 @@
use std::str::FromStr;
+use nalgebra::{allocator::Allocator, Const, DefaultAllocator, Dim, DimName, Dynamic, OVector, SVector, U1};
use rand::{Rng, RngCore};
#[derive(Debug, Clone, PartialEq)]
@@ 73,20 74,20 @@ impl BinaryString {
BinaryString::to_real_internal(self.vec.iter(), self.vec.len(), min, max)
}
- pub fn to_real(self: &Self, bounds: &Vec<Bounds>) -> Result<Vec<f64>, BinaryStringConversionError> {
- if bounds.len() == 0 {
- return Err(BinaryStringConversionError::NoBounds);
- }
-
- let chunk_size = self.vec.len() / bounds.len();
- if self.vec.len() % bounds.len() != 0 {
+ pub fn to_real<TDim>(self: &Self, min: &OVector<f64, TDim>, max: &OVector<f64, TDim>) -> Result<OVector<f64, TDim>, BinaryStringConversionError>
+ where
+ TDim: Dim,
+ DefaultAllocator: Allocator<TDim>,
+ {
+ let chunk_size = self.vec.len() / min.len();
+ if self.vec.len() % min.len() != 0 {
return Err(BinaryStringConversionError::DimensionMismatch);
}
- Ok(self.vec.chunks(chunk_size)
- .zip(bounds)
- .map(|(chunk, bound)| BinaryString::to_real_internal(chunk.iter(), chunk_size, bound.min(), bound.max()))
- .collect::<Vec<f64>>())
+ let iter = self.vec.chunks(chunk_size)
+ .zip(min.iter().zip(max))
+ .map(|(chunk, (&min, &max))| BinaryString::to_real_internal(chunk.iter(), chunk_size, min, max));
+ Ok(OVector::<f64, TDim>::from_iterator_generic(min.shape_generic().0, min.shape_generic().1, iter))
}
}
@@ 121,7 122,8 @@ impl<'a> IntoIterator for &'a BinaryString {
#[cfg(test)]
pub mod tests {
- use crate::{binary_string::BinaryString, test_infra::{load_test_file, DataArrOfReals}};
+ use crate::{binary_string::{BinaryString, BinaryStringConversionError}, test_infra::{load_test_file, DataArrOfReals}};
+ use nalgebra::SVector;
use super::Bounds;
@@ 170,15 172,12 @@ pub mod tests {
);
}
- #[cfg(test)]
- fn test_binary_string_to_real(file_name: &str, bounds: Vec<Bounds>) {
- use crate::binary_string::BinaryStringConversionError;
-
+ fn test_binary_string_to_real<const LEN: usize>(file_name: &str, min: SVector<f64, LEN>, max: SVector<f64, LEN>) {
let data = load_test_file::<i8, DataArrOfReals>(file_name);
for test in data {
let res = BinaryString::new(test.inp)
- .to_real(&bounds);
+ .to_real(&min, &max);
if !test.out.valid {
assert_eq!(
res,
@@ 187,7 186,7 @@ pub mod tests {
}
else {
assert_eq!(
- res.unwrap(),
+ res.unwrap().iter().map(|&x| x).collect::<Vec<_>>(),
test.out.vec
);
}
@@ 198,7 197,8 @@ pub mod tests {
fn test_binary_string_to_real_1d_1() {
test_binary_string_to_real(
"tests/Bin2Real_1D_1.txt",
- vec![Bounds::new(0.0, 1.0)]
+ SVector::<f64, 1>::new(0.0),
+ SVector::<f64, 1>::new(1.0),
);
}
@@ 206,7 206,8 @@ pub mod tests {
fn test_binary_string_to_real_1d_2() {
test_binary_string_to_real(
"tests/Bin2Real_1D_2.txt",
- vec![Bounds::new(0.0, 4095.0)]
+ SVector::<f64, 1>::new(0.0),
+ SVector::<f64, 1>::new(4095.0),
);
}
@@ 214,7 215,8 @@ pub mod tests {
fn test_binary_string_to_real_1d_3() {
test_binary_string_to_real(
"tests/Bin2Real_1D_3.txt",
- vec![Bounds::new(-5.0, 5.0)]
+ SVector::<f64, 1>::new(-5.0),
+ SVector::<f64, 1>::new(5.0),
);
}
@@ 222,7 224,8 @@ pub mod tests {
fn test_binary_string_to_real_2d_1() {
test_binary_string_to_real(
"tests/Bin2Real_2D_1.txt",
- vec![Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0)]
+ SVector::<f64, 2>::new(0.0, 0.0),
+ SVector::<f64, 2>::new(1.0, 1.0),
);
}
@@ 230,7 233,8 @@ pub mod tests {
fn test_binary_string_to_real_2d_2() {
test_binary_string_to_real(
"tests/Bin2Real_2D_2.txt",
- vec![Bounds::new(0.0, 63.0), Bounds::new(-32.0, 31.0)]
+ SVector::<f64, 2>::new(0.0, -32.0),
+ SVector::<f64, 2>::new(63.0, 31.0),
);
}
@@ 238,7 242,8 @@ pub mod tests {
fn test_binary_string_to_real_2d_3() {
test_binary_string_to_real(
"tests/Bin2Real_2D_3.txt",
- vec![Bounds::new(-5.0, 5.0), Bounds::new(0.0, 10.0)]
+ SVector::<f64, 2>::new(-5.0, 0.0),
+ SVector::<f64, 2>::new(5.0, 10.0),
);
}
@@ 246,7 251,8 @@ pub mod tests {
fn test_binary_string_to_real_3d_1() {
test_binary_string_to_real(
"tests/Bin2Real_3D_1.txt",
- vec![Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0)]
+ SVector::<f64, 3>::new(0.0, 0.0, 0.0),
+ SVector::<f64, 3>::new(1.0, 1.0, 1.0),
);
}
@@ 254,7 260,8 @@ pub mod tests {
fn test_binary_string_to_real_3d_2() {
test_binary_string_to_real(
"tests/Bin2Real_3D_2.txt",
- vec![Bounds::new(0.0, 15.0), Bounds::new(-8.0, 7.0), Bounds::new(-8.0, 8.0)]
+ SVector::<f64, 3>::new(0.0, -8.0, -8.0),
+ SVector::<f64, 3>::new(15.0, 7.0, 8.0),
);
}
@@ 262,7 269,8 @@ pub mod tests {
fn test_binary_string_to_real_4d_1() {
test_binary_string_to_real(
"tests/Bin2Real_4D_1.txt",
- vec![Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0)]
+ SVector::<f64, 4>::new(0.0, 0.0, 0.0, 0.0),
+ SVector::<f64, 4>::new(1.0, 1.0, 1.0, 1.0),
);
}
@@ 270,7 278,8 @@ pub mod tests {
fn test_binary_string_to_real_4d_2() {
test_binary_string_to_real(
"tests/Bin2Real_4D_2.txt",
- vec![Bounds::new(0.0, 7.0), Bounds::new(-4.0, 3.0), Bounds::new(-4.0, 4.0), Bounds::new(-8.0, 0.0)]
+ SVector::<f64, 4>::new(0.0, -4.0, -4.0, -8.0),
+ SVector::<f64, 4>::new(7.0, 3.0, 4.0, 0.0),
);
}
@@ 278,7 287,8 @@ pub mod tests {
fn test_binary_string_to_real_6d_1() {
test_binary_string_to_real(
"tests/Bin2Real_6D_1.txt",
- vec![Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0), Bounds::new(0.0, 1.0)]
+ SVector::<f64, 6>::zeros(),
+ SVector::<f64, 6>::from_element(1.0),
);
}
@@ 286,7 296,8 @@ pub mod tests {
fn test_binary_string_to_real_6d_2() {
test_binary_string_to_real(
"tests/Bin2Real_6D_2.txt",
- (0..=5).map(|x| Bounds::new(x as f64, (2 * (x + 1)) as f64)).collect::<Vec<_>>()
+ SVector::<f64, 6>::from_iterator((0..=5).map(|x| x as f64)),
+ SVector::<f64, 6>::from_iterator((0..=5).map(|x| (2 * (x + 1)) as f64)),
);
}
}
M env/src/fitness/mod.rs => env/src/fitness/mod.rs +22 -8
@@ 1,5 1,7 @@
use std::convert::Infallible;
+use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, SVector};
+
use crate::binary_string::{BinaryString, BinaryStringConversionError, Bounds};
pub mod labs;
@@ 16,29 18,41 @@ pub trait FitnessFunction {
fn fit(self: &Self, inp: &Self::In) -> Result<Self::Out, Self::Err>;
}
-pub struct BinaryFitnessWrapper<TFitness> {
- bounds: Vec<Bounds>,
+pub struct BinaryFitnessWrapper<D, TFitness>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ min: OVector<f64, D>,
+ max: OVector<f64, D>,
fitting_function: TFitness,
}
-impl<TFitness> BinaryFitnessWrapper<TFitness> {
- pub fn new(fitting_function: TFitness, bounds: Vec<Bounds>) -> Self {
+impl<D, TFitness> BinaryFitnessWrapper<D, TFitness>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn new(fitting_function: TFitness, min: OVector<f64, D>, max: OVector<f64, D>) -> Self {
BinaryFitnessWrapper {
fitting_function,
- bounds,
+ min,
+ max
}
}
}
-impl<TFitness> FitnessFunction for BinaryFitnessWrapper<TFitness>
+impl<D, TFitness> FitnessFunction for BinaryFitnessWrapper<D, TFitness>
where
- TFitness: FitnessFunction<In = Vec<f64>, Out = f64, Err = Infallible>
+ D: Dim,
+ DefaultAllocator: Allocator<D>,
+ TFitness: FitnessFunction<In = OVector<f64, D>, Out = f64, Err = Infallible>
{
type In = BinaryString;
type Out = f64;
type Err = BinaryStringConversionError;
fn fit(self: &Self, inp: &BinaryString) -> Result<f64, BinaryStringConversionError> {
- Ok(self.fitting_function.fit(&inp.to_real(&self.bounds)?).unwrap())
+ Ok(self.fitting_function.fit(&inp.to_real(&self.min, &self.max)?).unwrap())
}
}
M env/src/fitness/real.rs => env/src/fitness/real.rs +69 -47
@@ 1,16 1,24 @@
use std::{convert::Infallible, f64::consts::PI, marker::PhantomData};
-use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, SVector};
+use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, SVector, U1};
use super::FitnessFunction;
-pub struct Linear<const LEN: usize> {
+pub struct Linear<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
a0: f64,
- a: SVector<f64, LEN>,
+ a: OVector<f64, D>,
}
-impl<const LEN: usize> Linear<LEN> {
- pub fn new(a0: f64, a: SVector<f64, LEN>) -> Self {
+impl<D> Linear<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn new(a0: f64, a: OVector<f64, D>) -> Self {
Self {
a0,
a
@@ 18,8 26,13 @@ impl<const LEN: usize> Linear<LEN> {
}
}
-impl<const LEN: usize> FitnessFunction for Linear<LEN> {
- type In = SVector<f64, LEN>;
+impl<D> FitnessFunction for Linear<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>,
+ DefaultAllocator: Allocator<U1, D>
+{
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
@@ 28,13 41,21 @@ impl<const LEN: usize> FitnessFunction for Linear<LEN> {
}
}
-pub struct Step<const LEN: usize> {
+pub struct Step<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>,
+{
a0: f64,
- a: SVector<f64, LEN>,
+ a: OVector<f64, D>,
}
-impl<const LEN: usize> Step<LEN> {
- pub fn new(a0: f64, a: SVector<f64, LEN>) -> Self {
+impl<D> Step<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>,
+{
+ pub fn new(a0: f64, a: OVector<f64, D>) -> Self {
Self {
a0,
a
@@ 42,8 63,12 @@ impl<const LEN: usize> Step<LEN> {
}
}
-impl<const LEN: usize> FitnessFunction for Step<LEN> {
- type In = SVector<f64, LEN>;
+impl<D> FitnessFunction for Step<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>,
+{
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
@@ 52,11 77,11 @@ impl<const LEN: usize> FitnessFunction for Step<LEN> {
}
}
-pub struct Rastrigin<TDim: Dim> {
- _phantom: PhantomData<TDim>
+pub struct Rastrigin<D: Dim> {
+ _phantom: PhantomData<D>
}
-impl<TDim: Dim> Rastrigin<TDim> {
+impl<D: Dim> Rastrigin<D> {
pub fn new() -> Self {
Self {
_phantom: PhantomData
@@ 64,11 89,11 @@ impl<TDim: Dim> Rastrigin<TDim> {
}
}
-impl<TDim: Dim> FitnessFunction for Rastrigin<TDim>
+impl<D: Dim> FitnessFunction for Rastrigin<D>
where
- DefaultAllocator: Allocator<TDim>
+ DefaultAllocator: Allocator<D>
{
- type In = OVector<f64, TDim>;
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
@@ 80,8 105,8 @@ where
}
}
-pub struct Griewank<TDim: Dim> {
- _phantom: PhantomData<TDim>
+pub struct Griewank<D: Dim> {
+ _phantom: PhantomData<D>
}
impl<TDim: Dim> Griewank<TDim> {
@@ 92,11 117,11 @@ impl<TDim: Dim> Griewank<TDim> {
}
}
-impl<TDim: Dim> FitnessFunction for Griewank<TDim>
+impl<D: Dim> FitnessFunction for Griewank<D>
where
- DefaultAllocator: Allocator<TDim>
+ DefaultAllocator: Allocator<D>
{
- type In = OVector<f64, TDim>;
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
@@ 109,16 134,24 @@ where
}
}
-pub struct Schwefel<const LEN: usize>;
+pub struct Schwefel<D: Dim> {
+ _phantom: PhantomData<D>
+}
-impl<const LEN: usize> Schwefel<LEN> {
+impl<D: Dim> Schwefel<D> {
pub fn new() -> Self {
- Self
+ Self {
+ _phantom: PhantomData
+ }
}
}
-impl<const LEN: usize> FitnessFunction for Schwefel<LEN> {
- type In = SVector<f64, LEN>;
+impl<D> FitnessFunction for Schwefel<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
@@ 139,18 172,13 @@ pub mod tests {
#[test]
fn test_linear_1() {
- const MAX_LEN: usize = 10;
-
let data = load_test_file::<f64, f64>("tests/linear_1.txt");
- let offset = SVector::repeat(1.0);
- let linear = Linear::new(1.0, offset);
for test in data {
- let filled = test.inp.iter()
- .chain(vec![0f64; MAX_LEN - test.inp.len()].iter())
- .map(|x| *x)
- .collect::<Vec<_>>();
- let inp = SVector::<f64, MAX_LEN>::from_vec(filled);
+ let offset = OVector::<f64, Dyn>::from_element(test.inp.len(), 1.0);
+ let inp = OVector::<f64, Dyn>::from_vec(test.inp);
+
+ let linear = Linear::new(1.0, offset);
assert_eq!(
linear.fit(&inp).unwrap(),
@@ 161,18 189,12 @@ pub mod tests {
#[test]
fn test_linear_2() {
- const MAX_LEN: usize = 10;
-
let data = load_test_file::<f64, f64>("tests/linear_2.txt");
- let offset = SVector::from_vec((2..=11).map(|x| x as f64).collect());
- let linear = Linear::new(1.0, offset);
for test in data {
- let filled = test.inp.iter()
- .chain(vec![0f64; MAX_LEN - test.inp.len()].iter())
- .map(|x| *x)
- .collect::<Vec<_>>();
- let inp = SVector::<f64, MAX_LEN>::from_vec(filled);
+ let offset = OVector::<f64, Dyn>::from_iterator(test.inp.len(), (2..=test.inp.len()+1).map(|x| x as f64));
+ let linear = Linear::new(1.0, offset);
+ let inp = OVector::<f64, Dyn>::from_vec(test.inp);
assert_eq!(
linear.fit(&inp).unwrap(),
M env/src/fitness/rosenbrock.rs => env/src/fitness/rosenbrock.rs +25 -9
@@ 1,21 1,35 @@
-use std::convert::Infallible;
+use std::{convert::Infallible, marker::PhantomData};
+use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector};
+
use super::FitnessFunction;
-pub struct Rosenbrock;
+pub struct Rosenbrock<D> {
+ _phantom: PhantomData<D>
+}
-impl Rosenbrock {
+impl<D> Rosenbrock<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
pub fn new() -> Self {
- Rosenbrock
+ Rosenbrock {
+ _phantom: PhantomData
+ }
}
}
-impl FitnessFunction for Rosenbrock {
- type In = Vec<f64>;
+impl<D> FitnessFunction for Rosenbrock<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
- fn fit(self: &Self, inp: &Vec<f64>) -> Result<f64, Infallible> {
- Ok(inp.windows(2)
+ fn fit(self: &Self, inp: &OVector<f64, D>) -> Result<f64, Infallible> {
+ Ok(inp.as_slice().windows(2)
.map(|xs| 100.0 * (xs[1] - xs[0].powi(2)).powi(2) + (1.0 - xs[0]).powi(2))
.sum())
}
@@ 23,6 37,8 @@ impl FitnessFunction for Rosenbrock {
#[cfg(test)]
pub mod tests {
+ use nalgebra::{Dyn, OVector};
+
use crate::{fitness::{rosenbrock::Rosenbrock, FitnessFunction}, test_infra::load_test_file};
#[test]
@@ 31,7 47,7 @@ pub mod tests {
for test in data {
assert_eq!(
- Rosenbrock::new().fit(&test.inp).unwrap(),
+ Rosenbrock::<Dyn>::new().fit(&OVector::<_, Dyn>::from_vec(test.inp)).unwrap(),
test.out
)
}
M env/src/fitness/sphere.rs => env/src/fitness/sphere.rs +25 -8
@@ 1,24 1,38 @@
use std::convert::Infallible;
+use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, SVector};
+
use super::FitnessFunction;
-pub struct Sphere {
- offset: Vec<f64>
+pub struct Sphere<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ offset: OVector<f64, D>
}
-impl Sphere {
- pub fn new(offset: Vec<f64>) -> Self {
+impl<D> Sphere<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ pub fn new(offset: OVector<f64, D>) -> Self {
Sphere {
offset
}
}
}
-impl FitnessFunction for Sphere {
- type In = Vec<f64>;
+impl<D> FitnessFunction for Sphere<D>
+where
+ D: Dim,
+ DefaultAllocator: Allocator<D>
+{
+ type In = OVector<f64, D>;
type Out = f64;
type Err = Infallible;
- fn fit(self: &Self, chromosome: &Vec<f64>) -> Result<f64, Infallible> {
+ fn fit(self: &Self, chromosome: &OVector<f64, D>) -> Result<f64, Infallible> {
Ok(chromosome
.iter()
.zip(&self.offset)
@@ 29,6 43,8 @@ impl FitnessFunction for Sphere {
#[cfg(test)]
pub mod tests {
+ use nalgebra::{Dyn, OVector};
+
use crate::{fitness::{sphere::Sphere, FitnessFunction}, test_infra::load_test_file};
#[test]
@@ 37,7 53,8 @@ pub mod tests {
for test in data {
assert_eq!(
- Sphere::new(vec![1.0; 10]).fit(&test.inp).unwrap(),
+ Sphere::<Dyn>::new(OVector::<_, Dyn>::from_vec(vec![1.0; test.inp.len()]))
+ .fit(&OVector::<_, Dyn>::from_vec(test.inp)).unwrap(),
test.out
)
}
M env/src/local_search/mod.rs => env/src/local_search/mod.rs +7 -5
@@ 127,10 127,11 @@ pub mod tests {
fn test_local_search_sphere() {
let optimum = BinaryString::new(vec![0, 0, 1, 0, 0,
0, 0, 1, 0, 0]);
- let bounds = vec![Bounds::new(0.0, 31.0), Bounds::new(0.0, 31.0)];
- let optimum_real = optimum.to_real(&bounds).unwrap();
+ let min = SVector::<f64, 2>::from_element(0.0);
+ let max = SVector::<f64, 2>::from_element(31.0);
+ let optimum_real = optimum.to_real(&min, &max).unwrap();
let sphere = Sphere::new(optimum_real);
- let sphere_wrapped = BinaryFitnessWrapper::new(sphere, bounds);
+ let sphere_wrapped = BinaryFitnessWrapper::new(sphere, min, max);
let result = local_search_first_improving(
&sphere_wrapped,
@@ 228,8 229,9 @@ pub mod tests {
let rosenbrock = Rosenbrock::new();
let optimum = BinaryString::new(vec![1, 0, 0, 0, 1, 1, 0, 0, 0, 1]);
- let bounds = vec![Bounds::new(-16.0, 15.0), Bounds::new(-16.0, 15.0)];
- let rosenbrock_wrapped = BinaryFitnessWrapper::new(rosenbrock, bounds);
+ let min = SVector::<f64, 2>::from_element(-16.0);
+ let max = SVector::<f64, 2>::from_element(15.0);
+ let rosenbrock_wrapped = BinaryFitnessWrapper::new(rosenbrock, min, max);
let result = local_search_first_improving(
&rosenbrock_wrapped,