Example #1
0
    def test_PathList(self):
        def norm(x):
            if cwd[1] == ':' and x[0] == '/':
                x = cwd[:2] + x
            return x.replace('/',os.path.sep)
        cwd = os.getcwd() + os.path.sep
        c = ConfigBlock()

        c.declare('a', ConfigValue(None, PathList()))
        self.assertEqual(c.a, None)
        c.a = "/a/b/c"
        self.assertEqual(len(c.a), 1)
        self.assertTrue(os.path.sep in c.a[0])
        self.assertEqual(c.a[0], norm('/a/b/c'))

        c.a = ["a/b/c", "/a/b/c", "${CWD}/a/b/c"]
        self.assertEqual(len(c.a), 3)
        self.assertTrue(os.path.sep in c.a[0])
        self.assertEqual(c.a[0], norm(cwd+'a/b/c'))
        self.assertTrue(os.path.sep in c.a[1])
        self.assertEqual(c.a[1], norm('/a/b/c'))
        self.assertTrue(os.path.sep in c.a[2])
        self.assertEqual(c.a[2], norm(cwd+'a/b/c'))

        c.a = ()
        self.assertEqual(len(c.a), 0)
        self.assertIs(type(c.a), list)
Example #2
0
    def test_In(self):
        c = ConfigBlock()
        c.declare('a', ConfigValue(None, In([1,3,5])))
        self.assertEqual(c.a, None)
        c.a = 3
        self.assertEqual(c.a, 3)
        with self.assertRaises(ValueError):
            c.a = 2
        self.assertEqual(c.a, 3)
        with self.assertRaises(ValueError):
            c.a = {}
        self.assertEqual(c.a, 3)
        with self.assertRaises(ValueError):
            c.a = '1'
        self.assertEqual(c.a, 3)

        c.declare('b', ConfigValue(None, In([1,3,5], int)))
        self.assertEqual(c.b, None)
        c.b = 3
        self.assertEqual(c.b, 3)
        with self.assertRaises(ValueError):
            c.b = 2
        self.assertEqual(c.b, 3)
        with self.assertRaises(ValueError):
            c.b = {}
        self.assertEqual(c.b, 3)
        c.b = '1'
        self.assertEqual(c.b, 1)
Example #3
0
def default_pyomo_config():
    config = ConfigBlock("Pyomo configuration file")

    config.declare('paranoia_level', ConfigValue(
        0, int,
        'Pyomo paranoia and error checking level',
        """Higher levels of paranoia enable additional error checking and
        warning messages that may assist users in identifying likely
        modeling problems.
        Default=0""",
        visibility=ADVANCED_OPTION ) )

    return config
Example #4
0
 def test_NonNegativeFloat(self):
     c = ConfigBlock()
     c.declare('a', ConfigValue(5, NonNegativeFloat))
     self.assertEqual(c.a, 5)
     c.a = 4.
     self.assertEqual(c.a, 4)
     c.a = 6
     self.assertEqual(c.a, 6)
     c.a = 2.6
     self.assertEqual(c.a, 2.6)
     with self.assertRaises(ValueError):
         c.a = 'a'
     self.assertEqual(c.a, 2.6)
     c.a = 0
     self.assertEqual(c.a, 0)
     with self.assertRaises(ValueError):
         c.a = -4
     self.assertEqual(c.a, 0)
Example #5
0
 def test_NonPositiveFloat(self):
     c = ConfigBlock()
     c.declare('a', ConfigValue(-5, NonPositiveFloat))
     self.assertEqual(c.a, -5)
     c.a = -4.
     self.assertEqual(c.a, -4)
     c.a = -6
     self.assertEqual(c.a, -6)
     c.a = -2.6
     self.assertEqual(c.a, -2.6)
     with self.assertRaises(ValueError):
         c.a = 'a'
     self.assertEqual(c.a, -2.6)
     c.a = 0
     self.assertEqual(c.a, 0)
     with self.assertRaises(ValueError):
         c.a = 4
     self.assertEqual(c.a, 0)
Example #6
0
def _get_GDPopt_config():
    _supported_strategies = {
        'LOA',  # Logic-based outer approximation
        'GLOA',  # Global logic-based outer approximation
        'LBB',  # Logic-based branch-and-bound
        'RIC',  # Relaxation with Integer Cuts
    }
    CONFIG = ConfigBlock("GDPopt")
    CONFIG.declare(
        "iterlim",
        ConfigValue(default=100,
                    domain=NonNegativeInt,
                    description="Iteration limit."))
    CONFIG.declare(
        "time_limit",
        ConfigValue(
            default=600,
            domain=PositiveInt,
            description="Time limit (seconds, default=600)",
            doc="Seconds allowed until terminated. Note that the time limit can "
            "currently only be enforced between subsolver invocations. You may "
            "need to set subsolver time limits as well."))
    CONFIG.declare(
        "strategy",
        ConfigValue(default=None,
                    domain=In(_supported_strategies),
                    description="Decomposition strategy to use."))
    CONFIG.declare(
        "tee",
        ConfigValue(default=False,
                    description="Stream output to terminal.",
                    domain=bool))
    CONFIG.declare(
        "logger",
        ConfigValue(
            default='pyomo.contrib.gdpopt',
            description="The logger object or name to use for reporting.",
            domain=a_logger))
    _add_OA_configs(CONFIG)
    _add_BB_configs(CONFIG)
    _add_subsolver_configs(CONFIG)
    _add_tolerance_configs(CONFIG)
    return CONFIG
Example #7
0
 def test_NegativeInt(self):
     c = ConfigBlock()
     c.declare('a', ConfigValue(-5, NegativeInt))
     self.assertEqual(c.a, -5)
     c.a = -4.
     self.assertEqual(c.a, -4)
     c.a = -6
     self.assertEqual(c.a, -6)
     with self.assertRaises(ValueError):
         c.a = -2.6
     self.assertEqual(c.a, -6)
     with self.assertRaises(ValueError):
         c.a = 'a'
     self.assertEqual(c.a, -6)
     with self.assertRaises(ValueError):
         c.a = 0
     self.assertEqual(c.a, -6)
     with self.assertRaises(ValueError):
         c.a = 4
     self.assertEqual(c.a, -6)
