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
147pub struct Dtlz2 {
163 bounds: Vec<Bound>,
164 m: usize,
165}
166
167impl Dtlz2 {
168 pub fn new(m: usize, dim: usize) -> Self {
171 assert!(m >= 2 && dim > m, "DTLZ2 needs m >= 2 and dim > m");
172 Dtlz2 {
173 bounds: vec![(0.0, 1.0); dim],
174 m,
175 }
176 }
177}
178
179impl MultiProblem for Dtlz2 {
180 fn dim(&self) -> usize {
181 self.bounds.len()
182 }
183 fn bounds(&self) -> &[Bound] {
184 &self.bounds
185 }
186 fn n_objectives(&self) -> usize {
187 self.m
188 }
189 fn objectives(&self, x: &[f64]) -> Vec<f64> {
190 let m = self.m;
191 let g: f64 = x[m - 1..].iter().map(|&xi| (xi - 0.5).powi(2)).sum();
192 let half_pi = std::f64::consts::FRAC_PI_2;
193 let mut f = vec![1.0 + g; m];
194 for (i, fi) in f.iter_mut().enumerate() {
195 for &xj in x.iter().take(m - 1 - i) {
197 *fi *= (xj * half_pi).cos();
198 }
199 if i > 0 {
201 *fi *= (x[m - 1 - i] * half_pi).sin();
202 }
203 }
204 f
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211
212 #[test]
213 fn known_minima_are_zero() {
214 assert_eq!(Sphere::new(3).objective(&[0.0, 0.0, 0.0]), 0.0);
215 assert!(Rosenbrock::new(3).objective(&[1.0, 1.0, 1.0]).abs() < 1e-12);
216 assert!(Rastrigin::new(4).objective(&[0.0; 4]).abs() < 1e-12);
217 }
218
219 #[test]
220 fn dtlz2_front_lies_on_the_unit_sphere() {
221 let p = Dtlz2::new(3, 12);
223 for angles in [[0.0, 0.0], [0.5, 0.5], [1.0, 0.3]] {
224 let mut x = vec![0.5; 12];
225 x[0] = angles[0];
226 x[1] = angles[1];
227 let f = p.objectives(&x);
228 let sumsq: f64 = f.iter().map(|v| v * v).sum();
229 assert!((sumsq - 1.0).abs() < 1e-9, "Σf² = {sumsq}");
230 }
231 }
232
233 #[test]
234 fn zdt1_pareto_set_lies_on_the_analytical_front() {
235 let p = Zdt1::new(5);
237 for &f1 in &[0.0, 0.25, 0.5, 1.0] {
238 let mut x = vec![0.0; 5];
239 x[0] = f1;
240 let o = p.objectives(&x);
241 assert!((o[0] - f1).abs() < 1e-12);
242 assert!((o[1] - Zdt1::front_f2(f1)).abs() < 1e-12);
243 }
244 }
245}