1use num::{Float, FromPrimitive};
22use std::iter::Sum;
23
24pub fn styblinski_tang<T>(param: &[T]) -> T
37where
38 T: Float + FromPrimitive + Sum,
39{
40 T::from_f64(0.5).unwrap()
41 * param
42 .iter()
43 .map(|x| {
44 x.powi(4) - T::from_f64(16.0).unwrap() * x.powi(2) + T::from_f64(5.0).unwrap() * *x
45 })
46 .sum()
47}
48
49pub fn styblinski_tang_derivative<T>(param: &[T]) -> Vec<T>
51where
52 T: Float + FromPrimitive + Sum,
53{
54 let n2 = T::from_f64(2.0).unwrap();
55 let n2_5 = T::from_f64(2.5).unwrap();
56 let n16 = T::from_f64(16.0).unwrap();
57
58 param
59 .iter()
60 .map(|x| n2 * x.powi(3) - n16 * *x + n2_5)
61 .collect()
62}
63
64pub fn styblinski_tang_derivative_const<const N: usize, T>(param: &[T; N]) -> [T; N]
69where
70 T: Float + FromPrimitive + Sum,
71{
72 let n0 = T::from_f64(0.0).unwrap();
73 let n2 = T::from_f64(2.0).unwrap();
74 let n2_5 = T::from_f64(2.5).unwrap();
75 let n16 = T::from_f64(16.0).unwrap();
76
77 let mut out = [n0; N];
78
79 param
80 .iter()
81 .zip(out.iter_mut())
82 .map(|(x, o)| *o = n2 * x.powi(3) - n16 * *x + n2_5)
83 .count();
84
85 out
86}
87
88pub fn styblinski_tang_hessian<T>(param: &[T]) -> Vec<Vec<T>>
90where
91 T: Float + FromPrimitive + Sum,
92{
93 let n0 = T::from_f64(0.0).unwrap();
94 let n6 = T::from_f64(6.0).unwrap();
95 let n16 = T::from_f64(16.0).unwrap();
96
97 let n = param.len();
98 let mut out = vec![vec![n0; n]; n];
99
100 param
101 .iter()
102 .enumerate()
103 .map(|(i, x)| out[i][i] = n6 * x.powi(2) - n16)
104 .count();
105
106 out
107}
108
109pub fn styblinski_tang_hessian_const<const N: usize, T>(param: &[T; N]) -> [[T; N]; N]
114where
115 T: Float + FromPrimitive + Sum,
116{
117 let n0 = T::from_f64(0.0).unwrap();
118 let n6 = T::from_f64(6.0).unwrap();
119 let n16 = T::from_f64(16.0).unwrap();
120
121 let mut out = [[n0; N]; N];
122
123 param
124 .iter()
125 .enumerate()
126 .map(|(i, x)| out[i][i] = n6 * x.powi(2) - n16)
127 .count();
128
129 out
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use approx::assert_relative_eq;
136 use finitediff::FiniteDiff;
137 use proptest::prelude::*;
138 use std::f32;
139
140 #[test]
141 fn test_styblinski_tang_optimum() {
142 assert_relative_eq!(
143 styblinski_tang(&[-2.903534_f32, -2.903534_f32, -2.903534_f32]),
144 -117.49849,
145 epsilon = f32::EPSILON
146 );
147 assert_relative_eq!(
148 styblinski_tang(&[-2.903534_f64, -2.903534_f64, -2.903534_f64]),
149 -117.4984971113142,
150 epsilon = f64::EPSILON
151 );
152
153 let deriv = styblinski_tang_derivative(&[-2.903534_f64, -2.903534_f64, -2.903534_f64]);
154 for i in 0..3 {
155 assert_relative_eq!(deriv[i], 0.0, epsilon = 1e-5, max_relative = 1e-2);
156 }
157 }
158
159 proptest! {
160 #[test]
161 fn test_styblinski_tang_derivative_finitediff(a in -5.0..5.0,
162 b in -5.0..5.0,
163 c in -5.0..5.0,
164 d in -5.0..5.0,
165 e in -5.0..5.0,
166 f in -5.0..5.0,
167 g in -5.0..5.0,
168 h in -5.0..5.0) {
169 let param = [a, b, c, d, e, f, g, h];
170 let derivative = styblinski_tang_derivative(¶m);
171 let derivative_fd = Vec::from(param).central_diff(&|x| styblinski_tang(&x));
172 for i in 0..derivative.len() {
173 assert_relative_eq!(
174 derivative[i],
175 derivative_fd[i],
176 epsilon = 1e-5,
177 max_relative = 1e-2
178 );
179 }
180 }
181 }
182
183 proptest! {
184 #[test]
185 fn test_styblinski_tang_derivative_const_finitediff(a in -5.0..5.0,
186 b in -5.0..5.0,
187 c in -5.0..5.0,
188 d in -5.0..5.0,
189 e in -5.0..5.0,
190 f in -5.0..5.0,
191 g in -5.0..5.0,
192 h in -5.0..5.0) {
193 let param = [a, b, c, d, e, f, g, h];
194 let derivative = styblinski_tang_derivative_const(¶m);
195 let derivative_fd = Vec::from(param).central_diff(&|x| styblinski_tang(&x));
196 for i in 0..derivative.len() {
197 assert_relative_eq!(
198 derivative[i],
199 derivative_fd[i],
200 epsilon = 1e-5,
201 max_relative = 1e-2
202 );
203 }
204 }
205 }
206
207 proptest! {
208 #[test]
209 fn test_styblinski_tang_hessian_finitediff(a in -5.0..5.0,
210 b in -5.0..5.0,
211 c in -5.0..5.0,
212 d in -5.0..5.0,
213 e in -5.0..5.0,
214 f in -5.0..5.0,
215 g in -5.0..5.0,
216 h in -5.0..5.0) {
217 let param = [a, b, c, d, e, f, g, h];
218 let derivative = styblinski_tang_hessian(¶m);
219 let derivative_fd = Vec::from(param).central_hessian(&|x| styblinski_tang_derivative(&x));
220 for i in 0..derivative.len() {
221 for j in 0..derivative[i].len() {
222 assert_relative_eq!(
223 derivative[i][j],
224 derivative_fd[i][j],
225 epsilon = 1e-5,
226 max_relative = 1e-2
227 );
228 }
229 }
230 }
231 }
232
233 proptest! {
234 #[test]
235 fn test_styblinski_tang_hessian_const_finitediff(a in -5.0..5.0,
236 b in -5.0..5.0,
237 c in -5.0..5.0,
238 d in -5.0..5.0,
239 e in -5.0..5.0,
240 f in -5.0..5.0,
241 g in -5.0..5.0,
242 h in -5.0..5.0) {
243 let param = [a, b, c, d, e, f, g, h];
244 let derivative = styblinski_tang_hessian_const(¶m);
245 let derivative_fd = Vec::from(param).central_hessian(&|x| styblinski_tang_derivative(&x));
246 for i in 0..derivative.len() {
247 for j in 0..derivative[i].len() {
248 assert_relative_eq!(
249 derivative[i][j],
250 derivative_fd[i][j],
251 epsilon = 1e-5,
252 max_relative = 1e-2
253 );
254 }
255 }
256 }
257 }
258}