use crate::benchmarks::BenchmarkFn;
fn bounds_01(n: usize) -> Vec<(f64, f64)> {
vec![(0.0, 1.0); n]
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZDT1 {
n_vars: usize,
bounds: Vec<(f64, f64)>,
}
impl ZDT1 {
pub fn new(n_vars: usize) -> Self {
Self {
n_vars,
bounds: bounds_01(n_vars),
}
}
}
impl Default for ZDT1 {
fn default() -> Self {
Self::new(30)
}
}
impl BenchmarkFn for ZDT1 {
fn name(&self) -> &'static str {
"ZDT1"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0, 1.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n_vars,
"ZDT1::evaluate called with {} variables, expected {}",
x.len(),
self.n_vars
);
let f1 = x[0];
let g = 1.0 + 9.0 * x[1..].iter().sum::<f64>() / (self.n_vars - 1) as f64;
let f2 = g * (1.0 - (x[0] / g).sqrt());
vec![f1, f2]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZDT2 {
n_vars: usize,
bounds: Vec<(f64, f64)>,
}
impl ZDT2 {
pub fn new(n_vars: usize) -> Self {
Self {
n_vars,
bounds: bounds_01(n_vars),
}
}
}
impl Default for ZDT2 {
fn default() -> Self {
Self::new(30)
}
}
impl BenchmarkFn for ZDT2 {
fn name(&self) -> &'static str {
"ZDT2"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0, 1.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n_vars,
"ZDT2::evaluate called with {} variables, expected {}",
x.len(),
self.n_vars
);
let f1 = x[0];
let g = 1.0 + 9.0 * x[1..].iter().sum::<f64>() / (self.n_vars - 1) as f64;
let f2 = g * (1.0 - (x[0] / g).powi(2));
vec![f1, f2]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZDT3 {
n_vars: usize,
bounds: Vec<(f64, f64)>,
}
impl ZDT3 {
pub fn new(n_vars: usize) -> Self {
Self {
n_vars,
bounds: bounds_01(n_vars),
}
}
}
impl Default for ZDT3 {
fn default() -> Self {
Self::new(30)
}
}
impl BenchmarkFn for ZDT3 {
fn name(&self) -> &'static str {
"ZDT3"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0, 1.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n_vars,
"ZDT3::evaluate called with {} variables, expected {}",
x.len(),
self.n_vars
);
let f1 = x[0];
let g = 1.0 + 9.0 * x[1..].iter().sum::<f64>() / (self.n_vars - 1) as f64;
let x0_g = x[0] / g;
let f2 = g * (1.0 - x0_g.sqrt() - x0_g * (10.0 * std::f64::consts::PI * x[0]).sin());
vec![f1, f2]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZDT4 {
n_vars: usize,
bounds: Vec<(f64, f64)>,
}
impl ZDT4 {
pub fn new(n_vars: usize) -> Self {
let mut bounds = vec![(0.0, 1.0)]; bounds.extend(vec![(-5.0, 5.0); n_vars - 1]); Self { n_vars, bounds }
}
}
impl Default for ZDT4 {
fn default() -> Self {
Self::new(10)
}
}
impl BenchmarkFn for ZDT4 {
fn name(&self) -> &'static str {
"ZDT4"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0, 1.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n_vars,
"ZDT4::evaluate called with {} variables, expected {}",
x.len(),
self.n_vars
);
let f1 = x[0];
let g = 1.0
+ 10.0 * (self.n_vars - 1) as f64
+ x[1..]
.iter()
.map(|&xi| xi.powi(2) - 10.0 * (4.0 * std::f64::consts::PI * xi).cos())
.sum::<f64>();
let f2 = g * (1.0 - (x[0] / g).sqrt());
vec![f1, f2]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZDT5 {
n_vars: usize,
bounds: Vec<(f64, f64)>,
}
impl ZDT5 {
pub fn new(n_vars: usize) -> Self {
Self {
n_vars,
bounds: bounds_01(n_vars),
}
}
}
impl Default for ZDT5 {
fn default() -> Self {
Self::new(11)
}
}
impl BenchmarkFn for ZDT5 {
fn name(&self) -> &'static str {
"ZDT5"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![2.0, 5.5]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n_vars,
"ZDT5::evaluate called with {} variables, expected {}",
x.len(),
self.n_vars
);
let z0 = (1.0 + 30.0 * x[0]).floor();
let zi_sum: f64 = x[1..].iter().map(|&xi| (1.0 + 5.0 * xi).floor()).sum();
let u = z0;
let g = 1.0 + zi_sum;
let f1 = 1.0 + u;
let f2 = g / f1;
vec![f1, f2]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZDT6 {
n_vars: usize,
bounds: Vec<(f64, f64)>,
}
impl ZDT6 {
pub fn new(n_vars: usize) -> Self {
Self {
n_vars,
bounds: bounds_01(n_vars),
}
}
}
impl Default for ZDT6 {
fn default() -> Self {
Self::new(10)
}
}
impl BenchmarkFn for ZDT6 {
fn name(&self) -> &'static str {
"ZDT6"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0, 1.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n_vars,
"ZDT6::evaluate called with {} variables, expected {}",
x.len(),
self.n_vars
);
let f1 = 1.0 - (-4.0 * x[0]).exp() * (6.0 * std::f64::consts::PI * x[0]).sin().powi(6);
let g = 1.0 + 9.0 * (x[1..].iter().sum::<f64>() / (self.n_vars - 1) as f64).powf(0.25);
let f2 = g * (1.0 - (f1 / g).powi(2));
vec![f1, f2]
}
}