Example #8
0
 def test_PositiveInt(self):
     c = ConfigBlock()
     c.declare('a', ConfigValue(5, PositiveInt))
     self.assertEqual(c.a, 5)
     c.a = 4.
     self.assertEqual(c.a, 4)
     c.a = 6
     self.assertEqual(c.a, 6)
     with self.assertRaises(ValueError):
         c.a = 2.6
     self.assertEqual(c.a, 6)
     with self.assertRaises(ValueError):
         c.a = 'a'
     self.assertEqual(c.a, 6)
     with self.assertRaises(ValueError):
         c.a = 0
     self.assertEqual(c.a, 6)
     with self.assertRaises(ValueError):
         c.a = -4
     self.assertEqual(c.a, 6)
Example #9
0
def default_config_block(solver, init=False):
    config, blocks = ProblemConfigFactory('default').config_block(init)

    #
    # Solver
    #
    solver = ConfigBlock()
    solver.declare('solver name', ConfigValue(
                'glpk',
                str,
                'Solver name',
                None) )
    solver.declare('solver executable', ConfigValue(
        default=None,
        domain=str,
        description="The solver executable used by the solver interface.",
        doc=("The solver executable used by the solver interface. "
             "This option is only valid for those solver interfaces that "
             "interact with a local executable through the shell. If unset, "
             "the solver interface will attempt to find an executable within "
             "the search path of the shell's environment that matches a name "
             "commonly associated with the solver interface.")))
    solver.declare('io format', ConfigValue(
                None,
                str,
                'The type of IO used to execute the solver. Different solvers support different types of IO, but the following are common options: lp - generate LP files, nl - generate NL files, python - direct Python interface, os - generate OSiL XML files.',
                None) )
    solver.declare('manager', ConfigValue(
                'serial',
                str,
                'The technique that is used to manage solver executions.',
                None) )
    solver.declare('options', ConfigBlock(
                implicit=True,
                implicit_domain=ConfigValue(
                    None,
                    str,
                    'Solver option',
                    None),
                description="Options passed into the solver") )
    solver.declare('options string', ConfigValue(
                None,
                str,
                'String describing solver options',
                None) )
    solver.declare('suffixes', ConfigList(
                [],
                ConfigValue(None, str, 'Suffix', None),
                'Solution suffixes that will be extracted by the solver (e.g., rc, dual, or slack). The use of this option is not required when a suffix has been declared on the model using Pyomo\'s Suffix component.',
                None) )
    blocks['solver'] = solver
    #
    solver_list = config.declare('solvers', ConfigList(
                [],
                solver, #ConfigValue(None, str, 'Solver', None),
                'List of solvers.  The first solver in this list is the master solver.',
                None) )
    #
    # Make sure that there is one solver in the list.
    #
    # This will be the solver into which we dump command line options.
    # Note that we CANNOT declare the argparse options on the base block
    # definition above, as we use that definition as the DOMAIN TYPE for
    # the list of solvers.  As that information is NOT copied to
    # derivative blocks, the initial solver entry we are creating would
    # be missing all argparse information. Plus, if we were to have more
    # than one solver defined, we wouldn't want command line options
    # going to both.
    solver_list.append()
    solver_list[0].get('solver name').\
        declare_as_argument('--solver', dest='solver')
    solver_list[0].get('solver executable').\
        declare_as_argument('--solver-executable',
                            dest="solver_executable", metavar="FILE")
    solver_list[0].get('io format').\
        declare_as_argument('--solver-io', dest='io_format', metavar="FORMAT")
    solver_list[0].get('manager').\
        declare_as_argument('--solver-manager', dest="smanager_type",
                            metavar="TYPE")
    solver_list[0].get('options string').\
        declare_as_argument('--solver-options', dest='options_string',
                            metavar="STRING")
    solver_list[0].get('suffixes').\
        declare_as_argument('--solver-suffix', dest="solver_suffixes")

    #
    # Postprocess
    #
    config.declare('postprocess', ConfigList(
                [],
                ConfigValue(None, str, 'Module', None),
                'Specify a Python module that gets executed after optimization.',
                None) ).declare_as_argument(dest='postprocess')

    #
    # Postsolve
    #
    postsolve = config.declare('postsolve', ConfigBlock())
    postsolve.declare('print logfile', ConfigValue(
                False,
                bool,
                'Print the solver logfile after performing optimization.',
                None) ).declare_as_argument('-l', '--log', dest="log")
    postsolve.declare('save results', ConfigValue(
                None,
                str,
                'Specify the filename to which the results are saved.',
                None) ).declare_as_argument('--save-results', dest="save_results", metavar="FILE")
    postsolve.declare('show results', ConfigValue(
                False,
                bool,
                'Print the results object after optimization.',
                None) ).declare_as_argument(dest="show_results")
    postsolve.declare('results format', ConfigValue(
        None,
        str,
        'Specify the results format:  json or yaml.',
        None)
    ).declare_as_argument(
        '--results-format', dest="results_format", metavar="FORMAT"
    ).declare_as_argument(
        '--json', dest="results_format", action="store_const",
        const="json", help="Store results in JSON format")
    postsolve.declare('summary', ConfigValue(
                False,
                bool,
                'Summarize the final solution after performing optimization.',
                None) ).declare_as_argument(dest="summary")
    blocks['postsolve'] = postsolve

    #
    # Runtime
    #
    runtime = blocks['runtime']
    runtime.declare('only instance', ConfigValue(
                False,
                bool,
                "Generate a model instance, and then exit",
                None) ).declare_as_argument('--instance-only', dest='only_instance')
    runtime.declare('stream output', ConfigValue(
                False,
                bool,
                "Stream the solver output to provide information about the solver's progress.",
                None) ).declare_as_argument('--stream-output', '--stream-solver', dest="tee")
    #
    return config, blocks
