Skip to content

Commit 110a076

Browse files
committed
Non allocating versions for StaticArrays
1 parent 93b7789 commit 110a076

File tree

4 files changed

+60
-14
lines changed

4 files changed

+60
-14
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SparseDiffTools"
22
uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
33
authors = ["Pankaj Mishra <pankajmishra1511@gmail.com>", "Chris Rackauckas <contact@chrisrackauckas.com>"]
4-
version = "2.13.0"
4+
version = "2.14.0"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"

src/SparseDiffTools.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import ForwardDiff: Dual, jacobian, partials, DEFAULT_CHUNK_THRESHOLD
1616
using ArrayInterface, SparseArrays
1717
import ArrayInterface: matrix_colors
1818
import StaticArrays
19-
import StaticArrays: StaticArray
19+
import StaticArrays: StaticArray, SArray, MArray, Size
2020
# Others
2121
using SciMLOperators, LinearAlgebra, Random
2222
import DataStructures: DisjointSets, find_root!, union!

src/highlevel/common.jl

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ A cache for computing the Jacobian of type `AbstractMaybeSparseJacobianCache`.
173173
"""
174174
function 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)
@@ -189,20 +196,29 @@ function sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection,
189196
sparse_jacobian!(J, ad, cache, args...)
190197
return J
191198
end
199+
function sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection, f,
200+
x::SArray; kwargs...)
201+
cache = sparse_jacobian_cache(ad, sd, f, x; kwargs...)
202+
return sparse_jacobian_static_array(ad, cache, f, x)
203+
end
192204

193205
"""
194206
sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f, x)
195207
sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f!, fx, x)
196208
197209
Use the sparsity detection `cache` for computing the sparse Jacobian. This allocates a new
198-
Jacobian at every function call
210+
Jacobian at every function call.
199211
"""
200212
function sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache,
201213
args...)
202214
J = init_jacobian(cache)
203215
sparse_jacobian!(J, ad, cache, args...)
204216
return J
205217
end
218+
function sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache, f,
219+
x::SArray)
220+
return sparse_jacobian_static_array(ad, cache, f, x)
221+
end
206222

207223
"""
208224
sparse_jacobian!(J::AbstractMatrix, ad::AbstractADType, sd::AbstractSparsityDetection,
@@ -247,14 +263,18 @@ function __chunksize(::Union{AutoSparseForwardDiff{C}, AutoForwardDiff{C}}, x) w
247263
C isa ForwardDiff.Chunk && return C
248264
return __chunksize(Val(C), x)
249265
end
250-
__chunksize(::Val{nothing}, x) = ForwardDiff.Chunk(x)
266+
__chunksize(::Val{nothing}, x) = __chunksize(x)
251267
function __chunksize(::Val{C}, x) where {C}
252268
if C isa Integer && !(C isa Bool)
253-
return C 0 ? ForwardDiff.Chunk(x) : ForwardDiff.Chunk{C}()
269+
return C 0 ? __chunksize(x) : ForwardDiff.Chunk{C}()
254270
else
255271
error("$(C)::$(typeof(C)) is not a valid chunksize!")
256272
end
257273
end
274+
275+
__chunksize(x) = ForwardDiff.Chunk(x)
276+
__chunksize(x::StaticArray) = ForwardDiff.Chunk{ForwardDiff.pickchunksize(prod(Size(x)))}()
277+
258278
function __chunksize(::Union{AutoSparseForwardDiff{C}, AutoForwardDiff{C}}) where {C}
259279
C === nothing && return nothing
260280
C isa Integer && !(C isa Bool) && return C 0 ? nothing : Val(C)
@@ -273,18 +293,36 @@ end
273293
return :(nothing)
274294
end
275295

276-
function init_jacobian(c::AbstractMaybeSparseJacobianCache)
296+
"""
297+
init_jacobian(cache::AbstractMaybeSparseJacobianCache;
298+
preserve_immutable::Val = Val(false))
299+
300+
Initialize the Jacobian based on the cache. Uses sparse jacobians if possible.
301+
302+
If `preserve_immutable` is `true`, then the Jacobian returned might be immutable, this is
303+
relevant if the inputs are immutable like `StaticArrays`.
304+
"""
305+
function init_jacobian(c::AbstractMaybeSparseJacobianCache;
306+
preserve_immutable::Val = Val(false))
277307
T = promote_type(eltype(c.fx), eltype(c.x))
278-
return init_jacobian(__getfield(c, Val(:jac_prototype)), T, c.fx, c.x)
308+
return init_jacobian(__getfield(c, Val(:jac_prototype)), T, c.fx, c.x;
309+
preserve_immutable)
279310
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
311+
function init_jacobian(::Nothing, ::Type{T}, fx, x; kwargs...) where {T}
312+
return similar(fx, T, length(fx), length(x))
313+
end
314+
function init_jacobian(::Nothing, ::Type{T}, fx::StaticArray, x::StaticArray;
315+
preserve_immutable::Val{PI} = Val(true)) where {T, PI}
316+
if PI
317+
return StaticArrays.SArray{Tuple{length(fx), length(x)}, T}(I)
318+
else
319+
return StaticArrays.MArray{Tuple{length(fx), length(x)}, T}(undef)
320+
end
321+
end
322+
function init_jacobian(J, ::Type{T}, fx, x; kwargs...) where {T}
323+
return similar(J, T, size(J, 1), size(J, 2))
285324
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)
325+
init_jacobian(J::SparseMatrixCSC, ::Type{T}, fx, x; kwargs...) where {T} = T.(J)
288326

289327
__maybe_copy_x(_, x) = x
290328
__maybe_copy_x(_, ::Nothing) = nothing

src/highlevel/forward_mode.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,11 @@ function sparse_jacobian!(J::AbstractMatrix, _, cache::ForwardDiffJacobianCache,
7171
end
7272
return J
7373
end
74+
75+
function sparse_jacobian_static_array(_, cache::ForwardDiffJacobianCache, f, x::SArray)
76+
if cache.cache isa ForwardColorJacCache
77+
return forwarddiff_color_jacobian(f, x, cache.cache)
78+
else
79+
return ForwardDiff.jacobian(f, x, cache.cache)
80+
end
81+
end

0 commit comments

Comments
 (0)