Source code for pyomo.contrib.gdpopt.GDPopt

#  ___________________________________________________________________________
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2022
#  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.
#  ___________________________________________________________________________

"""Main driver module for GDPopt solver.

22.5.13 changes:
- rewrite of all algorithms
- deprecate 'strategy' in favor of 'algorithm'
- deprecate 'init_strategy' in favor of 'init_algorithm'
20.2.28 changes:
- bugfixes on tests
20.1.22 changes:
- improved subsolver time limit support for GAMS interface
- add maxTimeLimit exit condition for GDPopt-LBB
- add token Big M for reactivated constraints in GDPopt-LBB
- activate fbbt for branch-and-bound nodes
20.1.15 changes:
- internal cleanup of codebase
- merge GDPbb capabilities (logic-based branch and bound)
- refactoring of GDPbb code
- update logging information to include subsolver options
- improve SuppressInfeasibleWarning
- simplify mip preprocessing
- remove not-fully-implemented 'backtracking' from LOA
19.10.11 changes:
- bugfix on SolverStatus error message
19.5.13 changes:
- add handling to integer cuts for disjunct pruning during FBBT
19.4.23 changes:
- add support for linear subproblems
- use automatic differentiation for large constraints
- bugfixes on time limit support
- treat fixed variables as constants in GLOA cut generation
19.3.25 changes:
- add rudimentary time limit support
- start keeping basic changelog

from pyomo.common.config import document_kwargs_from_configdict, ConfigDict
from pyomo.contrib.gdpopt import __version__
from pyomo.contrib.gdpopt.config_options import (
from pyomo.opt.base import SolverFactory

def _handle_strategy_deprecation(config):
    # This method won't be needed when the strategy arg is removed, but for now,
    # we need to copy it over as algorithm. The config system already gave the
    # deprecation warning.
    if config.algorithm is None and config.strategy is not None:
        config.algorithm = config.strategy

[docs]@SolverFactory.register( 'gdpopt', doc='The GDPopt decomposition-based ' 'Generalized Disjunctive Programming (GDP) solver', ) class GDPoptSolver(object): """Decomposition solver for Generalized Disjunctive Programming (GDP) problems. The GDPopt (Generalized Disjunctive Programming optimizer) solver applies a variety of decomposition-based approaches to solve Generalized Disjunctive Programming (GDP) problems. GDP models can include nonlinear, continuous variables and constraints, as well as logical conditions. These approaches include: - Logic-based outer approximation (LOA) - Logic-based branch-and-bound (LBB) - Partial surrogate cuts [pending] - Generalized Bender decomposition [pending] This solver implementation was developed by Carnegie Mellon University in the research group of Ignacio Grossmann. For nonconvex problems, LOA may not report rigorous lower/upper bounds. Questions: Please make a post at StackOverflow and/or contact Qi Chen <> or David Bernal <>. Several key GDPopt components were prototyped by BS and MS students: - Logic-based branch and bound: Sunjeev Kale - MC++ interface: Johnny Bates - LOA set-covering initialization: Eloy Fernandez - Logic-to-linear transformation: Romeo Valentin """ CONFIG = ConfigDict("GDPopt") _add_common_configs(CONFIG)
[docs] @document_kwargs_from_configdict(CONFIG) def solve(self, model, **kwds): """Solve the model. Args: model (Block): a Pyomo model or block to be solved """ # The algorithm should have been specified as an argument to the solve # method. We will instantiate an ephemeral instance of the correct # solver and call its solve method. options = kwds.pop('options', {}) config = self.CONFIG(options, preserve_implicit=True) # Don't complain about extra things, they aren't for us. We just need to # get the algorithm and then our job is done. config.set_value(kwds, skip_implicit=True) alg_config = _get_algorithm_config()(options, preserve_implicit=True) alg_config.set_value(kwds, skip_implicit=True) _handle_strategy_deprecation(alg_config) algorithm = alg_config.algorithm if algorithm is None: raise ValueError( "No algorithm was specified to the solve method. " "Please specify an algorithm or use an " "algorithm-specific solver." ) # get rid of 'algorithm' and 'strategy' if they exist so that the solver # can validate. kwds.pop('algorithm', None) kwds.pop('strategy', None) # The algorithm has already been validated, so this will work. return SolverFactory(_supported_algorithms[algorithm][0]).solve(model, **kwds)
# Support use as a context manager under current solver API def __enter__(self): return self def __exit__(self, t, v, traceback): pass
[docs] def available(self, exception_flag=True): """Solver is always available. Though subsolvers may not be, they will raise an error when the time comes. """ return True
def license_is_valid(self): return True
[docs] def version(self): """Return a 3-tuple describing the solver version.""" return __version__
_metasolver = False