use std::{convert::Infallible, f64::consts::PI, marker::PhantomData}; use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OVector, SVector}; use super::FitnessFunction; pub struct Linear { a0: f64, a: SVector, } impl Linear { pub fn new(a0: f64, a: SVector) -> Self { Self { a0, a } } } impl FitnessFunction for Linear { type In = SVector; type Out = f64; type Err = Infallible; fn fit(self: &Self, inp: &Self::In) -> Result { Ok(self.a0 + (self.a.transpose() * inp).x) } } pub struct Step { a0: f64, a: SVector, } impl Step { pub fn new(a0: f64, a: SVector) -> Self { Self { a0, a } } } impl FitnessFunction for Step { type In = SVector; type Out = f64; type Err = Infallible; fn fit(self: &Self, inp: &Self::In) -> Result { Ok(self.a0 + inp.component_mul(&self.a).map(|x| x.floor()).sum()) } } pub struct Rastrigin { _phantom: PhantomData } impl Rastrigin { pub fn new() -> Self { Self { _phantom: PhantomData } } } impl FitnessFunction for Rastrigin where DefaultAllocator: Allocator { type In = OVector; type Out = f64; type Err = Infallible; fn fit(self: &Self, inp: &Self::In) -> Result { let dim = inp.len() as f64; Ok(10.0 * dim + inp.iter() .map(|x| x.powi(2) - 10.0 * (2.0 * PI * x).cos()) .sum::()) } } pub struct Griewank { _phantom: PhantomData } impl Griewank { pub fn new() -> Self { Self { _phantom: PhantomData } } } impl FitnessFunction for Griewank where DefaultAllocator: Allocator { type In = OVector; type Out = f64; type Err = Infallible; fn fit(self: &Self, inp: &Self::In) -> Result { Ok(1.0 + inp.map(|x| x.powi(2)).sum() / 4000.0 - inp .iter() .enumerate() .map(|(i, x)| (x / ((i + 1) as f64).sqrt()).cos()) .product::()) } } pub struct Schwefel; impl Schwefel { pub fn new() -> Self { Self } } impl FitnessFunction for Schwefel { type In = SVector; type Out = f64; type Err = Infallible; fn fit(self: &Self, inp: &Self::In) -> Result { Ok(-inp .map(|x| x * x.abs().sqrt().sin()) .sum()) } } #[cfg(test)] pub mod tests { use nalgebra::{Dyn, OVector, SVector}; use crate::{fitness::{real::{Linear, Rastrigin, Schwefel, Step}, FitnessFunction}, test_infra::load_test_file}; use super::Griewank; #[test] fn test_linear_1() { const MAX_LEN: usize = 10; let data = load_test_file::("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::>(); let inp = SVector::::from_vec(filled); assert_eq!( linear.fit(&inp).unwrap(), test.out ); } } #[test] fn test_linear_2() { const MAX_LEN: usize = 10; let data = load_test_file::("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::>(); let inp = SVector::::from_vec(filled); assert_eq!( linear.fit(&inp).unwrap(), test.out ); } } #[test] fn test_step_1() { const MAX_LEN: usize = 10; let data = load_test_file::("tests/step_1.txt"); let offset = SVector::repeat(1.0); let linear = Step::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::>(); let inp = SVector::::from_vec(filled); assert_eq!( linear.fit(&inp).unwrap(), test.out ); } } #[test] fn test_step_2() { const MAX_LEN: usize = 10; let data = load_test_file::("tests/step_2.txt"); let offset = SVector::from_vec((2..=11).map(|x| x as f64).collect()); let linear = Step::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::>(); let inp = SVector::::from_vec(filled); assert_eq!( linear.fit(&inp).unwrap(), test.out ); } } #[test] fn test_rastrigin() { let data = load_test_file::("tests/rastrigin.txt"); let linear = Rastrigin::::new(); for test in data { let inp = OVector::::from_vec(test.inp); assert_eq!( linear.fit(&inp).unwrap(), test.out ); } } #[test] fn test_griewank() { let data = load_test_file::("tests/griewank.txt"); let griewank = Griewank::::new(); for test in data { let inp = OVector::::from_vec(test.inp); assert_eq!( griewank.fit(&inp).unwrap(), test.out ); } } #[test] fn test_schwefel() { const MAX_LEN: usize = 10; let data = load_test_file::("tests/schwefel.txt"); let schwefel = Schwefel::new(); for test in data { let filled = test.inp.iter() .chain(vec![0f64; MAX_LEN - test.inp.len()].iter()) .map(|x| *x) .collect::>(); let inp = SVector::::from_vec(filled); assert_eq!( schwefel.fit(&inp).unwrap(), test.out ); } } }