Description
Enzyme fails to differentiate through solve for an MTK ODEProblem with DAE initialization (algebraic constraints with guesses). Three different calling conventions were tested, each producing a different error:
Enzyme.gradient(Reverse, loss, tunables) → EnzymeMutabilityException — closure captures mutable state (ODEProblem containing arrays)
Enzyme.gradient(Reverse, Const(loss), tunables) → EnzymeRuntimeActivityError — constant memory stored/returned to differentiable variable
Enzyme.gradient(set_runtime_activity(Reverse), Const(loss), tunables) → MethodError: no method matching MixedDuplicated(::ODESolution...)
MWE
import Pkg
Pkg.activate(; temp = true)
Pkg.add(["ModelingToolkit", "OrdinaryDiffEq", "Enzyme",
"SciMLSensitivity", "SciMLStructures", "SymbolicIndexingInterface"])
using ModelingToolkit, OrdinaryDiffEq, Enzyme
using ModelingToolkit: t_nounits as t, D_nounits as D
using SciMLSensitivity
import SciMLStructures as SS
using SymbolicIndexingInterface
# Minimal DAE system: ODE + algebraic constraint requiring initialization
@parameters a b
@variables x(t) y(t)
eqs = [
D(x) ~ a * x + y,
0 ~ x^2 - b * y, # algebraic constraint
]
@mtkbuild sys = ODESystem(eqs, t)
prob = ODEProblem(sys, [x => 1.0], (0.0, 1.0), [a => -0.5, b => 2.0],
guesses = [y => 1.0])
tunables, repack, _ = SS.canonicalize(SS.Tunable(), parameter_values(prob))
# Forward solve works fine
sol = solve(prob, Rodas5P())
loss = let prob = prob, repack = repack
p -> begin
new_prob = remake(prob; p = repack(p))
sol = solve(new_prob, Rodas5P(); abstol = 1e-8, reltol = 1e-6)
sum(sol)
end
end
# Attempt 1: plain Reverse
grad = Enzyme.gradient(Enzyme.Reverse, loss, tunables)
# => EnzymeMutabilityException
# Attempt 2: Const(loss)
grad = Enzyme.gradient(Enzyme.Reverse, Enzyme.Const(loss), tunables)
# => EnzymeRuntimeActivityError
# Attempt 3: set_runtime_activity + Const
grad = Enzyme.gradient(set_runtime_activity(Enzyme.Reverse), Enzyme.Const(loss), tunables)
# => MethodError: no method matching MixedDuplicated(::ODESolution...)
Errors
Attempt 1:
EnzymeMutabilityException: Function argument passed to autodiff cannot be proven readonly.
Attempt 2:
EnzymeRuntimeActivityError: Detected potential need for runtime activity.
Constant memory is stored (or returned) to a differentiable variable and correctness cannot be guaranteed with static activity analysis.
Attempt 3:
MethodError: no method matching MixedDuplicated(::ODESolution{Float64, 2, ...}, ...)
Environment
- Julia 1.12
- ModelingToolkit v11
- Enzyme v0.13 / Enzyme_jll v0.0.249
- SciMLSensitivity latest
Related
Description
Enzyme fails to differentiate through
solvefor an MTK ODEProblem with DAE initialization (algebraic constraints with guesses). Three different calling conventions were tested, each producing a different error:Enzyme.gradient(Reverse, loss, tunables)→EnzymeMutabilityException— closure captures mutable state (ODEProblemcontaining arrays)Enzyme.gradient(Reverse, Const(loss), tunables)→EnzymeRuntimeActivityError— constant memory stored/returned to differentiable variableEnzyme.gradient(set_runtime_activity(Reverse), Const(loss), tunables)→MethodError: no method matching MixedDuplicated(::ODESolution...)MWE
Errors
Attempt 1:
Attempt 2:
Attempt 3:
Environment
Related
inactive_noinlforgetproperty)@test_broken)