1use crate::problem::{Bound, MultiProblem, Problem};
9
10pub struct Sphere {
12 bounds: Vec<Bound>,
13}
14
15impl Sphere {
16 pub fn new(dim: usize) -> Self {
18 Sphere {
19 bounds: vec![(-5.12, 5.12); dim],
20 }
21 }
22}
23
24impl Problem for Sphere {
25 fn dim(&self) -> usize {
26 self.bounds.len()
27 }
28 fn bounds(&self) -> &[Bound] {
29 &self.bounds
30 }
31 fn objective(&self, x: &[f64]) -> f64 {
32 x.iter().map(|v| v * v).sum()
33 }
34}
35
36pub struct Rosenbrock {
39 bounds: Vec<Bound>,
40}
41
42impl Rosenbrock {
43 pub fn new(dim: usize) -> Self {
45 assert!(dim >= 2, "Rosenbrock needs at least 2 dimensions");
46 Rosenbrock {
47 bounds: vec![(-5.0, 10.0); dim],
48 }
49 }
50}
51
52impl Problem for Rosenbrock {
53 fn dim(&self) -> usize {
54 self.bounds.len()
55 }
56 fn bounds(&self) -> &[Bound] {
57 &self.bounds
58 }
59 fn objective(&self, x: &[f64]) -> f64 {
60 x.windows(2)
61 .map(|w| 100.0 * (w[1] - w[0] * w[0]).powi(2) + (1.0 - w[0]).powi(2))
62 .sum()
63 }
64}
65
66pub struct Rastrigin {
69 bounds: Vec<Bound>,
70}
71
72impl Rastrigin {
73 pub fn new(dim: usize) -> Self {
75 Rastrigin {
76 bounds: vec![(-5.12, 5.12); dim],
77 }
78 }
79}
80
81impl Problem for Rastrigin {
82 fn dim(&self) -> usize {
83 self.bounds.len()
84 }
85 fn bounds(&self) -> &[Bound] {
86 &self.bounds
87 }
88 fn objective(&self, x: &[f64]) -> f64 {
89 let n = x.len() as f64;
90 10.0 * n
91 + x.iter()
92 .map(|v| v * v - 10.0 * (2.0 * std::f64::consts::PI * v).cos())
93 .sum::<f64>()
94 }
95}
96
97pub struct Zdt1 {
110 bounds: Vec<Bound>,
111}
112
113impl Zdt1 {
114 pub fn new(dim: usize) -> Self {
116 assert!(dim >= 2, "ZDT1 needs at least 2 dimensions");
117 Zdt1 {
118 bounds: vec![(0.0, 1.0); dim],
119 }
120 }
121
122 pub fn front_f2(f1: f64) -> f64 {
124 1.0 - f1.sqrt()
125 }
126}
127
128impl MultiProblem for Zdt1 {
129 fn dim(&self) -> usize {
130 self.bounds.len()
131 }
132 fn bounds(&self) -> &[Bound] {
133 &self.bounds
134 }
135 fn n_objectives(&self) -> usize {
136 2
137 }
138 fn objectives(&self, x: &[f64]) -> Vec<f64> {
139 let n = x.len();
140 let f1 = x[0];
141 let g = 1.0 + 9.0 * x[1..].iter().sum::<f64>() / (n - 1) as f64;
142 let f2 = g * (1.0 - (f1 / g).sqrt());
143 vec![f1, f2]
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn known_minima_are_zero() {
153 assert_eq!(Sphere::new(3).objective(&[0.0, 0.0, 0.0]), 0.0);
154 assert!(Rosenbrock::new(3).objective(&[1.0, 1.0, 1.0]).abs() < 1e-12);
155 assert!(Rastrigin::new(4).objective(&[0.0; 4]).abs() < 1e-12);
156 }
157
158 #[test]
159 fn zdt1_pareto_set_lies_on_the_analytical_front() {
160 let p = Zdt1::new(5);
162 for &f1 in &[0.0, 0.25, 0.5, 1.0] {
163 let mut x = vec![0.0; 5];
164 x[0] = f1;
165 let o = p.objectives(&x);
166 assert!((o[0] - f1).abs() < 1e-12);
167 assert!((o[1] - Zdt1::front_f2(f1)).abs() < 1e-12);
168 }
169 }
170}