Skip to content

Commit c17ac30

Browse files
Setup with SparseDiffTools
1 parent 903b483 commit c17ac30

File tree

5 files changed

+124
-49
lines changed

5 files changed

+124
-49
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1515
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
1616
SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7"
1717
SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c"
18+
SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
1819
StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
1920
UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
2021

docs/src/solvers/NonlinearSystemSolvers.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,18 @@ then `NLSolveJL`'s `:anderson` can be a good choice.
2929

3030
These are the core solvers.
3131

32-
- `NewtonRaphson(;autodiff=true,chunk_size=12,diff_type=Val{:forward},linsolve=DEFAULT_LINSOLVE)`:
32+
- `NewtonRaphson()`:
3333
A Newton-Raphson method with swappable nonlinear solvers and autodiff methods
3434
for high performance on large and sparse systems.
3535

36+
#### Details on Controlling NonlinearSolve.jl Solvers
37+
38+
```julia
39+
NewtonRaphson(; chunk_size = Val{0}(), autodiff = Val{true}(),
40+
standardtag = Val{true}(), concrete_jac = nothing,
41+
diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS)
42+
```
43+
3644
### SimpleNonlinearSolve.jl
3745

3846
These methods are included with NonlinearSolve.jl by default, though SimpleNonlinearSolve.jl

src/NonlinearSolve.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ using RecursiveArrayTools
1010
import ArrayInterfaceCore
1111
import LinearSolve
1212
using DiffEqBase
13+
using SparseDiffTools
1314

1415
@reexport using SciMLBase
1516
@reexport using SimpleNonlinearSolve

src/jacobian.jl

Lines changed: 110 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,56 +13,131 @@ end
1313

1414
(uf::ImmutableJacobianWrapper)(u) = uf.f(u, uf.p)
1515

16-
function calc_J(solver, cache)
17-
@unpack u, f, p, alg = solver
18-
@unpack uf = cache
19-
uf.f = f
20-
uf.p = p
21-
J = jacobian(uf, u, solver)
22-
return J
16+
function sparsity_colorvec(f, x)
17+
sparsity = f.sparsity
18+
colorvec = DiffEqBase.has_colorvec(f) ? f.colorvec :
19+
(isnothing(sparsity) ? (1:length(x)) : matrix_colors(sparsity))
20+
sparsity, colorvec
2321
end
2422

25-
function calc_J(solver, uf::ImmutableJacobianWrapper)
26-
@unpack u, f, p, alg = solver
27-
J = jacobian(uf, u, solver)
28-
return J
23+
function jacobian_finitediff_forward!(J, f, x, jac_config, forwardcache, cache)
24+
(FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config, forwardcache,
25+
dir = diffdir(cache));
26+
maximum(jac_config.colorvec))
27+
end
28+
function jacobian_finitediff!(J, f, x, jac_config, cache)
29+
(FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config,
30+
dir = diffdir(cache));
31+
2 * maximum(jac_config.colorvec))
2932
end
3033

31-
function jacobian(f, x::Number, solver)
32-
if alg_autodiff(solver.alg)
33-
J = ForwardDiff.derivative(f, x)
34+
function jacobian!(J::AbstractMatrix{<:Number}, f, x::AbstractArray{<:Number},
35+
fx::AbstractArray{<:Number}, cache,
36+
jac_config)
37+
alg = unwrap_alg(cache, true)
38+
if alg_autodiff(alg)
39+
forwarddiff_color_jacobian!(J, f, x, jac_config)
40+
#cache.destats.nf += 1
3441
else
35-
J = FiniteDiff.finite_difference_derivative(f, x, alg_difftype(solver.alg),
36-
eltype(x))
42+
isforward = alg_difftype(alg) === Val{:forward}
43+
if isforward
44+
forwardcache = get_tmp_cache(cache, alg, unwrap_cache(cache, true))[2]
45+
f(forwardcache, x)
46+
#cache.destats.nf += 1
47+
tmp = jacobian_finitediff_forward!(J, f, x, jac_config, forwardcache,
48+
cache)
49+
else # not forward difference
50+
tmp = jacobian_finitediff!(J, f, x, jac_config, cache)
51+
end
52+
cache.destats.nf += tmp
3753
end
38-
return J
54+
nothing
3955
end
4056

41-
function jacobian(f, x, solver)
42-
if alg_autodiff(solver.alg)
43-
J = ForwardDiff.jacobian(f, x)
57+
function build_jac_config(alg, f::F1, uf::F2, du1, u, tmp, du2) where {F1, F2}
58+
haslinsolve = hasfield(typeof(alg), :linsolve)
59+
60+
if SciMLBase.has_jac(f) && # No Jacobian if has analytical solution
61+
((concrete_jac(alg) === nothing && (!haslinsolve || (haslinsolve && # No Jacobian if linsolve doesn't want it
62+
(alg.linsolve === nothing || LinearSolve.needs_concrete_A(alg.linsolve))))) ||
63+
(concrete_jac(alg) !== nothing && concrete_jac(alg))) # Jacobian if explicitly asked for
64+
jac_prototype = f.jac_prototype
65+
sparsity, colorvec = sparsity_colorvec(f, u)
66+
67+
if alg_autodiff(alg)
68+
_chunksize = get_chunksize(alg) === Val(0) ? nothing : get_chunksize(alg) # SparseDiffEq uses different convection...
69+
70+
T = if standardtag(alg)
71+
typeof(ForwardDiff.Tag(OrdinaryDiffEqTag(), eltype(u)))
72+
else
73+
typeof(ForwardDiff.Tag(uf, eltype(u)))
74+
end
75+
jac_config = ForwardColorJacCache(uf, u, _chunksize; colorvec = colorvec,
76+
sparsity = sparsity, tag = T)
77+
else
78+
if alg_difftype(alg) !== Val{:complex}
79+
jac_config = FiniteDiff.JacobianCache(tmp, du1, du2, alg_difftype(alg),
80+
colorvec = colorvec,
81+
sparsity = sparsity)
82+
else
83+
jac_config = FiniteDiff.JacobianCache(Complex{eltype(tmp)}.(tmp),
84+
Complex{eltype(du1)}.(du1), nothing,
85+
alg_difftype(alg), eltype(u),
86+
colorvec = colorvec,
87+
sparsity = sparsity)
88+
end
89+
end
4490
else
45-
J = FiniteDiff.finite_difference_jacobian(f, x, alg_difftype(solver.alg), eltype(x))
91+
jac_config = nothing
4692
end
47-
return J
93+
jac_config
4894
end
4995

