argmin_testfunctions/
holdertable.rs1use num::{Float, FromPrimitive};
25use std::f64::consts::PI;
26
27pub fn holder_table<T>(param: &[T; 2]) -> T
43where
44 T: Float + FromPrimitive,
45{
46 let [x1, x2] = *param;
47 let pi = T::from_f64(PI).unwrap();
48 let n1 = T::from_f64(1.0).unwrap();
49 -(x1.sin() * x2.cos() * (n1 - (x1.powi(2) + x2.powi(2)).sqrt() / pi).abs().exp()).abs()
50}
51
52pub fn holder_table_derivative<T>(param: &[T; 2]) -> [T; 2]
57where
58 T: Float + FromPrimitive,
59{
60 let [x1, x2] = *param;
61
62 let pi = T::from_f64(PI).unwrap();
63 let n0 = T::from_f64(0.0).unwrap();
64 let n1 = T::from_f64(1.0).unwrap();
65 let eps = T::epsilon();
66
67 let x1sin = x1.sin();
68 let x2sin = x2.sin();
69 let x1cos = x1.cos();
70 let x2cos = x2.cos();
71 let x1sinabs = x1sin.abs();
72 let x2cosabs = x2cos.abs();
73 let a = (x1.powi(2) + x2.powi(2)).sqrt();
74 let b = a / pi - n1;
75 let c = b.abs();
76 let d = c.exp();
77
78 if a <= eps {
79 [n0, n0]
80 } else {
81 [
82 -(x1 * x1sinabs * x2cosabs * b * d) / (pi * a * c)
83 - if x1sinabs <= eps {
84 n0
85 } else {
86 (x1sin * x1cos * x2cosabs * d) / (x1sinabs)
87 },
88 -(x2 * x1sinabs * x2cosabs * b * d) / (pi * a * c)
89 + if x2cosabs <= eps {
90 n0
91 } else {
92 (x2sin * x2cos * x1sinabs * d) / (x2cosabs)
93 },
94 ]
95 }
96}
97
98pub fn holder_table_hessian<T>(param: &[T; 2]) -> [[T; 2]; 2]
103where
104 T: Float + FromPrimitive,
105{
106 let [x1, x2] = *param;
107
108 let pi = T::from_f64(PI).unwrap();
109 let n0 = T::from_f64(0.0).unwrap();
110 let n1 = T::from_f64(1.0).unwrap();
111 let n2 = T::from_f64(2.0).unwrap();
112 let eps = T::epsilon();
113
114 let x1sin = x1.sin();
115 let x2sin = x2.sin();
116 let x1cos = x1.cos();
117 let x2cos = x2.cos();
118 let x1sinabs = x1sin.abs();
119 let x2cosabs = x2cos.abs();
120 let a = (x1.powi(2) + x2.powi(2)).sqrt();
121 let b = a / pi - n1;
122 let c = b.abs();
123 let d = c.exp();
124
125 let d1 = (x1sinabs * x2cosabs * d)
126 * (if a <= eps {
127 n0
128 } else {
129 -b / (pi * a * c) + (x1.powi(2) * b) / (pi * a.powi(3) * c)
130 - (x1.powi(2)) / (pi.powi(2) * (x1.powi(2) + x2.powi(2)))
131 } + n1)
132 - if x1sinabs <= eps || a <= eps {
133 n0
134 } else {
135 (n2 * x1 * x1sin * x1cos * x2cosabs * b * d) / (pi * a * c * x1sinabs)
136 };
137
138 let d2 = (x1sinabs * x2cosabs * d)
139 * (if a <= eps {
140 n0
141 } else {
142 -b / (pi * a * c) + (x2.powi(2) * b) / (pi * a.powi(3) * c)
143 - (x2.powi(2)) / (pi.powi(2) * (x1.powi(2) + x2.powi(2)))
144 } + n1)
145 + if x2cosabs <= eps || a <= eps {
146 n0
147 } else {
148 (n2 * x2 * x2sin * x2cos * x1sinabs * b * d) / (pi * a * c * x2cosabs)
149 };
150
151 let offdiag = if a <= eps || x1sinabs <= eps || x2cosabs <= eps {
152 n0
153 } else {
154 d * (-(x2 * x1sin * x1cos * x2cosabs * b) / (pi * x1sinabs * a * c)
155 + (x1 * x2 * x1sinabs * x2cosabs * b) / (pi * a.powi(3) * c)
156 - (x1 * x2 * x1sinabs * x2cosabs) / (pi.powi(2) * (x1.powi(2) + x2.powi(2)))
157 + (x1 * x1sinabs * x2sin * x2cos * b) / (pi * a * c * x2cosabs)
158 + (x1sin * x1cos * x2sin * x2cos) / (x1sinabs * x2cosabs))
159 };
160
161 [[d1, offdiag], [offdiag, d2]]
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use approx::assert_relative_eq;
168 use finitediff::FiniteDiff;
169 use proptest::prelude::*;
170 use std::f32;
171
172 #[test]
173 fn test_holder_table_optimum() {
174 assert_relative_eq!(
175 holder_table(&[8.05502_f32, 9.66459_f32]),
176 -19.2085,
177 epsilon = f32::EPSILON
178 );
179 assert_relative_eq!(
180 holder_table(&[-8.05502_f32, 9.66459_f32]),
181 -19.2085,
182 epsilon = f32::EPSILON
183 );
184 assert_relative_eq!(
185 holder_table(&[8.05502_f32, -9.66459_f32]),
186 -19.2085,
187 epsilon = f32::EPSILON
188 );
189 assert_relative_eq!(
190 holder_table(&[-8.05502_f32, -9.66459_f32]),
191 -19.2085,
192 epsilon = f32::EPSILON
193 );
194
195 for p in [
196 [8.05502, 9.66459],
197 [8.05502, -9.66459],
198 [-8.05502, 9.66459],
199 [-8.05502, -9.66459],
200 [0.0, 0.0],
201 ] {
202 let deriv = holder_table_derivative(&p);
203 for i in 0..2 {
204 assert_relative_eq!(deriv[i], 0.0, epsilon = 1e-4);
205 }
206 }
207 }
208
209 proptest! {
210 #[test]
211 fn test_holder_table_derivative_finitediff(a in -10.0..10.0, b in -10.0..10.0) {
212 let param = [a, b];
213 let derivative = holder_table_derivative(¶m);
214 let derivative_fd = Vec::from(param).central_diff(&|x| holder_table(&[x[0], x[1]]));
215 for i in 0..derivative.len() {
218 assert_relative_eq!(
219 derivative[i],
220 derivative_fd[i],
221 epsilon = 1e-5,
222 max_relative = 1e-2
223 );
224 }
225 }
226 }
227
228 proptest! {
229 #[test]
230 fn test_holder_table_hessian_finitediff(a in -10.0..10.0, b in -10.0..10.0) {
231 let param = [a, b];
232 let hessian = holder_table_hessian(¶m);
233 let hessian_fd =
234 Vec::from(param).forward_hessian(&|x| holder_table_derivative(&[x[0], x[1]]).to_vec());
235 let n = hessian.len();
236 for i in 0..n {
239 assert_eq!(hessian[i].len(), n);
240 for j in 0..n {
241 if hessian_fd[i][j].is_finite() {
242 assert_relative_eq!(
243 hessian[i][j],
244 hessian_fd[i][j],
245 epsilon = 1e-5,
246 max_relative = 1e-2
247 );
248 }
249 }
250 }
251 }
252 }
253}