@@ -125,7 +125,8 @@ function construct_jacobian_cache(
125125 end
126126 end
127127
128- return JacobianCache (J, f, fu, p, stats, autodiff, di_extras)
128+ ad_buffer = _jacobian_ad_buffer (J, f, fu, u, autodiff)
129+ return JacobianCache (J, ad_buffer, f, fu, p, stats, autodiff, di_extras)
129130end
130131
131132function construct_jacobian_cache (
@@ -134,7 +135,7 @@ function construct_jacobian_cache(
134135 linsolve = missing
135136 )
136137 if SciMLBase. has_jac (f) || SciMLBase. has_vjp (f) || SciMLBase. has_jvp (f)
137- return JacobianCache (fu, f, fu, p, stats, autodiff, nothing )
138+ return JacobianCache (fu, fu, f, fu, p, stats, autodiff, nothing )
138139 end
139140 if autodiff === nothing
140141 throw (ArgumentError (" `autodiff` argument to `construct_jacobian_cache` must be \
@@ -145,11 +146,37 @@ function construct_jacobian_cache(
145146 @assert ! (autodiff isa AutoSparse) " `autodiff` cannot be `AutoSparse` for scalar \
146147 nonlinear problems."
147148 di_extras = DI. prepare_derivative (f, autodiff, u, Constant (prob. p))
148- return JacobianCache (u, f, fu, p, stats, autodiff, di_extras)
149+ return JacobianCache (u, u, f, fu, p, stats, autodiff, di_extras)
150+ end
151+
152+ # ForwardDiff reshapes its destination before returning it. This adapter lets a dense
153+ # vector-to-vector Jacobian return the stored matrix directly instead of allocating an
154+ # equivalent array header on every evaluation.
155+ struct _JacobianADBuffer{T, M <: Matrix{T} } <: AbstractMatrix{T}
156+ data:: M
157+ end
158+
159+ Base. parent (A:: _JacobianADBuffer ) = A. data
160+ Base. size (A:: _JacobianADBuffer ) = size (parent (A))
161+ Base. axes (A:: _JacobianADBuffer ) = axes (parent (A))
162+ Base. IndexStyle (:: Type{<:_JacobianADBuffer} ) = IndexLinear ()
163+ @inline Base. getindex (A:: _JacobianADBuffer , i:: Int ) = parent (A)[i]
164+ @inline Base. setindex! (A:: _JacobianADBuffer , value, i:: Int ) = (parent (A)[i] = value)
165+ function Base. reshape (A:: _JacobianADBuffer , dims:: Dims )
166+ return dims == size (A) ? parent (A) : reshape (parent (A), dims)
167+ end
168+
169+ _jacobian_ad_buffer (J, f, fu, u, autodiff) = J
170+ function _jacobian_ad_buffer (
171+ J:: Matrix , f, fu:: Vector , u:: Vector , autodiff:: AutoForwardDiff
172+ )
173+ SciMLBase. isinplace (f) && ! SciMLBase. has_jac (f) || return J
174+ return _JacobianADBuffer (J)
149175end
150176
151177@concrete mutable struct JacobianCache <: AbstractJacobianCache
152178 J
179+ ad_buffer
153180 f <: NonlinearFunction
154181 fu
155182 p
@@ -218,7 +245,8 @@ function (cache::JacobianCache)(u)
218245 f. jac (J, u, p)
219246 else
220247 DI. jacobian! (
221- f, cache. fu, J, cache. di_extras, cache. autodiff, u, Constant (p)
248+ f, cache. fu, cache. ad_buffer, cache. di_extras, cache. autodiff, u,
249+ Constant (p)
222250 )
223251 end
224252 return J
0 commit comments