Skip to content

[Do Not Merge] Refactor cyipopt solve-time options to match classic Pyomo solver behavior#3871

Draft
adowling2 wants to merge 1 commit intoPyomo:mainfrom
adowling2:codex/refactor-cyipopt-solve-options
Draft

[Do Not Merge] Refactor cyipopt solve-time options to match classic Pyomo solver behavior#3871
adowling2 wants to merge 1 commit intoPyomo:mainfrom
adowling2:codex/refactor-cyipopt-solve-options

Conversation

@adowling2
Copy link
Member

Fixes # .

Summary/Motivation:

This PR makes the PyNumero cyipopt solver interface behave more like the classic Pyomo solver interfaces for solver options.

Before this change, SolverFactory("cyipopt") only consumed options stored on the solver object via solver.config.options, which meant callers needing one-shot overrides had to mutate solver state around a solve. That was inconsistent with the rest of Pyomo, where callers can generally pass ephemeral options directly to solve(...).

With this change:

  • SolverFactory("cyipopt").solve(model, solver_options={...}) is supported
  • SolverFactory("cyipopt").solve(model, options={...}) is also supported for legacy-style compatibility
  • per-call options override any defaults stored on the solver object for that solve only
  • solver defaults stored on solver.config.options are not permanently mutated by solve-time overrides
  • passing both options= and solver_options= raises an error, matching existing Pyomo conventions

Changes proposed in this PR:

  1. pyomo.contrib.pynumero.algorithms.solvers.cyipopt_solver.PyomoCyIpoptSolver
  • Added solve-time option merging in the public solver plugin used by SolverFactory("cyipopt")
  • Preserved existing solver defaults from config.options
  • Applied per-call overrides only to the active solve
  1. pyomo.contrib.doe.doe.DesignOfExperiments
  • Updated the grey-box cyipopt solve path to pass options through the solve call instead of relying solely on mutable solver state during the solve
  1. pyomo.contrib.mindtpy
  • Updated the legacy cyipopt paths so ephemeral settings like max_cpu_time and constr_viol_tol are added to solve-time kwargs instead of mutating opt.config.options
  • Kept existing behavior for non-cyipopt solvers unchanged
  1. Tests
  • Added focused regression tests for the public cyipopt interface covering:
    • default solver options still apply
    • per-call solver_options override defaults for a single solve
    • legacy options= support
    • defaults are restored after solve
    • mixed options= and solver_options= is rejected
  • Added MindtPy unit tests for the new cyipopt solve-time option plumbing

Public API Behavior

Before:

solver = pyo.SolverFactory("cyipopt")
solver.config.options["max_iter"] = 10
solver.solve(model)

One-shot overrides generally required mutating solver.config.options before solve and then restoring them afterward.

After:

solver = pyo.SolverFactory("cyipopt")
solver.config.options["max_iter"] = 10

solver.solve(model, solver_options={"max_iter": 1})
# or
solver.solve(model, options={"max_iter": 1})

In both cases, the solve uses max_iter=1 for that call only, and the stored default remains 10

Compatibility / Risk Notes

  • This is intentionally narrow and limited to solve-time option handling.
  • Existing code that sets persistent defaults on solver.config.options continues to work.
    options= remains supported for compatibility, but solver_options= is also accepted and is the preferred solve-time override path where applicable.
  • Passing both options= and solver_options= now raises a ValueError for cyipopt, matching behavior already used elsewhere in Pyomo.

Outstanding Tasks Before Review

  • Rerun the targeted tests in a Python 3.11 environment. I could not run the pytest targets in the current shell because the available interpreter is Python 3.9, while this checkout now imports Python 3.10+ syntax.

Suggested test commands once the environment is updated:

python -m pytest pyomo/contrib/pynumero/algorithms/solvers/tests/test_pyomo_cyipopt_solver_interface.py
python -m pytest pyomo/contrib/mindtpy/tests/test_cyipopt_options.py
python -m pytest pyomo/contrib/pynumero/algorithms/solvers/tests/test_cyipopt_solver.py
python -m pytest pyomo/contrib/doe/tests/test_greybox.py
python -m pytest pyomo/contrib/mindtpy/tests/test_mindtpy_grey_box.py

I am running a few minutes late; my previous meeting is running over.

Legal Acknowledgement

By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@adowling2
Copy link
Member Author

This PR was created with Codex as part of an educational experiment.

@adowling2 adowling2 marked this pull request as draft March 10, 2026 19:45
@adowling2 adowling2 changed the title Refactor cyipopt solve-time options to match classic Pyomo solver behavior [Do Not Merge] Refactor cyipopt solve-time options to match classic Pyomo solver behavior Mar 10, 2026
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.

1 participant