Skip to content

gradient!, jacobian! and hessian! do not support an immutable DiffResult unless x is a StaticArray #849

Description

@devmotion

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions