@@ -98,6 +98,18 @@ Base.eltype(cfg::AbstractConfig) = eltype(typeof(cfg))
98
98
99
99
@inline (chunksize (:: AbstractConfig{N} ):: Int ) where {N} = N
100
100
101
+ function maketag (kind:: Union{Symbol,Nothing} , f, X)
102
+ if kind === :default
103
+ return Tag (f, X)
104
+ elseif kind === :small
105
+ return SmallTag (f, X)
106
+ elseif kind === nothing
107
+ return nothing
108
+ else
109
+ throw (ArgumentError (" tag may be :default, :small, or nothing" ))
110
+ end
111
+ end
112
+
101
113
# ###################
102
114
# DerivativeConfig #
103
115
# ###################
@@ -107,7 +119,7 @@ struct DerivativeConfig{T,D} <: AbstractConfig{1}
107
119
end
108
120
109
121
"""
110
- ForwardDiff.DerivativeConfig(f!, y::AbstractArray, x::Real)
122
+ ForwardDiff.DerivativeConfig(f!, y::AbstractArray, x::Real; tag::Union{Symbol,Nothing} = :default )
111
123
112
124
Return a `DerivativeConfig` instance based on the type of `f!`, and the types/shapes of the
113
125
output vector `y` and the input value `x`.
@@ -120,12 +132,24 @@ If `f!` is `nothing` instead of the actual target function, then the returned in
120
132
be used with any target function. However, this will reduce ForwardDiff's ability to catch
121
133
and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
122
134
135
+ If `tag` is `:small`, a small hash-based tag is provided. This tracks perturbation confusion
136
+ with similar accuracy, but is much smaller when printing types.
137
+
123
138
This constructor does not store/modify `y` or `x`.
124
139
"""
140
+ @inline function DerivativeConfig (f:: F ,
141
+ y:: AbstractArray{Y} ,
142
+ x:: X ;
143
+ tag:: Union{Symbol,Nothing} = :default ) where {F,X<: Real ,Y<: Real }
144
+ # @inline ensures that, e.g., DerivativeConfig(...; tag = :small) will be well-inferred
145
+ T = @inline maketag (tag, f, X)
146
+ return @noinline DerivativeConfig (f,y,x,T)
147
+ end
148
+
125
149
function DerivativeConfig (f:: F ,
126
150
y:: AbstractArray{Y} ,
127
151
x:: X ,
128
- tag:: T = Tag (f, X) ) where {F,X<: Real ,Y<: Real ,T}
152
+ tag:: T ) where {F,X<: Real ,Y<: Real ,T}
129
153
duals = similar (y, Dual{T,Y,1 })
130
154
return DerivativeConfig {T,typeof(duals)} (duals)
131
155
end
@@ -143,24 +167,36 @@ struct GradientConfig{T,V,N,D} <: AbstractConfig{N}
143
167
end
144
168
145
169
"""
146
- ForwardDiff.GradientConfig(f, x::AbstractArray, chunk::Chunk = Chunk(x))
170
+ ForwardDiff.GradientConfig(f, x::AbstractArray, chunk::Chunk = Chunk(x); tag::Union{Symbol,Nothing} = :default )
147
171
148
172
Return a `GradientConfig` instance based on the type of `f` and type/shape of the input
149
173
vector `x`.
150
174
151
175
The returned `GradientConfig` instance contains all the work buffers required by
152
176
`ForwardDiff.gradient` and `ForwardDiff.gradient!`.
153
177
154
- If `f` is `nothing` instead of the actual target function, then the returned instance can
155
- be used with any target function. However, this will reduce ForwardDiff's ability to catch
156
- and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
178
+ If `f` or `tag` is `nothing`, then the returned instance can be used with any target function.
179
+ However, this will reduce ForwardDiff's ability to catch and prevent perturbation confusion
180
+ (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
181
+
182
+ If `tag` is `:small`, a small hash-based tag is provided. This tracks perturbation confusion
183
+ with similar accuracy, but is much smaller when printing types.
157
184
158
185
This constructor does not store/modify `x`.
159
186
"""
187
+ @inline function GradientConfig (f:: F ,
188
+ x:: AbstractArray{V} ,
189
+ c:: Chunk{N} = Chunk (x);
190
+ tag:: Union{Symbol,Nothing} = :default ) where {F,V,N}
191
+ # @inline ensures that, e.g., GradientConfig(...; tag = :small) will be well-inferred
192
+ T = @inline maketag (tag, f, V)
193
+ return @noinline GradientConfig (f,x,c,T)
194
+ end
195
+
160
196
function GradientConfig (f:: F ,
161
197
x:: AbstractArray{V} ,
162
- :: Chunk{N} = Chunk (x) ,
163
- :: T = Tag (f, V) ) where {F,V,N,T}
198
+ :: Chunk{N} ,
199
+ :: T ) where {F,V,N,T}
164
200
seeds = construct_seeds (Partials{N,V})
165
201
duals = similar (x, Dual{T,V,N})
166
202
return GradientConfig {T,V,N,typeof(duals)} (seeds, duals)
@@ -179,7 +215,7 @@ struct JacobianConfig{T,V,N,D} <: AbstractConfig{N}
179
215
end
180
216
181
217
"""
182
- ForwardDiff.JacobianConfig(f, x::AbstractArray, chunk::Chunk = Chunk(x))
218
+ ForwardDiff.JacobianConfig(f, x::AbstractArray, chunk::Chunk = Chunk(x); tag::Union{Symbol,Nothing} = :default )
183
219
184
220
Return a `JacobianConfig` instance based on the type of `f` and type/shape of the input
185
221
vector `x`.
@@ -188,23 +224,35 @@ The returned `JacobianConfig` instance contains all the work buffers required by
188
224
`ForwardDiff.jacobian` and `ForwardDiff.jacobian!` when the target function takes the form
189
225
`f(x)`.
190
226
191
- If `f` is `nothing` instead of the actual target function, then the returned instance can
192
- be used with any target function. However, this will reduce ForwardDiff's ability to catch
193
- and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
227
+ If `f` or `tag` is `nothing`, then the returned instance can be used with any target function.
228
+ However, this will reduce ForwardDiff's ability to catch and prevent perturbation confusion
229
+ (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
230
+
231
+ If `tag` is `:small`, a small hash-based tag is provided. This tracks perturbation confusion
232
+ with similar accuracy, but is much smaller when printing types.
194
233
195
234
This constructor does not store/modify `x`.
196
235
"""
236
+ @inline function JacobianConfig (f:: F ,
237
+ x:: AbstractArray{V} ,
238
+ c:: Chunk{N} = Chunk (x);
239
+ tag:: Union{Symbol,Nothing} = :default ) where {F,V,N}
240
+ # @inline ensures that, e.g., JacobianConfig(...; tag = :small) will be well-inferred
241
+ T = @inline maketag (tag, f, V)
242
+ return @noinline JacobianConfig (f,x,c,T)
243
+ end
244
+
197
245
function JacobianConfig (f:: F ,
198
246
x:: AbstractArray{V} ,
199
- :: Chunk{N} = Chunk (x) ,
200
- :: T = Tag (f, V) ) where {F,V,N,T}
247
+ :: Chunk{N} ,
248
+ :: T ) where {F,V,N,T}
201
249
seeds = construct_seeds (Partials{N,V})
202
250
duals = similar (x, Dual{T,V,N})
203
251
return JacobianConfig {T,V,N,typeof(duals)} (seeds, duals)
204
252
end
205
253
206
254
"""
207
- ForwardDiff.JacobianConfig(f!, y::AbstractArray, x::AbstractArray, chunk::Chunk = Chunk(x))
255
+ ForwardDiff.JacobianConfig(f!, y::AbstractArray, x::AbstractArray, chunk::Chunk = Chunk(x); tag::Union{Symbol,Nothing} = :default )
208
256
209
257
Return a `JacobianConfig` instance based on the type of `f!`, and the types/shapes of the
210
258
output vector `y` and the input vector `x`.
@@ -213,17 +261,30 @@ The returned `JacobianConfig` instance contains all the work buffers required by
213
261
`ForwardDiff.jacobian` and `ForwardDiff.jacobian!` when the target function takes the form
214
262
`f!(y, x)`.
215
263
216
- If `f!` is `nothing` instead of the actual target function, then the returned instance can
217
- be used with any target function. However, this will reduce ForwardDiff's ability to catch
218
- and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
264
+ If `f!` or `tag` is `nothing`, then the returned instance can be used with any target function.
265
+ However, this will reduce ForwardDiff's ability to catch and prevent perturbation confusion
266
+ (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
267
+
268
+ If `tag` is `:small`, a small hash-based tag is provided. This tracks perturbation confusion
269
+ with similar accuracy, but is much smaller when printing types.
219
270
220
271
This constructor does not store/modify `y` or `x`.
221
272
"""
273
+ @inline function JacobianConfig (f:: F ,
274
+ y:: AbstractArray{Y} ,
275
+ x:: AbstractArray{X} ,
276
+ c:: Chunk{N} = Chunk (x);
277
+ tag:: Union{Symbol,Nothing} = :default ) where {F,Y,X,N}
278
+ # @inline ensures that, e.g., JacobianConfig(...; tag = :small) will be well-inferred
279
+ T = @inline maketag (tag, f, X)
280
+ return @noinline JacobianConfig (f,y,x,c,T)
281
+ end
282
+
222
283
function JacobianConfig (f:: F ,
223
284
y:: AbstractArray{Y} ,
224
285
x:: AbstractArray{X} ,
225
- :: Chunk{N} = Chunk (x) ,
226
- :: T = Tag (f, X) ) where {F,Y,X,N,T}
286
+ :: Chunk{N} ,
287
+ :: T ) where {F,Y,X,N,T}
227
288
seeds = construct_seeds (Partials{N,X})
228
289
yduals = similar (y, Dual{T,Y,N})
229
290
xduals = similar (x, Dual{T,X,N})
@@ -244,7 +305,7 @@ struct HessianConfig{T,V,N,DG,DJ} <: AbstractConfig{N}
244
305
end
245
306
246
307
"""
247
- ForwardDiff.HessianConfig(f, x::AbstractArray, chunk::Chunk = Chunk(x))
308
+ ForwardDiff.HessianConfig(f, x::AbstractArray, chunk::Chunk = Chunk(x); tag::Union{Symbol,Nothing} = :default )
248
309
249
310
Return a `HessianConfig` instance based on the type of `f` and type/shape of the input
250
311
vector `x`.
@@ -255,41 +316,66 @@ configured for the case where the `result` argument is an `AbstractArray`. If
255
316
it is a `DiffResult`, the `HessianConfig` should instead be constructed via
256
317
`ForwardDiff.HessianConfig(f, result, x, chunk)`.
257
318
258
- If `f` is `nothing` instead of the actual target function, then the returned instance can
259
- be used with any target function. However, this will reduce ForwardDiff's ability to catch
260
- and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
319
+ If `f` or `tag` is `nothing`, then the returned instance can be used with any target function.
320
+ However, this will reduce ForwardDiff's ability to catch and prevent perturbation confusion
321
+ (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
322
+
323
+ If `tag` is `:small`, a small hash-based tag is provided. This tracks perturbation confusion
324
+ with similar accuracy, but is much smaller when printing types.
261
325
262
326
This constructor does not store/modify `x`.
263
327
"""
328
+ @inline function HessianConfig (f:: F ,
329
+ x:: AbstractArray{V} ,
330
+ chunk:: Chunk = Chunk (x);
331
+ tag:: Union{Symbol,Nothing} = :default ) where {F,V}
332
+ # @inline ensures that, e.g., HessianConfig(...; tag = :small) will be well-inferred
333
+ T = @inline maketag (tag, f, V)
334
+ return @noinline HessianConfig (f, x, chunk, T)
335
+ end
336
+
264
337
function HessianConfig (f:: F ,
265
338
x:: AbstractArray{V} ,
266
- chunk:: Chunk = Chunk (x) ,
267
- tag = Tag (f, V) ) where {F,V}
339
+ chunk:: Chunk ,
340
+ tag) where {F,V}
268
341
jacobian_config = JacobianConfig (f, x, chunk, tag)
269
342
gradient_config = GradientConfig (f, jacobian_config. duals, chunk, tag)
270
343
return HessianConfig (jacobian_config, gradient_config)
271
344
end
272
345
273
346
"""
274
- ForwardDiff.HessianConfig(f, result::DiffResult, x::AbstractArray, chunk::Chunk = Chunk(x))
347
+ ForwardDiff.HessianConfig(f, result::DiffResult, x::AbstractArray, chunk::Chunk = Chunk(x); tag::Union{Symbol,Nothing} = :default )
275
348
276
349
Return a `HessianConfig` instance based on the type of `f`, types/storage in `result`, and
277
350
type/shape of the input vector `x`.
278
351
279
352
The returned `HessianConfig` instance contains all the work buffers required by
280
353
`ForwardDiff.hessian!` for the case where the `result` argument is an `DiffResult`.
281
354
282
- If `f` is `nothing` instead of the actual target function, then the returned instance can
283
- be used with any target function. However, this will reduce ForwardDiff's ability to catch
284
- and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
355
+ If `f` or `tag` is `nothing`, then the returned instance can be used with any target function.
356
+ However, this will reduce ForwardDiff's ability to catch and prevent perturbation confusion
357
+ (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
358
+
359
+ If `tag` is `:small`, a small hash-based tag is provided. This tracks perturbation confusion
360
+ with similar accuracy, but is much smaller when printing types.
285
361
286
362
This constructor does not store/modify `x`.
287
363
"""
364
+ @inline function HessianConfig (f:: F ,
365
+ result:: DiffResult ,
366
+ x:: AbstractArray{V} ,
367
+ chunk:: Chunk = Chunk (x);
368
+ tag:: Union{Symbol,Nothing} = :default ) where {F,V}
369
+ # @inline ensures that, e.g., HessianConfig(...; tag = :small) will be well-inferred
370
+ T = @inline maketag (tag, f, V)
371
+ return @noinline HessianConfig (f, result, x, chunk, T)
372
+ end
373
+
288
374
function HessianConfig (f:: F ,
289
375
result:: DiffResult ,
290
376
x:: AbstractArray{V} ,
291
- chunk:: Chunk = Chunk (x) ,
292
- tag = Tag (f, V) ) where {F,V}
377
+ chunk:: Chunk ,
378
+ tag) where {F,V}
293
379
jacobian_config = JacobianConfig ((f,gradient), DiffResults. gradient (result), x, chunk, tag)
294
380
gradient_config = GradientConfig (f, jacobian_config. duals[2 ], chunk, tag)
295
381
return HessianConfig (jacobian_config, gradient_config)
0 commit comments