1use num::{Float, FromPrimitive};
21use std::iter::Sum;
22
23pub fn sphere<T>(param: &[T]) -> T
35where
36 T: Float + FromPrimitive + Sum,
37{
38 param.iter().map(|x| x.powi(2)).sum()
39}
40
41pub fn sphere_derivative<T>(param: &[T]) -> Vec<T>
51where
52 T: Float + FromPrimitive,
53{
54 let num2 = T::from_f64(2.0).unwrap();
55 param.iter().map(|x| num2 * *x).collect()
56}
57
58pub fn sphere_derivative_const<const N: usize, T>(param: &[T; N]) -> [T; N]
71where
72 T: Float + FromPrimitive,
73{
74 let num2 = T::from_f64(2.0).unwrap();
75 let mut deriv = [T::from_f64(0.0).unwrap(); N];
76 for i in 0..N {
77 deriv[i] = num2 * param[i];
78 }
79 deriv
80}
81
82pub fn sphere_hessian<T>(param: &[T]) -> Vec<Vec<T>>
84where
85 T: Float + FromPrimitive,
86{
87 let n = param.len();
88 let mut hessian = vec![vec![T::from_f64(0.0).unwrap(); n]; n];
89 for (i, row) in hessian.iter_mut().enumerate().take(n) {
90 row[i] = T::from_f64(2.0).unwrap();
91 }
92 hessian
93}
94
95pub fn sphere_hessian_const<const N: usize, T>(_param: &[T; N]) -> [[T; N]; N]
100where
101 T: Float + FromPrimitive,
102{
103 let mut hessian = [[T::from_f64(0.0).unwrap(); N]; N];
104 for (i, row) in hessian.iter_mut().enumerate().take(N) {
105 row[i] = T::from_f64(2.0).unwrap();
106 }
107 hessian
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use approx::assert_relative_eq;
114 use finitediff::FiniteDiff;
115 use proptest::prelude::*;
116
117 #[test]
118 fn test_sphere_optimum() {
119 assert_relative_eq!(sphere(&[0.0_f32, 0.0_f32]), 0.0, epsilon = f32::EPSILON);
120 assert_relative_eq!(sphere(&[0.0_f64, 0.0_f64]), 0.0, epsilon = f64::EPSILON);
121 }
122
123 proptest! {
124 #[test]
125 fn test_sphere(a in -10.0..10.0,
126 b in -10.0..10.0,
127 c in -10.0..10.0,
128 d in -10.0..10.0,
129 e in -10.0..10.0,
130 f in -10.0..10.0,
131 g in -10.0..10.0,
132 h in -10.0..10.0) {
133 let param: [f64; 8] = [a, b, c, d, e, f, g, h];
134 let v1 = sphere(¶m);
135 let v2 = a.powi(2) + b.powi(2) + c.powi(2) + d.powi(2) + e.powi(2) + f.powi(2) + g.powi(2) + h.powi(2);
136 assert_relative_eq!(v1, v2, epsilon = f64::EPSILON);
137 }
138 }
139
140 proptest! {
141 #[test]
142 fn test_sphere_derivative(a in -10.0..10.0,
143 b in -10.0..10.0,
144 c in -10.0..10.0,
145 d in -10.0..10.0,
146 e in -10.0..10.0,
147 f in -10.0..10.0,
148 g in -10.0..10.0,
149 h in -10.0..10.0) {
150 let param = [a, b, c, d, e, f, g, h];
151 let derivative = sphere_derivative(¶m);
152 let derivative_fd =
153 [2.0 * a, 2.0 * b, 2.0 * c, 2.0 * d, 2.0 * e, 2.0 * f, 2.0 * g, 2.0 * h];
154 for i in 0..derivative.len() {
155 assert_relative_eq!(
156 derivative[i],
157 derivative_fd[i],
158 epsilon = 1e-5,
159 max_relative = 1e-2
160 );
161 }
162 }
163 }
164
165 proptest! {
166 #[test]
167 fn test_sphere_derivative_const(a in -10.0..10.0,
168 b in -10.0..10.0,
169 c in -10.0..10.0,
170 d in -10.0..10.0,
171 e in -10.0..10.0,
172 f in -10.0..10.0,
173 g in -10.0..10.0,
174 h in -10.0..10.0) {
175 let param = [a, b, c, d, e, f, g, h];
176 let derivative = sphere_derivative_const(¶m);
177 let derivative_fd =
178 [2.0 * a, 2.0 * b, 2.0 * c, 2.0 * d, 2.0 * e, 2.0 * f, 2.0 * g, 2.0 * h];
179 for i in 0..derivative.len() {
180 assert_relative_eq!(
181 derivative[i],
182 derivative_fd[i],
183 epsilon = 1e-5,
184 max_relative = 1e-2,
185 );
186 }
187 }
188 }
189
190 proptest! {
191 #[test]
192 fn test_sphere_derivative_finitediff(a in -10.0..10.0,
193 b in -10.0..10.0,
194 c in -10.0..10.0,
195 d in -10.0..10.0,
196 e in -10.0..10.0,
197 f in -10.0..10.0,
198 g in -10.0..10.0,
199 h in -10.0..10.0) {
200 let param = [a, b, c, d, e, f, g, h];
201 let derivative = sphere_derivative(¶m);
202 let derivative_fd = Vec::from(param).central_diff(&|x| sphere(&x));
203 for i in 0..derivative.len() {
204 assert_relative_eq!(
205 derivative[i],
206 derivative_fd[i],
207 epsilon = 1e-5,
208 max_relative = 1e-2
209 );
210 }
211 }
212 }
213
214 proptest! {
215 #[test]
216 fn test_sphere_derivative_const_finitediff(a in -10.0..10.0,
217 b in -10.0..10.0,
218 c in -10.0..10.0,
219 d in -10.0..10.0,
220 e in -10.0..10.0,
221 f in -10.0..10.0,
222 g in -10.0..10.0,
223 h in -10.0..10.0) {
224 let param = [a, b, c, d, e, f, g, h];
225 let derivative = sphere_derivative_const(¶m);
226 let derivative_fd = Vec::from(param).central_diff(&|x| sphere(&x));
227 for i in 0..derivative.len() {
228 assert_relative_eq!(
229 derivative[i],
230 derivative_fd[i],
231 epsilon = 1e-5,
232 max_relative = 1e-2
233 );
234 }
235 }
236 }
237
238 proptest! {
239 #[test]
240 fn test_sphere_hessian(a in -10.0..10.0,
241 b in -10.0..10.0,
242 c in -10.0..10.0,
243 d in -10.0..10.0,
244 e in -10.0..10.0,
245 f in -10.0..10.0,
246 g in -10.0..10.0,
247 h in -10.0..10.0) {
248 let param = [a, b, c, d, e, f, g, h];
249 let hessian = sphere_hessian(¶m);
250 for i in 0..hessian.len() {
251 for j in 0..hessian.len() {
252 if i == j {
253 assert_relative_eq!(hessian[i][j], 2.0, epsilon = f64::EPSILON);
254 } else {
255 assert_relative_eq!(hessian[i][j], 0.0, epsilon = f64::EPSILON);
256 }
257 }
258 }
259 }
260 }
261
262 proptest! {
263 #[test]
264 fn test_sphere_hessian_const(a in -10.0..10.0,
265 b in -10.0..10.0,
266 c in -10.0..10.0,
267 d in -10.0..10.0,
268 e in -10.0..10.0,
269 f in -10.0..10.0,
270 g in -10.0..10.0,
271 h in -10.0..10.0) {
272 let param = [a, b, c, d, e, f, g, h];
273 let hessian = sphere_hessian_const(¶m);
274 for i in 0..hessian.len() {
275 for j in 0..hessian.len() {
276 if i == j {
277 assert_relative_eq!(hessian[i][j], 2.0, epsilon = f64::EPSILON);
278 } else {
279 assert_relative_eq!(hessian[i][j], 0.0, epsilon = f64::EPSILON);
280 }
281 }
282 }
283 }
284 }
285
286 proptest! {
287 #[test]
288 fn test_sphere_hessian_finitediff(a in -10.0..10.0,
289 b in -10.0..10.0,
290 c in -10.0..10.0,
291 d in -10.0..10.0,
292 e in -10.0..10.0,
293 f in -10.0..10.0,
294 g in -10.0..10.0,
295 h in -10.0..10.0) {
296 let param = [a, b, c, d, e, f, g, h];
297 let hessian = sphere_hessian(¶m);
298 let hessian_fd = Vec::from(param).central_hessian(&|x| sphere_derivative(&x));
299 for i in 0..hessian.len() {
300 for j in 0..hessian.len() {
301 assert_relative_eq!(
302 hessian[i][j],
303 hessian_fd[i][j],
304 epsilon = 1e-5,
305 max_relative = 1e-2
306 );
307 }
308 }
309 }
310 }
311
312 proptest! {
313 #[test]
314 fn test_sphere_hessian_const_finitediff(a in -10.0..10.0,
315 b in -10.0..10.0,
316 c in -10.0..10.0,
317 d in -10.0..10.0,
318 e in -10.0..10.0,
319 f in -10.0..10.0,
320 g in -10.0..10.0,
321 h in -10.0..10.0) {
322 let param = [a, b, c, d, e, f, g, h];
323 let hessian = sphere_hessian_const(¶m);
324 let hessian_fd = Vec::from(param).central_hessian(&|x| sphere_derivative(&x));
325 for i in 0..hessian.len() {
326 for j in 0..hessian.len() {
327 assert_relative_eq!(
328 hessian[i][j],
329 hessian_fd[i][j],
330 epsilon = 1e-5,
331 max_relative = 1e-2
332 );
333 }
334 }
335 }
336 }
337}