|
1 |
| -mutable struct JacobianWrapper{fType, pType} |
| 1 | +struct JacobianWrapper{fType, pType} |
2 | 2 | f::fType
|
3 | 3 | p::pType
|
4 | 4 | end
|
5 | 5 |
|
6 | 6 | (uf::JacobianWrapper)(u) = uf.f(u, uf.p)
|
7 | 7 | (uf::JacobianWrapper)(res, u) = uf.f(res, u, uf.p)
|
8 | 8 |
|
9 |
| -struct ImmutableJacobianWrapper{fType, pType} |
10 |
| - f::fType |
11 |
| - p::pType |
12 |
| -end |
| 9 | +struct NonlinearSolveTag end |
13 | 10 |
|
14 |
| -(uf::ImmutableJacobianWrapper)(u) = uf.f(u, uf.p) |
15 |
| - |
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 |
| 11 | +function sparsity_colorvec(f, x) |
| 12 | + sparsity = f.sparsity |
| 13 | + colorvec = DiffEqBase.has_colorvec(f) ? f.colorvec : |
| 14 | + (isnothing(sparsity) ? (1:length(x)) : matrix_colors(sparsity)) |
| 15 | + sparsity, colorvec |
23 | 16 | end
|
24 | 17 |
|
25 |
| -function calc_J(solver, uf::ImmutableJacobianWrapper) |
26 |
| - @unpack u, f, p, alg = solver |
27 |
| - J = jacobian(uf, u, solver) |
28 |
| - return J |
| 18 | +function jacobian_finitediff_forward!(J, f, x, jac_config, forwardcache, cache) |
| 19 | + (FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config, forwardcache); |
| 20 | + maximum(jac_config.colorvec)) |
| 21 | +end |
| 22 | +function jacobian_finitediff!(J, f, x, jac_config, cache) |
| 23 | + (FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config); |
| 24 | + 2 * maximum(jac_config.colorvec)) |
29 | 25 | end
|
30 | 26 |
|
31 |
| -function jacobian(f, x::Number, solver) |
32 |
| - if alg_autodiff(solver.alg) |
33 |
| - J = ForwardDiff.derivative(f, x) |
| 27 | +function jacobian!(J::AbstractMatrix{<:Number}, cache) |
| 28 | + f = cache.f |
| 29 | + uf = cache.uf |
| 30 | + x = cache.u |
| 31 | + fx = cache.fu |
| 32 | + jac_config = cache.jac_config |
| 33 | + alg = cache.alg |
| 34 | + |
| 35 | + if alg_autodiff(alg) |
| 36 | + forwarddiff_color_jacobian!(J, uf, x, jac_config) |
| 37 | + #cache.destats.nf += 1 |
34 | 38 | else
|
35 |
| - J = FiniteDiff.finite_difference_derivative(f, x, alg_difftype(solver.alg), |
36 |
| - eltype(x)) |
| 39 | + isforward = alg_difftype(alg) === Val{:forward} |
| 40 | + if isforward |
| 41 | + uf(fx, x) |
| 42 | + #cache.destats.nf += 1 |
| 43 | + tmp = jacobian_finitediff_forward!(J, uf, x, jac_config, fx, |
| 44 | + cache) |
| 45 | + else # not forward difference |
| 46 | + tmp = jacobian_finitediff!(J, uf, x, jac_config, cache) |
| 47 | + end |
| 48 | + #cache.destats.nf += tmp |
37 | 49 | end
|
38 |
| - return J |
| 50 | + nothing |
39 | 51 | end
|
40 | 52 |
|
41 |
| -function jacobian(f, x, solver) |
42 |
| - if alg_autodiff(solver.alg) |
43 |
| - J = ForwardDiff.jacobian(f, x) |
| 53 | +function build_jac_config(alg, f::F1, uf::F2, du1, u, tmp, du2) where {F1, F2} |
| 54 | + haslinsolve = hasfield(typeof(alg), :linsolve) |
| 55 | + |
| 56 | + if !SciMLBase.has_jac(f) && # No Jacobian if has analytical solution |
| 57 | + ((concrete_jac(alg) === nothing && (!haslinsolve || (haslinsolve && # No Jacobian if linsolve doesn't want it |
| 58 | + (alg.linsolve === nothing || LinearSolve.needs_concrete_A(alg.linsolve))))) || |
| 59 | + (concrete_jac(alg) !== nothing && concrete_jac(alg))) # Jacobian if explicitly asked for |
| 60 | + jac_prototype = f.jac_prototype |
| 61 | + sparsity, colorvec = sparsity_colorvec(f, u) |
| 62 | + |
| 63 | + if alg_autodiff(alg) |
| 64 | + _chunksize = get_chunksize(alg) === Val(0) ? nothing : get_chunksize(alg) # SparseDiffEq uses different convection... |
| 65 | + |
| 66 | + T = if standardtag(alg) |
| 67 | + typeof(ForwardDiff.Tag(NonlinearSolveTag(), eltype(u))) |
| 68 | + else |
| 69 | + typeof(ForwardDiff.Tag(uf, eltype(u))) |
| 70 | + end |
| 71 | + jac_config = ForwardColorJacCache(uf, u, _chunksize; colorvec = colorvec, |
| 72 | + sparsity = sparsity, tag = T) |
| 73 | + else |
| 74 | + if alg_difftype(alg) !== Val{:complex} |
| 75 | + jac_config = FiniteDiff.JacobianCache(tmp, du1, du2, alg_difftype(alg), |
| 76 | + colorvec = colorvec, |
| 77 | + sparsity = sparsity) |
| 78 | + else |
| 79 | + jac_config = FiniteDiff.JacobianCache(Complex{eltype(tmp)}.(tmp), |
| 80 | + Complex{eltype(du1)}.(du1), nothing, |
| 81 | + alg_difftype(alg), eltype(u), |
| 82 | + colorvec = colorvec, |
| 83 | + sparsity = sparsity) |
| 84 | + end |
| 85 | + end |
44 | 86 | else
|
45 |
| - J = FiniteDiff.finite_difference_jacobian(f, x, alg_difftype(solver.alg), eltype(x)) |
| 87 | + jac_config = nothing |
46 | 88 | end
|
47 |
| - return J |
| 89 | + jac_config |
48 | 90 | end
|
49 | 91 |
|
50 |
| -function calc_J!(J, solver, cache) |
51 |
| - @unpack f, u, p, alg = solver |
52 |
| - @unpack du1, uf, jac_config = cache |
| 92 | +function get_chunksize(jac_config::ForwardDiff.JacobianConfig{T, V, N, D}) where {T, V, N, D |
| 93 | + } |
| 94 | + Val(N) |
| 95 | +end # don't degrade compile time information to runtime information |
53 | 96 |
|
54 |
| - uf.f = f |
55 |
| - uf.p = p |
56 |
| - |
57 |
| - jacobian!(J, uf, u, du1, solver, jac_config) |
| 97 | +function jacobian_finitediff(f, x, ::Type{diff_type}, dir, colorvec, sparsity, |
| 98 | + jac_prototype) where {diff_type} |
| 99 | + (FiniteDiff.finite_difference_derivative(f, x, diff_type, eltype(x), dir = dir), 2) |
| 100 | +end |
| 101 | +function jacobian_finitediff(f, x::AbstractArray, ::Type{diff_type}, dir, colorvec, |
| 102 | + sparsity, jac_prototype) where {diff_type} |
| 103 | + f_in = diff_type === Val{:forward} ? f(x) : similar(x) |
| 104 | + ret_eltype = eltype(f_in) |
| 105 | + J = FiniteDiff.finite_difference_jacobian(f, x, diff_type, ret_eltype, f_in, |
| 106 | + dir = dir, colorvec = colorvec, |
| 107 | + sparsity = sparsity, |
| 108 | + jac_prototype = jac_prototype) |
| 109 | + return J, _nfcount(maximum(colorvec), diff_type) |
58 | 110 | end
|
| 111 | +function jacobian(cache, f::F) where {F} |
| 112 | + x = cache.u |
| 113 | + alg = cache.alg |
| 114 | + uf = cache.uf |
| 115 | + local tmp |
59 | 116 |
|
60 |
| -function jacobian!(J, f, x, fx, solver, jac_config) |
61 |
| - alg = solver.alg |
62 |
| - if alg_autodiff(alg) |
63 |
| - ForwardDiff.jacobian!(J, f, fx, x, jac_config) |
| 117 | + if DiffEqBase.has_jac(cache.f) |
| 118 | + J = f.jac(cache.u, cache.p) |
| 119 | + elseif alg_autodiff(alg) |
| 120 | + J, tmp = jacobian_autodiff(uf, x, cache.f, alg) |
64 | 121 | else
|
65 |
| - FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config) |
| 122 | + jac_prototype = cache.f.jac_prototype |
| 123 | + sparsity, colorvec = sparsity_colorvec(cache.f, x) |
| 124 | + dir = true |
| 125 | + J, tmp = jacobian_finitediff(uf, x, alg_difftype(alg), dir, colorvec, sparsity, |
| 126 | + jac_prototype) |
66 | 127 | end
|
67 |
| - nothing |
| 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 / |
| 139 | + SparseDiffTools.getsize(ForwardDiff.pickchunksize(maxcolor)))) : |
| 140 | + Int(ceil(maxcolor / _unwrap_val(chunk_size))) |
| 141 | + (forwarddiff_color_jacobian(f, x, colorvec = colorvec, sparsity = sparsity, |
| 142 | + jac_prototype = jac_prototype, chunksize = chunk_size), |
| 143 | + num_of_chunks) |
68 | 144 | end
|
0 commit comments