Source code for pyomo.contrib.gdpopt.ric

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

from pyomo.common.config import document_kwargs_from_configdict
from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm
from pyomo.contrib.gdpopt.config_options import (
    _add_mip_solver_configs,
    _add_nlp_solver_configs,
    _add_tolerance_configs,
    _add_oa_configs,
)
from pyomo.contrib.gdpopt.create_oa_subproblems import (
    _get_discrete_problem_and_subproblem,
)
from pyomo.contrib.gdpopt.oa_algorithm_utils import _OAAlgorithmMixIn
from pyomo.contrib.gdpopt.cut_generation import add_no_good_cut
from pyomo.contrib.gdpopt.solve_discrete_problem import solve_MILP_discrete_problem
from pyomo.contrib.gdpopt.util import time_code
from pyomo.core import Objective
from pyomo.opt.base import SolverFactory

# ESJ: In the future, if we have a direct interface to cplex or gurobi, we
# should get the integer solutions several-at-a-time with a solution pool or
# something of the like...


[docs]@SolverFactory.register( 'gdpopt.ric', doc="The RIC (relaxation with integer cuts) Generalized Disjunctive " "Programming (GDP) solver", ) class GDP_RIC_Solver(_GDPoptAlgorithm, _OAAlgorithmMixIn): """The GDPopt (Generalized Disjunctive Programming optimizer) relaxation with integer cuts (RIC) solver. Accepts models that can include nonlinear, continuous variables and constraints, as well as logical conditions. For non-convex problems, RIC will not be exact unless the NLP subproblems are solved globally. """ CONFIG = _GDPoptAlgorithm.CONFIG() _add_mip_solver_configs(CONFIG) _add_nlp_solver_configs(CONFIG, default_solver='ipopt') _add_tolerance_configs(CONFIG) _add_oa_configs(CONFIG) algorithm = 'RIC' # Override solve() to customize the docstring for this solver
[docs] @document_kwargs_from_configdict(CONFIG, doc=_GDPoptAlgorithm.solve.__doc__) def solve(self, model, **kwds): return super().solve(model, **kwds)
def _solve_gdp(self, original_model, config): logger = config.logger (discrete_problem_util_block, subproblem_util_block) = ( _get_discrete_problem_and_subproblem(self, config) ) discrete_problem = discrete_problem_util_block.parent_block() subproblem = subproblem_util_block.parent_block() discrete_problem_obj = next( discrete_problem.component_data_objects( Objective, active=True, descend_into=True ) ) self._log_header(logger) # main loop while not config.iterlim or self.iteration < config.iterlim: self.iteration += 1 # solve linear discrete problem with time_code(self.timing, 'mip'): mip_feasible = solve_MILP_discrete_problem( discrete_problem_util_block, self, config ) self._update_bounds_after_discrete_problem_solve( mip_feasible, discrete_problem_obj, logger ) # Check termination conditions if self.any_termination_criterion_met(config): break with time_code(self.timing, 'nlp'): self._fix_discrete_soln_solve_subproblem_and_add_cuts( discrete_problem_util_block, subproblem_util_block, config ) # Add integer cut with time_code(self.timing, "integer cut generation"): add_no_good_cut(discrete_problem_util_block, config) # Check termination conditions if self.any_termination_criterion_met(config): break def _add_cuts_to_discrete_problem( self, subproblem_util_block, discrete_problem_util_block, objective_sense, config, timing, ): # Nothing to do here pass