metaheurustics/test_function/
additional.rs1use ndarray::{s, Array1};
2use std::f64::consts::PI;
3use super::TestFunction;
4use crate::algorithm::ObjectiveFunction;
5
6#[derive(Debug)]
9pub struct Griewank {
10 dims: usize,
11}
12
13impl Griewank {
14 pub fn new(dimensions: usize) -> Self {
15 Self { dims: dimensions }
16 }
17}
18
19impl ObjectiveFunction for Griewank {
20 fn evaluate(&self, x: &Array1<f64>) -> f64 {
21 let sum = x.iter().map(|&xi| xi * xi / 4000.0).sum::<f64>();
22 let prod = x.iter().enumerate()
23 .map(|(i, &xi)| (xi / ((i + 1) as f64).sqrt()).cos())
24 .product::<f64>();
25
26 1.0 + sum - prod
27 }
28
29 fn dimensions(&self) -> usize {
30 self.dims
31 }
32
33 fn bounds(&self) -> (Vec<f64>, Vec<f64>) {
34 (
35 vec![-600.0; self.dims],
36 vec![600.0; self.dims]
37 )
38 }
39}
40
41impl TestFunction for Griewank {
42 fn global_minimum(&self) -> f64 {
43 0.0
44 }
45
46 fn global_minimum_position(&self) -> Array1<f64> {
47 Array1::zeros(self.dims)
48 }
49
50 fn name(&self) -> &'static str {
51 "Griewank Function"
52 }
53}
54
55#[derive(Debug)]
58pub struct Schwefel {
59 dims: usize,
60}
61
62impl Schwefel {
63 pub fn new(dimensions: usize) -> Self {
64 Self { dims: dimensions }
65 }
66}
67
68impl ObjectiveFunction for Schwefel {
69 fn evaluate(&self, x: &Array1<f64>) -> f64 {
70 418.9829 * self.dims as f64
71 - x.iter()
72 .map(|&xi| xi * (xi.abs().sqrt()).sin())
73 .sum::<f64>()
74 }
75
76 fn dimensions(&self) -> usize {
77 self.dims
78 }
79
80 fn bounds(&self) -> (Vec<f64>, Vec<f64>) {
81 (
82 vec![-500.0; self.dims],
83 vec![500.0; self.dims]
84 )
85 }
86}
87
88impl TestFunction for Schwefel {
89 fn global_minimum(&self) -> f64 {
90 0.0
91 }
92
93 fn global_minimum_position(&self) -> Array1<f64> {
94 Array1::from_elem(self.dims, 420.9687)
95 }
96
97 fn name(&self) -> &'static str {
98 "Schwefel Function"
99 }
100}
101
102#[derive(Debug)]
106pub struct Levy {
107 dims: usize,
108}
109
110impl Levy {
111 pub fn new(dimensions: usize) -> Self {
112 Self { dims: dimensions }
113 }
114}
115
116impl ObjectiveFunction for Levy {
117 fn evaluate(&self, x: &Array1<f64>) -> f64 {
118 let w: Array1<f64> = x.mapv(|xi| 1.0 + (xi - 1.0) / 4.0);
119
120 let term1 = (PI * w[0]).sin().powi(2);
121
122 let term2 = w.slice(s![..-1])
123 .iter()
124 .map(|&wi| {
125 (wi - 1.0).powi(2) * (1.0 + 10.0 * (PI * wi + 1.0).sin().powi(2))
126 })
127 .sum::<f64>();
128
129 let n = w.len() - 1;
130 let term3 = (w[n] - 1.0).powi(2) * (1.0 + (2.0 * PI * w[n]).sin().powi(2));
131
132 term1 + term2 + term3
133 }
134
135 fn dimensions(&self) -> usize {
136 self.dims
137 }
138
139 fn bounds(&self) -> (Vec<f64>, Vec<f64>) {
140 (
141 vec![-10.0; self.dims],
142 vec![10.0; self.dims]
143 )
144 }
145}
146
147impl TestFunction for Levy {
148 fn global_minimum(&self) -> f64 {
149 0.0
150 }
151
152 fn global_minimum_position(&self) -> Array1<f64> {
153 Array1::ones(self.dims)
154 }
155
156 fn name(&self) -> &'static str {
157 "Levy Function"
158 }
159}
160
161#[derive(Debug)]
164pub struct Michalewicz {
165 dims: usize,
166 m: f64,
167}
168
169impl Michalewicz {
170 pub fn new(dimensions: usize, m: f64) -> Self {
171 Self { dims: dimensions, m }
172 }
173}
174
175impl ObjectiveFunction for Michalewicz {
176 fn evaluate(&self, x: &Array1<f64>) -> f64 {
177 -x.iter().enumerate()
178 .map(|(i, &xi)| {
179 xi.sin() * ((i + 1) as f64 * xi * xi / PI).sin().powf(2.0 * self.m)
180 })
181 .sum::<f64>()
182 }
183
184 fn dimensions(&self) -> usize {
185 self.dims
186 }
187
188 fn bounds(&self) -> (Vec<f64>, Vec<f64>) {
189 (
190 vec![0.0; self.dims],
191 vec![PI; self.dims]
192 )
193 }
194}
195
196impl TestFunction for Michalewicz {
197 fn global_minimum(&self) -> f64 {
198 match self.dims {
199 2 => -1.8013,
200 5 => -4.687658,
201 10 => -9.66015,
202 _ => f64::NEG_INFINITY, }
204 }
205
206 fn global_minimum_position(&self) -> Array1<f64> {
207 Array1::from_elem(self.dims, 2.20)
210 }
211
212 fn name(&self) -> &'static str {
213 "Michalewicz Function"
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220 use approx::assert_relative_eq;
221
222 #[test]
223 fn test_griewank_minimum() {
224 let griewank = Griewank::new(2);
225 let x = Array1::zeros(2);
226 assert_relative_eq!(griewank.evaluate(&x), 0.0, epsilon = 1e-10);
227 }
228
229 #[test]
230 fn test_schwefel_bounds() {
231 let schwefel = Schwefel::new(2);
232 let (lower, upper) = schwefel.bounds();
233 assert_eq!(lower[0], -500.0);
234 assert_eq!(upper[0], 500.0);
235 }
236
237 #[test]
238 fn test_levy_minimum() {
239 let levy = Levy::new(2);
240 let x = Array1::ones(2);
241 assert_relative_eq!(levy.evaluate(&x), 0.0, epsilon = 1e-10);
242 }
243
244 #[test]
245 fn test_michalewicz_bounds() {
246 let michalewicz = Michalewicz::new(2, 10.0);
247 let (lower, upper) = michalewicz.bounds();
248 assert_eq!(lower[0], 0.0);
249 assert_relative_eq!(upper[0], PI, epsilon = 1e-10);
250 }
251}