#[derive(Debug, Clone)]
pub struct Benchmark {
pub name: &'static str,
pub bound: f64,
pub optimum_value: f64,
}
pub fn sphere(x: &[f64]) -> f64 {
x.iter().map(|&xi| xi * xi).sum()
}
pub fn rastrigin(x: &[f64]) -> f64 {
let n = x.len() as f64;
10.0 * n
+ x.iter()
.map(|&xi| xi * xi - 10.0 * (2.0 * std::f64::consts::PI * xi).cos())
.sum::<f64>()
}
pub fn rosenbrock(x: &[f64]) -> f64 {
x.windows(2)
.map(|w| {
let (xi, xj) = (w[0], w[1]);
100.0 * (xj - xi * xi).powi(2) + (1.0 - xi).powi(2)
})
.sum()
}
pub fn ackley(x: &[f64]) -> f64 {
let n = x.len() 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();
-20.0 * (-0.2 * (sum_sq / n).sqrt()).exp() - (sum_cos / n).exp() + 20.0 + std::f64::consts::E
}
pub fn griewank(x: &[f64]) -> f64 {
let sum: f64 = x.iter().map(|&xi| xi * xi).sum::<f64>() / 4000.0;
let prod: f64 = x
.iter()
.enumerate()
.map(|(i, &xi)| (xi / ((i + 1) as f64).sqrt()).cos())
.product();
1.0 + sum - prod
}
pub fn schwefel(x: &[f64]) -> f64 {
let n = x.len() as f64;
418.982_887_272_433_8 * n - x.iter().map(|&xi| xi * xi.abs().sqrt().sin()).sum::<f64>()
}
pub fn bent_cigar(x: &[f64]) -> f64 {
if x.is_empty() {
return 0.0;
}
x[0] * x[0] + 1e6 * x[1..].iter().map(|&xi| xi * xi).sum::<f64>()
}
pub fn discus(x: &[f64]) -> f64 {
if x.is_empty() {
return 0.0;
}
1e6 * x[0] * x[0] + x[1..].iter().map(|&xi| xi * xi).sum::<f64>()
}
pub fn elliptic(x: &[f64]) -> f64 {
let n = x.len();
if n <= 1 {
return x.first().map_or(0.0, |&v| v * v);
}
x.iter()
.enumerate()
.map(|(i, &xi)| 1e6_f64.powf(i as f64 / (n - 1) as f64) * xi * xi)
.sum()
}
pub fn zakharov(x: &[f64]) -> f64 {
let sum_sq: f64 = x.iter().map(|&xi| xi * xi).sum();
let sum_half: f64 = x
.iter()
.enumerate()
.map(|(i, &xi)| 0.5 * (i + 1) as f64 * xi)
.sum();
sum_sq + sum_half.powi(2) + sum_half.powi(4)
}
pub fn levy(x: &[f64]) -> f64 {
if x.is_empty() {
return 0.0;
}
let pi = std::f64::consts::PI;
let w: Vec<f64> = x.iter().map(|&xi| 1.0 + (xi - 1.0) / 4.0).collect();
let n = w.len();
let term1 = (pi * w[0]).sin().powi(2);
let term_mid: f64 = w[..n - 1]
.iter()
.map(|&wi| (wi - 1.0).powi(2) * (1.0 + 10.0 * (pi * wi + 1.0).sin().powi(2)))
.sum();
let term_last = (w[n - 1] - 1.0).powi(2) * (1.0 + (2.0 * pi * w[n - 1]).sin().powi(2));
term1 + term_mid + term_last
}
pub fn expanded_schaffer(x: &[f64]) -> f64 {
fn g(a: f64, b: f64) -> f64 {
let s = a * a + b * b;
0.5 + (s.sqrt().sin().powi(2) - 0.5) / (1.0 + 0.001 * s).powi(2)
}
let n = x.len();
if n == 0 {
return 0.0;
}
if n == 1 {
return g(x[0], x[0]);
}
(0..n).map(|i| g(x[i], x[(i + 1) % n])).sum()
}
pub const SPHERE: Benchmark = Benchmark {
name: "sphere",
bound: 5.12,
optimum_value: 0.0,
};
pub const RASTRIGIN: Benchmark = Benchmark {
name: "rastrigin",
bound: 5.12,
optimum_value: 0.0,
};
pub const ROSENBROCK: Benchmark = Benchmark {
name: "rosenbrock",
bound: 2.048,
optimum_value: 0.0,
};
pub const ACKLEY: Benchmark = Benchmark {
name: "ackley",
bound: 32.768,
optimum_value: 0.0,
};
pub const GRIEWANK: Benchmark = Benchmark {
name: "griewank",
bound: 600.0,
optimum_value: 0.0,
};
pub const SCHWEFEL: Benchmark = Benchmark {
name: "schwefel",
bound: 500.0,
optimum_value: 0.0,
};
pub const BENT_CIGAR: Benchmark = Benchmark {
name: "bent_cigar",
bound: 100.0,
optimum_value: 0.0,
};
pub const DISCUS: Benchmark = Benchmark {
name: "discus",
bound: 100.0,
optimum_value: 0.0,
};
pub const ELLIPTIC: Benchmark = Benchmark {
name: "elliptic",
bound: 100.0,
optimum_value: 0.0,
};
pub const ZAKHAROV: Benchmark = Benchmark {
name: "zakharov",
bound: 10.0,
optimum_value: 0.0,
};
pub const LEVY: Benchmark = Benchmark {
name: "levy",
bound: 10.0,
optimum_value: 0.0,
};
pub const EXPANDED_SCHAFFER: Benchmark = Benchmark {
name: "expanded_schaffer",
bound: 100.0,
optimum_value: 0.0,
};
pub const ALL: &[Benchmark] = &[
SPHERE,
RASTRIGIN,
ROSENBROCK,
ACKLEY,
GRIEWANK,
SCHWEFEL,
BENT_CIGAR,
DISCUS,
ELLIPTIC,
ZAKHAROV,
LEVY,
EXPANDED_SCHAFFER,
];
pub fn meta(name: &str) -> Option<&'static Benchmark> {
ALL.iter().find(|b| b.name == name)
}