Skip to content

Generate Logic-Based Discrete Benders Decomposition - #1

Open
AlbertLee125 wants to merge 7 commits into
mainfrom
ldbd_dev
Open

Generate Logic-Based Discrete Benders Decomposition#1
AlbertLee125 wants to merge 7 commits into
mainfrom
ldbd_dev

Conversation

@AlbertLee125

Copy link
Copy Markdown
Owner

I have generated the ldbd.py based on Zedong's LD-SDA code. The codes have room to improve by setting the format and setting up some of the configuration for the application. I desparately need help from everyone.

CONFIG, default_nlp_init_method=restore_vars_to_original_values
)
_add_tolerance_configs(CONFIG)
_add_ldsda_configs(CONFIG)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You might also need to add configs for LDBD.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

like

_add_ldbd_configs(CONFIG)

?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes, if you need it.

# iteration = 1
# Main loop for generating Benders cuts and solving the master problem
if 'tolerance' not in config:
config.declare('tolerance', ConfigValue(default=1e-5, domain=float, description="Convergence tolerance"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Check if we can use the bound tolerance.

objective_value = value(self.master_problem.z)

# Optionally, print the values for debugging
print(f"Solved master problem. Objective value (z): {objective_value}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Replace print with logging.

Ensure that we use the correct solver, like Gurobi, for the master problem.
"""
# Ensure that we are using the correct solver for the master problem
milp_solver = config.mip_solver if config.mip_solver else "gurobi"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Since the default value of config.mip_solver is gurobi, we can remove the check here.

Comment thread pyomo/contrib/gdpopt/ldbd.py Outdated
# subproblem_model.pprint() # Display all model components before solving

# Step 5: Solve the subproblem using Gurobi
solver = SolverFactory('gurobi')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Use config.mip_solver.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Or create a new config for this.


# Step 6: Solve the subproblem for the newly generated external variable values
# Evaluate the subproblem objective value for the new external variable values from the master problem
primal_improved, new_sub_obj_value = self._solve_GDP_subproblem(external_var_values, 'Benders cut generation', config)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It might be better to set the search type to 'Benders iteration' or 'Benders subproblem', instead of 'Benders cut generation'.

logger.info(f"z_value: {z_value}, subproblem objective: {new_sub_obj_value}, z_diff: {z_diff}")

# If the solution converged, stop the loop
if z_diff <= tolerance:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Use self.LB and self.UB and move the bound check in the self.any_termination_criterion_met method.

Comment thread pyomo/contrib/gdpopt/ldbd.py Outdated
TransformationFactory('contrib.detect_fixed_vars').apply_to(subproblem)
TransformationFactory('contrib.propagate_fixed_vars').apply_to(subproblem)
TransformationFactory('contrib.deactivate_trivial_constraints').apply_to(subproblem, tmp=False, ignore_infeasible=False)
TransformationFactory('gdp.bigm').apply_to(subproblem)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Move bigm reformulation before fbbt.

self.explored_point_dict = {}

# Debugging: Print or log the initial current point, explored set, and explored dictionary
print(f"Initial current point: {self.current_point}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You can use logger.debug for the debugging output.

for i, external_var_info in enumerate(util_block.external_var_info_list):
var_name = f'external_var_{i}'
initial_value = self.current_point[i] # Set initial point value for first iteration
var = Var(within=NonNegativeIntegers, bounds=(external_var_info.LB, external_var_info.UB), initialize=initial_value)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this (including the following setattr) is too complicated. I personally don't care about the names of the variables here. Do you use the name external_var_{i} somewhere else in the code?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You can define a list of variables like
subproblem_model.p = Var(range(num_disjunctions), within=Reals, initialize=0.0), since you already know the number of the variables.
Then set the initial value, LB and UB one by one.

@AlbertLee125 AlbertLee125 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

m = build_model()
    pyo.SolverFactory("gdpopt.ldbd").solve(
        m,
        minlp_solver="gams",
        minlp_solver_args=dict(
            solver="knitro",
            add_options=["option optcr=0.001;"],
            # tee=True,
            keepfiles=True,
        ),
        starting_point=[3, 3, 3],
        logical_constraint_list=[
            m.lim["mixer"].name,
            m.lim["reactor"].name,
            m.lim["centrifuge"].name,
        ],
        direction_norm="Linf",
        tee=True,
        infinity_output=1e+8
    )

This is the input how I ran the small batch. I think it is good to know. I just wrote it on the Pull Request. And the config infinity_output is the value that replaces infinity. The code is designed for the minimizatioin problem. I will make a option for the minimization problem.

AlbertLee125 pushed a commit that referenced this pull request Feb 3, 2026
Removed the tabulate dependency and replaced it with simple logger output.
Fixed _solve_GDP_subproblem so primal_bound is None when the solver fails (not just on preprocessing infeasibility).
AlbertLee125 pushed a commit that referenced this pull request Feb 11, 2026
AlbertLee125 pushed a commit that referenced this pull request Feb 19, 2026
* TXP-7757: removed most deprecation warnings up to current unpublished release

* Fixed more warnings

* Missing version agnostic functions

* Fixed version specific LPStatus enums + renamed get-lb/ub methods

* Suggested improvements
AlbertLee125 pushed a commit that referenced this pull request Feb 19, 2026
[Xpress] Remove deprecation warnings (#1)
AlbertLee125 pushed a commit that referenced this pull request Apr 16, 2026
Fix no results returned when no discrete variables are present in Min…
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.

4 participants