22# #
33# # Graveyard of Alternative Functions
44# #
5- # # In Nodedal and Wright, epsilon was calculated as
6- # #
7- # # epsilon = sqrt(eps())
8- # #
9- # # In the examples I've tested, this strategy is best when x is small
10- # # and becomes very bad when x is larger
11- # #
125# # The proper setting of epsilon depends on whether we're doing central
136# # differencing or forward differencing. See, for example, section 5.7 of
147# # Numerical Recipes.
2114# #
2215# #############################################################################
2316
17+ macro forwardrule (x, T, e)
18+ x, T, e = esc (x), esc (T), esc (e)
19+ quote
20+ $ e = sqrt (eps ($ T)) * max (one ($ T), abs ($ x))
21+ end
22+ end
23+
24+ macro centralrule (x, T, e)
25+ x, T, e = esc (x), esc (T), esc (e)
26+ quote
27+ $ e = cbrt (eps ($ T)) * max (one ($ T), abs ($ x))
28+ end
29+ end
30+
31+ macro hessianrule (x, T, e)
32+ x, T, e = esc (x), esc (T), esc (e)
33+ quote
34+ $ e = eps ($ T)^ (1 / 4 ) * max (one ($ T), abs ($ x))
35+ end
36+ end
37+
38+ macro complexrule (x, T, e)
39+ x, T, e = esc (x), esc (T), esc (e)
40+ quote
41+ $ e = eps ($ x)
42+ end
43+ end
44+
2445function finite_difference {T <: Number} (f:: Function ,
2546 x:: T ,
2647 dtype:: Symbol = :central )
2748 if dtype == :forward
28- epsilon = sqrt ( eps (T)) * max ( one (T), abs (x))
49+ @forwardrule x T epsilon
2950 xplusdx = x + epsilon
30- # use machine-representable numbers
3151 return (f (xplusdx) - f (x)) / epsilon
3252 elseif dtype == :central
33- epsilon = cbrt ( eps (T)) * max ( one (T), abs (x))
53+ @centralrule x T epsilon
3454 xplusdx, xminusdx = x + epsilon, x - epsilon
35- # Is it better to do 2 * epsilon or xplusdx - xminusdx?
36- return (f (xplusdx) - f (xminusdx)) / (2 * epsilon)
55+ return (f (xplusdx) - f (xminusdx)) / (epsilon + epsilon)
3756 elseif dtype == :complex
38- epsilon = eps (x)
57+ @complexrule x T epsilon
3958 xplusdx = x + epsilon * im
4059 return imag (f (xplusdx)) / epsilon
4160 else
@@ -63,7 +82,7 @@ function finite_difference!{S <: Number, T <: Number}(f::Function,
6382 # Establish a baseline value of f(x).
6483 f_x = f (x)
6584 for i = 1 : n
66- epsilon = sqrt ( eps ( max ( one (T), abs ( x[i]))))
85+ @forwardrule x[i] S epsilon
6786 oldx = x[i]
6887 x[i] = oldx + epsilon
6988 f_xplusdx = f (x)
@@ -72,14 +91,14 @@ function finite_difference!{S <: Number, T <: Number}(f::Function,
7291 end
7392 elseif dtype == :central
7493 for i = 1 : n
75- epsilon = cbrt ( eps ( max ( one (T), abs ( x[i]))))
94+ @centralrule x[i] S epsilon
7695 oldx = x[i]
7796 x[i] = oldx + epsilon
7897 f_xplusdx = f (x)
7998 x[i] = oldx - epsilon
8099 f_xminusdx = f (x)
81100 x[i] = oldx
82- g[i] = (f_xplusdx - f_xminusdx) / (2 * epsilon)
101+ g[i] = (f_xplusdx - f_xminusdx) / (epsilon + epsilon)
83102 end
84103 else
85104 error (" dtype must be :forward or :central" )
@@ -119,7 +138,7 @@ function finite_difference_jacobian!{R <: Number,
119138 # Iterate over each dimension of the gradient separately.
120139 if dtype == :forward
121140 for i = 1 : n
122- epsilon = sqrt ( eps ( max ( one (T), abs ( x[i]))))
141+ @forwardrule x[i] R epsilon
123142 oldx = x[i]
124143 x[i] = oldx + epsilon
125144 f_xplusdx = f (x)
@@ -128,14 +147,14 @@ function finite_difference_jacobian!{R <: Number,
128147 end
129148 elseif dtype == :central
130149 for i = 1 : n
131- epsilon = cbrt ( eps ( max ( one (T), abs ( x[i]))))
150+ @centralrule x[i] R epsilon
132151 oldx = x[i]
133152 x[i] = oldx + epsilon
134153 f_xplusdx = f (x)
135154 x[i] = oldx - epsilon
136155 f_xminusdx = f (x)
137156 x[i] = oldx
138- J[:, i] = (f_xplusdx - f_xminusdx) / (2 * epsilon)
157+ J[:, i] = (f_xplusdx - f_xminusdx) / (epsilon + epsilon)
139158 end
140159 else
141160 error (" dtype must :forward or :central" )
165184# #
166185# #############################################################################
167186
168- function finite_difference_hessian {T <: Number} (f:: Function , x:: T )
169- epsilon = eps (max (one (T), abs (x)))^ (1 / 4 )
187+ function finite_difference_hessian {T <: Number} (f:: Function ,
188+ x:: T )
189+ @hessianrule x T epsilon
170190 (f (x + epsilon) - 2 * f (x) + f (x - epsilon))/ epsilon^ 2
171191end
172192function finite_difference_hessian (f:: Function ,
@@ -189,21 +209,22 @@ function finite_difference_hessian!{S <: Number,
189209 # What is the dimension of x?
190210 n = length (x)
191211
212+ epsilon = NaN
192213 # TODO : Remove all these copies
193214 xpp, xpm, xmp, xmm = copy (x), copy (x), copy (x), copy (x)
194215 fx = f (x)
195216 for i = 1 : n
196217 xi = x[i]
197- epsilon = eps ( max ( one (T), abs ( x[i]))) ^ ( 1 / 4 )
218+ @hessianrule x[i] S epsilon
198219 xpp[i], xmm[i] = xi + epsilon, xi - epsilon
199220 H[i, i] = (f (xpp) - 2 * fx + f (xmm)) / epsilon^ 2
200- epsiloni = cbrt ( eps ( max ( one (T), abs ( x[i]))))
221+ @centralrule x[i] S epsiloni
201222 xp = xi + epsiloni
202223 xm = xi - epsiloni
203224 xpp[i], xpm[i], xmp[i], xmm[i] = xp, xp, xm, xm
204225 for j = i+ 1 : n
205226 xj = x[j]
206- epsilonj = cbrt ( eps ( max ( one (T), abs ( x[j]))))
227+ @centralrule x[j] S epsilonj
207228 xp = xj + epsilonj
208229 xm = xj - epsilonj
209230 xpp[j], xpm[j], xmp[j], xmm[j] = xp, xm, xp, xm
@@ -228,10 +249,10 @@ function finite_difference_hessian{T <: Number}(f::Function,
228249 # Return the Hessian
229250 return H
230251end
231- function finite_difference_hessian {T} (f:: Function ,
232- g:: Function ,
233- x:: Vector{T} ,
234- dtype:: Symbol = :central )
252+ function finite_difference_hessian {T <: Number } (f:: Function ,
253+ g:: Function ,
254+ x:: Vector{T} ,
255+ dtype:: Symbol = :central )
235256 finite_difference_jacobian (g, x, dtype)
236257end
237258
0 commit comments