@@ -173,6 +173,13 @@ A cache for computing the Jacobian of type `AbstractMaybeSparseJacobianCache`.
173
173
"""
174
174
function sparse_jacobian_cache end
175
175
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
+
176
183
"""
177
184
sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection, f, x; fx=nothing)
178
185
sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection, f!, fx, x)
@@ -181,6 +188,9 @@ Sequentially calls `sparse_jacobian_cache` and `sparse_jacobian!` to compute the
181
188
`f` at `x`. Use this if the jacobian for `f` is computed exactly once. In all other
182
189
cases, use `sparse_jacobian_cache` once to generate the cache and use `sparse_jacobian!`
183
190
with 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.
184
194
"""
185
195
function sparse_jacobian (ad:: AbstractADType , sd:: AbstractMaybeSparsityDetection , args... ;
186
196
kwargs... )
@@ -189,20 +199,32 @@ function sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection,
189
199
sparse_jacobian! (J, ad, cache, args... )
190
200
return J
191
201
end
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
192
207
193
208
"""
194
209
sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f, x)
195
210
sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f!, fx, x)
196
211
197
212
Use 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.
199
217
"""
200
218
function sparse_jacobian (ad:: AbstractADType , cache:: AbstractMaybeSparseJacobianCache ,
201
219
args... )
202
220
J = init_jacobian (cache)
203
221
sparse_jacobian! (J, ad, cache, args... )
204
222
return J
205
223
end
224
+ function sparse_jacobian (ad:: AbstractADType , cache:: AbstractMaybeSparseJacobianCache , f,
225
+ x:: SArray )
226
+ return sparse_jacobian_static_array (ad, cache, f, x)
227
+ end
206
228
207
229
"""
208
230
sparse_jacobian!(J::AbstractMatrix, ad::AbstractADType, sd::AbstractSparsityDetection,
@@ -247,14 +269,18 @@ function __chunksize(::Union{AutoSparseForwardDiff{C}, AutoForwardDiff{C}}, x) w
247
269
C isa ForwardDiff. Chunk && return C
248
270
return __chunksize (Val (C), x)
249
271
end
250
- __chunksize (:: Val{nothing} , x) = ForwardDiff . Chunk (x)
272
+ __chunksize (:: Val{nothing} , x) = __chunksize (x)
251
273
function __chunksize (:: Val{C} , x) where {C}
252
274
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} ()
254
276
else
255
277
error (" $(C) ::$(typeof (C)) is not a valid chunksize!" )
256
278
end
257
279
end
280
+
281
+ __chunksize (x) = ForwardDiff. Chunk (x)
282
+ __chunksize (x:: StaticArray ) = ForwardDiff. Chunk {ForwardDiff.pickchunksize(prod(Size(x)))} ()
283
+
258
284
function __chunksize (:: Union{AutoSparseForwardDiff{C}, AutoForwardDiff{C}} ) where {C}
259
285
C === nothing && return nothing
260
286
C isa Integer && ! (C isa Bool) && return C ≤ 0 ? nothing : Val (C)
@@ -273,18 +299,36 @@ end
273
299
return :(nothing )
274
300
end
275
301
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 ))
277
313
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)
279
316
end
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 ))
285
330
end
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)
288
332
289
333
__maybe_copy_x (_, x) = x
290
334
__maybe_copy_x (_, :: Nothing ) = nothing
0 commit comments