From c41cafa2aa10e5df675ba19b0fc72c002194012f Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sat, 10 Oct 2026 00:21:16 -0400 Subject: [PATCH] Remove Core.Box captures from OptimizationLBFGSB __solve Drop `local x` and give the unconstrained branch its own iter/loss names so closures stop boxing captures and every function evaluation no longer dispatches dynamically. Co-Authored-By: Chris Rackauckas Co-Authored-By: Cursor Agent Agent-Harness: Cursor Agent 2026.10.01-14929f9 Agent-Model: unknown (Cursor auto) Agent-Session: local session, transcript /home/crackauc/sandbox/goals/performance/jobs/opt/opt-lbfgsb/log.txt on amdci2 --- lib/OptimizationLBFGSB/src/OptimizationLBFGSB.jl | 10 ++++------ lib/OptimizationLBFGSB/test/core_tests.jl | 11 +++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/OptimizationLBFGSB/src/OptimizationLBFGSB.jl b/lib/OptimizationLBFGSB/src/OptimizationLBFGSB.jl index 8dd2164e5d..6c5b95c89b 100644 --- a/lib/OptimizationLBFGSB/src/OptimizationLBFGSB.jl +++ b/lib/OptimizationLBFGSB/src/OptimizationLBFGSB.jl @@ -90,8 +90,6 @@ end function SciMLBase.__solve(cache::OptimizationCache{O}) where {O <: LBFGSB} maxiters = OptimizationBase._check_and_convert_maxiters(cache.solver_args.maxiters) - local x - solver_kwargs = __map_optimizer_args(cache, cache.opt; maxiters, cache.solver_args...) if !isnothing(cache.f.cons) @@ -220,12 +218,12 @@ function SciMLBase.__solve(cache::OptimizationCache{O}) where {O <: LBFGSB} stats = stats, retcode = opt_ret ) else - iter_count = Ref(0) + ub_iter_count = Ref(0) encountered_inf_nan = Ref(false) - _loss = function (θ) + ub_loss = function (θ) x = cache.f(θ, cache.p) - iter_count[] += 1 + ub_iter_count[] += 1 # Track if we encounter Inf/NaN values in the objective if !isfinite(x[1]) encountered_inf_nan[] = true @@ -267,7 +265,7 @@ function SciMLBase.__solve(cache::OptimizationCache{O}) where {O <: LBFGSB} t0 = time() res = optimizer( - _loss, _grad!, cache.u0, bounds; m = cache.opt.m, solver_kwargs... + ub_loss, _grad!, cache.u0, bounds; m = cache.opt.m, solver_kwargs... ) # Extract the task message from the result diff --git a/lib/OptimizationLBFGSB/test/core_tests.jl b/lib/OptimizationLBFGSB/test/core_tests.jl index fc0f76bc83..f372fe5e3d 100644 --- a/lib/OptimizationLBFGSB/test/core_tests.jl +++ b/lib/OptimizationLBFGSB/test/core_tests.jl @@ -95,4 +95,15 @@ import SciMLBase @test res_safe.u[1] < 0.0 @test res_safe.u[1] > -0.5 end + + # Regression: unconstrained LBFGSB path must not box `x` / dual-branch + # `iter_count`/`_loss` into Core.Box (dynamic dispatch on every eval). + @testset "no Core.Box in unconstrained LBFGSB __solve" begin + optf_box = OptimizationFunction(rosenbrock, OptimizationBase.AutoForwardDiff()) + prob_box = OptimizationProblem(optf_box, zeros(2)) + cache_box = init(prob_box, OptimizationLBFGSB.LBFGSB()) + src = only(code_typed(SciMLBase.__solve, (typeof(cache_box),)))[1] + nboxes = count(t -> t === Core.Box, something(src.ssavaluetypes, [])) + @test nboxes == 0 + end end