Skip to content

Fix GDPopt LBB solver error handling - #4032

Closed
william-xue wants to merge 1 commit into
Pyomo:mainfrom
william-xue:fix/gdpopt-runtimeerror-status
Closed

william-xue wants to merge 1 commit into
Pyomo:mainfrom
william-xue:fix/gdpopt-runtimeerror-status

Conversation

@william-xue

@william-xue william-xue commented Aug 28, 2026

Copy link
Copy Markdown

Fixes #4023.

Summary/Motivation:

GDPopt LBB currently catches every RuntimeError raised by a node subproblem solver and converts it into infeasible bounds:

except RuntimeError as e:
    logger.debug("Solver encountered RuntimeError. Treating as infeasible. ...")

A solver infrastructure, licensing, or interface failure is not proof of mathematical infeasibility. Treating it as such can prune a feasible branch of the search tree, and hides a failed local screening solve — the user sees infeasible/a converged bound instead of an infrastructure error. This affects both the evaluated-node path and the local-screening path in pyomo/contrib/gdpopt/branch_and_bound.py.

Changes proposed in this PR:

  • Re-raise RuntimeError from both the evaluated-node solve and the local-screening solve instead of converting it into synthetic infeasible bounds.
  • Add solver-independent regression tests in pyomo/contrib/gdpopt/tests/test_LBB.py covering both paths with a fake subsolver that raises RuntimeError (one-variable bounded model, SubproblemErrors test class).
  • Leave the existing handling of FBBT-proven infeasibility and explicit infeasible termination conditions untouched.

AI-Use Disclosure

  • AI tools were NOT used during the preparation of this PR

or

  • AI tools contributed to the development of this PR

    • AI tools generated documentation (including the PR description/comments, code comments, and/or Sphinx documentation)
    • AI tools generated tests (baselines, examples, and/or code)
    • AI tools generated code (apart from tests)

    Review process (select ONE):

    • Rewritten: All AI-generated content was rewritten by me before being committed.
    • Reviewed/verified: I retained AI-generated content and verified it before committing. Verification included (as applicable):
      • Ran the code and fixed issues
      • Added and ran tests
      • Checked correctness/logic of code and tests
      • Checked for alignment with the contribution guide
      • Considered security implications
    • As-is: AI-generated content was commited directly to the repository

Notes for reviewers (optional):
Least confident point, and the reason for the focused question below: whether re-raising is the preferred contract here, or whether LBB should instead catch a narrower exception and surface a distinct status. I kept the change minimal (re-raise + regressions) so the decision stays with the maintainers. Note also that the local-screening path is behavior-visible: a subsolver RuntimeError there previously produced a bound that could hide the failure, and now propagates out of solve().

Validation (re-run on current main, no upstream changes in pyomo/contrib/gdpopt since the branch point)

  • .venv/bin/python -m pytest -q pyomo/contrib/gdpopt/tests/test_LBB.py -k "SubproblemErrors"2 passed, 13 deselected
  • .venv/bin/python -m pytest -q pyomo/contrib/gdpopt/tests/test_LBB.py2 passed, 11 skipped, 2 deselected
  • .venv/bin/python -m black --check pyomo/contrib/gdpopt/branch_and_bound.py pyomo/contrib/gdpopt/tests/test_LBB.py2 files would be left unchanged
  • git diff --check — clean

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.

@blnicho

blnicho commented Aug 31, 2026

Copy link
Copy Markdown
Member

@william-xue we welcome contributions from the community but please make sure to review our contributor guide: https://pyomo.readthedocs.io/en/latest/contribution_guide.html

In particular, we require all contributors to use our PR template (without modifications) so this will be closed by policy. Please feel free to reopen with the correct template and we will happily review it.

@william-xue

Copy link
Copy Markdown
Author

Reopening this PR is not possible (GitHub returns a validation error on reopen), so the same commit and diff are now proposed in #4041 with the repository PR template used unmodified, as you suggested. Thanks for the pointer to the contribution guide.

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.

GDPopt LBB treats solver RuntimeError as node infeasibility

2 participants