argmin_testfunctions/
crossintray.rs1use std::f64::consts::PI;
27
28use num::{Float, FromPrimitive};
29
30pub fn cross_in_tray<T>(param: &[T; 2]) -> T
50where
51 T: Float + Into<f64> + FromPrimitive,
52{
53 let x1: f64 = param[0].into();
54 let x2: f64 = param[1].into();
55 T::from_f64(
56 -0.0001
57 * ((x1.sin() * x2.sin() * (100.0 - (x1.powi(2) + x2.powi(2)).sqrt() / PI).abs().exp())
58 .abs()
59 + 1.0)
60 .powf(0.1),
61 )
62 .unwrap()
63}
64
65pub fn cross_in_tray_derivative<T>(param: &[T; 2]) -> [T; 2]
69where
70 T: Float + Into<f64> + FromPrimitive,
71{
72 let x1: f64 = param[0].into();
73 let x2: f64 = param[1].into();
74
75 let a = (x1.powi(2) + x2.powi(2)).sqrt();
76 let b = a / PI - 100.0;
77 let c = b.abs().exp();
78 let x2sin = x2.sin();
79 let x2sinabs = x2sin.abs();
80 let x1sin = x1.sin();
81 let x1sinabs = x1sin.abs();
82 let x1cos = x1.cos();
83 let x2cos = x2.cos();
84 let denom = PI * a * b.abs();
85
86 [
87 T::from_f64({
88 -1e-5
89 * (if denom.abs() <= f64::EPSILON {
90 0.0
91 } else {
92 (x2sinabs * x1 * b * c * x1sinabs) / denom
93 } + if x1sinabs <= f64::EPSILON {
94 0.0
95 } else {
96 (x2sinabs * x1sin * x1cos * c) / x1sinabs
97 })
98 / (x2sinabs * x1sinabs * c + 1.0).powf(0.9)
99 })
100 .unwrap(),
101 T::from_f64({
102 -1e-5
103 * (if denom.abs() <= f64::EPSILON {
104 0.0
105 } else {
106 (x2sinabs * x2 * b * c * x1sinabs) / denom
107 } + if x2sinabs <= f64::EPSILON {
108 0.0
109 } else {
110 (x1sinabs * x2sin * x2cos * c) / x2sinabs
111 })
112 / (x2sinabs * x1sinabs * c + 1.0).powf(0.9)
113 })
114 .unwrap(),
115 ]
116}
117
118pub fn cross_in_tray_hessian<T>(param: &[T; 2]) -> [[T; 2]; 2]
124where
125 T: Float + Into<f64> + FromPrimitive,
126{
127 let x1: f64 = param[0].into();
128 let x2: f64 = param[1].into();
129
130 let a = (x1.powi(2) + x2.powi(2)).sqrt();
131 let b = a / PI - 100.0;
132 let c = b.abs().exp();
133 let x2sin = x2.sin();
134 let x2sinabs = x2sin.abs();
135 let x1sin = x1.sin();
136 let x1sinabs = x1sin.abs();
137 let x1cos = x1.cos();
138 let x2cos = x2.cos();
139 let denom = PI * a * b.abs();
140 let d = x1sinabs * x2sinabs * b * c / denom;
141
142 let h1 = T::from_f64({
143 9.0 * 1e-6 * (d * x1 + (x1sin * x1cos * x2sinabs * c) / x1sinabs).powi(2)
144 / (x1sinabs * x2sinabs * c + 1.0).powf(1.9)
145 - 1e-5
146 * (d - x1.powi(2)
147 * ((x1sinabs * x2sinabs * b * c) / (PI * a.powi(3) * b.abs())
148 - (x1sinabs * x2sinabs * c) / (PI.powi(2) * (x1.powi(2) + x2.powi(2))))
149 - x2sinabs * x1sinabs * c
150 + (2.0 * x1sin * x1cos * x2sinabs * x1 * b * c) / (denom * x1sinabs))
151 / (x1sinabs * x2sinabs * c + 1.0).powf(0.9)
152 })
153 .unwrap();
154
155 let h2 = T::from_f64({
156 9.0 * 1e-6 * (d * x2 + (x2sin * x2cos * x1sinabs * c) / x2sinabs).powi(2)
157 / (x1sinabs * x2sinabs * c + 1.0).powf(1.9)
158 - 1e-5
159 * (d - x2.powi(2)
160 * ((x1sinabs * x2sinabs * b * c) / (PI * a.powi(3) * b.abs())
161 - (x1sinabs * x2sinabs * c) / (PI.powi(2) * (x1.powi(2) + x2.powi(2))))
162 - x2sinabs * x1sinabs * c
163 + (2.0 * x2sin * x2cos * x1sinabs * x2 * b * c) / (denom * x2sinabs))
164 / (x1sinabs * x2sinabs * c + 1.0).powf(0.9)
165 })
166 .unwrap();
167
168 let offdiag = T::from_f64({
169 (9.0 * 1e-6
170 * (x1 * d + (x1sin * x1cos * x2sinabs * c) / x1sinabs)
171 * (x2 * d + (x2sin * x2cos * x1sinabs * c) / x2sinabs))
172 / (x1sinabs * x2sinabs * c + 1.0).powf(1.9)
173 - ((x2 * x1sin * x1cos * x2sinabs * b * c) / (PI * x1sinabs * a * b.abs())
174 - (x1 * x2 * x1sinabs * x2sinabs * b * c) / (PI * a.powi(3) * b.abs())
175 + (x1 * x2 * x1sinabs * x2sinabs * c) / (PI.powi(2) * (x1.powi(2) + x2.powi(2)))
176 + (x1 * x2sin * x2cos * x1sinabs * b * c) / (PI * a * b.abs() * x2sinabs)
177 + (x1sin * x1cos * x2sin * x2cos * c) / (x1sinabs * x2sinabs))
178 / (100_000.0 * (x1sinabs * x2sinabs * c + 1.0).powf(0.9))
179 })
180 .unwrap();
181
182 [[h1, offdiag], [offdiag, h2]]
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use approx::assert_relative_eq;
189 use finitediff::FiniteDiff;
190 use proptest::prelude::*;
191 use std::f32;
192
193 #[test]
194 fn test_cross_in_tray_optimum() {
195 assert_relative_eq!(
199 cross_in_tray(&[1.34941_f64, 1.34941_f64]),
200 -2.062611870,
201 epsilon = f32::EPSILON.into()
202 );
203 assert_relative_eq!(
204 cross_in_tray(&[1.34941_f64, -1.34941_f64]),
205 -2.062611870,
206 epsilon = f32::EPSILON.into()
207 );
208 assert_relative_eq!(
209 cross_in_tray(&[-1.34941_f64, 1.34941_f64]),
210 -2.062611870,
211 epsilon = f32::EPSILON.into()
212 );
213 assert_relative_eq!(
214 cross_in_tray(&[-1.34941_f64, -1.34941_f64]),
215 -2.062611870,
216 epsilon = f32::EPSILON.into()
217 );
218 assert_relative_eq!(
219 cross_in_tray(&[1.34941_f32, 1.34941_f32]),
220 -2.062611870,
221 epsilon = f32::EPSILON.into()
222 );
223 assert_relative_eq!(
224 cross_in_tray(&[1.34941_f32, -1.34941_f32]),
225 -2.062611870,
226 epsilon = f32::EPSILON.into()
227 );
228 assert_relative_eq!(
229 cross_in_tray(&[-1.34941_f32, 1.34941_f32]),
230 -2.062611870,
231 epsilon = f32::EPSILON.into()
232 );
233 assert_relative_eq!(
234 cross_in_tray(&[-1.34941_f32, -1.34941_f32]),
235 -2.062611870,
236 epsilon = f32::EPSILON.into()
237 );
238
239 for p in [
240 [1.34941_f64, 1.34941_f64],
241 [1.34941_f64, -1.34941_f64],
242 [-1.34941_f64, 1.34941_f64],
243 [-1.34941_f64, -1.34941_f64],
244 [0.0_f64, 0.0_f64],
245 ] {
246 let deriv = cross_in_tray_derivative(&p);
247 for i in 0..2 {
248 assert_relative_eq!(deriv[i], 0.0, epsilon = 1e-6);
249 }
250 }
251 }
252
253 proptest! {
254 #[test]
255 fn test_cross_in_tray_derivative_finitediff(a in -10.0..10.0, b in -10.0..10.0) {
256 let param = [a, b];
257 let derivative = cross_in_tray_derivative(¶m);
258 let derivative_fd = Vec::from(param).central_diff(&|x| cross_in_tray(&[x[0], x[1]]));
259 for i in 0..derivative.len() {
262 assert_relative_eq!(
263 derivative[i],
264 derivative_fd[i],
265 epsilon = 1e-4,
266 max_relative = 1e-2
267 );
268 }
269 }
270 }
271
272 proptest! {
273 #[test]
274 fn test_cross_in_tray_hessian_finitediff(a in -10.0..10.0, b in -10.0..10.0) {
275 let param = [a, b];
276 let hessian = cross_in_tray_hessian(¶m);
277 let hessian_fd =
278 Vec::from(param).central_hessian(&|x| cross_in_tray_derivative(&[x[0], x[1]]).to_vec());
279 let n = hessian.len();
280 for i in 0..n {
283 assert_eq!(hessian[i].len(), n);
284 for j in 0..n {
285 if hessian[i][j].is_finite() {
286 assert_relative_eq!(
287 hessian[i][j],
288 hessian_fd[i][j],
289 epsilon = 1e-5,
290 max_relative = 1e-2
291 );
292 }
293 }
294 }
295 }
296 }
297}