@@ -173,6 +173,13 @@ A cache for computing the Jacobian of type `AbstractMaybeSparseJacobianCache`.
173173"""
174174function sparse_jacobian_cache end
175175
176+ function sparse_jacobian_static_array (ad, cache, f, x:: SArray )
177+ # Not the most performant fallback
178+ J = init_jacobian (cache)
179+ sparse_jacobian! (J, ad, cache, f, MArray (x))
180+ return J
181+ end
182+
176183"""
177184 sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection, f, x; fx=nothing)
178185 sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection, f!, fx, x)
@@ -181,6 +188,9 @@ Sequentially calls `sparse_jacobian_cache` and `sparse_jacobian!` to compute the
181188`f` at `x`. Use this if the jacobian for `f` is computed exactly once. In all other
182189cases, use `sparse_jacobian_cache` once to generate the cache and use `sparse_jacobian!`
183190with the same cache to compute the jacobian.
191+
192+ If `x` is a StaticArray, then this function tries to use a non-allocating implementation for
193+ the jacobian computation. This is possible only for a limited backends currently.
184194"""
185195function sparse_jacobian (ad:: AbstractADType , sd:: AbstractMaybeSparsityDetection , args... ;
186196 kwargs... )
@@ -189,20 +199,32 @@ function sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection,
189199 sparse_jacobian! (J, ad, cache, args... )
190200 return J
191201end
202+ function sparse_jacobian (ad:: AbstractADType , sd:: AbstractMaybeSparsityDetection , f,
203+ x:: SArray ; kwargs... )
204+ cache = sparse_jacobian_cache (ad, sd, f, x; kwargs... )
205+ return sparse_jacobian_static_array (ad, cache, f, x)
206+ end
192207
193208"""
194209 sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f, x)
195210 sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f!, fx, x)
196211
197212Use the sparsity detection `cache` for computing the sparse Jacobian. This allocates a new
198- Jacobian at every function call
213+ Jacobian at every function call.
214+
215+ If `x` is a StaticArray, then this function tries to use a non-allocating implementation for
216+ the jacobian computation. This is possible only for a limited backends currently.
199217"""
200218function sparse_jacobian (ad:: AbstractADType , cache:: AbstractMaybeSparseJacobianCache ,
201219 args... )
202220 J = init_jacobian (cache)
203221 sparse_jacobian! (J, ad, cache, args... )
204222 return J
205223end
224+ function sparse_jacobian (ad:: AbstractADType , cache:: AbstractMaybeSparseJacobianCache , f,
225+ x:: SArray )
226+ return sparse_jacobian_static_array (ad, cache, f, x)
227+ end
206228
207229"""
208230 sparse_jacobian!(J::AbstractMatrix, ad::AbstractADType, sd::AbstractSparsityDetection,
@@ -247,14 +269,18 @@ function __chunksize(::Union{AutoSparseForwardDiff{C}, AutoForwardDiff{C}}, x) w
247269 C isa ForwardDiff. Chunk && return C
248270 return __chunksize (Val (C), x)
249271end
250- __chunksize (:: Val{nothing} , x) = ForwardDiff . Chunk (x)
272+ __chunksize (:: Val{nothing} , x) = __chunksize (x)
251273function __chunksize (:: Val{C} , x) where {C}
252274 if C isa Integer && ! (C isa Bool)
253- return C ≤ 0 ? ForwardDiff . Chunk (x) : ForwardDiff. Chunk {C} ()
275+ return C ≤ 0 ? __chunksize (x) : ForwardDiff. Chunk {C} ()
254276 else
255277 error (" $(C) ::$(typeof (C)) is not a valid chunksize!" )
256278 end
257279end
280+
281+ __chunksize (x) = ForwardDiff. Chunk (x)
282+ __chunksize (x:: StaticArray ) = ForwardDiff. Chunk {ForwardDiff.pickchunksize(prod(Size(x)))} ()
283+
258284function __chunksize (:: Union{AutoSparseForwardDiff{C}, AutoForwardDiff{C}} ) where {C}
259285 C === nothing && return nothing
260286 C isa Integer && ! (C isa Bool) && return C ≤ 0 ? nothing : Val (C)
@@ -273,18 +299,36 @@ end
273299 return :(nothing )
274300end
275301
276- function init_jacobian (c:: AbstractMaybeSparseJacobianCache )
302+ """
303+ init_jacobian(cache::AbstractMaybeSparseJacobianCache;
304+ preserve_immutable::Val = Val(false))
305+
306+ Initialize the Jacobian based on the cache. Uses sparse jacobians if possible.
307+
308+ If `preserve_immutable` is `true`, then the Jacobian returned might be immutable, this is
309+ relevant if the inputs are immutable like `StaticArrays`.
310+ """
311+ function init_jacobian (c:: AbstractMaybeSparseJacobianCache ;
312+ preserve_immutable:: Val = Val (false ))
277313 T = promote_type (eltype (c. fx), eltype (c. x))
278- return init_jacobian (__getfield (c, Val (:jac_prototype )), T, c. fx, c. x)
314+ return init_jacobian (__getfield (c, Val (:jac_prototype )), T, c. fx, c. x;
315+ preserve_immutable)
279316end
280- init_jacobian (:: Nothing , :: Type{T} , fx, x) where {T} = similar (fx, T, length (fx), length (x))
281- function init_jacobian (:: Nothing , :: Type{T} , fx:: StaticArray , x:: StaticArray ) where {T}
282- # We want to construct a MArray to preserve types
283- J = StaticArrays. MArray {Tuple{length(fx), length(x)}, T} (undef)
284- return J
317+ function init_jacobian (:: Nothing , :: Type{T} , fx, x; kwargs... ) where {T}
318+ return similar (fx, T, length (fx), length (x))
319+ end
320+ function init_jacobian (:: Nothing , :: Type{T} , fx:: StaticArray , x:: StaticArray ;
321+ preserve_immutable:: Val{PI} = Val (true )) where {T, PI}
322+ if PI
323+ return StaticArrays. SArray {Tuple{length(fx), length(x)}, T} (I)
324+ else
325+ return StaticArrays. MArray {Tuple{length(fx), length(x)}, T} (undef)
326+ end
327+ end
328+ function init_jacobian (J, :: Type{T} , fx, x; kwargs... ) where {T}
329+ return similar (J, T, size (J, 1 ), size (J, 2 ))
285330end
286- init_jacobian (J, :: Type{T} , _, _) where {T} = similar (J, T, size (J, 1 ), size (J, 2 ))
287- init_jacobian (J:: SparseMatrixCSC , :: Type{T} , _, _) where {T} = T .(J)
331+ init_jacobian (J:: SparseMatrixCSC , :: Type{T} , fx, x; kwargs... ) where {T} = T .(J)
288332
289333__maybe_copy_x (_, x) = x
290334__maybe_copy_x (_, :: Nothing ) = nothing
0 commit comments