@@ -98,6 +98,18 @@ Base.eltype(cfg::AbstractConfig) = eltype(typeof(cfg))
9898
9999@inline (chunksize (:: AbstractConfig{N} ):: Int ) where {N} = N
100100
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+
101113# ###################
102114# DerivativeConfig #
103115# ###################
@@ -107,7 +119,7 @@ struct DerivativeConfig{T,D} <: AbstractConfig{1}
107119end
108120
109121"""
110- ForwardDiff.DerivativeConfig(f!, y::AbstractArray, x::Real)
122+ ForwardDiff.DerivativeConfig(f!, y::AbstractArray, x::Real; tag::Union{Symbol,Nothing} = :default )
111123
112124Return a `DerivativeConfig` instance based on the type of `f!`, and the types/shapes of the
113125output 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
120132be used with any target function. However, this will reduce ForwardDiff's ability to catch
121133and prevent perturbation confusion (see https://github.com/JuliaDiff/ForwardDiff.jl/issues/83).
122134
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+
123138This constructor does not store/modify `y` or `x`.
124139"""
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+
125149function DerivativeConfig (f:: F ,
126150 y:: AbstractArray{Y} ,
127151 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}
129153 duals = similar (y, Dual{T,Y,1 })
130154 return DerivativeConfig {T,typeof(duals)} (duals)
131155end
@@ -143,24 +167,36 @@ struct GradientConfig{T,V,N,D} <: AbstractConfig{N}
143167end
144168
145169"""
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 )
147171
148172Return a `GradientConfig` instance based on the type of `f` and type/shape of the input
149173vector `x`.
150174
151175The returned `GradientConfig` instance contains all the work buffers required by
152176`ForwardDiff.gradient` and `ForwardDiff.gradient!`.
153177
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.
157184
158185This constructor does not store/modify `x`.
159186"""
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+
160196function GradientConfig (f:: F ,
161197 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}
164200 seeds = construct_seeds (Partials{N,V})
165201 duals = similar (x, Dual{T,V,N})
166202 return GradientConfig {T,V,N,typeof(duals)} (seeds, duals)
@@ -179,7 +215,7 @@ struct JacobianConfig{T,V,N,D} <: AbstractConfig{N}
179215end
180216
181217"""
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 )
183219
184220Return a `JacobianConfig` instance based on the type of `f` and type/shape of the input
185221vector `x`.
@@ -188,23 +224,35 @@ The returned `JacobianConfig` instance contains all the work buffers required by
188224`ForwardDiff.jacobian` and `ForwardDiff.jacobian!` when the target function takes the form
189225`f(x)`.
190226
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.
194233
195234This constructor does not store/modify `x`.
196235"""
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+
197245function JacobianConfig (f:: F ,
198246 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}
201249 seeds = construct_seeds (Partials{N,V})
202250 duals = similar (x, Dual{T,V,N})
203251 return JacobianConfig {T,V,N,typeof(duals)} (seeds, duals)
204252end
205253
206254"""
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 )
208256
209257Return a `JacobianConfig` instance based on the type of `f!`, and the types/shapes of the
210258output vector `y` and the input vector `x`.
@@ -213,17 +261,30 @@ The returned `JacobianConfig` instance contains all the work buffers required by
213261`ForwardDiff.jacobian` and `ForwardDiff.jacobian!` when the target function takes the form
214262`f!(y, x)`.
215263
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.
219270
220271This constructor does not store/modify `y` or `x`.
221272"""
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+
222283function JacobianConfig (f:: F ,
223284 y:: AbstractArray{Y} ,
224285 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}
227288 seeds = construct_seeds (Partials{N,X})
228289 yduals = similar (y, Dual{T,Y,N})
229290 xduals = similar (x, Dual{T,X,N})
@@ -244,7 +305,7 @@ struct HessianConfig{T,V,N,DG,DJ} <: AbstractConfig{N}
244305end
245306
246307"""
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 )
248309
249310Return a `HessianConfig` instance based on the type of `f` and type/shape of the input
250311vector `x`.
@@ -255,41 +316,66 @@ configured for the case where the `result` argument is an `AbstractArray`. If
255316it is a `DiffResult`, the `HessianConfig` should instead be constructed via
256317`ForwardDiff.HessianConfig(f, result, x, chunk)`.
257318
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.
261325
262326This constructor does not store/modify `x`.
263327"""
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+
264337function HessianConfig (f:: F ,
265338 x:: AbstractArray{V} ,
266- chunk:: Chunk = Chunk (x) ,
267- tag = Tag (f, V) ) where {F,V}
339+ chunk:: Chunk ,
340+ tag) where {F,V}
268341 jacobian_config = JacobianConfig (f, x, chunk, tag)
269342 gradient_config = GradientConfig (f, jacobian_config. duals, chunk, tag)
270343 return HessianConfig (jacobian_config, gradient_config)
271344end
272345
273346"""
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 )
275348
276349Return a `HessianConfig` instance based on the type of `f`, types/storage in `result`, and
277350type/shape of the input vector `x`.
278351
279352The returned `HessianConfig` instance contains all the work buffers required by
280353`ForwardDiff.hessian!` for the case where the `result` argument is an `DiffResult`.
281354
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.
285361
286362This constructor does not store/modify `x`.
287363"""
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+
288374function HessianConfig (f:: F ,
289375 result:: DiffResult ,
290376 x:: AbstractArray{V} ,
291- chunk:: Chunk = Chunk (x) ,
292- tag = Tag (f, V) ) where {F,V}
377+ chunk:: Chunk ,
378+ tag) where {F,V}
293379 jacobian_config = JacobianConfig ((f,gradient), DiffResults. gradient (result), x, chunk, tag)
294380 gradient_config = GradientConfig (f, jacobian_config. duals[2 ], chunk, tag)
295381 return HessianConfig (jacobian_config, gradient_config)
0 commit comments