Skip to content

Enzyme 2nd order fix#322

Merged
amontoison merged 8 commits into
JuliaSmoothOptimizers:mainfrom
michel2323:ms/enzyme
Feb 14, 2026
Merged

Enzyme 2nd order fix#322
amontoison merged 8 commits into
JuliaSmoothOptimizers:mainfrom
michel2323:ms/enzyme

Conversation

@michel2323
Copy link
Copy Markdown
Collaborator

No description provided.

@michel2323 michel2323 marked this pull request as ready for review February 13, 2026 17:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the Enzyme-based AD backends and test harness to improve/enable second-order (Hessian / Hvprod) functionality and run Enzyme tests in CI.

Changes:

  • Refactors Enzyme backend implementations to use preallocated buffers and new Enzyme autodiff call patterns for Jacobian/Hessian/Hvprod.
  • Introduces and tests a new predefined backend entry (:enzyme_backend) and adjusts which backend symbol is used in test suites.
  • Enables the Enzyme CPU test step in Buildkite and adds Enzyme + ADNLPModels to the test project deps.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/enzyme.jl Major refactor of Enzyme AD backend structs/buffers and Hvprod/Jprod/Jtprod/Hessian implementations.
test/enzyme.jl Adds :enzyme_backend predefined backend for tests and updates sparse Hessian test invocations.
test/sparse_hessian.jl Adjusts sparse Hessian tests (signature now includes info; edits Rosenbrock test setup).
test/nlp/nlpmodelstest.jl Skips view-subarray tests for :enzyme_backend as well as :enzyme.
test/nls/nlpmodelstest.jl Same skip adjustment for NLS tests.
test/Project.toml Adds ADNLPModels and Enzyme to the test project dependencies.
.buildkite/pipeline.yml Re-enables the Enzyme CPU test step in CI.
src/ADNLPModels.jl Leaves commented debug code in get_lag.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/sparse_hessian.jl
function sparse_hessian(backend, info, kw)
@testset "Basic Hessian derivative with backend=$(backend) -- $info -- T=$(T)" for T in (
Float32,
Float64,
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The Float32 test case was removed, so this test no longer exercises sparse Hessian behavior under single precision. If Float32 is still expected to work for the non-Enzyme backends, please keep Float32 in this loop (or gate it only for the backends/types that cannot support it) to avoid losing coverage.

Suggested change
Float64,
Float64,
Float32,

Copilot uses AI. Check for mistakes.
Comment thread test/sparse_hessian.jl

# Test also the implementation of the backends
b = nlp.adbackend.hessian_backend
@show b
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

@show b will print backend internals during normal test runs and can make CI logs noisy. Please remove this debug output (or guard it behind a debug flag).

Suggested change
@show b

Copilot uses AI. Check for mistakes.
Comment thread test/sparse_hessian.jl
Comment on lines +73 to +78
# res = 0
# n = length(x)
# for i in 1:(n-1)
# res += 100 * (x[i + 1] - x[i]^2)^2 + (x[i] - 1)^2
# end
# res
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Large blocks of commented-out implementation code inside the test function make it harder to maintain and review. Please remove the commented-out loop version (or convert it into a dedicated alternative implementation used by a test if it’s still needed).

Suggested change
# res = 0
# n = length(x)
# for i in 1:(n-1)
# res += 100 * (x[i + 1] - x[i]^2)^2 + (x[i] - 1)^2
# end
# res

Copilot uses AI. Check for mistakes.
Comment thread test/sparse_hessian.jl
Comment on lines +81 to +83
# x -> sum(100 * (x[i + 1] - x[i]^2)^2 + (x[i] - 1)^2 for i = 1:(n - 1)),
# x -> sum(100 * (x[i + 1] - x[i]^2)^2 + (x[i] - 1)^2 for i = 1:3),
# x -> 100 * (x[2] - x[1]^2)^2 + (x[1] - 1)^2,
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The commented-out alternative objective definitions around the ADNLPModel construction add noise and make it unclear which definition is intended. Please remove these commented lines unless they are needed for a specific, active test case.

Suggested change
# x -> sum(100 * (x[i + 1] - x[i]^2)^2 + (x[i] - 1)^2 for i = 1:(n - 1)),
# x -> sum(100 * (x[i + 1] - x[i]^2)^2 + (x[i] - 1)^2 for i = 1:3),
# x -> 100 * (x[2] - x[1]^2)^2 + (x[1] - 1)^2,

Copilot uses AI. Check for mistakes.
Comment thread src/ADNLPModels.jl Outdated
Comment thread test/enzyme.jl
Comment on lines +65 to +66
const test_enzyme = true

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

const test_enzyme = true appears to be unused in the test suite (no other references). If it’s not required for conditional logic in the included files, consider removing it to avoid dead test configuration state.

Suggested change
const test_enzyme = true

Copilot uses AI. Check for mistakes.
Comment thread src/enzyme.jl Outdated
Enzyme.Const(Enzyme.gradient!),
Enzyme.Const(Enzyme.Reverse),
copyto!(b.xbuf, x)
_hvp!(Enzyme.DuplicatedNoNeed(b.grad, Hv), b.f, b.xbuf, v)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

In the :obj Hvprod! method, Float64[] is passed as the y argument. This hard-codes Float64 and can introduce unnecessary specialization/type-instability (and may break if callers use Float32/BigFloat/etc.). Prefer passing an empty vector matching eltype(x) (e.g., similar(x, 0) or a preallocated empty buffer stored on the backend).

Suggested change
_hvp!(Enzyme.DuplicatedNoNeed(b.grad, Hv), b.f, b.xbuf, v)
_hvp!(Enzyme.DuplicatedNoNeed(b.grad, Hv), b., b.xbuf, v, similar(x, 0), obj_weight, b.cx)

Copilot uses AI. Check for mistakes.
Comment thread src/enzyme.jl
Comment on lines 395 to 401
hess = zeros(T, n, n)
fill!(b.seed, zero(T))
for i = 1:n
b.seed[i] = one(T)
Enzyme.hvp!(b.Hv, Enzyme.Const(f), x, b.seed)
grad = Enzyme.make_zero(x)
_hvp!(Enzyme.DuplicatedNoNeed(grad, b.Hv), f, x, b.seed)
view(hess, :, i) .= b.Hv
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

hessian(::EnzymeReverseADHessian, ...) allocates grad = Enzyme.make_zero(x) inside the for i = 1:n loop, which adds O(n) allocations per Hessian call. Consider allocating/reusing this buffer once (e.g., store it on the backend struct) to reduce allocation overhead, especially for larger n.

Copilot uses AI. Check for mistakes.
Comment thread test/Project.toml
Comment on lines 1 to 3
[deps]
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

ADNLPModels and Enzyme were added to [deps], but there are no corresponding [compat] entries. Since this test project already pins compat for other deps, adding compat bounds here would help keep CI reproducible and avoid breakages from upstream Enzyme releases.

Copilot uses AI. Check for mistakes.
Comment thread test/sparse_hessian.jl
Comment on lines +68 to +70
# n = 4
x0 = ones(T, 4)
function f(x)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

n = 4 was removed/commented out here, but the test file still uses n later (in the matrix_free Extended Rosenbrock model). As written this will cause UndefVarError: n not defined when that later block executes; either reintroduce n or replace those generator bounds with length(x).

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 0% with 98 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.75%. Comparing base (fc3ab2f) to head (cf5f009).
⚠️ Report is 36 commits behind head on main.

Files with missing lines Patch % Lines
src/enzyme.jl 0.00% 98 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main     #322       +/-   ##
===========================================
- Coverage   92.23%   76.75%   -15.48%     
===========================================
  Files          13       13               
  Lines        1597     1876      +279     
===========================================
- Hits         1473     1440       -33     
- Misses        124      436      +312     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@amontoison amontoison merged commit adaffab into JuliaSmoothOptimizers:main Feb 14, 2026
28 of 30 checks passed
@amontoison amontoison deleted the ms/enzyme branch February 14, 2026 01:40
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.

3 participants