@@ -99,6 +99,18 @@ Base.eltype(cfg::AbstractConfig) = eltype(typeof(cfg))
9999
100100@inline (chunksize (:: AbstractConfig{N} ):: Int ) where {N} = N
101101
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+
102114# ###################
103115# DerivativeConfig #
104116# ###################
@@ -108,7 +120,7 @@ struct DerivativeConfig{T,D} <: AbstractConfig{1}
108120end
109121
110122"""
111- ForwardDiff.DerivativeConfig(f!, y::AbstractArray, x::Real)
123+ ForwardDiff.DerivativeConfig(f!, y::AbstractArray, x::Real; tag::Union{Symbol,Nothing} = :default )
112124
113125Return a `DerivativeConfig` instance based on the type of `f!`, and the types/shapes of the
114126output 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
121133be used with any target function. However, this will reduce ForwardDiff's ability to catch
122134and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
123135
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+
124139This constructor does not store/modify `y` or `x`.
125140"""
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+
126150function DerivativeConfig (f:: F ,
127151 y:: AbstractArray{Y} ,
128152 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}
130154 duals = similar (y, Dual{T,Y,1 })
131155 return DerivativeConfig {T,typeof(duals)} (duals)
132156end
@@ -144,24 +168,36 @@ struct GradientConfig{T,V,N,D} <: AbstractConfig{N}
144168end
145169
146170"""
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 )
148172
149173Return a `GradientConfig` instance based on the type of `f` and type/shape of the input
150174vector `x`.
151175
152176The returned `GradientConfig` instance contains all the work buffers required by
153177`ForwardDiff.gradient` and `ForwardDiff.gradient!`.
154178
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.
158185
159186This constructor does not store/modify `x`.
160187"""
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+
161197function GradientConfig (f:: F ,
162198 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}
165201 seeds = construct_seeds (Partials{N,V})
166202 duals = similar (x, Dual{T,V,N})
167203 return GradientConfig {T,V,N,typeof(duals)} (seeds, duals)
@@ -180,7 +216,7 @@ struct JacobianConfig{T,V,N,D} <: AbstractConfig{N}
180216end
181217
182218"""
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 )
184220
185221Return a `JacobianConfig` instance based on the type of `f` and type/shape of the input
186222vector `x`.
@@ -189,23 +225,35 @@ The returned `JacobianConfig` instance contains all the work buffers required by
189225`ForwardDiff.jacobian` and `ForwardDiff.jacobian!` when the target function takes the form
190226`f(x)`.
191227
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.
195234
196235This constructor does not store/modify `x`.
197236"""
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+
198246function JacobianConfig (f:: F ,
199247 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}
202250 seeds = construct_seeds (Partials{N,V})
203251 duals = similar (x, Dual{T,V,N})
204252 return JacobianConfig {T,V,N,typeof(duals)} (seeds, duals)
205253end
206254
207255"""
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 )
209257
210258Return a `JacobianConfig` instance based on the type of `f!`, and the types/shapes of the
211259output vector `y` and the input vector `x`.
@@ -214,17 +262,30 @@ The returned `JacobianConfig` instance contains all the work buffers required by
214262`ForwardDiff.jacobian` and `ForwardDiff.jacobian!` when the target function takes the form
215263`f!(y, x)`.
216264
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.
220271
221272This constructor does not store/modify `y` or `x`.
222273"""
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+
223284function JacobianConfig (f:: F ,
224285 y:: AbstractArray{Y} ,
225286 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}
228289 seeds = construct_seeds (Partials{N,X})
229290 yduals = similar (y, Dual{T,Y,N})
230291 xduals = similar (x, Dual{T,X,N})
@@ -245,7 +306,7 @@ struct HessianConfig{T,V,N,DG,DJ} <: AbstractConfig{N}
245306end
246307
247308"""
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 )
249310
250311Return a `HessianConfig` instance based on the type of `f` and type/shape of the input
251312vector `x`.
@@ -256,41 +317,66 @@ configured for the case where the `result` argument is an `AbstractArray`. If
256317it is a `DiffResult`, the `HessianConfig` should instead be constructed via
257318`ForwardDiff.HessianConfig(f, result, x, chunk)`.
258319
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.
262326
263327This constructor does not store/modify `x`.
264328"""
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+
265338function HessianConfig (f:: F ,
266339 x:: AbstractArray{V} ,
267- chunk:: Chunk = Chunk (x) ,
268- tag = Tag (f, V) ) where {F,V}
340+ chunk:: Chunk ,
341+ tag) where {F,V}
269342 jacobian_config = JacobianConfig (f, x, chunk, tag)
270343 gradient_config = GradientConfig (f, jacobian_config. duals, chunk, tag)
271344 return HessianConfig (jacobian_config, gradient_config)
272345end
273346
274347"""
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 )
276349
277350Return a `HessianConfig` instance based on the type of `f`, types/storage in `result`, and
278351type/shape of the input vector `x`.
279352
280353The returned `HessianConfig` instance contains all the work buffers required by
281354`ForwardDiff.hessian!` for the case where the `result` argument is an `DiffResult`.
282355
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.
286362
287363This constructor does not store/modify `x`.
288364"""
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+
289375function HessianConfig (f:: F ,
290376 result:: DiffResult ,
291377 x:: AbstractArray{V} ,
292- chunk:: Chunk = Chunk (x) ,
293- tag = Tag (f, V) ) where {F,V}
378+ chunk:: Chunk ,
379+ tag) where {F,V}
294380 jacobian_config = JacobianConfig ((f,gradient), DiffResults. gradient (result), x, chunk, tag)
295381 gradient_config = GradientConfig (f, jacobian_config. duals[2 ], chunk, tag)
296382 return HessianConfig (jacobian_config, gradient_config)
0 commit comments