Example #10
0
    def test_Path(self):
        def norm(x):
            if cwd[1] == ':' and x[0] == '/':
                x = cwd[:2] + x
            return x.replace('/',os.path.sep)
        cwd = os.getcwd() + os.path.sep
        c = ConfigBlock()

        c.declare('a', ConfigValue(None, Path()))
        self.assertEqual(c.a, None)
        c.a = "/a/b/c"
        self.assertTrue(os.path.sep in c.a)
        self.assertEqual(c.a, norm('/a/b/c'))
        c.a = "a/b/c"
        self.assertTrue(os.path.sep in c.a)
        self.assertEqual(c.a, norm(cwd+'a/b/c'))
        c.a = "${CWD}/a/b/c"
        self.assertTrue(os.path.sep in c.a)
        self.assertEqual(c.a, norm(cwd+'a/b/c'))
        c.a = None
        self.assertIs(c.a, None)

        c.declare('b', ConfigValue(None, Path('rel/path')))
        self.assertEqual(c.b, None)
        c.b = "/a/b/c"
        self.assertTrue(os.path.sep in c.b)
        self.assertEqual(c.b, norm('/a/b/c'))
        c.b = "a/b/c"
        self.assertTrue(os.path.sep in c.b)
        self.assertEqual(c.b, norm(cwd+'rel/path/a/b/c'))
        c.b = "${CWD}/a/b/c"
        self.assertTrue(os.path.sep in c.b)
        self.assertEqual(c.b, norm(cwd+'a/b/c'))
        c.b = None
        self.assertIs(c.b, None)

        c.declare('c', ConfigValue(None, Path('/my/dir')))
        self.assertEqual(c.c, None)
        c.c = "/a/b/c"
        self.assertTrue(os.path.sep in c.c)
        self.assertEqual(c.c, norm('/a/b/c'))
        c.c = "a/b/c"
        self.assertTrue(os.path.sep in c.c)
        self.assertEqual(c.c, norm('/my/dir/a/b/c'))
        c.c = "${CWD}/a/b/c"
        self.assertTrue(os.path.sep in c.c)
        self.assertEqual(c.c, norm(cwd+'a/b/c'))
        c.c = None
        self.assertIs(c.c, None)

        c.declare('d_base', ConfigValue("${CWD}", str))
        c.declare('d', ConfigValue(None, Path(c.get('d_base'))))
        self.assertEqual(c.d, None)
        c.d = "/a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm('/a/b/c'))
        c.d = "a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm(cwd+'a/b/c'))
        c.d = "${CWD}/a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm(cwd+'a/b/c'))
        
        c.d_base = '/my/dir'
        c.d = "/a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm('/a/b/c'))
        c.d = "a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm('/my/dir/a/b/c'))
        c.d = "${CWD}/a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm(cwd+'a/b/c'))

        c.d_base = 'rel/path'
        c.d = "/a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm('/a/b/c'))
        c.d = "a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm(cwd+'rel/path/a/b/c'))
        c.d = "${CWD}/a/b/c"
        self.assertTrue(os.path.sep in c.d)
        self.assertEqual(c.d, norm(cwd+'a/b/c'))

        try:
            Path.SuppressPathExpansion = True
            c.d = "/a/b/c"
            self.assertTrue('/' in c.d)
            self.assertTrue('\\' not in c.d)
            self.assertEqual(c.d, '/a/b/c')
            c.d = "a/b/c"
            self.assertTrue('/' in c.d)
            self.assertTrue('\\' not in c.d)
            self.assertEqual(c.d, 'a/b/c')
            c.d = "${CWD}/a/b/c"
            self.assertTrue('/' in c.d)
            self.assertTrue('\\' not in c.d)
            self.assertEqual(c.d, "${CWD}/a/b/c")
        finally:
            Path.SuppressPathExpansion = False
Example #11
0
    # Rule to calculate am for cubic equations of state
    default = 0


class MixingRuleB(Enum):
    # Rule to calculate bm for cubic equations of state
    default = 0


# Value for smoothing epsilon for SafeLog when used
eps_SL = 1E-8

CubicConfig = ConfigBlock()
CubicConfig.declare(
    "type",
    ConfigValue(domain=In(CubicType),
                description="Equation of state to use",
                doc="Enum indicating type of cubic equation of state to use."))
CubicConfig.declare(
    "mixing_rule_a",
    ConfigValue(
        default=MixingRuleA.default,
        domain=In(MixingRuleA),
        description="Mixing rule for parameter am for cubic EoS",
        doc="Enum indicating type of mixing rule for parameter am to use."))
