Source code for benderslib.benders.logicbased

# coding:utf-8
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2021-2026 Peng-Hui Guo <[email protected]>

import inspect
from typing import Callable, Type

from ..core import (
    BendersParams,
    MasterProblem,
    SubProblem,
    SubProblems,
    BendersSolver,
    LogicBasedSubProblem,
    CutGenerator,
    _FuncWrapperSub
)


[docs] class LogicBasedBenders(BendersSolver): """An implementation of :doc:`../tutorials/lbbd`. The Logic-based Benders Decomposition is highly customizable. When using non-standard solvers that are not natively supported by BendersLib (typically heuristics or exact algorithms), users need to define their own subproblem, inheriting from :class:`LogicBasedSubProblem`. Users also need to implement their own optimality/feasibility cut generator, inheriting from :class:`CutGenerator`. Parameters ---------- master_problem : MasterProblem An instance of :class:`MasterProblem` representing the master problem. sub_problem : LogicBasedSubProblem | SubProblem | Callable | SubProblems An instance of :class:`LogicBasedSubProblem` representing the subproblem. Alternatively, users can provide a function that takes the values of complicating variables as input and returns the optimal objective value and cut information. complicating_vars : list[str] A list of names of the complicating variables. optimality_cut : Type[CutGenerator] | Callable | None, optional A class inheriting from :class:`CutGenerator` (or a function) to generate optimality cuts. If not provided, no optimality cut will be added. feasibility_cut : Type[CutGenerator] | Callable | None, optional A class inheriting from :class:`CutGenerator` (or a function) to generate feasibility cuts. If not provided, no feasibility cut will be added. params : BendersParams, optional An instance of :class:`BendersParams` containing parameters for the Benders decomposition process. If not provided, default parameters will be used. Example ---------- .. code-block:: python from benderslib import LogicBasedBenders, MasterProblem, LogicBasedSubProblem, CutGenerator from benderslib.solvers import Gurobi # Define master problem model master_model = ... # Define your master problem model here mp = MasterProblem(Gurobi(master_model)) # Define a custom logic-based subproblem class MyLogicBasedSubProblem(LogicBasedSubProblem): def solve(): # Implement the logic to solve the subproblem given the complicating variable values self.status = ... self.obj = ... self.var_values = ... sp = MyLogicBasedSubProblem() # Define a custom optimality cut generator class MyOptimalityCutGenerator(CutGenerator): def generate_cut(self, master_solution, subproblem): cuts = [] # Implement the logic to generate an optimality cut cut = ... cuts.append(cut) return cuts # Define complicating variables complicating_vars = ['x1', 'x2', 'x3'] # Initialize and solve BD = LogicBasedBenders(mp, sp, complicating_vars, optimality_cut=MyOptimalityCutGenerator) BD.solve() """ def __init__( self, master_problem: MasterProblem, sub_problem: LogicBasedSubProblem | SubProblem | Callable | SubProblems, complicating_vars: list[str], optimality_cut: Type[CutGenerator] | Callable | None = None, feasibility_cut: Type[CutGenerator] | Callable | None = None, params: BendersParams | None = None ): if inspect.isfunction(sub_problem): sub_problem = _FuncWrapperSub(complicating_vars, sub_problem) super().__init__( master_problem, sub_problem, complicating_vars, optimality_cut, feasibility_cut, params )