Skip to content

Fix verbose handling in OptimizationMOI#1235

Merged
ChrisRackauckas merged 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:fix-optimizationmoi-verbose
Jun 25, 2026
Merged

Fix verbose handling in OptimizationMOI#1235
ChrisRackauckas merged 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:fix-optimizationmoi-verbose

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor

Summary

Fixes a crash when verbose is passed to a MOI optimizer through OptimizationMOI. There are two manifestations, both from the same root cause — __map_optimizer_args was never updated for the OptimizationVerbosity system, while verbose flows into the cache's solver_args:

  1. FieldError: type MOIOptimizationNLPCache has no field verbose — the @SciMLMessage calls read cache.verbose, but the MOI caches (MOIOptimizationNLPCache / MOIOptimizationCache) keep solve kwargs in solver_args and have no verbose field. Triggered whenever a common tolerance (abstol/reltol/maxiters) is passed alongside verbose.
  2. Unable to add option "verbose" ... must be ::String, ::Integer, or ::Float64verbose was splatted from solver_args into the raw optimizer-attribute loop, so even a plain verbose=-solve (no tolerance) failed by trying to set verbose as an Ipopt RawOptimizerAttribute.

Fix

__map_optimizer_args now consumes verbose as a named keyword (so it is no longer forwarded into the raw-attribute loop) and runs it through OptimizationBase._process_verbose_param to obtain a valid OptimizationVerbosity for the @SciMLMessage calls. The now-unused cache argument is dropped and both call sites updated.

How it surfaced

Reported via the BoundaryValueDiffEq optimization-based BVP path (the rocket optimal-control example), which builds an OptimizationProblem and calls solve(prob, Ipopt.Optimizer(); abstol=..., verbose=OptimizationVerbosity()) — hitting manifestation (1).

Testing

  • New @testset "verbose kwarg" covering all three cases (verbose-only, verbose+abstol, verbose=true). Each reproduces a pre-fix failure and passes after.
  • Full OptimizationMOI Core suite run locally on Julia 1.12.6 — all green (the 2 Broken in cache are pre-existing @test_broken):
    verbose kwarg | 3  3  3.1s
    
  • End-to-end: the original rocket BVP script (MIRK4(; optimize = Ipopt.Optimizer())) now returns retcode = Success (max height 1.0128323), matching the OptimizationIpopt result.

This PR is a draft and should be ignored until reviewed by @ChrisRackauckas.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RtJAi7bALH5XkakjS6Yb6j

ChrisRackauckas-Claude and others added 2 commits June 24, 2026 22:06
`__map_optimizer_args` read `cache.verbose`, but the MOI caches
(`MOIOptimizationNLPCache`/`MOIOptimizationCache`) store solve kwargs in
`solver_args` and have no `verbose` field, so passing `verbose` together with a
common tolerance threw `FieldError: type MOIOptimizationNLPCache has no field
verbose`. Separately, `verbose` was splatted from `solver_args` into the raw
optimizer-attribute loop, so a plain `verbose=`-solve failed with
`Unable to add option "verbose"`.

Consume `verbose` as a named keyword of `__map_optimizer_args` (so it is no
longer forwarded as a raw solver attribute) and run it through
`_process_verbose_param` for the `@SciMLMessage` calls. Both manifestations
surface through the BoundaryValueDiffEq optimization-based BVP path, which
passes `abstol` and an `OptimizationVerbosity` to the optimizer.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtJAi7bALH5XkakjS6Yb6j
Two pre-existing Aqua failures in the OptimizationMOI QA suite:

- Declare the SciMLBase solver-trait methods defined on the MathOptInterface
  optimizer types (`__init`, `allowsbounds`, `requiresgradient`, ...) as allowed
  via `piracies = (treat_as_own = [...],)`. These are an intentional interface
  extension, not piracy.
- Add the missing `[compat]` bound for `ReverseDiff` (a test-only `[extras]`
  dependency), which Aqua's deps_compat check requires.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtJAi7bALH5XkakjS6Yb6j
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor Author

Pushed two follow-up commits addressing the OptimizationMOI QA (Aqua) failures, which are pre-existing on master (confirmed by running QA against a clean master worktree — same failures, independent of the verbose fix):

  • Allowed piracy: the SciMLBase solver-trait methods defined on the MathOptInterface optimizer types are an intentional interface extension, now declared via Aqua.test_all(...; piracies = (treat_as_own = [MOI.AbstractOptimizer, MOI.OptimizerWithAttributes],)). Aqua now passes 11/11.
  • deps_compat: added the missing [compat] bound ReverseDiff = "1" for the test-only [extras] dependency.

The third QA finding (a JET error on MOIOptimizationNLPCache's setproperty! setfield! fallback) is unrelated to this PR and is fixed separately in #1236. I verified locally that with this PR and #1236 applied, JET.test_package passes cleanly (0 errors) and Aqua passes 11/11 — the two together turn the QA job green.

Should be ignored until reviewed by @ChrisRackauckas.

@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review June 25, 2026 09:59
@ChrisRackauckas ChrisRackauckas merged commit 2d4c3bf into SciML:master Jun 25, 2026
36 of 46 checks passed
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.

2 participants