CubicConfig.declare(
    "mixing_rule_b",
    ConfigValue(
        default=MixingRuleB.default,
        domain=In(MixingRuleB),
        description="Mixing rule for parameter bm for cubic EoS",
Example #12
0
class _ECPBounder(OptSolver):
    """
    This class is used for testing
    """
    def __init__(self, subproblem_solver):
        self._subproblem_solver = pe.SolverFactory(subproblem_solver)
        if isinstance(self._subproblem_solver, PersistentSolver):
            self._using_persistent_solver = True
        else:
            self._using_persistent_solver = False
        self._relaxations = ComponentSet()
        self._relaxations_not_tracking_solver = ComponentSet()
        self._relaxations_with_added_cuts = ComponentSet()
        self._pyomo_model = None

        self.options = ConfigBlock()
        self.options.declare(
            'feasibility_tol',
            ConfigValue(default=1e-6,
                        domain=NonNegativeFloat,
                        doc='Tolerance below which cuts will not be added'))
        self.options.declare(
            'max_iter',
            ConfigValue(default=30,
                        domain=NonNegativeInt,
                        doc='Maximum number of iterations'))
        self.options.declare(
            'keep_cuts',
            ConfigValue(
                default=False,
                domain=In([True, False]),
                doc='Whether or not to keep the cuts generated after the solve'
            ))
        self.options.declare(
            'time_limit',
            ConfigValue(default=float('inf'),
                        domain=NonNegativeFloat,
                        doc='Time limit in seconds'))

        self.subproblem_solver_options = ConfigBlock(implicit=True)

    def solve(self, *args, **kwargs):
        t0 = time.time()
        logger.info('{0:<10}{1:<12}{2:<12}{3:<12}{4:<12}'.format(
            'Iter', 'objective', 'max_viol', 'time', '# cuts'))

        if not self._using_persistent_solver:
            self._pyomo_model = args[0]

        options = self.options(kwargs.pop('options', dict()))
        subproblem_solver_options = self.subproblem_solver_options(
            kwargs.pop('subproblem_solver_options', dict()))

        obj = None
        for _obj in self._pyomo_model.component_data_objects(pe.Objective,
                                                             descend_into=True,
                                                             active=True,
                                                             sort=True):
            if obj is not None:
                raise ValueError('Found multiple active objectives')
            obj = _obj
        if obj is None:
            raise ValueError('Could not find any active objectives')

        final_res = SolverResults()

        self._relaxations = ComponentSet()
        self._relaxations_not_tracking_solver = ComponentSet()
        self._relaxations_with_added_cuts = ComponentSet()
        for b in self._pyomo_model.component_data_objects(pe.Block,
                                                          descend_into=True,
                                                          active=True,
                                                          sort=True):
            if isinstance(b, (BaseRelaxationData, BaseRelaxation)):
                self._relaxations.add(b)
                if self._using_persistent_solver:
                    if self not in b._persistent_solvers:
                        b.add_persistent_solver(self)
                        self._relaxations_not_tracking_solver.add(b)

        for _iter in range(options.max_iter):
            if time.time() - t0 > options.time_limit:
                final_res.solver.termination_condition = pe.TerminationCondition.maxTimeLimit
                final_res.solver.status = pe.SolverStatus.aborted
                logger.warning('ECPBounder: time limit reached.')
                break
            if self._using_persistent_solver:
                res = self._subproblem_solver.solve(
                    save_results=False, options=subproblem_solver_options)
            else:
                res = self._subproblem_solver.solve(
                    self._pyomo_model, options=subproblem_solver_options)
            if res.solver.termination_condition != pe.TerminationCondition.optimal:
                final_res.solver.termination_condition = pe.TerminationCondition.other
                final_res.solver.status = pe.SolverStatus.aborted
                logger.warning(
                    'ECPBounder: subproblem did not terminate optimally')
                break

            num_cuts_added = 0
            max_viol = 0
            for b in self._relaxations:
                viol = None
                if b.is_rhs_convex():
                    viol = pe.value(b.get_rhs_expr()) - b.get_aux_var().value
                elif b.is_rhs_concave():
                    viol = b.get_aux_var().value - pe.value(b.get_rhs_expr())
                if viol is not None:
                    if viol > max_viol:
                        max_viol = viol
                    if viol > options.feasibility_tol:
                        b.add_cut(keep_cut=options.keep_cuts)
                        self._relaxations_with_added_cuts.add(b)
                        num_cuts_added += 1

            if obj.sense == pe.minimize:
                obj_val = res.problem.lower_bound
                final_res.problem.sense = pe.minimize
                final_res.problem.upper_bound = None
                final_res.problem.lower_bound = obj_val
            else:
                obj_val = res.problem.upper_bound
                final_res.problem.sense = pe.maximize
                final_res.problem.lower_bound = None
                final_res.problem.upper_bound = obj_val
            elapsed_time = time.time() - t0
            logger.info(
                '{0:<10d}{1:<12.3e}{2:<12.3e}{3:<12.3e}{4:<12d}'.format(
                    _iter, obj_val, max_viol, elapsed_time, num_cuts_added))

            if num_cuts_added == 0:
                final_res.solver.termination_condition = pe.TerminationCondition.optimal
                final_res.solver.status = pe.SolverStatus.ok
                logger.info('ECPBounder: converged!')
                break

            if _iter == options.max_iter - 1:
                final_res.solver.termination_condition = pe.TerminationCondition.maxIterations
                final_res.solver.status = pe.SolverStatus.aborted
                logger.warning(
                    'ECPBounder: reached maximum number of iterations')

        if not options.keep_cuts:
            for b in self._relaxations_with_added_cuts:
                b.rebuild()

        if self._using_persistent_solver:
            for b in self._relaxations_not_tracking_solver:
                b.remove_persistent_solver(self)

        final_res.solver.wallclock_time = time.time() - t0
        return final_res
Example #13
0
        'w': -1,
        'omegaA': 0.45724,
        'coeff_b': 0.07780
    },
    CubicType.SRK: {
        'u': 1,
        'w': 0,
        'omegaA': 0.42748,
        'coeff_b': 0.08664
    }
}

CubicConfig = ConfigBlock()
CubicConfig.declare(
    "type",
    ConfigValue(domain=In(CubicType),
                description="Equation of state to use",
                doc="Enum indicating type of cubic equation of state to use."))


class Cubic(EoSBase):
    @staticmethod
    def common(b, pobj):
        ctype = pobj._cubic_type
        cname = pobj.config.equation_of_state_options["type"].name

        if hasattr(b, cname + "_fw"):
            # Common components already constructed by previous phase
            return

        # Create expressions for coefficients
