1616# # In the examples I've tested, this strategy is best when x is small
1717# # and becomes very bad when x is larger
1818# #
19- # # In previous iteration of derivative_numer, epsilon was calculated as
20- # #
21- # # epsilon = eps(max(1.0, abs(x)))^(1/3)
22- # #
23- # # In the examples I've tested, this strategy is bad when x is small
24- # # and becomes better when x is larger
25- # #
26- # # The current approach comes from minFunc
27- # #
28- # # epsilon = 2 * sqrt(1e-12) * (1 + norm(x))
29- # #
30- # # TODO : Perform a systematic comparison across several functions
31- # # and several ranges of inputs
19+ # # The proper setting of epsilon depends on whether we're doing central
20+ # # differencing or forward differencing. See, for example, section 5.7 of
21+ # # Numerical Recipes.
3222# #
3323# #############################################################################
3424
4131function finite_difference {T <: Number} (f:: Function ,
4232 x:: T ,
4333 dtype:: Symbol )
44- epsilon = 2 * sqrt (1e-12 ) * (1 + norm (x))
45-
4634 if dtype == :forward
47- return (f (x + epsilon) - f (x)) / epsilon
35+ epsilon = sqrt (eps (max (one (T), abs (x))))
36+ xplusdx = x + epsilon
37+ return (f (xplusdx) - f (x)) / (xplusdx - x) # use machine-representable numbers
4838 elseif dtype == :central
49- return (f (x + epsilon) - f (x - epsilon)) / (2 * epsilon)
39+ epsilon = cbrt (eps (max (one (T), abs (x))))
40+ xplusdx, xminusdx = x + epsilon, x - epsilon
41+ return (f (xplusdx) - f (xminusdx)) / (xplusdx - xminusdx)
5042 else
5143 error (" dtype must be :forward or :central" )
5244 end
@@ -62,8 +54,6 @@ finite_difference(f::Function, x::Number) = finite_difference(f, x, :central)
6254function finite_difference {T <: Number} (f:: Function ,
6355 x:: Vector{T} ,
6456 dtype:: Symbol )
65- epsilon = 2 * sqrt (1e-12 ) * (1 + norm (x))
66-
6757 # What is the dimension of x?
6858 n = length (x)
6959
@@ -78,15 +68,17 @@ function finite_difference{T <: Number}(f::Function,
7868 f_x = f (x)
7969 xplusdx = copy (x)
8070 for i = 1 : n
71+ epsilon = sqrt (eps (max (one (T), abs (x[i]))))
8172 xplusdx[i] = x[i] + epsilon
82- differential[i] = (f (xplusdx) - f_x) / epsilon
73+ differential[i] = (f (xplusdx) - f_x) / (xplusdx[i] - x[i])
8374 xplusdx[i] = x[i]
8475 end
8576 elseif dtype == :central
8677 xplusdx, xminusdx = copy (x), copy (x)
8778 for i = 1 : n
79+ epsilon = cbrt (eps (max (one (T), abs (x[i]))))
8880 xplusdx[i], xminusdx[i] = x[i] + epsilon, x[i] - epsilon
89- differential[i] = (f (xplusdx) - f (xminusdx)) / (2 * epsilon )
81+ differential[i] = (f (xplusdx) - f (xminusdx)) / (xplusdx[i] - xminusdx[i] )
9082 xplusdx[i], xminusdx[i] = x[i], x[i]
9183 end
9284 else
10799# #############################################################################
108100
109101function finite_difference_jacobian {T <: Number} (f:: Function , x:: Vector{T} , dtype:: Symbol )
110- epsilon = 2 * sqrt (1e-12 ) * (1 + norm (x))
111-
112102 # What is the dimension of x?
113103 n = length (x)
114104
@@ -122,16 +112,18 @@ function finite_difference_jacobian{T <: Number}(f::Function, x::Vector{T}, dtyp
122112 if dtype == :forward
123113 xplusdx = copy (x)
124114 for i = 1 : n
115+ epsilon = sqrt (eps (max (one (T), abs (x[i]))))
125116 xplusdx[i] = x[i] + epsilon
126- J[:, i] = (f (xplusdx) - f_x) / epsilon
117+ J[:, i] = (f (xplusdx) - f_x) / (xplusdx[i] - x[i])
127118 xplusdx[i] = x[i]
128119 end
129120 return J
130121 elseif dtype == :central
131122 xplusdx, xminusdx = copy (x), copy (x)
132123 for i = 1 : n
124+ epsilon = cbrt (eps (max (one (T), abs (x[i]))))
133125 xplusdx[i], xminusdx[i] = x[i] + epsilon, x[i] - epsilon
134- J[:, i] = (f (xplusdx) - f (xminusdx)) / (2 * epsilon )
126+ J[:, i] = (f (xplusdx) - f (xminusdx)) / (xplusdx[i] - xminusdx[i] )
135127 xplusdx[i], xminusdx[i] = x[i], x[i]
136128 end
137129 return J
@@ -142,72 +134,58 @@ end
142134
143135# #############################################################################
144136# #
145- # # Second derivative of f: R^n -> R
137+ # # Second derivative of f: R -> R
146138# #
147139# #############################################################################
148140
149- function finite_difference_hessian (f:: Function , g:: Function , x:: Number , dtype:: Symbol )
150- epsilon = 2 * sqrt (1e-12 ) * (1 + norm (x))
151-
152- if dtype == :forward
153- return (g (x + epsilon) - g (x)) / epsilon
154- elseif dtype == :central
155- return (g (x + epsilon) - g (x - epsilon)) / (2 * epsilon)
156- else
157- error (" dtype must :forward or :central" )
158- end
159- end
160- function finite_difference_hessian (f:: Function , x:: Number , dtype:: Symbol )
161- finite_difference_hessian (f, derivative (f), x, dtype)
162- end
163- function finite_difference_hessian (f:: Function , x:: Number )
164- finite_difference_hessian (f, derivative (f), x, :central )
141+ function finite_difference_hessian {T <: Number} (f:: Function , x:: T )
142+ epsilon = eps (max (one (T), abs (x)))^ (1 / 4 )
143+ (f (x + epsilon) - 2 * f (x) + f (x - epsilon))/ epsilon^ 2
165144end
145+ finite_difference_hessian (f:: Function , g:: Function , x:: Number , dtype:: Symbol ) = finite_difference (g, x, dtype)
146+ finite_difference_hessian (f:: Function , g:: Function , x:: Number ) = finite_difference (g, x, :central )
147+
166148
167149# #############################################################################
168150# #
169151# # Hessian of f: R^n -> R
170152# #
171153# #############################################################################
172154
173- function finite_difference_hessian {T <: Number} (f:: Function , g:: Function , x:: Vector{T} , dtype:: Symbol )
174- epsilon = 2 * sqrt (1e-12 ) * (1 + norm (x))
175-
155+ function finite_difference_hessian {T <: Number} (f:: Function , x:: Vector{T} )
176156 # What is the dimension of x?
177157 n = length (x)
178158
179159 # Initialize an empty Hessian
180160 H = Array (Float64, n, n)
181161
182- if dtype == :forward
183- g_x = g (x)
184- xplusdx = copy (x)
185- for i in 1 : n
186- xplusdx[i] = x[i] + epsilon
187- H[:, i] = (g (xplusdx) - g_x) / epsilon
188- xplusdx[i] = x[i]
162+ xpp, xpm, xmp, xmm = copy (x), copy (x), copy (x), copy (x)
163+ fx = f (x)
164+ for i = 1 : n
165+ xi = x[i]
166+ epsilon = eps (max (one (T), abs (x[i])))^ (1 / 4 )
167+ xpp[i], xmm[i] = xi + epsilon, xi - epsilon
168+ H[i, i] = (f (xpp) - 2 * fx + f (xmm)) / epsilon^ 2
169+ epsiloni = cbrt (eps (max (one (T), abs (x[i]))))
170+ xp = xi + epsiloni
171+ xm = xi - epsiloni
172+ xpp[i], xpm[i], xmp[i], xmm[i] = xp, xp, xm, xm
173+ for j = i+ 1 : n
174+ xj = x[j]
175+ epsilonj = cbrt (eps (max (one (T), abs (x[j]))))
176+ xp = xj + epsilonj
177+ xm = xj - epsilonj
178+ xpp[j], xpm[j], xmp[j], xmm[j] = xp, xm, xp, xm
179+ H[i, j] = (f (xpp) - f (xpm) - f (xmp) + f (xmm))/ (4 * epsiloni* epsilonj)
180+ xpp[j], xpm[j], xmp[j], xmm[j] = xj, xj, xj, xj
189181 end
190- symmetrize! (H)
191- return H
192- elseif dtype == :central
193- xplusdx, xminusdx = copy (x), copy (x)
194- for i = 1 : n
195- xplusdx[i], xminusdx[i] = x[i] + epsilon, x[i] - epsilon
196- H[:, i] = (g (xplusdx) - g (xminusdx)) / (2 * epsilon)
197- xplusdx[i], xminusdx[i] = x[i], x[i]
198- end
199- symmetrize! (H)
200- return H
201- else
202- error (" dtype must :forward or :central" )
182+ xpp[i], xpm[i], xmp[i], xmm[i] = xi, xi, xi, xi
203183 end
184+ symmetrize! (H)
185+ H
204186end
205- function finite_difference_hessian {T <: Number} (f:: Function , x:: Vector{T} , dtype:: Symbol )
206- finite_difference_hessian (f, gradient (f), x, dtype)
207- end
208- function finite_difference_hessian {T <: Number} (f:: Function , x:: Vector{T} )
209- finite_difference_hessian (f, gradient (f), x, :central )
210- end
187+ finite_difference_hessian {T} (f:: Function , g:: Function , x:: Vector{T} , dtype:: Symbol ) = finite_difference_jacobian (g, x, dtype)
188+ finite_difference_hessian {T} (f:: Function , g:: Function , x:: Vector{T} ) = finite_difference_jacobian (g, x, :central )
211189
212190# #############################################################################
213191# #
0 commit comments