Skip to content

Conversation

aasgerr
Copy link
Contributor

@aasgerr aasgerr commented Aug 20, 2025

This PR refactors the presolve interval tightener into a base class (_SPIntervalTightenerBase) and two concrete classes: SPFBBT for FBBT and SPOBBT for OBBT, thus adding the OBBT functionality to "Distributed Subproblem Presolve" (#373).

To enable OBBT, the user needs to use the --obbt command line option in addition to the existing --presolve option.

Leveraging the existing optimization-based bounds tightening (OBBT) available in Pyomo, this presolver will tighten the bounds on the non-anticipative variables by default, however, the user can specify the --full-obbt command line option to run OBBT on all variables.

If the non-anticipative variables have different bounds, the bounds among the non-anticipative variables will be synchronized to utilize the tightest available bound.

Further, there are options to specify solver and solver-specific options in presolve_args for the user.

@bknueven
Copy link
Collaborator

We should add a test to the examples which exercises this functionality. Maybe SSLP?

@bknueven bknueven requested a review from DLWoodruff August 20, 2025 20:37
Copy link
Collaborator

@DLWoodruff DLWoodruff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty great. I had a few minor comments embedded.
You should add a one paragraph section to the bottom of generic_cylinders.rst and in that paragraph you should mention that the presolve does not work with persistent solvers. (aside: I just put in my (long) todo list an item to add a pickle-after-presolve option that would pickle the presolved scenarios and shut down (I think it might be too difficult to allow one solver for presolve and another for the rest))

@@ -278,6 +278,28 @@ def popular_args(self):
domain=str,
default='')

def presolve_args(self):
self.add_to_config("obbt",
description="Use OBBT presolver",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this description should be changed to "Use the optimization based bounds tightening as part of the presolver" and maybe in all other descriptions, "OBBT" should be replaced with "OBBT/FBBT"
Also, look at this in config.py:
self.add_to_config("presolve",
description="Run the distributed presolver. "
"Currently only does distributed feasibility-based bounds tightening.",

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other descriptions are OBBT specific, did not make changes to those.

@@ -112,7 +98,7 @@ def presolve(self):

# update the bounds if changed
for sub_n, _, k, s in self.opt.subproblem_scenario_generator():
feas_tol = self.subproblem_tighteners[sub_n].config.feasibility_tol
feas_tol = 1e-8 #self.subproblem_tighteners[sub_n].config.feasibility_tol
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uncool (but you already knew that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added subproblem_tighteners as a property so that we are able to pickup feasibility_tol from the object itself, since SPOBBT uses SPFBBT as an object.

# TODO: this will create the solver twice, once here and again
# before the first solve ... need to resolve this issue
self.solver = obbt_options.get("solver_name", self.opt.options["solver_name"])
self.solver_options = obbt_options.get("solver_options")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh. Through no fault of this PR, solver options are not what they should be. I'm pretty sure that cfg.max_solver_threads needs to be explicitly picked up here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done to allow the use of GAMS solver options, which is done differently.

@aasgerr
Copy link
Contributor Author

aasgerr commented Aug 26, 2025

I have added documentation for presolve (FBBT and OBBT) in generic_cylinders.rst

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.

3 participants