use crate::benchmarks::BenchmarkFn;
const SPHERE_LOW: f64 = -5.12;
const SPHERE_HIGH: f64 = 5.12;
const RASTRIGIN_LOW: f64 = -5.12;
const RASTRIGIN_HIGH: f64 = 5.12;
const ACKLEY_LOW: f64 = -32.0;
const ACKLEY_HIGH: f64 = 32.0;
fn repeat_bounds(low: f64, high: f64, n: usize) -> Vec<(f64, f64)> {
vec![(low, high); n]
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Sphere {
pub n: usize,
bounds: Vec<(f64, f64)>,
}
impl Sphere {
pub fn new(n: usize) -> Self {
Self {
n,
bounds: repeat_bounds(SPHERE_LOW, SPHERE_HIGH, n),
}
}
}
impl Default for Sphere {
fn default() -> Self {
Self::new(30)
}
}
impl BenchmarkFn for Sphere {
fn name(&self) -> &'static str {
"Sphere"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n,
"Sphere::evaluate called with {} variables, expected {}",
x.len(),
self.n
);
vec![x.iter().map(|xi| xi * xi).sum()]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rastrigin {
pub n: usize,
bounds: Vec<(f64, f64)>,
}
impl Rastrigin {
pub fn new(n: usize) -> Self {
Self {
n,
bounds: repeat_bounds(RASTRIGIN_LOW, RASTRIGIN_HIGH, n),
}
}
}
impl Default for Rastrigin {
fn default() -> Self {
Self::new(30)
}
}
impl BenchmarkFn for Rastrigin {
fn name(&self) -> &'static str {
"Rastrigin"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n,
"Rastrigin::evaluate called with {} variables, expected {}",
x.len(),
self.n
);
let sum: f64 = x
.iter()
.map(|xi| xi * xi - 10.0 * (2.0 * std::f64::consts::PI * xi).cos())
.sum();
vec![10.0 * self.n as f64 + sum]
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Ackley {
pub n: usize,
bounds: Vec<(f64, f64)>,
}
impl Ackley {
pub fn new(n: usize) -> Self {
Self {
n,
bounds: repeat_bounds(ACKLEY_LOW, ACKLEY_HIGH, n),
}
}
}
impl Default for Ackley {
fn default() -> Self {
Self::new(30)
}
}
impl BenchmarkFn for Ackley {
fn name(&self) -> &'static str {
"Ackley"
}
fn bounds(&self) -> &[(f64, f64)] {
&self.bounds
}
fn optimum_value(&self) -> Vec<f64> {
vec![0.0]
}
fn evaluate(&self, x: &[f64]) -> Vec<f64> {
assert_eq!(
x.len(),
self.n,
"Ackley::evaluate called with {} variables, expected {}",
x.len(),
self.n
);
let n = self.n as f64;
let sum_sq: f64 = x.iter().map(|xi| xi * xi).sum();
let sum_cos: f64 = x
.iter()
.map(|xi| (2.0 * std::f64::consts::PI * xi).cos())
.sum();
let term1 = -20.0 * (-0.2 * (sum_sq / n).sqrt()).exp();
let term2 = -(sum_cos / n).exp();
vec![term1 + term2 + 20.0 + std::f64::consts::E]
}
}