Add LD-BD implementation merged with main#8
Conversation
…nt test for LD-BD solver.
…qual obj neighbor
There was a problem hiding this comment.
Pull request overview
This PR adds a new GDPopt discrete-search solver implementation for Logic-based Discrete Benders Decomposition (LD-BD), along with supporting shared discrete-search infrastructure (base class + enums), configuration options, plugin registration, and a comprehensive test suite.
Changes:
- Introduce
gdpopt.ldbdsolver implementation and register it via GDPopt plugins. - Add shared discrete-search primitives (
SearchPhase,DirectionNorm) and a discrete algorithm base class with point tracking / caching support. - Add LD-BD unit and integration-style tests, plus configuration wiring for LD-BD-specific options.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
pyomo/contrib/gdpopt/ldbd.py |
Implements the LD-BD algorithm, master MILP, separation LP, and refinement loop. |
pyomo/contrib/gdpopt/discrete_algorithm_base_class.py |
Adds a reusable discrete-search base with point registry, caching, and subproblem evaluation helpers used by LD-BD. |
pyomo/contrib/gdpopt/discrete_search_enums.py |
Defines lightweight enums used by discrete-search solvers for phases and neighborhood norms. |
pyomo/contrib/gdpopt/config_options.py |
Adds _add_ldbd_configs to expose LD-BD-specific configuration options. |
pyomo/contrib/gdpopt/plugins.py |
Registers the new gdpopt.ldbd solver module for discovery/loading. |
pyomo/contrib/gdpopt/tests/test_ldbd.py |
Adds extensive unit tests (mock-based) and an integration-style solve test for LD-BD. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@bernalde @AlbertLee125 The PR of LD-BD is ready to review |
bernalde
left a comment
There was a problem hiding this comment.
Some changes need to be addressed before merging this PR. More importantly, the tests are failing, so we need to make sure that those are passing
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
I just checked the test failures, those failures are not because of test_ldbd.py, but other tests in the pyomo |
|
There are some linting mistakes related to the files changed here and some coverage files not generated correctly. I believe these are your errors: |
bernalde
left a comment
There was a problem hiding this comment.
Besides the small comments the tests are fialing. Here are some excerpts of those tests, but you need to make sure they pass before merging:
> FAILED pyomo/contrib/gdpopt/tests/test_LBB.py::TestGDPopt_LBB::test_LBB_8PP - ValueError: No value for uninitialized VarData object flow[4]
> FAILED pyomo/contrib/gdpopt/tests/test_LBB.py::TestGDPopt_LBB::test_LBB_8PP_max - ValueError: No value for uninitialized VarData object flow[4]
> FAILED pyomo/contrib/gdpopt/tests/test_LBB.py::TestGDPopt_LBB::test_LBB_8PP_with_screening - AssertionError: False is not true
> FAILED pyomo/contrib/gdpopt/tests/test_LBB.py::TestGDPopt_LBB::test_LBB_strip_pack - ValueError: No value for uninitialized ScalarVar object strip_length
> FAILED pyomo/contrib/gdpopt/tests/test_LBB.py::TestGDPopt_LBB_Z3::test_LBB_8PP - ValueError: No value for uninitialized VarData object flow[4]
> FAILED pyomo/contrib/gdpopt/tests/test_LBB.py::TestGDPopt_LBB_Z3::test_LBB_strip_pack - ValueError: No value for uninitialized ScalarVar object strip_length
> FAILED pyomo/contrib/gdpopt/tests/test_enumerate.py::TestGDPoptEnumerate::test_solve_GDP_do_not_iterate_over_Boolean_variables - RuntimeError: Solver does not currently have valid duals. Please check the termination condition.
> FAILED pyomo/contrib/gdpopt/tests/test_enumerate.py::TestGDPoptEnumerate::test_solve_GDP_do_not_iterate_over_discrete_variables - RuntimeError: Solver does not currently have valid duals. Please check the termination condition.
> FAILED pyomo/contrib/gdpopt/tests/test_enumerate.py::TestGDPoptEnumerate::test_solve_GDP_iterate_over_Boolean_variables - RuntimeError: Solver does not currently have valid duals. Please check the termination condition.
> FAILED pyomo/contrib/gdpopt/tests/test_enumerate.py::TestGDPoptEnumerate::test_solve_GDP_iterate_over_discrete_variables - RuntimeError: Solver does not currently have valid duals. Please check the termination condition.
> FAILED pyomo/contrib/gdpopt/tests/test_enumerate.py::TestGDPoptEnumerate::test_unbounded_GDP - RuntimeError: A feasible solution was not found, so no solution can be loaded. If using the appsi.solvers.Highs interface, you can set opt.config.load_solution=False. If using the environ.SolverFactory interface, you can set opt.solve(model, load_solutions = False). Then you can check results.termination_condition and results.best_feasible_objective before loading a solution.
> FAILED pyomo/contrib/gdpopt/tests/test_gdpopt.py::TestGDPopt::test_LOA_8PP_logical_default_init - pyomo.common.errors.DeveloperError: Internal Pyomo implementation error:
> 'GDPopt unable to handle MINLP subproblem termination condition of
> unknown. Results: \nSolver: \n- Status: ok\n Termination condition:
> unknown\n Error rc: 0\n Time: 0.019835710525512695\n'
> Please report this to the Pyomo Developers.
> FAILED pyomo/contrib/gdpopt/tests/test_gdpopt.py::TestGDPopt::test_LOA_8PP_logical_maxBinary - pyomo.common.errors.DeveloperError: Internal Pyomo implementation error:
> 'GDPopt unable to handle MINLP subproblem termination condition of
> unknown. Results: \nSolver: \n- Status: ok\n Termination condition:
> unknown\n Error rc: 0\n Time: 0.019213199615478516\n'
> Please report this to the Pyomo Developers.
> FAILED pyomo/contrib/gdpopt/tests/test_gdpopt.py::TestGDPoptRIC::test_RIC_8PP_logical_default_init - pyomo.common.errors.DeveloperError: Internal Pyomo implementation error:
> 'GDPopt unable to handle MINLP subproblem termination condition of
> unknown. Results: \nSolver: \n- Status: ok\n Termination condition:
> unknown\n Error rc: 0\n Time: 0.019325733184814453\n'
> Please report this to the Pyomo Developers.
|
Tests are failing because you are missing an is appsi highs available check for them |
I will review the tests. Btw, that is very strange. I did not change anything in the tests. They are running well in other PRs but fail in this PR. |
bernalde
left a comment
There was a problem hiding this comment.
I would revent all the changes in the GDPOpt tests and file issues on the pyomo repo to be fixed later. Leave breadcrumbs at most
| # import duals whenever `model.dual.import_enabled()` is true. HiGHS does not | ||
| # provide valid duals for MIP/MILP in general, which can raise at load time. | ||
| # Additionally, APPSI HiGHS raises if asked to load solutions when no feasible | ||
| # solution exists (e.g., unbounded/infeasible), which breaks the unbounded test. |
There was a problem hiding this comment.
I think let's leave this here, but this reveals a larger bug with GDPOpt. File a bug with a MWE in the pyomo branch and add the issue number here
| # By default, do not run large example-based tests (e.g., logical 8PP) or | ||
| # global-solver-dependent tests (GLOA). These can require commercial solvers or | ||
| # be slow/fragile across environments. Enable explicitly if desired. | ||
| RUN_LARGE_TESTS = bool(int(os.environ.get('PYOMO_GDPOPT_RUN_LARGE_TESTS', '0'))) |
There was a problem hiding this comment.
This requires adding some new global variables to the execution of the code, which will not fly in the pyomo repository. Let's just skip these tests if you do not have baron installed and file a bug about this as well
|
Hi team, I’ve investigated the current CI failures across Linux, macOS, and Windows. The failures in pyomo/contrib/solver/tests/solvers are not caused by the code changes in this PR. The root cause is an expired GAMS license in the test environment. It appears the license might have expired a few days ago, which is why we are seeing identical failures across all platforms. Interestingly, the tests for MindtPy (pyomo/main Pyomo#3861) and GDPOpt are still passing (likely because they use different solver paths or have different fallback mechanisms), but the core solver tests are blocked. This same issue is also affecting the LDBD PR and other active MindtPy PRs. Once the GAMS license is renewed in the CI environment, these tests should return to green. |
|
I merged this PR as it is the stepping stone for upcoming PRs with work on LDSDA and LBBD |
Fixes # .
Summary/Motivation:
Add LD-BD implementation
Changes proposed in this PR:
pyomo\pyomo\contrib\gdpopt\ldbd.pypyomo\pyomo\contrib\gdpopt\discrete_search_enums.pypyomo\pyomo\contrib\gdpopt\discrete_algorithm_base_class.pypyomo\pyomo\contrib\gdpopt\tests\test_ldbd.pyLegal Acknowledgement
By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution: