Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9fa88e6

Browse files
committedFeb 12, 2024·
Added derivative and Hessian for Styblinski-Tang test function
1 parent 7bf5ce8 commit 9fa88e6

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed
 

‎crates/argmin-testfunctions/src/styblinskitang.rs

+190
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,95 @@ where
4242
.sum()
4343
}
4444

45+
/// Derivative of Styblinski-Tang test function
46+
pub fn styblinski_tang_derivative<T>(param: &[T]) -> Vec<T>
47+
where
48+
T: Float + FromPrimitive + Sum,
49+
{
50+
let n2 = T::from_f64(2.0).unwrap();
51+
let n2_5 = T::from_f64(2.5).unwrap();
52+
let n16 = T::from_f64(16.0).unwrap();
53+
54+
param
55+
.iter()
56+
.map(|x| n2 * x.powi(3) - n16 * *x + n2_5)
57+
.collect()
58+
}
59+
60+
/// Derivative of Styblinski-Tang test function
61+
///
62+
/// This is the const generics version, which requires the number of parameters to be known
63+
/// at compile time.
64+
pub fn styblinski_tang_derivative_const<const N: usize, T>(param: &[T; N]) -> [T; N]
65+
where
66+
T: Float + FromPrimitive + Sum,
67+
{
68+
let n0 = T::from_f64(0.0).unwrap();
69+
let n2 = T::from_f64(2.0).unwrap();
70+
let n2_5 = T::from_f64(2.5).unwrap();
71+
let n16 = T::from_f64(16.0).unwrap();
72+
73+
let mut out = [n0; N];
74+
75+
param
76+
.iter()
77+
.zip(out.iter_mut())
78+
.map(|(x, o)| *o = n2 * x.powi(3) - n16 * *x + n2_5)
79+
.count();
80+
81+
out
82+
}
83+
84+
/// Hessian of Styblinski-Tang test function
85+
pub fn styblinski_tang_hessian<T>(param: &[T]) -> Vec<Vec<T>>
86+
where
87+
T: Float + FromPrimitive + Sum,
88+
{
89+
let n0 = T::from_f64(0.0).unwrap();
90+
let n6 = T::from_f64(6.0).unwrap();
91+
let n16 = T::from_f64(16.0).unwrap();
92+
93+
let n = param.len();
94+
let mut out = vec![vec![n0; n]; n];
95+
96+
param
97+
.iter()
98+
.enumerate()
99+
.map(|(i, x)| out[i][i] = n6 * x.powi(2) - n16)
100+
.count();
101+
102+
out
103+
}
104+
105+
/// Hessian of Styblinski-Tang test function
106+
///
107+
/// This is the const generics version, which requires the number of parameters to be known
108+
/// at compile time.
109+
pub fn styblinski_tang_hessian_const<const N: usize, T>(param: &[T; N]) -> [[T; N]; N]
110+
where
111+
T: Float + FromPrimitive + Sum,
112+
{
113+
let n0 = T::from_f64(0.0).unwrap();
114+
let n6 = T::from_f64(6.0).unwrap();
115+
let n16 = T::from_f64(16.0).unwrap();
116+
117+
let mut out = [[n0; N]; N];
118+
119+
param
120+
.iter()
121+
.enumerate()
122+
.map(|(i, x)| out[i][i] = n6 * x.powi(2) - n16)
123+
.count();
124+
125+
out
126+
}
127+
45128
#[cfg(test)]
46129
mod tests {
47130
use super::*;
48131
use approx::assert_relative_eq;
132+
use finitediff::FiniteDiff;
133+
use proptest::prelude::*;
49134
use std::f32;
50135

51136
#[test]
@@ -60,5 +145,110 @@ mod tests {
60145
-117.4984971113142,
61146
epsilon = f64::EPSILON
62147
);
148+
149+
let deriv = styblinski_tang_derivative(&[-2.903534_f64, -2.903534_f64, -2.903534_f64]);
150+
for i in 0..3 {
151+
assert_relative_eq!(deriv[i], 0.0, epsilon = 1e-5, max_relative = 1e-5);
152+
}
153+
}
154+
155+
proptest! {
156+
#[test]
157+
fn test_styblinski_tang_derivative_finitediff(a in -5.0..5.0,
158+
b in -5.0..5.0,
159+
c in -5.0..5.0,
160+
d in -5.0..5.0,
161+
e in -5.0..5.0,
162+
f in -5.0..5.0,
163+
g in -5.0..5.0,
164+
h in -5.0..5.0) {
165+
let param = [a, b, c, d, e, f, g, h];
166+
let derivative = styblinski_tang_derivative(&param);
167+
let derivative_fd = Vec::from(param).central_diff(&|x| styblinski_tang(&x));
168+
for i in 0..derivative.len() {
169+
assert_relative_eq!(
170+
derivative[i],
171+
derivative_fd[i],
172+
epsilon = std::f64::EPSILON,
173+
max_relative = 1e-3
174+
);
175+
}
176+
}
177+
}
178+
179+
proptest! {
180+
#[test]
181+
fn test_styblinski_tang_derivative_const_finitediff(a in -5.0..5.0,
182+
b in -5.0..5.0,
183+
c in -5.0..5.0,
184+
d in -5.0..5.0,
185+
e in -5.0..5.0,
186+
f in -5.0..5.0,
187+
g in -5.0..5.0,
188+
h in -5.0..5.0) {
189+
let param = [a, b, c, d, e, f, g, h];
190+
let derivative = styblinski_tang_derivative_const(&param);
191+
let derivative_fd = Vec::from(param).central_diff(&|x| styblinski_tang(&x));
192+
for i in 0..derivative.len() {
193+
assert_relative_eq!(
194+
derivative[i],
195+
derivative_fd[i],
196+
epsilon = std::f64::EPSILON,
197+
max_relative = 1e-3
198+
);
199+
}
200+
}
201+
}
202+
203+
proptest! {
204+
#[test]
205+
fn test_styblinski_tang_hessian_finitediff(a in -5.0..5.0,
206+
b in -5.0..5.0,
207+
c in -5.0..5.0,
208+
d in -5.0..5.0,
209+
e in -5.0..5.0,
210+
f in -5.0..5.0,
211+
g in -5.0..5.0,
212+
h in -5.0..5.0) {
213+
let param = [a, b, c, d, e, f, g, h];
214+
let derivative = styblinski_tang_hessian(&param);
215+
let derivative_fd = Vec::from(param).central_hessian(&|x| styblinski_tang_derivative(&x));
216+
for i in 0..derivative.len() {
217+
for j in 0..derivative[i].len() {
218+
assert_relative_eq!(
219+
derivative[i][j],
220+
derivative_fd[i][j],
221+
epsilon = std::f64::EPSILON,
222+
max_relative = 1e-3
223+
);
224+
}
225+
}
226+
}
227+
}
228+
229+
proptest! {
230+
#[test]
231+
fn test_styblinski_tang_hessian_const_finitediff(a in -5.0..5.0,
232+
b in -5.0..5.0,
233+
c in -5.0..5.0,
234+
d in -5.0..5.0,
235+
e in -5.0..5.0,
236+
f in -5.0..5.0,
237+
g in -5.0..5.0,
238+
h in -5.0..5.0) {
239+
let param = [a, b, c, d, e, f, g, h];
240+
let derivative = styblinski_tang_hessian_const(&param);
241+
let derivative_fd = Vec::from(param).central_hessian(&|x| styblinski_tang_derivative(&x));
242+
for i in 0..derivative.len() {
243+
for j in 0..derivative[i].len() {
244+
assert_relative_eq!(
245+
derivative[i][j],
246+
derivative_fd[i][j],
247+
epsilon = std::f64::EPSILON,
248+
max_relative = 1e-3
249+
);
250+
}
251+
}
252+
}
63253
}
64254
}

0 commit comments

Comments
 (0)
Please sign in to comment.