@@ -54,17 +54,188 @@ where
54
54
let n10 = T :: from_f64 ( 10.0 ) . unwrap ( ) ;
55
55
let pi = T :: from_f64 ( PI ) . unwrap ( ) ;
56
56
57
- let w = |x : T | n1 - ( x - n1) / n4;
57
+ let w = |x : T | n1 + ( x - n1) / n4;
58
58
59
59
( pi * w ( param[ 0 ] ) ) . sin ( ) . powi ( 2 )
60
60
+ param[ 1 ..( plen - 1 ) ]
61
61
. iter ( )
62
62
. map ( |x| w ( * x) )
63
- . map ( |wi : T | ( wi - n1) . powi ( 2 ) * ( n1 + n10 * ( pi * wi + n1) ) )
63
+ . map ( |wi : T | ( wi - n1) . powi ( 2 ) * ( n1 + n10 * ( pi * wi + n1) . sin ( ) . powi ( 2 ) ) )
64
64
. sum ( )
65
65
+ ( w ( param[ plen - 1 ] ) - n1) . powi ( 2 ) * ( n1 + ( n2 * pi * w ( param[ plen - 1 ] ) ) . sin ( ) . powi ( 2 ) )
66
66
}
67
67
68
+ /// Derivative of Levy test function
69
+ pub fn levy_derivative < T > ( param : & [ T ] ) -> Vec < T >
70
+ where
71
+ T : Float + FromPrimitive + Sum ,
72
+ {
73
+ let d = param. len ( ) ;
74
+ assert ! ( d >= 2 ) ;
75
+
76
+ let n1 = T :: from_f64 ( 1.0 ) . unwrap ( ) ;
77
+ let n2 = T :: from_f64 ( 2.0 ) . unwrap ( ) ;
78
+ let n4 = T :: from_f64 ( 4.0 ) . unwrap ( ) ;
79
+ let n5 = T :: from_f64 ( 5.0 ) . unwrap ( ) ;
80
+ let n8 = T :: from_f64 ( 8.0 ) . unwrap ( ) ;
81
+ let n10 = T :: from_f64 ( 10.0 ) . unwrap ( ) ;
82
+ let n16 = T :: from_f64 ( 16.0 ) . unwrap ( ) ;
83
+ let pi = T :: from_f64 ( PI ) . unwrap ( ) ;
84
+
85
+ param
86
+ . iter ( )
87
+ . enumerate ( )
88
+ . map ( |( i, x) | ( i, x, pi * ( ( * x - n1) / n4 + n1) ) )
89
+ . map ( |( i, & x, wp) | {
90
+ if i == 0 {
91
+ pi / n2 * wp. cos ( ) * wp. sin ( )
92
+ } else if i == d - 1 {
93
+ ( ( n2 * wp) . sin ( ) . powi ( 2 ) + n1) * ( x - n1) / n8
94
+ + pi / n16 * ( n2 * wp) . cos ( ) * ( n2 * wp) . sin ( ) * ( x - n1) . powi ( 2 )
95
+ } else {
96
+ ( n10 * ( wp + n1) . sin ( ) . powi ( 2 ) + n1) * ( x - n1) / n8
97
+ + n5 / n16 * pi * ( wp + n1) . cos ( ) * ( wp + n1) . sin ( ) * ( x - n1) . powi ( 2 )
98
+ }
99
+ } )
100
+ . collect ( )
101
+ }
102
+
103
+ /// Derivative of Levy test function
104
+ ///
105
+ /// This is the const generics version, which requires the number of parameters to be known
106
+ /// at compile time.
107
+ pub fn levy_derivative_const < const N : usize , T > ( param : & [ T ; N ] ) -> [ T ; N ]
108
+ where
109
+ T : Float + FromPrimitive + Sum ,
110
+ {
111
+ assert ! ( N >= 2 ) ;
112
+
113
+ let n1 = T :: from_f64 ( 1.0 ) . unwrap ( ) ;
114
+ let n0 = T :: from_f64 ( 0.0 ) . unwrap ( ) ;
115
+ let n2 = T :: from_f64 ( 2.0 ) . unwrap ( ) ;
116
+ let n4 = T :: from_f64 ( 4.0 ) . unwrap ( ) ;
117
+ let n5 = T :: from_f64 ( 5.0 ) . unwrap ( ) ;
118
+ let n8 = T :: from_f64 ( 8.0 ) . unwrap ( ) ;
119
+ let n10 = T :: from_f64 ( 10.0 ) . unwrap ( ) ;
120
+ let n16 = T :: from_f64 ( 16.0 ) . unwrap ( ) ;
121
+ let pi = T :: from_f64 ( PI ) . unwrap ( ) ;
122
+
123
+ let mut out = [ n0; N ] ;
124
+
125
+ param
126
+ . iter ( )
127
+ . zip ( out. iter_mut ( ) )
128
+ . enumerate ( )
129
+ . map ( |( i, ( x, o) ) | ( i, x, pi * ( ( * x - n1) / n4 + n1) , o) )
130
+ . map ( |( i, & x, wp, o) | {
131
+ * o = if i == 0 {
132
+ pi / n2 * wp. cos ( ) * wp. sin ( )
133
+ } else if i == N - 1 {
134
+ ( ( n2 * wp) . sin ( ) . powi ( 2 ) + n1) * ( x - n1) / n8
135
+ + pi / n16 * ( n2 * wp) . cos ( ) * ( n2 * wp) . sin ( ) * ( x - n1) . powi ( 2 )
136
+ } else {
137
+ ( n10 * ( wp + n1) . sin ( ) . powi ( 2 ) + n1) * ( x - n1) / n8
138
+ + n5 / n16 * pi * ( wp + n1) . cos ( ) * ( wp + n1) . sin ( ) * ( x - n1) . powi ( 2 )
139
+ }
140
+ } )
141
+ . count ( ) ;
142
+ out
143
+ }
144
+
145
+ /// Hessian of Levy test function
146
+ pub fn levy_hessian < T > ( param : & [ T ] ) -> Vec < Vec < T > >
147
+ where
148
+ T : Float + FromPrimitive + Sum ,
149
+ {
150
+ let d = param. len ( ) ;
151
+ assert ! ( d >= 2 ) ;
152
+
153
+ let x = param;
154
+
155
+ let n0 = T :: from_f64 ( 0.0 ) . unwrap ( ) ;
156
+ let n1 = T :: from_f64 ( 1.0 ) . unwrap ( ) ;
157
+ let n2 = T :: from_f64 ( 2.0 ) . unwrap ( ) ;
158
+ let n4 = T :: from_f64 ( 4.0 ) . unwrap ( ) ;
159
+ let n5 = T :: from_f64 ( 5.0 ) . unwrap ( ) ;
160
+ let n6 = T :: from_f64 ( 6.0 ) . unwrap ( ) ;
161
+ let n8 = T :: from_f64 ( 8.0 ) . unwrap ( ) ;
162
+ let n10 = T :: from_f64 ( 10.0 ) . unwrap ( ) ;
163
+ let n32 = T :: from_f64 ( 32.0 ) . unwrap ( ) ;
164
+ let n64 = T :: from_f64 ( 64.0 ) . unwrap ( ) ;
165
+ let pi = T :: from_f64 ( PI ) . unwrap ( ) ;
166
+ let pi2 = T :: from_f64 ( PI . powi ( 2 ) ) . unwrap ( ) ;
167
+
168
+ let mut out = vec ! [ vec![ n0; d] ; d] ;
169
+
170
+ for i in 0 ..d {
171
+ let xin1 = x[ i] - n1;
172
+ let wp = pi * ( xin1 / n4 + n1) ;
173
+ out[ i] [ i] = if i == 0 {
174
+ pi2 / n8 * ( wp. cos ( ) . powi ( 2 ) - wp. sin ( ) . powi ( 2 ) )
175
+ } else if i == d - 1 {
176
+ -( n4 * pi * xin1 * ( pi * x[ i] ) . sin ( ) + ( pi2 * xin1. powi ( 2 ) - n2) * ( pi * x[ i] ) . cos ( )
177
+ - n6)
178
+ / n32
179
+ } else {
180
+ let wp1cos = ( wp + n1) . cos ( ) ;
181
+ let wp1sin = ( wp + n1) . sin ( ) ;
182
+ n5 / n4 * pi * wp1cos * wp1sin * xin1
183
+ + n5 / n64 * pi2 * xin1. powi ( 2 ) * ( wp1cos. powi ( 2 ) - wp1sin. powi ( 2 ) )
184
+ + ( n10 * wp1sin. powi ( 2 ) + n1) / n8
185
+ }
186
+ }
187
+
188
+ out
189
+ }
190
+
191
+ /// Hessian of Levy test function
192
+ ///
193
+ /// This is the const generics version, which requires the number of parameters to be known
194
+ /// at compile time.
195
+ pub fn levy_hessian_const < const N : usize , T > ( param : & [ T ; N ] ) -> [ [ T ; N ] ; N ]
196
+ where
197
+ T : Float + FromPrimitive + Sum ,
198
+ {
199
+ assert ! ( N >= 2 ) ;
200
+
201
+ let x = param;
202
+
203
+ let n0 = T :: from_f64 ( 0.0 ) . unwrap ( ) ;
204
+ let n1 = T :: from_f64 ( 1.0 ) . unwrap ( ) ;
205
+ let n2 = T :: from_f64 ( 2.0 ) . unwrap ( ) ;
206
+ let n4 = T :: from_f64 ( 4.0 ) . unwrap ( ) ;
207
+ let n5 = T :: from_f64 ( 5.0 ) . unwrap ( ) ;
208
+ let n6 = T :: from_f64 ( 6.0 ) . unwrap ( ) ;
209
+ let n8 = T :: from_f64 ( 8.0 ) . unwrap ( ) ;
210
+ let n10 = T :: from_f64 ( 10.0 ) . unwrap ( ) ;
211
+ let n32 = T :: from_f64 ( 32.0 ) . unwrap ( ) ;
212
+ let n64 = T :: from_f64 ( 64.0 ) . unwrap ( ) ;
213
+ let pi = T :: from_f64 ( PI ) . unwrap ( ) ;
214
+ let pi2 = T :: from_f64 ( PI . powi ( 2 ) ) . unwrap ( ) ;
215
+
216
+ let mut out = [ [ n0; N ] ; N ] ;
217
+
218
+ for i in 0 ..N {
219
+ let xin1 = x[ i] - n1;
220
+ let wp = pi * ( xin1 / n4 + n1) ;
221
+ out[ i] [ i] = if i == 0 {
222
+ pi2 / n8 * ( wp. cos ( ) . powi ( 2 ) - wp. sin ( ) . powi ( 2 ) )
223
+ } else if i == N - 1 {
224
+ -( n4 * pi * xin1 * ( pi * x[ i] ) . sin ( ) + ( pi2 * xin1. powi ( 2 ) - n2) * ( pi * x[ i] ) . cos ( )
225
+ - n6)
226
+ / n32
227
+ } else {
228
+ let wp1cos = ( wp + n1) . cos ( ) ;
229
+ let wp1sin = ( wp + n1) . sin ( ) ;
230
+ n5 / n4 * pi * wp1cos * wp1sin * xin1
231
+ + n5 / n64 * pi2 * xin1. powi ( 2 ) * ( wp1cos. powi ( 2 ) - wp1sin. powi ( 2 ) )
232
+ + ( n10 * wp1sin. powi ( 2 ) + n1) / n8
233
+ }
234
+ }
235
+
236
+ out
237
+ }
238
+
68
239
/// Levy test function No. 13
69
240
///
70
241
/// Defined as
@@ -180,6 +351,16 @@ mod tests {
180
351
fn test_levy_optimum ( ) {
181
352
assert_relative_eq ! ( levy( & [ 1_f32 , 1_f32 , 1_f32 ] ) , 0.0 , epsilon = f32 :: EPSILON ) ;
182
353
assert_relative_eq ! ( levy( & [ 1_f64 , 1_f64 , 1_f64 ] ) , 0.0 , epsilon = f64 :: EPSILON ) ;
354
+
355
+ let deriv = levy_derivative ( & [ 1_f64 , 1_f64 , 1_f64 ] ) ;
356
+ for i in 0 ..2 {
357
+ assert_relative_eq ! ( deriv[ i] , 0.0 , epsilon = 1e-12 , max_relative = 1e-12 ) ;
358
+ }
359
+
360
+ let deriv = levy_derivative_const ( & [ 1_f64 , 1_f64 , 1_f64 ] ) ;
361
+ for i in 0 ..2 {
362
+ assert_relative_eq ! ( deriv[ i] , 0.0 , epsilon = 1e-12 , max_relative = 1e-12 ) ;
363
+ }
183
364
}
184
365
185
366
#[ test]
@@ -243,4 +424,92 @@ mod tests {
243
424
}
244
425
}
245
426
}
427
+
428
+ proptest ! {
429
+ #[ test]
430
+ fn test_levy_derivative_finitediff( a in -10.0 ..10.0 , b in -10.0 ..10.0 , c in -10.0 ..10.0 ) {
431
+ let param = [ a, b, c] ;
432
+ let derivative = levy_derivative( & param) ;
433
+ let derivative_fd = Vec :: from( param) . central_diff( & |x| levy( & [ x[ 0 ] , x[ 1 ] , x[ 2 ] ] ) ) ;
434
+ // println!("1: {derivative:?} at {param:?}");
435
+ // println!("2: {derivative_fd:?} at {param:?}");
436
+ for i in 0 ..derivative. len( ) {
437
+ assert_relative_eq!(
438
+ derivative[ i] ,
439
+ derivative_fd[ i] ,
440
+ epsilon = 1e-6 ,
441
+ max_relative = 1e-4 ,
442
+ ) ;
443
+ }
444
+ }
445
+ }
446
+
447
+ proptest ! {
448
+ #[ test]
449
+ fn test_levy_derivative_const_finitediff( a in -10.0 ..10.0 , b in -10.0 ..10.0 , c in -10.0 ..10.0 ) {
450
+ let param = [ a, b, c] ;
451
+ let derivative = levy_derivative_const( & param) ;
452
+ let derivative_fd = Vec :: from( param) . central_diff( & |x| levy( & [ x[ 0 ] , x[ 1 ] , x[ 2 ] ] ) ) ;
453
+ // println!("1: {derivative:?} at {param:?}");
454
+ // println!("2: {derivative_fd:?} at {param:?}");
455
+ for i in 0 ..derivative. len( ) {
456
+ assert_relative_eq!(
457
+ derivative[ i] ,
458
+ derivative_fd[ i] ,
459
+ epsilon = 1e-6 ,
460
+ max_relative = 1e-4 ,
461
+ ) ;
462
+ }
463
+ }
464
+ }
465
+
466
+ proptest ! {
467
+ #[ test]
468
+ fn test_levy_hessian_finitediff( a in -10.0 ..10.0 , b in -10.0 ..10.0 , c in -10.0 ..10.0 ) {
469
+ let param = [ a, b, c] ;
470
+ let hessian = levy_hessian( & param) ;
471
+ let hessian_fd = Vec :: from( param) . central_hessian( & |x| levy_derivative( & x) . to_vec( ) ) ;
472
+ let n = hessian. len( ) ;
473
+ // println!("1: {hessian:?} at {param:?}");
474
+ // println!("2: {hessian_fd:?} at {param:?}");
475
+ for i in 0 ..n {
476
+ assert_eq!( hessian[ i] . len( ) , n) ;
477
+ for j in 0 ..n {
478
+ if hessian[ i] [ j] . is_finite( ) {
479
+ assert_relative_eq!(
480
+ hessian[ i] [ j] ,
481
+ hessian_fd[ i] [ j] ,
482
+ epsilon = f64 :: EPSILON ,
483
+ max_relative = 1e-3
484
+ ) ;
485
+ }
486
+ }
487
+ }
488
+ }
489
+ }
490
+
491
+ proptest ! {
492
+ #[ test]
493
+ fn test_levy_hessian_const_finitediff( a in -10.0 ..10.0 , b in -10.0 ..10.0 , c in -10.0 ..10.0 ) {
494
+ let param = [ a, b, c] ;
495
+ let hessian = levy_hessian_const( & param) ;
496
+ let hessian_fd = Vec :: from( param) . central_hessian( & |x| levy_derivative( & x) . to_vec( ) ) ;
497
+ let n = hessian. len( ) ;
498
+ // println!("1: {hessian:?} at {param:?}");
499
+ // println!("2: {hessian_fd:?} at {param:?}");
500
+ for i in 0 ..n {
501
+ assert_eq!( hessian[ i] . len( ) , n) ;
502
+ for j in 0 ..n {
503
+ if hessian[ i] [ j] . is_finite( ) {
504
+ assert_relative_eq!(
505
+ hessian[ i] [ j] ,
506
+ hessian_fd[ i] [ j] ,
507
+ epsilon = f64 :: EPSILON ,
508
+ max_relative = 1e-3
509
+ ) ;
510
+ }
511
+ }
512
+ }
513
+ }
514
+ }
246
515
}
0 commit comments