@@ -34,16 +34,20 @@ function finite_difference{T <: Number}(f::Function,
3434 if dtype == :forward
3535 epsilon = sqrt (eps (max (one (T), abs (x))))
3636 xplusdx = x + epsilon
37- return (f (xplusdx) - f (x)) / (xplusdx - x) # use machine-representable numbers
37+ # use machine-representable numbers
38+ return (f (xplusdx) - f (x)) / epsilon
3839 elseif dtype == :central
3940 epsilon = cbrt (eps (max (one (T), abs (x))))
4041 xplusdx, xminusdx = x + epsilon, x - epsilon
41- return (f (xplusdx) - f (xminusdx)) / (xplusdx - xminusdx)
42+ # Is it better to do 2 * epsilon or xplusdx - xminusdx?
43+ return (f (xplusdx) - f (xminusdx)) / (2 * epsilon)
4244 else
4345 error (" dtype must be :forward or :central" )
4446 end
4547end
46- finite_difference (f:: Function , x:: Number ) = finite_difference (f, x, :central )
48+ function finite_difference (f:: Function , x:: Number )
49+ finite_difference (f, x, :central )
50+ end
4751
4852# #############################################################################
4953# #
@@ -53,7 +57,7 @@ finite_difference(f::Function, x::Number) = finite_difference(f, x, :central)
5357
5458function finite_difference! {S <: Number, T <: Number} (f:: Function ,
5559 x:: Vector{S} ,
56- differential :: Vector{T} ,
60+ g :: Vector{T} ,
5761 dtype:: Symbol )
5862 # What is the dimension of x?
5963 n = length (x)
@@ -70,7 +74,7 @@ function finite_difference!{S <: Number, T <: Number}(f::Function,
7074 x[i] = oldx + epsilon
7175 f_xplusdx = f (x)
7276 x[i] = oldx
73- differential [i] = (f_xplusdx - f_x) / epsilon
77+ g [i] = (f_xplusdx - f_x) / epsilon
7478 end
7579 elseif dtype == :central
7680 for i = 1 : n
@@ -81,23 +85,25 @@ function finite_difference!{S <: Number, T <: Number}(f::Function,
8185 x[i] = oldx - epsilon
8286 f_xminusdx = f (x)
8387 x[i] = oldx
84- differential [i] = (f_xplusdx - f_xminusdx) / (2 * epsilon)
88+ g [i] = (f_xplusdx - f_xminusdx) / (2 * epsilon)
8589 end
8690 else
8791 error (" dtype must be :forward or :central" )
8892 end
8993
90- # Return the estimated gradient.
91- return differential
94+ return
9295end
9396function finite_difference {T <: Number} (f:: Function ,
9497 x:: Vector{T} ,
9598 dtype:: Symbol )
96- # What is the dimension of x?
97- n = length (x)
98- differential = Array (Float64, n)
99- finite_difference! (f, x, differential, dtype)
100- return differential
99+ # Allocate memory for gradient
100+ g = Array (Float64, length (x))
101+
102+ # Mutate allocated gradient
103+ finite_difference! (f, x, g, dtype)
104+
105+ # Return mutated gradient
106+ return g
101107end
102108function finite_difference {T <: Number} (f:: Function , x:: Vector{T} )
103109 finite_difference (f, x, :central )
@@ -109,39 +115,57 @@ end
109115# #
110116# #############################################################################
111117
112- # TODO : Add mutating version
113- function finite_difference_jacobian {T <: Number} (f:: Function , x:: Vector{T} , dtype:: Symbol )
118+ function finite_difference_jacobian!{R <: Number ,
119+ S <: Number ,
120+ T <: Number }(f:: Function ,
121+ x:: Vector{R} ,
122+ f_x:: Vector{S} ,
123+ J:: Array{T} ,
124+ dtype:: Symbol )
114125 # What is the dimension of x?
115- n = length (x)
116-
117- # Establish a baseline for f_x
118- f_x = f (x)
119-
120- # Initialize the Jacobian matrix
121- J = zeros (length (f_x), n)
126+ m, n = size (J)
122127
123128 # Iterate over each dimension of the gradient separately.
124129 if dtype == :forward
125- xplusdx = copy (x)
126130 for i = 1 : n
127131 epsilon = sqrt (eps (max (one (T), abs (x[i]))))
128- xplusdx[i] = x[i] + epsilon
129- J[:, i] = (f (xplusdx) - f_x) / (xplusdx[i] - x[i])
130- xplusdx[i] = x[i]
132+ oldx = x[i]
133+ x[i] = oldx + epsilon
134+ f_xplusdx = f (x)
135+ x[i] = oldx
136+ J[:, i] = (f_xplusdx - f_x) / epsilon
131137 end
132- return J
133138 elseif dtype == :central
134- xplusdx, xminusdx = copy (x), copy (x)
135139 for i = 1 : n
136140 epsilon = cbrt (eps (max (one (T), abs (x[i]))))
137- xplusdx[i], xminusdx[i] = x[i] + epsilon, x[i] - epsilon
138- J[:, i] = (f (xplusdx) - f (xminusdx)) / (xplusdx[i] - xminusdx[i])
139- xplusdx[i], xminusdx[i] = x[i], x[i]
141+ oldx = x[i]
142+ x[i] = oldx + epsilon
143+ f_xplusdx = f (x)
144+ x[i] = oldx - epsilon
145+ f_xminusdx = f (x)
146+ x[i] = oldx
147+ J[:, i] = (f_xplusdx - f_xminusdx) / (2 * epsilon)
140148 end
141- return J
142149 else
143150 error (" dtype must :forward or :central" )
144151 end
152+
153+ return
154+ end
155+ function finite_difference_jacobian {T <: Number} (f:: Function ,
156+ x:: Vector{T} ,
157+ dtype:: Symbol )
158+ # Establish a baseline for f_x
159+ f_x = f (x)
160+
161+ # Allocate space for the Jacobian matrix
162+ J = zeros (length (f_x), length (x))
163+
164+ # Compute Jacobian inside allocated matrix
165+ finite_difference_jacobian! (f, x, f_x, J, dtype)
166+
167+ # Return Jacobian
168+ return J
145169end
146170
147171# #############################################################################
@@ -154,25 +178,32 @@ function finite_difference_hessian{T <: Number}(f::Function, x::T)
154178 epsilon = eps (max (one (T), abs (x)))^ (1 / 4 )
155179 (f (x + epsilon) - 2 * f (x) + f (x - epsilon))/ epsilon^ 2
156180end
157- finite_difference_hessian (f:: Function , g:: Function , x:: Number , dtype:: Symbol ) = finite_difference (g, x, dtype)
158- finite_difference_hessian (f:: Function , g:: Function , x:: Number ) = finite_difference (g, x, :central )
159-
181+ function finite_difference_hessian (f:: Function ,
182+ g:: Function ,
183+ x:: Number ,
184+ dtype:: Symbol )
185+ finite_difference (g, x, dtype)
186+ end
187+ function finite_difference_hessian (f:: Function ,
188+ g:: Function ,
189+ x:: Number )
190+ finite_difference (g, x, :central )
191+ end
160192
161193# #############################################################################
162194# #
163195# # Hessian of f: R^n -> R
164196# #
165197# #############################################################################
166198
167- # TODO : Add mutating version
168-
169- function finite_difference_hessian {T <: Number} (f:: Function , x:: Vector{T} )
199+ function finite_difference_hessian!{S <: Number ,
200+ T <: Number }(f:: Function ,
201+ x:: Vector{S} ,
202+ H:: Array{T} )
170203 # What is the dimension of x?
171204 n = length (x)
172205
173- # Initialize an empty Hessian
174- H = Array (Float64, n, n)
175-
206+ # TODO : Remove all these copies
176207 xpp, xpm, xmp, xmm = copy (x), copy (x), copy (x), copy (x)
177208 fx = f (x)
178209 for i = 1 : n
@@ -196,7 +227,20 @@ function finite_difference_hessian{T <: Number}(f::Function, x::Vector{T})
196227 xpp[i], xpm[i], xmp[i], xmm[i] = xi, xi, xi, xi
197228 end
198229 symmetrize! (H)
199- H
230+ end
231+ function finite_difference_hessian {T <: Number} (f:: Function ,
232+ x:: Vector{T} )
233+ # What is the dimension of x?
234+ n = length (x)
235+
236+ # Allocate an empty Hessian
237+ H = Array (Float64, n, n)
238+
239+ # Mutate the allocated Hessian
240+ finite_difference_hessian! (f, x, H)
241+
242+ # Return the Hessian
243+ return H
200244end
201245finite_difference_hessian {T} (f:: Function , g:: Function , x:: Vector{T} , dtype:: Symbol ) = finite_difference_jacobian (g, x, dtype)
202246finite_difference_hessian {T} (f:: Function , g:: Function , x:: Vector{T} ) = finite_difference_jacobian (g, x, :central )
0 commit comments