Example #14
0
def minlp_config_block(init=False):
    config = ConfigBlock(
        "Configuration for a canonical model construction and optimization sequence"
    )
    blocks = {}

    #
    # Data
    #
    data = config.declare('data', ConfigBlock())
    data.declare(
        'files',
        ConfigList([], ConfigValue(None, str, 'Filename', None),
                   'Model data files', None))
    data.declare(
        'namespaces',
        ConfigList(
            [], ConfigValue(None, str, 'Namespace', None),
            'A namespace that is used to select data in Pyomo data files.',
            None)).declare_as_argument('--namespace',
                                       dest='namespaces',
                                       action='append')
    blocks['data'] = data

    #
    # Model
    #
    model = config.declare('model', ConfigBlock())
    model.declare(
        'filename',
        ConfigValue(None, str, 'The Python module that specifies the model',
                    None))
    model.declare(
        'object name',
        ConfigValue(
            None, str,
            'The name of the model object that is created in the specified Pyomo module',
            None)).declare_as_argument('--model-name', dest='model_name')
    model.declare('type', ConfigValue(None, str, 'The problem type', None))
    model.declare(
        'options',
        ConfigBlock(implicit=True,
                    description='Options used to construct the model'))
    model.declare(
        'linearize expressions',
        ConfigValue(
            False, bool,
            'An option intended for use on linear or mixed-integer models in which expression trees in a model (constraints or objectives) are compacted into a more memory-efficient and concise form.',
            None))
    model.declare(
        'save file',
        ConfigValue(
            None, str,
            "The filename to which the model is saved. The suffix of this filename specifies the file format.",
            None))
    model.declare(
        'save format',
        ConfigValue(
            None, str,
            "The format that the model is saved. When specified, this overrides the format implied by the 'save file' option.",
            None))
    model.declare(
        'symbolic solver labels',
        ConfigValue(
            False, bool,
            'When interfacing with the solver, use symbol names derived from the model. For example, \"my_special_variable[1_2_3]\" instead of \"v1\". Useful for debugging. When using the ASL interface (--solver-io=nl), generates corresponding .row (constraints) and .col (variables) files. The ordering in these files provides a mapping from ASL index to symbolic model names.',
            None)).declare_as_argument(dest='symbolic_solver_labels')
    model.declare(
        'file determinism',
        ConfigValue(
            1, int,
            'When interfacing with a solver using file based I/O, set the effort level for ensuring the file creation process is determistic. The default (1) sorts the index of components when transforming the model. Anything less than 1 disables index sorting. Anything greater than 1 additionaly sorts by component name to override declartion order.',
            None)).declare_as_argument(dest='file_determinism')
    blocks['model'] = model

    #
    # Transform
    #
    transform = ConfigBlock()
    transform.declare(
        'name', ConfigValue(None, str, 'Name of the model transformation',
                            None))
    transform.declare(
        'options',
        ConfigBlock(implicit=True, description='Transformation options'))
    blocks['transform'] = transform
    #
    transform_list = config.declare(
        'transform',
        ConfigList([], ConfigValue(None, str, 'Transformation',
                                   None), 'List of model transformations',
                   None)).declare_as_argument(dest='transformations',
                                              action='append')
    if init:
        transform_list.append()

    #
    # Preprocess
    #
    config.declare(
        'preprocess',
        ConfigList([], ConfigValue(
            None, str, 'Module', None
        ), 'Specify a Python module that gets immediately executed (before the optimization model is setup).',
                   None)).declare_as_argument(dest='preprocess')

    #
    # Runtime
    #
    runtime = config.declare('runtime', ConfigBlock())
    runtime.declare(
        'logging',
        ConfigValue(None, str,
                    'Logging level:  quiet, warning, info, verbose, debug',
                    None)).declare_as_argument(dest="logging", metavar="LEVEL")
    runtime.declare(
        'logfile',
        ConfigValue(None, str, 'Redirect output to the specified file.',
                    None)).declare_as_argument(dest="output", metavar="FILE")
    runtime.declare(
        'catch errors',
        ConfigValue(
            False, bool,
            'Trigger failures for exceptions to print the program stack.',
            None)).declare_as_argument('-c', '--catch-errors', dest="catch")
    runtime.declare(
        'disable gc',
        ConfigValue(False, bool, 'Disable the garbage collecter.',
                    None)).declare_as_argument('--disable-gc',
                                               dest='disable_gc')
    runtime.declare(
        'interactive',
        ConfigValue(
            False, bool,
            'After executing Pyomo, launch an interactive Python shell. If IPython is installed, this shell is an IPython shell.',
            None))
    runtime.declare('keep files',
                    ConfigValue(False, bool, 'Keep temporary files',
                                None)).declare_as_argument('-k',
                                                           '--keepfiles',
                                                           dest='keepfiles')
    runtime.declare(
        'paths',
        ConfigList([], ConfigValue(None, str, 'Path', None),
                   'Give a path that is used to find the Pyomo python files.',
                   None)).declare_as_argument('--path', dest='path')
    runtime.declare(
        'profile count',
        ConfigValue(
            0, int,
            'Enable profiling of Python code. The value of this option is the number of functions that are summarized.',
            None)).declare_as_argument(dest='profile_count', metavar='COUNT')
    runtime.declare(
        'profile memory',
        ConfigValue(
            0, int,
            "Report memory usage statistics for the generated instance and any associated processing steps. A value of 0 indicates disabled. A value of 1 forces the print of the total memory after major stages of the pyomo script. A value of 2 forces summary memory statistics after major stages of the pyomo script. A value of 3 forces detailed memory statistics during instance creation and various steps of preprocessing. Values equal to 4 and higher currently provide no additional information. Higher values automatically enable all functionality associated with lower values, e.g., 3 turns on detailed and summary statistics.",
            None))
    runtime.declare(
        'report timing',
        ConfigValue(
            False, bool,
            'Report various timing statistics during model construction.',
            None)).declare_as_argument(dest='report_timing')
    runtime.declare(
        'tempdir',
        ConfigValue(
            None, str,
            'Specify the directory where temporary files are generated.',
            None)).declare_as_argument(dest='tempdir')
    blocks['runtime'] = runtime
    #
    return config, blocks
Example #15
0
    # Error message for when a property is called for but no option provided
    def __init__(self, block, prop):
        self.prop = prop
        self.block = block

    def __str__(self):
        return f"Generic Reaction Package instance {self.block} called for " \
               f"{self.prop}, but was not provided with a method " \
               f"for this property. Please add a method for this property " \
               f"in the reaction parameter configuration."


rxn_config = ConfigBlock()
rxn_config.declare(
    "stoichiometry",
    ConfigValue(domain=dict,
                description="Stoichiometry of reaction",
                doc="Dict describing stoichiometry of reaction"))
rxn_config.declare(
    "heat_of_reaction",
    ConfigValue(
        description="Method for calculating specific heat of reaction",
        doc="Valid Python class containing instructions on how to calculate "
        "the heat of reaction for this reaction."))
