Skip to content

Commit d2f35b7

Browse files
Merge pull request #285 from avik-pal/ap/speed
More extensive use of Polyester
2 parents 01a5e5f + 9fa3444 commit d2f35b7

File tree

5 files changed

+141
-25
lines changed

5 files changed

+141
-25
lines changed

Diff for: Project.toml

+5-1
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 <[email protected]>", "Chris Rackauckas <[email protected]>"]
4-
version = "2.16.0"
4+
version = "2.17.0"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -27,12 +27,14 @@ VertexSafeGraphs = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f"
2727

2828
[weakdeps]
2929
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
30+
Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588"
3031
PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b"
3132
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
3233
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
3334

3435
[extensions]
3536
SparseDiffToolsEnzymeExt = "Enzyme"
37+
SparseDiffToolsPolyesterExt = "Polyester"
3638
SparseDiffToolsPolyesterForwardDiffExt = "PolyesterForwardDiff"
3739
SparseDiffToolsSymbolicsExt = "Symbolics"
3840
SparseDiffToolsZygoteExt = "Zygote"
@@ -49,6 +51,7 @@ ForwardDiff = "0.10"
4951
Graphs = "1"
5052
LinearAlgebra = "<0.0.1, 1"
5153
PackageExtensionCompat = "1"
54+
Polyester = "0.7.9"
5255
PolyesterForwardDiff = "0.1.1"
5356
Random = "1.6"
5457
Reexport = "1"
@@ -70,6 +73,7 @@ BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
7073
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
7174
IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153"
7275
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
76+
Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588"
7377
PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b"
7478
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
7579
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"

Diff for: ext/SparseDiffToolsPolyesterExt.jl

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
module SparseDiffToolsPolyesterExt
2+
3+
using Adapt, ArrayInterface, ForwardDiff, FiniteDiff, Polyester, SparseDiffTools,
4+
SparseArrays
5+
import SparseDiffTools: polyesterforwarddiff_color_jacobian, ForwardColorJacCache,
6+
__parameterless_type
7+
8+
function cld_fast(a::A, b::B) where {A, B}
9+
T = promote_type(A, B)
10+
return cld_fast(a % T, b % T)
11+
end
12+
function cld_fast(n::T, d::T) where {T}
13+
x = Base.udiv_int(n, d)
14+
x += n != d * x
15+
return x
16+
end
17+
18+
function polyesterforwarddiff_color_jacobian(J::AbstractMatrix{<:Number}, f::F,
19+
x::AbstractArray{<:Number}, jac_cache::ForwardColorJacCache) where {F}
20+
t = jac_cache.t
21+
dx = jac_cache.dx
22+
p = jac_cache.p
23+
colorvec = jac_cache.colorvec
24+
sparsity = jac_cache.sparsity
25+
chunksize = jac_cache.chunksize
26+
maxcolor = maximum(colorvec)
27+
28+
vecx = vec(x)
29+
30+
nrows, ncols = size(J)
31+
32+
if !(sparsity isa Nothing)
33+
rows_index, cols_index = ArrayInterface.findstructralnz(sparsity)
34+
rows_index = [rows_index[i] for i in 1:length(rows_index)]
35+
cols_index = [cols_index[i] for i in 1:length(cols_index)]
36+
else
37+
rows_index = 1:nrows
38+
cols_index = 1:ncols
39+
end
40+
41+
if J isa AbstractSparseMatrix
42+
fill!(nonzeros(J), zero(eltype(J)))
43+
else
44+
fill!(J, zero(eltype(J)))
45+
end
46+
47+
batch((length(p), min(length(p), Threads.nthreads()))) do _, start, stop
48+
color_i = (start - 1) * chunksize + 1
49+
for i in start:stop
50+
partial_i = p[i]
51+
t_ = reshape(eltype(t).(vecx, ForwardDiff.Partials.(partial_i)), size(t))
52+
fx = f(t_)
53+
for j in 1:chunksize
54+
dx = vec(ForwardDiff.partials.(fx, j))
55+
pick_inds = [idx
56+
for idx in 1:length(rows_index)
57+
if colorvec[cols_index[idx]] == color_i]
58+
rows_index_c = rows_index[pick_inds]
59+
cols_index_c = cols_index[pick_inds]
60+
@inbounds @simd for i in 1:length(rows_index_c)
61+
J[rows_index_c[i], cols_index_c[i]] = dx[rows_index_c[i]]
62+
end
63+
color_i += 1
64+
end
65+
end
66+
end
67+
return J
68+
end
69+
70+
end

