@@ -23,15 +23,18 @@ function GradientCache(
23
23
end
24
24
25
25
if typeof (x)<: AbstractArray # the vector->scalar case
26
- # need cache arrays for epsilon (c1) and x1 (c2)
26
+ # need cache arrays for x1 (c1) and epsilon (c2, only if non-StridedArray )
27
27
if fdtype!= Val{:complex } # complex-mode FD only needs one cache, for x+eps*im
28
- if typeof (c1)== Void || eltype (c1)!= real ( eltype (x) )
29
- _c1 = zeros ( real ( eltype (x)), size (x) )
28
+ if typeof (c1)!= typeof (x) || size (c1)!= size (x )
29
+ _c1 = similar (x )
30
30
else
31
31
_c1 = c1
32
32
end
33
- if typeof (c2)!= typeof (x) || size (c2)!= size (x)
34
- _c2 = similar (x)
33
+ if typeof (c2)!= Void && x<: StridedVector
34
+ warn (" c2 cache isn't necessary when x<:StridedVector." )
35
+ end
36
+ if typeof (c2)== Void || eltype (c2)!= real (eltype (x)) && ! (x<: StridedVector )
37
+ _c2 = zeros (real (eltype (x)), size (x))
35
38
else
36
39
_c2 = c2
37
40
end
@@ -128,46 +131,100 @@ function finite_difference_gradient!(df::AbstractArray{<:Number}, f, x::Abstract
128
131
cache:: GradientCache{T1,T2,T3,fdtype,returntype,inplace} ) where {T1,T2,T3,fdtype,returntype,inplace}
129
132
130
133
# NOTE: in this case epsilon is a vector, we need two arrays for epsilon and x1
131
- # c1 denotes epsilon , c2 is x1, pre-set to the values of x by the cache constructor
134
+ # c1 denotes x1 , c2 is epsilon
132
135
fx, c1, c2 = cache. fx, cache. c1, cache. c2
133
136
if fdtype != Val{:complex }
134
137
epsilon_factor = compute_epsilon_factor (fdtype, eltype (x))
135
- @. c1 = compute_epsilon (fdtype, x, epsilon_factor)
136
- copy! (c2 ,x)
138
+ @. c2 = compute_epsilon (fdtype, x, epsilon_factor)
139
+ copy! (c1 ,x)
137
140
end
138
141
if fdtype == Val{:forward }
139
142
@inbounds for i ∈ eachindex (x)
140
- c2[i] += c1[i]
143
+ epsilon = c2[i]
144
+ c1_old = c1[i]
145
+ c1[i] += epsilon
141
146
if typeof (fx) != Void
142
- df[i] = (f (c2 ) - fx) / c1[i]
147
+ df[i] = (f (c1 ) - fx) / epsilon
143
148
else
144
- df[i] = (f (c2 ) - f (x)) / c1[i]
149
+ df[i] = (f (c1 ) - f (x)) / epsilon
145
150
end
146
- c2 [i] -= c1[i]
151
+ c1 [i] = c1_old
147
152
end
148
153
elseif fdtype == Val{:central }
149
154
@inbounds for i ∈ eachindex (x)
150
- c2[i] += c1[i]
151
- x[i] -= c1[i]
152
- df[i] = (f (c2) - f (x)) / (2 * c1[i])
153
- c2[i] -= c1[i]
154
- x[i] += c1[i]
155
+ epsilon = c2[i]
156
+ c1_old = c1[i]
157
+ c1[i] += epsilon
158
+ x_old = x[i]
159
+ x[i] -= epsilon
160
+ df[i] = (f (c1) - f (x)) / (2 * epsilon)
161
+ c1[i] = c1_old
162
+ x[i] = x_old
155
163
end
156
164
elseif fdtype == Val{:complex } && returntype <: Real
157
165
copy! (c1,x)
158
166
epsilon_complex = eps (real (eltype (x)))
159
167
# we use c1 here to avoid typing issues with x
160
168
@inbounds for i ∈ eachindex (x)
169
+ c1_old = c1[i]
161
170
c1[i] += im* epsilon_complex
162
171
df[i] = imag (f (c1)) / epsilon_complex
163
- c1[i] -= im * epsilon_complex
172
+ c1[i] = c1_old
164
173
end
165
174
else
166
175
fdtype_error (returntype)
167
176
end
168
177
df
169
178
end
179
+ #=
180
+ function finite_difference_gradient!(df::StridedVector{<:Number}, f, x::StridedVector{<:Number},
181
+ cache::GradientCache{T1,T2,T3,fdtype,returntype,inplace}) where {T1,T2,T3,fdtype,returntype,inplace}
170
182
183
+ # c1 is x1, c2 shouldn't exist in this case
184
+ fx, c1, c2 = cache.fx, cache.c1, cache.c2
185
+ if fdtype != Val{:complex}
186
+ epsilon_factor = compute_epsilon_factor(fdtype, eltype(x))
187
+ copy!(c1,x)
188
+ end
189
+ if fdtype == Val{:forward}
190
+ @inbounds for i ∈ eachindex(x)
191
+ epsilon = compute_epsilon(fdtype, x[i], epsilon_factor)
192
+ c2_old = c2[i]
193
+ c2[i] += epsilon
194
+ if typeof(fx) != Void
195
+ df[i] = (f(c2) - fx) / epsilon
196
+ else
197
+ df[i] = (f(c2) - f(x)) / epsilon
198
+ end
199
+ c2[i] = c2_old
200
+ end
201
+ elseif fdtype == Val{:central}
202
+ @inbounds for i ∈ eachindex(x)
203
+ epsilon = compute_epsilon(fdtype, x[i], epsilon_factor)
204
+ c2_old = c2[i]
205
+ c2[i] += epsilon
206
+ x_old = x[i]
207
+ x[i] -= epsilon
208
+ df[i] = (f(c2) - f(x)) / (2*epsilon)
209
+ c2[i] = c2_old
210
+ x[i] = x_old
211
+ end
212
+ elseif fdtype == Val{:complex} && returntype <: Real
213
+ copy!(c1,x)
214
+ epsilon_complex = eps(real(eltype(x)))
215
+ # we use c1 here to avoid typing issues with x
216
+ @inbounds for i ∈ eachindex(x)
217
+ c1_old = c1[i]
218
+ c1[i] += im*epsilon_complex
219
+ df[i] = imag(f(c1)) / epsilon_complex
220
+ c1[i] = c1_old
221
+ end
222
+ else
223
+ fdtype_error(returntype)
224
+ end
225
+ df
226
+ end
227
+ =#
171
228
# vector of derivatives of a scalar->vector map
172
229
# this is effectively a vector of partial derivatives, but we still call it a gradient
173
230
function finite_difference_gradient! (df:: AbstractArray{<:Number} , f, x:: Number ,
0 commit comments