Skip to content

Support non-Array AbstractVectors for AutoEnzyme hess and fgh!#1274

Open
wsmoses wants to merge 7 commits into
masterfrom
enzyme_componentvector_hessian
Open

Support non-Array AbstractVectors for AutoEnzyme hess and fgh!#1274
wsmoses wants to merge 7 commits into
masterfrom
enzyme_componentvector_hessian

Conversation

@wsmoses

@wsmoses wsmoses commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Found this while doing the second order scimlsensitivity testing

In OptimizationEnzymeExt.jl (

lines 157–165
), the Hessian (hess) and gradient-Hessian (fgh!) builders construct the shadow vectors using plain Array(r) and zeros(eltype(x), length(x)):

julia
# In OptimizationEnzymeExt.jl (CURRENT CODE)
vdθ  = Tuple((Array(r) for r in eachrow(I(length(x)) * one(eltype(x)))))  # NTuple{N, Vector}
bθ   = zeros(eltype(x), length(x))                                        # Vector
vdbθ = Tuple(zeros(eltype(x), length(x)) for i in eachindex(x))            # NTuple{N, Vector}
When x (or θ) is a custom container type like ComponentVector, θ has type ComponentVector{...}, but its shadows in vdθ, bθ, and vdbθ are plain Vectors.

Enzyme requires BatchDuplicated(primal, shadow) to have the exact same type for both primal and shadow elements (T and NTuple{N, T}). Passing Vector shadows for a ComponentVector primal causes Enzyme.BatchDuplicated to fail with a MethodError.

@wsmoses
wsmoses requested a review from ChrisRackauckas July 19, 2026 05:41
function hess(res, θ, p = p)
Enzyme.make_zero!(bθ)
Enzyme.make_zero!.(vdbθ)
θ_arr = θ isa Array ? θ : Array(θ)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't correct, it's coercing into an array which for example would not be the correct behavior on GPUArrays.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the existing behavior here:

        vdθ = Tuple((Array(r) for r in eachrow(I(length(x)) * one(eltype(x)))))

already does the conversion [we just need to match this for both primal+shadow]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well then that's the incorrect part that should get fixed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how? you cannot guarantee the primal/shadow are the same type [and index offsets] in a nice way that I can think of offhand otherwise (ofc longer term you can make a helper to adapt the array type, but that's a follow up)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make_zero, Adapt.jl, ArrayInterface.restructure

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any of those work here, but I'll let you continue it

optprob_view.fgh(G_view, H_view, x_view)
@test G1 == G_view
@test H1 == H_view

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should test other things like GPUArrays, StaticArrays, ComponentArrays, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let you take over this PR then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's fine.

@wsmoses

wsmoses commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

also for context iirc this was needed for the second order ode tests in scimlsensitivity

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants