Skip to content

Commit 69aaa0b

Browse files
committed
Add tests
1 parent 110a076 commit 69aaa0b

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Zygote = "0.6"
6262
julia = "1.6"
6363

6464
[extras]
65+
AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a"
6566
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
6667
BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
6768
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
@@ -75,4 +76,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
7576
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
7677

7778
[targets]
78-
test = ["Test", "BandedMatrices", "BlockBandedMatrices", "Enzyme", "IterativeSolvers", "Pkg", "Random", "SafeTestsets", "Symbolics", "Zygote", "StaticArrays"]
79+
test = ["Test", "BandedMatrices", "BlockBandedMatrices", "Enzyme", "IterativeSolvers", "Pkg", "Random", "SafeTestsets", "Symbolics", "Zygote", "StaticArrays", "AllocCheck"]

src/highlevel/common.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ Sequentially calls `sparse_jacobian_cache` and `sparse_jacobian!` to compute the
188188
`f` at `x`. Use this if the jacobian for `f` is computed exactly once. In all other
189189
cases, use `sparse_jacobian_cache` once to generate the cache and use `sparse_jacobian!`
190190
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.
191194
"""
192195
function sparse_jacobian(ad::AbstractADType, sd::AbstractMaybeSparsityDetection, args...;
193196
kwargs...)
@@ -208,6 +211,9 @@ end
208211
209212
Use the sparsity detection `cache` for computing the sparse Jacobian. This allocates a new
210213
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.
211217
"""
212218
function sparse_jacobian(ad::AbstractADType, cache::AbstractMaybeSparseJacobianCache,
213219
args...)
@@ -326,3 +332,14 @@ init_jacobian(J::SparseMatrixCSC, ::Type{T}, fx, x; kwargs...) where {T} = T.(J)
326332

327333
__maybe_copy_x(_, x) = x
328334
__maybe_copy_x(_, ::Nothing) = nothing
335+
336+
# Create a mutable version of the input array
337+
function __make_mutable(x)
338+
if ArrayInterface.can_setindex(x)
339+
return x
340+
else
341+
y = similar(x)
342+
copyto!(y, x)
343+
return y
344+
end
345+
end

src/highlevel/finite_diff.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ __getfield(c::FiniteDiffJacobianCache, ::Val{:jac_prototype}) = c.jac_prototype
1010

1111
function sparse_jacobian_cache(fd::Union{AutoSparseFiniteDiff, AutoFiniteDiff},
1212
sd::AbstractMaybeSparsityDetection, f::F, x; fx = nothing) where {F}
13+
x = __make_mutable(x) # FiniteDiff is bad at handling immutables
1314
coloring_result = sd(fd, f, x)
1415
fx = fx === nothing ? similar(f(x)) : fx
1516
if coloring_result isa NoMatrixColoring
@@ -25,6 +26,7 @@ end
2526

2627
function sparse_jacobian_cache(fd::Union{AutoSparseFiniteDiff, AutoFiniteDiff},
2728
sd::AbstractMaybeSparsityDetection, f!::F, fx, x) where {F}
29+
x = __make_mutable(x) # FiniteDiff is bad at handling immutables
2830
coloring_result = sd(fd, f!, fx, x)
2931
if coloring_result isa NoMatrixColoring
3032
cache = FiniteDiff.JacobianCache(x, fx)

test/test_sparse_jacobian.jl

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Sparse Jacobian tests
2-
using SparseDiffTools, Symbolics, ForwardDiff, LinearAlgebra, SparseArrays, Zygote, Enzyme
3-
using Test
2+
using AllocCheck, SparseDiffTools,
3+
Symbolics, ForwardDiff, LinearAlgebra, SparseArrays, Zygote, Enzyme, Test, StaticArrays
44

55
@views function fdiff(y, x) # in-place
66
L = length(x)
@@ -163,3 +163,29 @@ SPARSITY_DETECTION_ALGS = [JacPrototypeSparsityDetection(; jac_prototype = J_spa
163163
end
164164
end
165165
end
166+
167+
# Testing that the non-sparse jacobian's are non-allocating.
168+
fvcat(x) = vcat(x, x)
169+
170+
x_sa = @SVector randn(Float32, 10);
171+
172+
J_true_sa = ForwardDiff.jacobian(fvcat, x_sa)
173+
174+
@check_allocs function __sparse_jacobian_no_allocs(ad, sd, f::F, x) where {F}
175+
return sparse_jacobian(ad, sd, f, x)
176+
end
177+
178+
@testset "Static Arrays" begin
179+
@testset "No Allocations: $(difftype)" for difftype in (AutoSparseForwardDiff(),
180+
AutoForwardDiff())
181+
J = __sparse_jacobian_no_allocs(difftype, NoSparsityDetection(), fvcat, x_sa)
182+
@test J J_true_sa
183+
end
184+
185+
@testset "Other Backends: $(difftype)" for difftype in (AutoSparseZygote(),
186+
AutoZygote(), AutoSparseEnzyme(), AutoEnzyme(), AutoSparseFiniteDiff(),
187+
AutoFiniteDiff())
188+
J = sparse_jacobian(difftype, NoSparsityDetection(), fvcat, x_sa)
189+
@test J J_true_sa
190+
end
191+
end

0 commit comments

Comments
 (0)