50-
function calc_J!(J, solver, cache)
51-
@unpack f, u, p, alg = solver
52-
@unpack du1, uf, jac_config = cache
96+
function get_chunksize(jac_config::ForwardDiff.JacobianConfig{T, V, N, D}) where {T, V, N, D
97+
}
98+
Val(N)
99+
end # don't degrade compile time information to runtime information
53100

54-
uf.f = f
55-
uf.p = p
56-
57-
jacobian!(J, uf, u, du1, solver, jac_config)
101+
function jacobian_finitediff(f, x, ::Type{diff_type}, dir, colorvec, sparsity,
102+
jac_prototype) where {diff_type}
103+
(FiniteDiff.finite_difference_derivative(f, x, diff_type, eltype(x), dir = dir), 2)
58104
end
59-
60-
function jacobian!(J, f, x, fx, solver, jac_config)
61-
alg = solver.alg
105+
function jacobian_finitediff(f, x::AbstractArray, ::Type{diff_type}, dir, colorvec,
106+
sparsity, jac_prototype) where {diff_type}
107+
f_in = diff_type === Val{:forward} ? f(x) : similar(x)
108+
ret_eltype = eltype(f_in)
109+
J = FiniteDiff.finite_difference_jacobian(f, x, diff_type, ret_eltype, f_in,
110+
dir = dir, colorvec = colorvec,
111+
sparsity = sparsity,
112+
jac_prototype = jac_prototype)
113+
return J, _nfcount(maximum(colorvec), diff_type)
114+
end
115+
function jacobian(f, x, cache)
116+
alg = unwrap_alg(cache, true)
117+
local tmp
62118
if alg_autodiff(alg)
63-
ForwardDiff.jacobian!(J, f, fx, x, jac_config)
119+
J, tmp = jacobian_autodiff(f, x, cache.f, alg)
64120
else
65-
FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config)
121+
jac_prototype = cache.f.jac_prototype
122+
sparsity, colorvec = sparsity_colorvec(cache.f, x)
123+
dir = diffdir(cache)
124+
J, tmp = jacobian_finitediff(f, x, alg_difftype(alg), dir, colorvec, sparsity,
125+
jac_prototype)
66126
end
67-
nothing
127+
cache.destats.nf += tmp
128+
J
129+
end
130+
131+
jacobian_autodiff(f, x, nonlinfun, alg) = (ForwardDiff.derivative(f, x), 1, alg)
132+
function jacobian_autodiff(f, x::AbstractArray, nonlinfun, alg)
133+
jac_prototype = nonlinfun.jac_prototype
134+
sparsity, colorvec = sparsity_colorvec(nonlinfun, x)
135+
maxcolor = maximum(colorvec)
136+
chunk_size = get_chunksize(alg) === Val(0) ? nothing : get_chunksize(alg)
137+
num_of_chunks = chunk_size === nothing ?
138+
Int(ceil(maxcolor / getsize(ForwardDiff.pickchunksize(maxcolor)))) :
139+
Int(ceil(maxcolor / _unwrap_val(chunk_size)))
140+
(forwarddiff_color_jacobian(f, x, colorvec = colorvec, sparsity = sparsity,
141+
jac_prototype = jac_prototype, chunksize = chunk_size),
142+
num_of_chunks)
68143
end

src/raphson.jl

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,10 @@ function jacobian_caches(alg::NewtonRaphson, f, u, p, ::Val{true})
6565
linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true,
6666
Pl = Pl, Pr = Pr)
6767

68-
du1 = zero(u)
68+
du1 = zero(u); du2 = zero(u)
6969
tmp = zero(u)
70-
if alg_autodiff(alg)
71-
jac_config = ForwardDiff.JacobianConfig(uf, du1, u)
72-
else
73-
if alg.diff_type != Val{:complex}
74-
du2 = zero(u)
75-
jac_config = FiniteDiff.JacobianCache(tmp, du1, du2, alg.diff_type)
76-
else
77-
jac_config = FiniteDiff.JacobianCache(Complex{eltype(tmp)}.(tmp),
78-
Complex{eltype(du1)}.(du1), nothing,
79-
alg.diff_type, eltype(u))
80-
end
81-
end
70+
jac_config = build_jac_config(alg, f, uf, du1, u, tmp, du2)
71+
8272
uf, linsolve, J, du1, jac_config
8373
end
8474

0 commit comments

Comments
 (0)