Skip to content

Commit 4d25fac

Browse files
ChrisRackauckas-ClaudeChrisRackauckasclaude
authored
OptimizationBase: fix Enzyme out-of-place grad/fg wiring (SciML#1284)
Two pre-existing bugs in the `OptimizationFunction{false}` method of `OptimizationEnzymeExt.instantiate_function`: - The fallback that forwards a user-supplied gradient was gated on `fg == true` rather than `g == true`, so `g = true, fg = false` with a supplied `f.grad` produced `grad === nothing`. Every other extension, and the in-place Enzyme method, gate on `g`. - The generated `fg!` differentiated into `res_fg` but returned `res`, the buffer belonging to the `grad` branch. With `g = false` that name is never assigned and `fg!` throws `UndefVarError: res not defined`; with `g = true` it silently returns the untouched gradient buffer — `[0.0, 0.0]` on a first call. Claude-Session: https://claude.ai/code/session_014Uj4Pu1LKHYqLSTLfPYDPo Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e254f94 commit 4d25fac

3 files changed

Lines changed: 32 additions & 3 deletions

File tree

lib/OptimizationBase/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "OptimizationBase"
22
uuid = "bca83a33-5cc9-4baa-983d-23429ab6bcbb"
3-
version = "5.2.3"
3+
version = "5.2.4"
44
authors = ["Vaibhav Dixit <vaibhavyashdixit@gmail.com> and contributors"]
55

66
[deps]

lib/OptimizationBase/ext/OptimizationEnzymeExt.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ function OptimizationBase.instantiate_function(
524524
)
525525
return res
526526
end
527-
elseif fg == true
527+
elseif g == true
528528
grad = (θ, p = p) -> f.grad(θ, p)
529529
else
530530
grad = nothing
@@ -545,7 +545,7 @@ function OptimizationBase.instantiate_function(
545545
Enzyme.Duplicated(θ, res_fg),
546546
Const(p)
547547
)[2]
548-
return y, res
548+
return y, res_fg
549549
end
550550
elseif fg == true
551551
fg! = (θ, p = p) -> f.fg(θ, p)

lib/OptimizationBase/test/AD/adtests.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,3 +1423,32 @@ end
14231423
@test Gad Gref
14241424
end
14251425
end
1426+
1427+
@testset "Enzyme out-of-place grad/fg wiring" begin
1428+
rosen(x, p = nothing) = (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2
1429+
rosen_grad(x, p = nothing) = [
1430+
-2 * (1 - x[1]) - 400 * x[1] * (x[2] - x[1]^2),
1431+
200 * (x[2] - x[1]^2),
1432+
]
1433+
ad = AutoEnzyme()
1434+
z = [0.5, 0.7]
1435+
gref = rosen_grad(z)
1436+
1437+
# `g` alone must honour a supplied gradient; it used to be gated on `fg`.
1438+
optf = OptimizationBase.instantiate_function(
1439+
OptimizationFunction{false}(rosen, ad; grad = rosen_grad),
1440+
zeros(2), ad, nothing; g = true, fg = false
1441+
)
1442+
@test optf.grad !== nothing
1443+
@test optf.grad(z) gref
1444+
1445+
# The AD `fg!` must return the buffer it differentiated into, with or without `g`.
1446+
for g in (false, true)
1447+
optf = OptimizationBase.instantiate_function(
1448+
OptimizationFunction{false}(rosen, ad), zeros(2), ad, nothing; g = g, fg = true
1449+
)
1450+
y, G = optf.fg(z)
1451+
@test y rosen(z)
1452+
@test G gref
1453+
end
1454+
end

0 commit comments

Comments
 (0)