Diff for: ext/SparseDiffToolsPolyesterForwardDiffExt.jl

+47-15
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
module SparseDiffToolsPolyesterForwardDiffExt
22

3-
using ADTypes, SparseDiffTools, PolyesterForwardDiff
3+
using ADTypes, SparseDiffTools, PolyesterForwardDiff, UnPack, Random, SparseArrays
44
import ForwardDiff
55
import SparseDiffTools: AbstractMaybeSparseJacobianCache, AbstractMaybeSparsityDetection,
66
ForwardColorJacCache, NoMatrixColoring, sparse_jacobian_cache,
77
sparse_jacobian!,
8-
sparse_jacobian_static_array, __standard_tag, __chunksize
8+
sparse_jacobian_static_array, __standard_tag, __chunksize,
9+
polyesterforwarddiff_color_jacobian,
10+
polyesterforwarddiff_color_jacobian!
911

1012
struct PolyesterForwardDiffJacobianCache{CO, CA, J, FX, X} <:
1113
AbstractMaybeSparseJacobianCache
@@ -17,18 +19,14 @@ struct PolyesterForwardDiffJacobianCache{CO, CA, J, FX, X} <:
1719
end
1820

1921
function sparse_jacobian_cache(
20-
ad::Union{AutoSparsePolyesterForwardDiff,
21-
AutoPolyesterForwardDiff},
22-
sd::AbstractMaybeSparsityDetection, f::F, x;
23-
fx = nothing) where {F}
22+
ad::Union{AutoSparsePolyesterForwardDiff, AutoPolyesterForwardDiff},
23+
sd::AbstractMaybeSparsityDetection, f::F, x; fx = nothing) where {F}
2424
coloring_result = sd(ad, f, x)
2525
fx = fx === nothing ? similar(f(x)) : fx
2626
if coloring_result isa NoMatrixColoring
2727
cache = __chunksize(ad, x)
2828
jac_prototype = nothing
2929
else
30-
@warn """Currently PolyesterForwardDiff does not support sparsity detection
31-
natively. Falling back to using ForwardDiff.jl""" maxlog=1
3230
tag = __standard_tag(nothing, x)
3331
# Colored ForwardDiff passes `tag` directly into Dual so we need the `typeof`
3432
cache = ForwardColorJacCache(f, x, __chunksize(ad); coloring_result.colorvec,
@@ -39,17 +37,16 @@ function sparse_jacobian_cache(
3937
end
4038

4139
function sparse_jacobian_cache(
42-
ad::Union{AutoSparsePolyesterForwardDiff,
43-
AutoPolyesterForwardDiff},
44-
sd::AbstractMaybeSparsityDetection, f!::F, fx,
45-
x) where {F}
40+
ad::Union{AutoSparsePolyesterForwardDiff, AutoPolyesterForwardDiff},
41+
sd::AbstractMaybeSparsityDetection, f!::F, fx, x) where {F}
4642
coloring_result = sd(ad, f!, fx, x)
4743
if coloring_result isa NoMatrixColoring
4844
cache = __chunksize(ad, x)
4945
jac_prototype = nothing
5046
else
5147
@warn """Currently PolyesterForwardDiff does not support sparsity detection
52-
natively. Falling back to using ForwardDiff.jl""" maxlog=1
48+
natively for inplace functions. Falling back to using
49+
ForwardDiff.jl""" maxlog=1
5350
tag = __standard_tag(nothing, x)
5451
# Colored ForwardDiff passes `tag` directly into Dual so we need the `typeof`
5552
cache = ForwardColorJacCache(f!, x, __chunksize(ad); coloring_result.colorvec,
@@ -62,7 +59,7 @@ end
6259
function sparse_jacobian!(J::AbstractMatrix, _, cache::PolyesterForwardDiffJacobianCache,
6360
f::F, x) where {F}
6461
if cache.cache isa ForwardColorJacCache
65-
forwarddiff_color_jacobian(J, f, x, cache.cache) # Use Sparse ForwardDiff
62+
polyesterforwarddiff_color_jacobian(J, f, x, cache.cache)
6663
else
6764
PolyesterForwardDiff.threaded_jacobian!(f, J, x, cache.cache) # Don't try to exploit sparsity
6865
end
@@ -72,11 +69,46 @@ end
7269
function sparse_jacobian!(J::AbstractMatrix, _, cache::PolyesterForwardDiffJacobianCache,
7370
f!::F, fx, x) where {F}
7471
if cache.cache isa ForwardColorJacCache
75-
forwarddiff_color_jacobian!(J, f!, x, cache.cache) # Use Sparse ForwardDiff
72+
forwarddiff_color_jacobian!(J, f!, x, cache.cache)
7673
else
7774
PolyesterForwardDiff.threaded_jacobian!(f!, fx, J, x, cache.cache) # Don't try to exploit sparsity
7875
end
7976
return J
8077
end
8178

79+
## Approximate Sparsity Detection
80+
function (alg::ApproximateJacobianSparsity)(
81+
ad::AutoSparsePolyesterForwardDiff, f::F, x; fx = nothing, kwargs...) where {F}
82+
@unpack ntrials, rng = alg
83+
fx = fx === nothing ? f(x) : fx
84+
ck = __chunksize(ad, x)
85+
J = fill!(similar(fx, length(fx), length(x)), 0)
86+
J_cache = similar(J)
87+
x_ = similar(x)
88+
for _ in 1:ntrials
89+
randn!(rng, x_)
90+
PolyesterForwardDiff.threaded_jacobian!(f, J_cache, x_, ck)
91+
@. J += abs(J_cache)
92+
end
93+
return (JacPrototypeSparsityDetection(; jac_prototype = sparse(J), alg.alg))(ad, f, x;
94+
fx, kwargs...)
95+
end
96+
97+
function (alg::ApproximateJacobianSparsity)(
98+
ad::AutoSparsePolyesterForwardDiff, f::F, fx, x;
99+
kwargs...) where {F}
100+
@unpack ntrials, rng = alg
101+
ck = __chunksize(ad, x)
102+
J = fill!(similar(fx, length(fx), length(x)), 0)
103+
J_cache = similar(J)
104+
x_ = similar(x)
105+
for _ in 1:ntrials
106+
randn!(rng, x_)
107+
PolyesterForwardDiff.threaded_jacobian!(f, fx, J_cache, x_, ck)
108+
@. J += abs(J_cache)
109+
end
110+
return (JacPrototypeSparsityDetection(; jac_prototype = sparse(J), alg.alg))(ad, f, x;
111+
fx, kwargs...)
112+
end
113+
82114
end

Diff for: src/differentiation/compute_jacobian_ad.jl

+9-7
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ function forwarddiff_color_jacobian(f::F, x::AbstractArray{<:Number},
173173
end
174174
end
175175

176+
# Defined in extension. Polyester version of `forwarddiff_color_jacobian`
177+
function polyesterforwarddiff_color_jacobian end
178+
176179
# When J is mutable, this version of forwarddiff_color_jacobian will mutate J to avoid allocations
177180
function forwarddiff_color_jacobian(J::AbstractMatrix{<:Number}, f::F,
178181
x::AbstractArray{<:Number},
@@ -249,9 +252,8 @@ function forwarddiff_color_jacobian(J::AbstractMatrix{<:Number}, f::F,
249252
end
250253

251254
# When J is immutable, this version of forwarddiff_color_jacobian will avoid mutating J
252-
function forwarddiff_color_jacobian_immutable(f, x::AbstractArray{<:Number},
253-
jac_cache::ForwardColorJacCache,
254-
jac_prototype = nothing)
255+
function forwarddiff_color_jacobian_immutable(f::F, x::AbstractArray{<:Number},
256+
jac_cache::ForwardColorJacCache, jac_prototype = nothing) where {F}
255257
t = jac_cache.t
256258
dx = jac_cache.dx
257259
p = jac_cache.p
@@ -315,16 +317,16 @@ function forwarddiff_color_jacobian_immutable(f, x::AbstractArray{<:Number},
315317
return J
316318
end
317319

318-
function forwarddiff_color_jacobian!(J::AbstractMatrix{<:Number}, f,
320+
function forwarddiff_color_jacobian!(J::AbstractMatrix{<:Number}, f::F,
319321
x::AbstractArray{<:Number}; dx = similar(x, size(J, 1)), colorvec = 1:length(x),
320-
sparsity = ArrayInterface.has_sparsestruct(J) ? J : nothing)
322+
sparsity = ArrayInterface.has_sparsestruct(J) ? J : nothing) where {F}
321323
forwarddiff_color_jacobian!(J, f, x, ForwardColorJacCache(f, x; dx, colorvec, sparsity))
322324
end
323325

324326
function forwarddiff_color_jacobian!(J::AbstractMatrix{<:Number},
325-
f,
327+
f::F,
326328
x::AbstractArray{<:Number},
327-
jac_cache::ForwardColorJacCache)
329+
jac_cache::ForwardColorJacCache) where {F}
328330
t = jac_cache.t
329331
fx = jac_cache.fx
330332
dx = jac_cache.dx

Diff for: src/highlevel/coloring.jl

+10-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ function (alg::ApproximateJacobianSparsity)(
3636
ad::AbstractSparseADType, f::F, x; fx = nothing,
3737
kwargs...) where {F}
3838
if !(ad isa AutoSparseForwardDiff)
39-
@warn "$(ad) support for approximate jacobian not implemented. Using ForwardDiff instead." maxlog=1
39+
if ad isa AutoSparsePolyesterForwardDiff
40+
@warn "$(ad) is only supported if `PolyesterForwardDiff` is explicitly loaded. Using ForwardDiff instead." maxlog=1
41+
else
42+
@warn "$(ad) support for approximate jacobian not implemented. Using ForwardDiff instead." maxlog=1
43+
end
4044
end
4145
@unpack ntrials, rng = alg
4246
fx = fx === nothing ? f(x) : fx
@@ -56,7 +60,11 @@ end
5660
function (alg::ApproximateJacobianSparsity)(ad::AbstractSparseADType, f::F, fx, x;
5761
kwargs...) where {F}
5862
if !(ad isa AutoSparseForwardDiff)
59-
@warn "$(ad) support for approximate jacobian not implemented. Using ForwardDiff instead." maxlog=1
63+
if ad isa AutoSparsePolyesterForwardDiff
64+
@warn "$(ad) is only supported if `PolyesterForwardDiff` is explicitly loaded. Using ForwardDiff instead." maxlog=1
65+
else
66+
@warn "$(ad) support for approximate jacobian not implemented. Using ForwardDiff instead." maxlog=1
67+
end
6068
end
6169
@unpack ntrials, rng = alg
6270
cfg = ForwardDiff.JacobianConfig(f, fx, x)

0 commit comments

Comments
 (0)