use crate::problem::{Bound, MultiProblem, Problem};
pub struct Sphere {
bounds: Vec<Bound>,
}
impl Sphere {
pub fn new(dim: usize) -> Self {
Sphere {
bounds: vec![(-5.12, 5.12); dim],
}
}
}
impl Problem for Sphere {
fn dim(&self) -> usize {
self.bounds.len()
}
fn bounds(&self) -> &[Bound] {
&self.bounds
}
fn objective(&self, x: &[f64]) -> f64 {
x.iter().map(|v| v * v).sum()
}
}
pub struct Rosenbrock {
bounds: Vec<Bound>,
}
impl Rosenbrock {
pub fn new(dim: usize) -> Self {
assert!(dim >= 2, "Rosenbrock needs at least 2 dimensions");
Rosenbrock {
bounds: vec![(-5.0, 10.0); dim],
}
}
}
impl Problem for Rosenbrock {
fn dim(&self) -> usize {
self.bounds.len()
}
fn bounds(&self) -> &[Bound] {
&self.bounds
}
fn objective(&self, x: &[f64]) -> f64 {
x.windows(2)
.map(|w| 100.0 * (w[1] - w[0] * w[0]).powi(2) + (1.0 - w[0]).powi(2))
.sum()
}
}
pub struct Rastrigin {
bounds: Vec<Bound>,
}
impl Rastrigin {
pub fn new(dim: usize) -> Self {
Rastrigin {
bounds: vec![(-5.12, 5.12); dim],
}
}
}
impl Problem for Rastrigin {
fn dim(&self) -> usize {
self.bounds.len()
}
fn bounds(&self) -> &[Bound] {
&self.bounds
}
fn objective(&self, x: &[f64]) -> f64 {
let n = x.len() as f64;
10.0 * n
+ x.iter()
.map(|v| v * v - 10.0 * (2.0 * std::f64::consts::PI * v).cos())
.sum::<f64>()
}
}
pub struct Zdt1 {
bounds: Vec<Bound>,
}
impl Zdt1 {
pub fn new(dim: usize) -> Self {
assert!(dim >= 2, "ZDT1 needs at least 2 dimensions");
Zdt1 {
bounds: vec![(0.0, 1.0); dim],
}
}
pub fn front_f2(f1: f64) -> f64 {
1.0 - f1.sqrt()
}
}
impl MultiProblem for Zdt1 {
fn dim(&self) -> usize {
self.bounds.len()
}
fn bounds(&self) -> &[Bound] {
&self.bounds
}
fn n_objectives(&self) -> usize {
2
}
fn objectives(&self, x: &[f64]) -> Vec<f64> {
let n = x.len();
let f1 = x[0];
let g = 1.0 + 9.0 * x[1..].iter().sum::<f64>() / (n - 1) as f64;
let f2 = g * (1.0 - (f1 / g).sqrt());
vec![f1, f2]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_minima_are_zero() {
assert_eq!(Sphere::new(3).objective(&[0.0, 0.0, 0.0]), 0.0);
assert!(Rosenbrock::new(3).objective(&[1.0, 1.0, 1.0]).abs() < 1e-12);
assert!(Rastrigin::new(4).objective(&[0.0; 4]).abs() < 1e-12);
}
#[test]
fn zdt1_pareto_set_lies_on_the_analytical_front() {
let p = Zdt1::new(5);
for &f1 in &[0.0, 0.25, 0.5, 1.0] {
let mut x = vec![0.0; 5];
x[0] = f1;
let o = p.objectives(&x);
assert!((o[0] - f1).abs() < 1e-12);
assert!((o[1] - Zdt1::front_f2(f1)).abs() < 1e-12);
}
}
}