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