Skip to content

Commit b2c1a07

Browse files
committed
Path to use FiniteDiff for ApproximateSparsityDetection
1 parent 84de29e commit b2c1a07

File tree

6 files changed

+71
-11
lines changed

6 files changed

+71
-11
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.14.0"
4+
version = "2.15.0"
55

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

ext/SparseDiffToolsEnzymeExt.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
module SparseDiffToolsEnzymeExt
22

33
import ArrayInterface: fast_scalar_indexing
4-
import SparseDiffTools: __f̂,
5-
__maybe_copy_x, __jacobian!, __gradient, __gradient!, AutoSparseEnzyme
4+
import SparseDiffTools: __f̂, __maybe_copy_x, __jacobian!, __gradient, __gradient!,
5+
AutoSparseEnzyme, __test_backend_loaded
66
# FIXME: For Enzyme we currently assume reverse mode
77
import ADTypes: AutoEnzyme
88
using Enzyme
99

1010
using ForwardDiff
1111

12+
@inline __test_backend_loaded(::Union{AutoSparseEnzyme, AutoEnzyme}) = nothing
13+
1214
## Satisfying High-Level Interface for Sparse Jacobians
1315
function __gradient(::Union{AutoSparseEnzyme, AutoEnzyme}, f, x, cols)
1416
dx = zero(x)

ext/SparseDiffToolsZygoteExt.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module SparseDiffToolsZygoteExt
22

33
using ADTypes, LinearAlgebra, Zygote
4-
import SparseDiffTools: SparseDiffTools, DeivVecTag, AutoDiffVJP
4+
import SparseDiffTools: SparseDiffTools, DeivVecTag, AutoDiffVJP, __test_backend_loaded
55
import ForwardDiff: ForwardDiff, Dual, partials
66
import SciMLOperators: update_coefficients, update_coefficients!
77
import Setfield: @set!
@@ -12,6 +12,8 @@ import SparseDiffTools: numback_hesvec!,
1212
import SparseDiffTools: __f̂, __jacobian!, __gradient, __gradient!
1313
import ADTypes: AutoZygote, AutoSparseZygote
1414

15+
@inline __test_backend_loaded(::Union{AutoSparseZygote, AutoZygote}) = nothing
16+
1517
## Satisfying High-Level Interface for Sparse Jacobians
1618
function __gradient(::Union{AutoSparseZygote, AutoZygote}, f::F, x, cols) where {F}
1719
_, ∂x, _ = Zygote.gradient(__f̂, f, x, cols)

src/highlevel/coloring.jl

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,70 @@ end
3434
## Right now we hardcode it to use `ForwardDiff`
3535
function (alg::ApproximateJacobianSparsity)(ad::AbstractSparseADType, f::F, x; fx = nothing,
3636
kwargs...) where {F}
37+
if !(ad isa AutoSparseForwardDiff)
38+
@warn "$(ad) support for approximate jacobian not implemented. Using ForwardDiff instead." maxlog=1
39+
end
3740
@unpack ntrials, rng = alg
3841
fx = fx === nothing ? f(x) : fx
39-
J = fill!(similar(fx, length(fx), length(x)), 0)
4042
cfg = ForwardDiff.JacobianConfig(f, x)
43+
J = fill!(similar(fx, length(fx), length(x)), 0)
44+
J_cache = similar(J)
45+
x_ = similar(x)
46+
for _ in 1:ntrials
47+
randn!(rng, x_)
48+
ForwardDiff.jacobian!(J_cache, f, x_, cfg)
49+
@. J += abs(J_cache)
50+
end
51+
return (JacPrototypeSparsityDetection(; jac_prototype = sparse(J), alg.alg))(ad, f, x;
52+
fx, kwargs...)
53+
end
54+
55+
function (alg::ApproximateJacobianSparsity)(ad::AbstractSparseADType, f::F, fx, x;
56+
kwargs...) where {F}
57+
if !(ad isa AutoSparseForwardDiff)
58+
@warn "$(ad) support for approximate jacobian not implemented. Using ForwardDiff instead." maxlog=1
59+
end
60+
@unpack ntrials, rng = alg
61+
cfg = ForwardDiff.JacobianConfig(f, fx, x)
62+
J = fill!(similar(fx, length(fx), length(x)), 0)
63+
J_cache = similar(J)
64+
x_ = similar(x)
65+
for _ in 1:ntrials
66+
randn!(rng, x_)
67+
ForwardDiff.jacobian!(J_cache, f, fx, x_, cfg)
68+
@. J += abs(J_cache)
69+
end
70+
return (JacPrototypeSparsityDetection(; jac_prototype = sparse(J), alg.alg))(ad, f, x;
71+
fx, kwargs...)
72+
end
73+
74+
function (alg::ApproximateJacobianSparsity)(ad::AutoSparseFiniteDiff, f::F, x; fx = nothing,
75+
kwargs...) where {F}
76+
@unpack ntrials, rng = alg
77+
fx = fx === nothing ? f(x) : fx
78+
cache = FiniteDiff.JacobianCache(x, fx)
79+
J = fill!(similar(fx, length(fx), length(x)), 0)
80+
x_ = similar(x)
4181
for _ in 1:ntrials
42-
x_ = similar(x)
4382
randn!(rng, x_)
44-
J .+= abs.(ForwardDiff.jacobian(f, x_, cfg))
83+
J_cache = FiniteDiff.finite_difference_jacobian(f, x, cache)
84+
@. J += abs(J_cache)
4585
end
4686
return (JacPrototypeSparsityDetection(; jac_prototype = sparse(J), alg.alg))(ad, f, x;
4787
fx, kwargs...)
4888
end
4989

