Skip to content

Robust options for Enzyme#378

Merged
amontoison merged 4 commits intomainfrom
ms/robust_enzyme
Feb 25, 2026
Merged

Robust options for Enzyme#378
amontoison merged 4 commits intomainfrom
ms/robust_enzyme

Conversation

@michel2323
Copy link
Copy Markdown
Collaborator

Alexis, you had issues with OptimalControl.jl and Enzyme. I've set here the most robust options for Enzyme. Maybe it works now. The compile time might be slower now.

I couldn't run your example. It gives an unrelated error. Maybe I use it wrong.

╰─$ julia --project enzyme.jl                                                                                                                                           1 ↵
ERROR: LoadError: MethodError: no method matching iterate(::CTDirect.DOCP{CTDirect.Midpoint, Model{CTModels.Autonomous, CTModels.TimesModel{CTModels.FixedTimeModel{Int64}, CTModels.FixedTimeModel{Float64}}, CTModels.StateModel, CTModels.ControlModel, CTModels.EmptyVariableModel, var"#fun##296#16", CTModels.LagrangeObjectiveModel{var"#fun##301#17"}, CTModels.ConstraintsModel{Tuple{Vector{Float64}, CTModels.var"#path_cons_nl!#build##1"{Tuple{}, Vector{Int64}, Int64}, Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, var"#fun##289#15", Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, Vector{Int64}, Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, Vector{Int64}, Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, Vector{Int64}, Vector{Float64}, Vector{Symbol}}}, var"#18#19"}, CTDirect.ADNLPBackend})
The function `iterate` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  iterate(::Pkg.Resolve.NodePerm, Any...)
   @ Pkg ~/.julia/juliaup/julia-1.12.5+0.x64.linux.gnu/share/julia/stdlib/v1.12/Pkg/src/Resolve/maxsum.jl:242
  iterate(::Pipe, ::Int64)
   @ Base stream.jl:1297
  iterate(::Pipe)
   @ Base stream.jl:1296
  ...

Stacktrace:
 [1] indexed_iterate(I::CTDirect.DOCP{CTDirect.Midpoint, Model{CTModels.Autonomous, CTModels.TimesModel{CTModels.FixedTimeModel{Int64}, CTModels.FixedTimeModel{Float64}}, CTModels.StateModel, CTModels.ControlModel, CTModels.EmptyVariableModel, var"#fun##296#16", CTModels.LagrangeObjectiveModel{var"#fun##301#17"}, CTModels.ConstraintsModel{Tuple{Vector{Float64}, CTModels.var"#path_cons_nl!#build##1"{Tuple{}, Vector{Int64}, Int64}, Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, var"#fun##289#15", Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, Vector{Int64}, Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, Vector{Int64}, Vector{Float64}, Vector{Symbol}}, Tuple{Vector{Float64}, Vector{Int64}, Vector{Float64}, Vector{Symbol}}}, var"#18#19"}, CTDirect.ADNLPBackend}, i::Int64)
   @ Base ./tuple.jl:165
 [2] top-level scope
   @ ~/project/enzyme.jl:24

Copilot AI review requested due to automatic review settings February 17, 2026 16:55
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

This PR adjusts the Enzyme-based AD extension to use more “robust” Enzyme configuration and runtime-activity mode selection, aiming to reduce Enzyme failures on complex structs/typing patterns (e.g., OptimalControl.jl use cases), at the cost of potentially slower compilation.

Changes:

  • Set Enzyme global robustness options (strictAliasing!, looseTypeAnalysis!) when the extension loads.
  • Switch multiple Enzyme entrypoints (autodiff, jacobian) to use Enzyme.set_runtime_activity(...) for Forward/Reverse modes.

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

Comment on lines +8 to +10
# Configure Enzyme for robustness
Enzyme.API.strictAliasing!(false) # handle Union types in Printf/@sprintf
Enzyme.API.looseTypeAnalysis!(true) # handle unresolved types in complex structs
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

These Enzyme configuration calls are executed at module top-level. In Julia, top-level side effects may run during precompilation and won’t reliably re-run when loading the precompiled extension, so the settings may not actually be applied in user sessions. Consider moving this configuration into __init__() (and optionally guarding with isdefined/try to avoid hard load failures) so it is applied at runtime when the extension is loaded. Also note this mutates global Enzyme state for the whole Julia process; if possible, scope it (or make it opt-in) to avoid impacting other packages using Enzyme.

Suggested change
# Configure Enzyme for robustness
Enzyme.API.strictAliasing!(false) # handle Union types in Printf/@sprintf
Enzyme.API.looseTypeAnalysis!(true) # handle unresolved types in complex structs
function __init__()
# Configure Enzyme for robustness at runtime (not during precompilation)
try
if isdefined(Enzyme, :API)
Enzyme.API.strictAliasing!(false) # handle Union types in Printf/@sprintf
Enzyme.API.looseTypeAnalysis!(true) # handle unresolved types in complex structs
end
catch err
# Avoid hard failures if Enzyme's API or availability changes
@debug "Failed to configure Enzyme in ADNLPModelsEnzymeExt.__init__" exception = (err, catch_backtrace())
end
end

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 17, 2026

Package name latest stable
JSOSuite
PartiallySeparableNLPModels
PartiallySeparableSolvers
SolverTest

@amontoison
Copy link
Copy Markdown
Member

amontoison commented Feb 17, 2026

@michel2323
The MWE is:

using OptimalControl
using NLPModelsIpopt
using Enzyme

x0 = [ 0.
       1. ]
A = [  0. 1.
      -1. 0. ]
B = [ 0.
      1. ]
Q = [ 1. 0.
      0. 1. ]
R = 1.
tf = 3.

ocp = @def begin
    t  [0, tf], time
    x  R², state
    u  R, control
    x(0) == x0
    (t) == A * x(t) + B * u(t)
    0.5( x(t)' * Q * x(t) + u(t)' * R * u(t) )  min
end

solve(ocp; adnlp_backend = :enzyme)

@michel2323
Copy link
Copy Markdown
Collaborator Author

michel2323 commented Feb 18, 2026

The MWE should work now 🙂.

@amontoison
Copy link
Copy Markdown
Member

The unit tests for Enzyme are failing now :(

@michel2323
Copy link
Copy Markdown
Collaborator Author

I'll take a look...

@amontoison
Copy link
Copy Markdown
Member

@jbcaillau

# In short: this is not a numerical precision issue, but a limitation of
# Enzyme when differentiating LLVM bit-manipulation code generated for
# packed Dual numbers
(backend == ADNLPModels.SparseEnzymeADHessian) && (T == Float32) && continue
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.

@jbcaillau @michel2323
The issue with single precision is very deep...

@amontoison amontoison merged commit e5fdf7e into main Feb 25, 2026
28 of 30 checks passed
@amontoison amontoison deleted the ms/robust_enzyme branch February 25, 2026 02:45
@jbcaillau
Copy link
Copy Markdown

thanks @michel2323 for the fix. @amontoison et al: looking forward the new release (cc: @PierreMartinon)

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.

4 participants