Summary
GDP_LBB_Solver._solve_gdp() calls a stale private method, self._get_final_results_object(), when GDPopt LBB exits through the time-limit branch. The current GDPopt base class exposes _get_final_pyomo_results_object() instead, so LBB raises AttributeError instead of returning a normal SolverResults object with maxTimeLimit.
This appears to be distinct from, but related to, the broader open LBB correctness issue in #2483.
Minimal reproducer
This MWE forces the LBB time-limit branch to isolate the stale method call. It does not require external solvers or the downstream GDPlib model.
import pyomo
import pyomo.environ as pyo
from pyomo.gdp import Disjunct, Disjunction
from pyomo.contrib.gdpopt.branch_and_bound import GDP_LBB_Solver
print("pyomo", pyomo.__version__)
print(
"has _get_final_results_object",
hasattr(GDP_LBB_Solver, "_get_final_results_object"),
)
print(
"has _get_final_pyomo_results_object",
hasattr(GDP_LBB_Solver, "_get_final_pyomo_results_object"),
)
# Force the time-limit exit path without depending on solver runtime.
GDP_LBB_Solver.reached_time_limit = lambda self, config: True
m = pyo.ConcreteModel()
m.x = pyo.Var(bounds=(0, 2))
m.d1 = Disjunct()
m.d2 = Disjunct()
m.d1.c = pyo.Constraint(expr=m.x <= 0.5)
m.d2.c = pyo.Constraint(expr=m.x >= 1.5)
m.disj = Disjunction(expr=[m.d1, m.d2])
m.obj = pyo.Objective(expr=m.x)
pyo.SolverFactory("gdpopt.lbb").solve(m, time_limit=1, tee=False)
Actual output
pyomo 6.10.0
has _get_final_results_object False
has _get_final_pyomo_results_object True
WARNING: 09/06/22: The GDPopt LBB algorithm currently has known issues. Please
use the results with caution and report any bugs!
Traceback (most recent call last):
File "<string>", line 1, in <module>
File ".../pyomo/contrib/gdpopt/branch_and_bound.py", line 90, in solve
return super().solve(model, **kwds)
File ".../pyomo/contrib/gdpopt/algorithm_base_class.py", line 128, in solve
self._solve_gdp(model, config)
File ".../pyomo/contrib/gdpopt/branch_and_bound.py", line 239, in _solve_gdp
return self._get_final_results_object()
AttributeError: 'GDP_LBB_Solver' object has no attribute '_get_final_results_object'. Did you mean: '_get_final_pyomo_results_object'?
Expected behavior
LBB should return a normal Pyomo SolverResults object from the time-limit branch, with the termination condition set by reached_time_limit(config).
Likely fix
In pyomo/contrib/gdpopt/branch_and_bound.py, the time-limit branch currently contains:
return self._get_final_results_object()
The leaf-node return path in the same method already uses the current method name:
return self._get_final_pyomo_results_object()
Changing the time-limit branch to call _get_final_pyomo_results_object() appears to resolve the AttributeError. A local monkeypatch aliasing the old name to the current method let the time-limit path return normally in the downstream reproducer.
Downstream context
This was encountered while benchmarking GDPlib's gdp_col model:
In the GDPlib run, both DICOPT-backed and BARON-backed gdpopt.lbb campaigns reached this same AttributeError after the LBB time-limit path. With a local method-name monkeypatch, the same gdp_col LBB path returned maxTimeLimit cleanly, although it still did not find a feasible incumbent. That suggests the stale method call is a reporting/control-flow bug independent of the model formulation.
Environment
Observed locally with:
- Pyomo: 6.10.0
- Python: 3.12.13
- OS/platform: Linux WSL2, glibc 2.39
I also checked pyomo/contrib/gdpopt/branch_and_bound.py on upstream Pyomo/pyomo main via GitHub and saw the same stale call in the time-limit branch.
Summary
GDP_LBB_Solver._solve_gdp()calls a stale private method,self._get_final_results_object(), when GDPopt LBB exits through the time-limit branch. The current GDPopt base class exposes_get_final_pyomo_results_object()instead, so LBB raisesAttributeErrorinstead of returning a normalSolverResultsobject withmaxTimeLimit.This appears to be distinct from, but related to, the broader open LBB correctness issue in #2483.
Minimal reproducer
This MWE forces the LBB time-limit branch to isolate the stale method call. It does not require external solvers or the downstream GDPlib model.
Actual output
Expected behavior
LBB should return a normal Pyomo
SolverResultsobject from the time-limit branch, with the termination condition set byreached_time_limit(config).Likely fix
In
pyomo/contrib/gdpopt/branch_and_bound.py, the time-limit branch currently contains:The leaf-node return path in the same method already uses the current method name:
Changing the time-limit branch to call
_get_final_pyomo_results_object()appears to resolve theAttributeError. A local monkeypatch aliasing the old name to the current method let the time-limit path return normally in the downstream reproducer.Downstream context
This was encountered while benchmarking GDPlib's
gdp_colmodel:gdp_colto fix benchmark issues SECQUOIA/gdplib#66In the GDPlib run, both DICOPT-backed and BARON-backed
gdpopt.lbbcampaigns reached this sameAttributeErrorafter the LBB time-limit path. With a local method-name monkeypatch, the samegdp_colLBB path returnedmaxTimeLimitcleanly, although it still did not find a feasible incumbent. That suggests the stale method call is a reporting/control-flow bug independent of the model formulation.Environment
Observed locally with:
I also checked
pyomo/contrib/gdpopt/branch_and_bound.pyon upstreamPyomo/pyomomainvia GitHub and saw the same stale call in the time-limit branch.