The methods in src store derivatives by mutating the buffer they pull out of a DiffResult, so they cannot handle a result whose buffers are genuinely immutable. The StaticArrays extension does handle one, but its methods are only reached when x is itself a StaticArray.
using ForwardDiff, DiffResults, StaticArrays
x = [1.0, 2.0, 3.0]
sq(z) = z .^ 2
# succeeds or fails depending only on the chunk size
for c in (1, 2, 3)
cfg = ForwardDiff.GradientConfig(prod, x, ForwardDiff.Chunk{c}())
ForwardDiff.gradient!(DiffResults.GradientResult(@SVector zeros(3)), prod, x, cfg)
end
# chunk 1, 2: ERROR: setindex!(::SVector{3, Float64}, value, ::Int) is not defined.
# chunk 3: ImmutableDiffResult(6.0, ([6.0, 3.0, 2.0],))
ForwardDiff.hessian!(DiffResults.HessianResult(@SVector zeros(3)), prod, x)
# ERROR: setindex!(::SVector{3, Float64}, value, ::Int) is not defined.
ForwardDiff.jacobian!(DiffResults.JacobianResult(@SVector(zeros(3)), @SVector(zeros(3))), sq, x)
# ERROR: MethodError: no method matching extract_jacobian!(…, ::ImmutableDiffResult{…}, …)
All three work with x = SVector(1.0, 2.0, 3.0).
Cause
extract_gradient_chunk! (gradient.jl#L83-L86) and hessian!(::DiffResult, …) (hessian.jl#L69) write the extracted buffer via setindex!/broadcast, and extract_jacobian! (jacobian.jl#L104) only has AbstractArray and MutableDiffResult methods.
Vector-mode gradient! shows what the others need: extract_gradient!(::Type{T}, ::DiffResult, ::Dual) stores through DiffResults.gradient!, rebuilding the struct instead of writing the buffer.
Scope
Only about genuinely immutable buffers. A result holding MArray buffers hits some of the same errors, but that is DiffResults#25 — those are writable and should give a MutableDiffResult.
Independent of #696; reproduces before and after the re-aliasing fix there.
ForwardDiff master (v1.4.6), Julia 1.12.7, StaticArrays 1.9.22, DiffResults 1.1.0.
The methods in
srcstore derivatives by mutating the buffer they pull out of aDiffResult, so they cannot handle a result whose buffers are genuinely immutable. The StaticArrays extension does handle one, but its methods are only reached whenxis itself aStaticArray.All three work with
x = SVector(1.0, 2.0, 3.0).Cause
extract_gradient_chunk!(gradient.jl#L83-L86) andhessian!(::DiffResult, …)(hessian.jl#L69) write the extracted buffer viasetindex!/broadcast, andextract_jacobian!(jacobian.jl#L104) only hasAbstractArrayandMutableDiffResultmethods.Vector-mode
gradient!shows what the others need:extract_gradient!(::Type{T}, ::DiffResult, ::Dual)stores throughDiffResults.gradient!, rebuilding the struct instead of writing the buffer.Scope
Only about genuinely immutable buffers. A result holding
MArraybuffers hits some of the same errors, but that is DiffResults#25 — those are writable and should give aMutableDiffResult.Independent of #696; reproduces before and after the re-aliasing fix there.
ForwardDiff master (v1.4.6), Julia 1.12.7, StaticArrays 1.9.22, DiffResults 1.1.0.