rxn_config.declare(
    "concentration_form",
    ConfigValue(
        default=None,
        domain=In(ConcentrationForm),
        description="Form to use for concentration terms in reaction equation",
        doc=
Example #16
0
def _get_MindtPy_config():
    """Set up the configurations for MindtPy.

    Returns
    -------
    CONFIG : ConfigBlock
        The specific configurations for MindtPy
    """
    CONFIG = ConfigBlock('MindtPy')

    CONFIG.declare(
        'iteration_limit',
        ConfigValue(
            default=50,
            domain=NonNegativeInt,
            description='Iteration limit',
            doc='Number of maximum iterations in the decomposition methods.'))
    CONFIG.declare(
        'stalling_limit',
        ConfigValue(
            default=15,
            domain=PositiveInt,
            description='Stalling limit',
            doc=
            'Stalling limit for primal bound progress in the decomposition methods.'
        ))
    CONFIG.declare(
        'time_limit',
        ConfigValue(
            default=600,
            domain=PositiveInt,
            description='Time limit (seconds, default=600)',
            doc='Seconds allowed until terminated. Note that the time limit can'
            'currently only be enforced between subsolver invocations. You may'
            'need to set subsolver time limits as well.'))
    CONFIG.declare(
        'strategy',
        ConfigValue(
            default='OA',
            domain=In(['OA', 'ECP', 'GOA', 'FP']),
            description='Decomposition strategy',
            doc='MINLP Decomposition strategy to be applied to the method. '
            'Currently available Outer Approximation (OA), Extended Cutting '
            'Plane (ECP), Global Outer Approximation (GOA) and Feasibility Pump (FP).'
        ))
    CONFIG.declare(
        'add_regularization',
        ConfigValue(
            default=None,
            domain=In([
                'level_L1', 'level_L2', 'level_L_infinity', 'grad_lag',
                'hess_lag', 'hess_only_lag', 'sqp_lag'
            ]),
            description='add regularization',
            doc=
            'Solving a regularization problem before solve the fixed subproblem'
            'the objective function of the regularization problem.'))
    CONFIG.declare(
        'init_strategy',
        ConfigValue(
            default=None,
            domain=In(['rNLP', 'initial_binary', 'max_binary', 'FP']),
            description='Initialization strategy',
            doc='Initialization strategy used by any method. Currently the '
            'continuous relaxation of the MINLP (rNLP), solve a maximal '
            'covering problem (max_binary), and fix the initial value for '
            'the integer variables (initial_binary).'))
    CONFIG.declare(
        'max_slack',
        ConfigValue(
            default=1000.0,
            domain=PositiveFloat,
            description='Maximum slack variable',
            doc=
            'Maximum slack variable value allowed for the Outer Approximation '
            'cuts.'))
    CONFIG.declare(
        'OA_penalty_factor',
        ConfigValue(
            default=1000.0,
            domain=PositiveFloat,
            description='Outer Approximation slack penalty factor',
            doc=
            'In the objective function of the Outer Approximation method, the '
            'slack variables corresponding to all the constraints get '
            'multiplied by this number and added to the objective.'))
    CONFIG.declare(
        'call_after_main_solve',
        ConfigValue(
            default=_DoNothing(),
            domain=None,
            description='Function to be executed after every main problem',
            doc='Callback hook after a solution of the main problem.'))
    CONFIG.declare(
        'call_after_subproblem_solve',
        ConfigValue(
            default=_DoNothing(),
            domain=None,
            description='Function to be executed after every subproblem',
            doc='Callback hook after a solution of the nonlinear subproblem.'))
    CONFIG.declare(
        'call_after_subproblem_feasible',
        ConfigValue(default=_DoNothing(),
                    domain=None,
                    description=
                    'Function to be executed after every feasible subproblem',
                    doc='Callback hook after a feasible solution'
                    ' of the nonlinear subproblem.'))
    CONFIG.declare(
        'tee',
        ConfigValue(default=False,
                    description='Stream output to terminal.',
                    domain=bool))
    CONFIG.declare(
        'logger',
        ConfigValue(
            default='pyomo.contrib.mindtpy',
            description='The logger object or name to use for reporting.',
            domain=a_logger))
    CONFIG.declare(
        'logging_level',
        ConfigValue(
            default=logging.INFO,
            domain=NonNegativeInt,
            description='The logging level for MindtPy.'
            'CRITICAL = 50, ERROR = 40, WARNING = 30, INFO = 20, DEBUG = 10, NOTSET = 0',
        ))
    CONFIG.declare(
        'integer_to_binary',
        ConfigValue(
            default=False,
            description=
            'Convert integer variables to binaries (for no-good cuts).',
            domain=bool))
    CONFIG.declare(
        'add_no_good_cuts',
        ConfigValue(
            default=False,
            description=
            'Add no-good cuts (no-good cuts) to binary variables to disallow same integer solution again.'
            'Note that integer_to_binary flag needs to be used to apply it to actual integers and not just binaries.',
            domain=bool))
    CONFIG.declare(
        'use_tabu_list',
        ConfigValue(
            default=False,
            description=
            'Use tabu list and incumbent callback to disallow same integer solution again.',
            domain=bool))
    CONFIG.declare(
        'add_affine_cuts',
        ConfigValue(default=False,
                    description='Add affine cuts drive from MC++.',
                    domain=bool))
    CONFIG.declare(
        'single_tree',
        ConfigValue(
            default=False,
            description=
            'Use single tree implementation in solving the MIP main problem.',
            domain=bool))
    CONFIG.declare(
        'solution_pool',
        ConfigValue(
            default=False,
            description='Use solution pool in solving the MIP main problem.',
            domain=bool))
    CONFIG.declare(
        'num_solution_iteration',
        ConfigValue(
            default=5,
            description=
            'The number of MIP solutions (from the solution pool) used to generate the fixed NLP subproblem in each iteration.',
            domain=PositiveInt))
    CONFIG.declare(
        'add_slack',
        ConfigValue(
            default=False,
            description='Whether add slack variable here.'
            'slack variables here are used to deal with nonconvex MINLP.',
            domain=bool))
    CONFIG.declare(
        'cycling_check',
        ConfigValue(
            default=True,
            description=
            'Check if OA algorithm is stalled in a cycle and terminate.',
            domain=bool))
    CONFIG.declare(
        'feasibility_norm',
        ConfigValue(
            default='L_infinity',
            domain=In(['L1', 'L2', 'L_infinity']),
            description=
            'Different forms of objective function in feasibility subproblem.')
    )
    CONFIG.declare(
        'differentiate_mode',
        ConfigValue(default='reverse_symbolic',
                    domain=In(['reverse_symbolic', 'sympy']),
                    description='Differentiate mode to calculate jacobian.'))
    CONFIG.declare(
        'linearize_inactive',
        ConfigValue(default=False,
                    description='Add OA cuts for inactive constraints.',
                    domain=bool))
    CONFIG.declare(
        'use_mcpp',
        ConfigValue(
            default=False,
            description=
            "Use package MC++ to set a bound for variable 'objective_value', which is introduced when the original problem's objective function is nonlinear.",
            domain=bool))
    CONFIG.declare(
        'equality_relaxation',
        ConfigValue(
            default=False,
            description=
            'Use dual solution from the NLP solver to add OA cuts for equality constraints.',
            domain=bool))
    CONFIG.declare(
        'calculate_dual',
        ConfigValue(default=False,
                    description='Calculate duals of the NLP subproblem.',
                    domain=bool))
    CONFIG.declare(
        'use_fbbt',
        ConfigValue(default=False,
                    description=
                    'Use fbbt to tighten the feasible region of the problem.',
                    domain=bool))
    CONFIG.declare(
        'use_dual_bound',
        ConfigValue(
            default=True,
            description=
            'Add dual bound constraint to enforce the objective satisfies best-found dual bound.',
            domain=bool))
    CONFIG.declare(
        'heuristic_nonconvex',
        ConfigValue(
            default=False,
            description=
            'Use dual solution from the NLP solver and slack variables to add OA cuts for equality constraints (Equality relaxation)'
            'and minimize the sum of the slack variables (Augmented Penalty).',
            domain=bool))
    CONFIG.declare(
        'partition_obj_nonlinear_terms',
        ConfigValue(
            default=True,
            description=
            'Partition objective with the sum of nonlinear terms using epigraph reformulation.',
            domain=bool))

    _add_subsolver_configs(CONFIG)
    _add_tolerance_configs(CONFIG)
    _add_fp_configs(CONFIG)
    _add_bound_configs(CONFIG)
    _add_loa_configs(CONFIG)
    return CONFIG
Example #17
0
def _get_GDPopt_config():
    CONFIG = ConfigBlock("MindtPy")
    CONFIG.declare("bound_tolerance", ConfigValue(
        default=1E-4,
        domain=PositiveFloat,
        description="Bound tolerance",
        doc="Relative tolerance for bound feasibility checks."
    ))
    CONFIG.declare("iteration_limit", ConfigValue(
        default=50,
        domain=PositiveInt,
        description="Iteration limit",
        doc="Number of maximum iterations in the decomposition methods."
    ))
    CONFIG.declare("stalling_limit", ConfigValue(
        default=15,
        domain=PositiveInt,
        description="Stalling limit",
        doc="Stalling limit for progress in the decomposition methods."
    ))
    CONFIG.declare("time_limit", ConfigValue(
        default=600,
        domain=PositiveInt,
        description="Time limit (seconds, default=600)",
        doc="Seconds allowed until terminated. Note that the time limit can"
            "currently only be enforced between subsolver invocations. You may"
            "need to set subsolver time limits as well."
    ))
    CONFIG.declare("strategy", ConfigValue(
        default="OA",
        domain=In(["OA", "GBD", "ECP", "PSC", "GOA"]),
        description="Decomposition strategy",
        doc="MINLP Decomposition strategy to be applied to the method. "
            "Currently available Outer Approximation (OA), Extended Cutting "
            "Plane (ECP), Partial Surrogate Cuts (PSC), and Generalized "
            "Benders Decomposition (GBD)."
    ))
    CONFIG.declare("init_strategy", ConfigValue(
        default=None,
        domain=In(["rNLP", "initial_binary", "max_binary"]),
        description="Initialization strategy",
        doc="Initialization strategy used by any method. Currently the "
            "continuous relaxation of the MINLP (rNLP), solve a maximal "
            "covering problem (max_binary), and fix the initial value for "
            "the integer variables (initial_binary)."
    ))
    CONFIG.declare("max_slack", ConfigValue(
        default=1000.0,
        domain=PositiveFloat,
        description="Maximum slack variable",
        doc="Maximum slack variable value allowed for the Outer Approximation "
            "cuts."
    ))
    CONFIG.declare("OA_penalty_factor", ConfigValue(
        default=1000.0,
        domain=PositiveFloat,
        description="Outer Approximation slack penalty factor",
        doc="In the objective function of the Outer Approximation method, the "
            "slack variables corresponding to all the constraints get "
            "multiplied by this number and added to the objective."
    ))
    CONFIG.declare("ecp_tolerance", ConfigValue(
        default=None,
        domain=PositiveFloat,
        description="ECP tolerance",
        doc="Feasibility tolerance used to determine the stopping criterion in"
            "the ECP method. As long as nonlinear constraint are violated for "
            "more than this tolerance, the method will keep iterating."
    ))
    CONFIG.declare("nlp_solver", ConfigValue(
        default="ipopt",
        domain=In(["ipopt", "gams", "baron"]),
        description="NLP subsolver name",
        doc="Which NLP subsolver is going to be used for solving the nonlinear"
            "subproblems."
    ))
    CONFIG.declare("nlp_solver_args", ConfigBlock(
        implicit=True,
        description="NLP subsolver options",
        doc="Which NLP subsolver options to be passed to the solver while "
            "solving the nonlinear subproblems."
    ))
    CONFIG.declare("mip_solver", ConfigValue(
        default="glpk",
        domain=In(["gurobi", "cplex", "cbc", "glpk", "gams",
                   "gurobi_persistent", "cplex_persistent"]),
        description="MIP subsolver name",
        doc="Which MIP subsolver is going to be used for solving the mixed-"
            "integer master problems."
    ))
    CONFIG.declare("mip_solver_args", ConfigBlock(
        implicit=True,
        description="MIP subsolver options",
        doc="Which MIP subsolver options to be passed to the solver while "
            "solving the mixed-integer master problems."
    ))
    CONFIG.declare("call_after_master_solve", ConfigValue(
        default=_DoNothing(),
        domain=None,
        description="Function to be executed after every master problem",
        doc="Callback hook after a solution of the master problem."
    ))
    CONFIG.declare("call_after_subproblem_solve", ConfigValue(
        default=_DoNothing(),
        domain=None,
        description="Function to be executed after every subproblem",
        doc="Callback hook after a solution of the nonlinear subproblem."
    ))
    CONFIG.declare("call_after_subproblem_feasible", ConfigValue(
        default=_DoNothing(),
        domain=None,
        description="Function to be executed after every feasible subproblem",
        doc="Callback hook after a feasible solution"
            " of the nonlinear subproblem."
    ))
    CONFIG.declare("tee", ConfigValue(
        default=False,
        description="Stream output to terminal.",
        domain=bool
    ))
    CONFIG.declare("solver_tee", ConfigValue(
        default=False,
        description="Stream the output of mip solver and nlp solver to terminal.",
        domain=bool
    ))
    CONFIG.declare("logger", ConfigValue(
        default='pyomo.contrib.mindtpy',
        description="The logger object or name to use for reporting.",
        domain=a_logger
    ))
    CONFIG.declare("small_dual_tolerance", ConfigValue(
        default=1E-8,
        description="When generating cuts, small duals multiplied "
                    "by expressions can cause problems. Exclude all duals "
                    "smaller in absolute value than the following."
    ))
    CONFIG.declare("integer_tolerance", ConfigValue(
        default=1E-5,
        description="Tolerance on integral values."
    ))
    CONFIG.declare("constraint_tolerance", ConfigValue(
        default=1E-6,
        description="Tolerance on constraint satisfaction."
    ))
    CONFIG.declare("variable_tolerance", ConfigValue(
        default=1E-8,
        description="Tolerance on variable bounds."
    ))
    CONFIG.declare("zero_tolerance", ConfigValue(
        default=1E-7,
        description="Tolerance on variable equal to zero."
    ))
    CONFIG.declare("initial_feas", ConfigValue(
        default=True,
        description="Apply an initial feasibility step.",
        domain=bool
    ))
    CONFIG.declare("obj_bound", ConfigValue(
        default=1E15,
        domain=PositiveFloat,
        description="Bound applied to the linearization of the objective function if master MILP is unbounded."
    ))
    CONFIG.declare("integer_to_binary", ConfigValue(
        default=False,
        description="Convert integer variables to binaries (for integer cuts).",
        domain=bool
    ))
    CONFIG.declare("add_nogood_cuts", ConfigValue(
        default=False,
        description="Add integer cuts (no-good cuts) to binary variables to disallow same integer solution again."
                    "Note that 'integer_to_binary' flag needs to be used to apply it to actual integers and not just binaries.",
        domain=bool
    ))
    CONFIG.declare("single_tree", ConfigValue(
        default=False,
        description="Use single tree implementation in solving the MILP master problem.",
        domain=bool
    ))
    CONFIG.declare("solution_pool", ConfigValue(
        default=False,
        description="Use solution pool in solving the MILP master problem.",
        domain=bool
    ))
    CONFIG.declare("add_slack", ConfigValue(
        default=False,
        description="whether add slack variable here."
                    "slack variables here are used to deal with nonconvex MINLP.",
        domain=bool
    ))
    CONFIG.declare("continuous_var_bound", ConfigValue(
        default=1e10,
        description="default bound added to unbounded continuous variables in nonlinear constraint if single tree is activated.",
        domain=PositiveFloat
    ))
    CONFIG.declare("integer_var_bound", ConfigValue(
        default=1e9,
        description="default bound added to unbounded integral variables in nonlinear constraint if single tree is activated.",
        domain=PositiveFloat
    ))
    CONFIG.declare("cycling_check", ConfigValue(
        default=True,
        description="check if OA algorithm is stalled in a cycle and terminate.",
        domain=bool
    ))
    CONFIG.declare("feasibility_norm", ConfigValue(
        default="L_infinity",
        domain=In(["L1", "L2", "L_infinity"]),
        description="different forms of objective function in feasibility subproblem."
    ))
    CONFIG.declare("differentiate_mode", ConfigValue(
        default="reverse_symbolic",
        domain=In(["reverse_symbolic", "sympy"]),
        description="differentiate mode to calculate jacobian."
    ))
    CONFIG.declare("linearize_inactive", ConfigValue(
        default=False,
        description="Add OA cuts for inactive constraints.",
        domain=bool
    ))
    CONFIG.declare("use_mcpp", ConfigValue(
        default=False,
        description="use package MC++ to set a bound for variable 'objective_value', which is introduced when the original problem's objective function is nonlinear.",
        domain=bool
    ))
    CONFIG.declare("use_dual", ConfigValue(
        default=True,
        description="use dual solution from the nlp solver to add OA cuts for equality constraints.",
        domain=bool
    ))
    CONFIG.declare("use_fbbt", ConfigValue(
        default=False,
        description="use fbbt to tighten the feasible region of the problem",
        domain=bool
    ))
    CONFIG.declare("threads", ConfigValue(
        default=0,
        domain=NonNegativeInt,
        description="Threads",
        doc="Threads used by milp solver and nlp solver."
    ))
    CONFIG.declare("use_dual_bound", ConfigValue(
        default=True,
        description="add dual bound constraint to enforce the objective function should improve on the best found dual bound",
        domain=bool
    ))
    return CONFIG