Skip to content

Commit 18425a7

Browse files
committed
major refactor in choice of epsilon for all finite_difference methods
1 parent d338f4a commit 18425a7

File tree

1 file changed

+49
-28
lines changed

1 file changed

+49
-28
lines changed

src/finite_difference.jl

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
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.
@@ -21,21 +14,47 @@
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+
2445
function 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")
@@ -165,8 +184,9 @@ end
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
171191
end
172192
function 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
230251
end
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)
236257
end
237258

0 commit comments

Comments
 (0)