Skip to content

Commit 9dfc02a

Browse files
Minor code cleanup
1 parent 507f191 commit 9dfc02a

File tree

1 file changed

+86
-42
lines changed

1 file changed

+86
-42
lines changed

src/finite_difference.jl

Lines changed: 86 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -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
4547
end
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

5458
function 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
9295
end
9396
function 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
101107
end
102108
function 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
145169
end
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
156180
end
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
200244
end
201245
finite_difference_hessian{T}(f::Function, g::Function, x::Vector{T}, dtype::Symbol) = finite_difference_jacobian(g, x, dtype)
202246
finite_difference_hessian{T}(f::Function, g::Function, x::Vector{T}) = finite_difference_jacobian(g, x, :central)

0 commit comments

Comments
 (0)