50-
function (alg::ApproximateJacobianSparsity)(ad::AbstractSparseADType, f!::F, fx, x;
90+
function (alg::ApproximateJacobianSparsity)(ad::AutoSparseFiniteDiff, f!::F, fx, x;
5191
kwargs...) where {F}
5292
@unpack ntrials, rng = alg
53-
cfg = ForwardDiff.JacobianConfig(f!, fx, x)
93+
cache = FiniteDiff.JacobianCache(x, fx)
5494
J = fill!(similar(fx, length(fx), length(x)), 0)
95+
J_cache = similar(J)
96+
x_ = similar(x)
5597
for _ in 1:ntrials
56-
x_ = similar(x)
5798
randn!(rng, x_)
58-
J .+= abs.(ForwardDiff.jacobian(f!, fx, x_, cfg))
99+
FiniteDiff.finite_difference_jacobian!(J_cache, f!, x_, cache)
100+
@. J += abs(J_cache)
59101
end
60102
return (JacPrototypeSparsityDetection(; jac_prototype = sparse(J), alg.alg))(ad, f!, fx,
61103
x; kwargs...)

src/highlevel/common.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,15 @@ init_jacobian(J::SparseMatrixCSC, ::Type{T}, fx, x; kwargs...) where {T} = T.(J)
332332

333333
__maybe_copy_x(_, x) = x
334334
__maybe_copy_x(_, ::Nothing) = nothing
335+
336+
# Check Backend has been loaded
337+
## We pay a small compile time cost for this, but it avoids cryptic error messages
338+
@inline function __test_backend_loaded(ad::AbstractADType)
339+
error("$(ad) requires $(__backend(ad)).jl to be loaded. Please load it.")
340+
end
341+
342+
@inline __backend(ad) = nothing
343+
@inline __backend(::Union{AutoEnzyme, AutoSparseEnzyme}) = :Enzyme
344+
@inline __backend(::Union{AutoZygote, AutoSparseZygote}) = :Zygote
345+
@inline __backend(::Union{AutoForwardDiff, AutoSparseForwardDiff}) = :ForwardDiff
346+
@inline __backend(::Union{AutoFiniteDiff, AutoSparseFiniteDiff}) = :FiniteDiff

src/highlevel/reverse_mode.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ end
2828

2929
function sparse_jacobian!(J::AbstractMatrix, ad, cache::ReverseModeJacobianCache, args...)
3030
if cache.coloring isa NoMatrixColoring
31+
__test_backend_loaded(ad)
3132
return __jacobian!(J, ad, args...)
3233
else
3334
return __sparse_jacobian_reverse_impl!(J, ad, cache.idx_vec, cache.coloring,
@@ -43,6 +44,7 @@ end
4344
function __sparse_jacobian_reverse_impl!(J::AbstractMatrix, ad, idx_vec,
4445
cache::MatrixColoringResult, f::F, fx, x) where {F}
4546
# If `fx` is `nothing` then assume `f` is not in-place
47+
__test_backend_loaded(ad)
4648
x_ = __maybe_copy_x(ad, x)
4749
fx_ = __maybe_copy_x(ad, fx)
4850
@unpack colorvec, nz_rows, nz_cols = cache

0 commit comments

Comments
 (0)