Skip to content

Chunked jacobian throws for Diagonal/LowerTriangular/UpperTriangular inputs #839

Description

@devmotion

jacobian allocates its result with chunksize(cfg) columns, which is structural_length(x), but reshape_jacobian reshapes it to length(xdual) columns. For inputs whose structural length differs from their length the two disagree, so chunk mode always throws while vector mode works.

julia> using ForwardDiff, LinearAlgebra

julia> g(z) = [sum(z), sum(abs2, z)];

julia> x = UpperTriangular(rand(3, 3));

julia> size(ForwardDiff.jacobian(g, x))   # vector mode
(2, 6)

julia> ForwardDiff.jacobian(g, x, ForwardDiff.JacobianConfig(g, x, ForwardDiff.Chunk{2}()))
ERROR: DimensionMismatch: new dimensions (2, 9) must be consistent with array length 12

All three wrapper types, only the full-length chunk survives:

input chunk=1 chunk=2 chunk=structural_length(x)
UpperTriangular(rand(3,3)) DimensionMismatch DimensionMismatch (2, 6)
LowerTriangular(rand(3,3)) DimensionMismatch DimensionMismatch (2, 6)
Diagonal(rand(3,3)) DimensionMismatch DimensionMismatch (2, 3)

Since Chunk(x) picks the full structural length for anything up to DEFAULT_CHUNK_THRESHOLD, this only shows up for larger inputs or an explicit Chunk. Introduced in #739.

Worth deciding the column convention at the same time: jacobian currently uses structural columns while gradient returns a result shaped like x. See the discussion in #837, where I argued for indexing the Hessian by the linear indices of x on both axes.

ForwardDiff v1.4.5, Julia 1.12.6.

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