Example #1
0
    def test_getattr_setattr(self):
        config = ConfigBlock()
        foo = config.declare('foo', ConfigBlock(implicit=True, implicit_domain=int))
        foo.declare('explicit_bar', ConfigValue(0, int))

        self.assertEqual(1, len(foo))
        self.assertEqual(0, foo['explicit_bar'])
        self.assertEqual(0, foo.explicit_bar)
        foo.explicit_bar = 10
        self.assertEqual(1, len(foo))
        self.assertEqual(10, foo['explicit_bar'])
        self.assertEqual(10, foo.explicit_bar)

        foo.implicit_bar = 20
        self.assertEqual(2, len(foo))
        self.assertEqual(20, foo['implicit bar'])
        self.assertEqual(20, foo.implicit_bar)

        try:
            config.baz = 10
        except ValueError:
            pass
        except:
            raise
        else:
            self.fail("Expected implicit assignment to explicit block to raise ValueError")

        try:
            a = config.baz
        except AttributeError:
            pass
        except:
            raise
        else:
            self.fail("Expected implicit assignment to explicit block to raise ValueError")
Example #2
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 #3
0
    def saveTemplate(self, filename=None, template_options=None):
        '''
        Save the project as a YAML formatted file. Uses the filename stored in
        opts['configure']['output prefix'], use setConfigureOption('output prefix',f)
        to set this name.
        '''
        if filename is None:
            filename = self.opts['configure']['output prefix'] + '.yml'

        from pywst.common.wst_config import Path
        _SPE = True
        Path.SuppressPathExpansion, _SPE = _SPE, Path.SuppressPathExpansion
        try:
            fid = open(filename, 'wt')
            templ = ConfigBlock("%s configuration template" % self.module)
            for k in self.module_blocks:
                templ.declare(k, self.opts[k]())
            if template_options is not None:
                templ.set_value(template_options)
            fid.write(templ.generate_yaml_template(indent_spacing=2, width=95))
            fid.close()
        except:
            print 'Error saving "%s"' % filename
            raise
        finally:
            Path.SuppressPathExpansion, _SPE = _SPE, Path.SuppressPathExpansion

        print "Writing template file " + filename
        return True
Example #4
0
 def saveVisOutput(self, outfilename, config, module_blocks,
                   template_options):
     fid = open(outfilename, 'wt')
     templ = ConfigBlock("# YML input file for visualization")
     for k in module_blocks:
         templ.declare(k, config[k]())
     if template_options is not None:
         templ.set_value(template_options)
     fid.write(templ.generate_yaml_template(indent_spacing=2, width=95))
     fid.close()
Example #5
0
def _add_subsolver_configs(CONFIG):
    CONFIG.declare(
        "mip_solver",
        ConfigValue(default="gurobi",
                    description="Mixed integer linear solver to use."))
    CONFIG.declare(
        "mip_solver_args",
        ConfigBlock(
            description="Keyword arguments to send to the MILP subsolver "
            "solve() invocation",
            implicit=True))
    CONFIG.declare(
        "nlp_solver",
        ConfigValue(default="ipopt", description="Nonlinear solver to use"))
    CONFIG.declare(
        "nlp_solver_args",
        ConfigBlock(
            description="Keyword arguments to send to the NLP subsolver "
            "solve() invocation",
            implicit=True))
    CONFIG.declare(
        "minlp_solver",
        ConfigValue(default="baron", description="MINLP solver to use"))
    CONFIG.declare(
        "minlp_solver_args",
        ConfigBlock(
            description="Keyword arguments to send to the MINLP subsolver "
            "solve() invocation",
            implicit=True))
    CONFIG.declare(
        "local_minlp_solver",
        ConfigValue(default="bonmin", description="MINLP solver to use"))
    CONFIG.declare(
        "local_minlp_solver_args",
        ConfigBlock(
            description="Keyword arguments to send to the local MINLP subsolver "
            "solve() invocation",
            implicit=True))
Example #6
0
    def test_implicit_entries(self):
        config = ConfigBlock()
        try:
            config['test'] = 5
            self.fail("Expected ConfigBlock to throw a ValueError for implicit declarations")
        except ValueError:
            self.assertEqual(
                sys.exc_info()[1].args, 
                ("Key 'test' not defined in Config Block '' and Block disallows implicit entries",) )

        config = ConfigBlock(implicit=True)
        config['implicit_1'] = 5
        config.declare( 'formal', ConfigValue( 42, int ) )
        config['implicit_2'] = 5
        print(config.display())
        self.assertEqual( 3, len(config) )
        self.assertEqual( ['implicit_1','formal','implicit_2'], 
                          list(config.iterkeys()) )
        config.reset()
        self.assertEqual( 1, len(config) )
        self.assertEqual( ['formal'], 
                          list(config.iterkeys()) )
Example #7
0
    def test_1(self):
        '''
        The simplest case that the black box has only two inputs and there is only one black block involved
        '''
        def blackbox(a,b):
            return sin(a-b)

        m = self.m
        bb = ExternalFunction(blackbox)
        m.eflist = [bb]
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + bb(m.x[0],m.x[1]) == 2*sqrt(2.0))
        pI = PyomoInterface(m, [bb], ConfigBlock())
        self.assertEqual(pI.lx,2)
        self.assertEqual(pI.ly,1)
        self.assertEqual(pI.lz,3)
        self.assertEqual(len(list(identify_variables(m.c1.body))),3)
        self.assertEqual(len(list(identify_variables(m.c2.body))),2)
Example #8
0
 def saveOutput(self, outfilename, config, module_blocks, template_options):
     fid = open(outfilename, 'wt')
     templ = ConfigBlock("%s output" % self.module)
     for k in module_blocks:
         templ.declare(k, config[k]())
     if template_options is not None:
         templ.set_value(template_options)
     if self.opts['configure']['debug']:
         fid.write('---\n')
     fid.write(templ.generate_yaml_template(indent_spacing=2, width=95))
     if self.opts['configure']['debug']:
         fid.write('---\n')
         fid.write("#%s input\n" % self.module)
         out = self.opts.display(content_filter='userdata')
         fid.write(out)
     fid.close()
Example #9
0
    def test_2(self):
        '''
        The simplest case that the black box has only one inputs and there is only a formula
        '''
        def blackbox(a):
            return sin(a)

        m = self.m
        bb = ExternalFunction(blackbox)
        m.eflist = [bb]
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + bb(m.x[0]-m.x[1]) == 2*sqrt(2.0))
        pI = PyomoInterface(m, [bb], ConfigBlock())
        self.assertEqual(pI.lx,1)
        self.assertEqual(pI.ly,1)
        self.assertEqual(pI.lz,5)
        self.assertEqual(len(list(identify_variables(m.c1.body))),3)
        self.assertEqual(len(list(identify_variables(m.c2.body))),2)
        self.assertEqual(len(m.tR.conset),1)
        self.assertEqual(len(list(identify_variables(m.tR.conset[1].body))),3)
Example #10
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(
        'pyro host',
        ConfigValue(
            None, str,
            "The hostname to bind on when searching for a Pyro nameserver.",
            None))
    solver.declare(
        'pyro port',
        ConfigValue(
            None, int,
            "The port to bind on when searching for a Pyro nameserver.", 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('pyro host').\
        declare_as_argument('--pyro-host', dest="pyro_host")
    solver_list[0].get('pyro port').\
        declare_as_argument('--pyro-port', dest="pyro_port")
    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 #11
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')
    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 #12
0
class TrustRegionSolver(OptSolver):
    """
    A trust region filter method for black box / glass box optimizaiton
    Solves nonlinear optimization problems containing external function calls
    through automatic construction of reduced models (ROM), also known as
    surrogate models.
    Currently implements linear and quadratic reduced models.
    See Eason, Biegler (2016) AIChE Journal for more details

    Arguments:
    """
    #    + param.CONFIG.generte_yaml_template()

    CONFIG = ConfigBlock('Trust Region')

    CONFIG.declare(
        'solver',
        ConfigValue(default='ipopt',
                    description='solver to use, defaults to ipopt',
                    doc=''))

    CONFIG.declare(
        'solver_options',
        ConfigBlock(implicit=True,
                    description='options to pass to the subproblem solver',
                    doc=''))

    # Initialize trust radius
    CONFIG.declare(
        'trust radius',
        ConfigValue(default=1.0, domain=PositiveFloat, description='', doc=''))

    # Initialize sample region
    CONFIG.declare(
        'sample region',
        ConfigValue(default=True, domain=bool, description='', doc=''))

    # Initialize sample radius
    # TODO do we need to keep the if statement?
    if CONFIG.sample_region:
        default_sample_radius = 0.1
    else:
        default_sample_radius = CONFIG.trust_radius / 2.0

    CONFIG.declare(
        'sample radius',
        ConfigValue(default=default_sample_radius,
                    domain=PositiveFloat,
                    description='',
                    doc=''))

    # Initialize radius max
    CONFIG.declare(
        'radius max',
        ConfigValue(default=1000.0 * CONFIG.trust_radius,
                    domain=PositiveFloat,
                    description='',
                    doc=''))

    # Termination tolerances
    CONFIG.declare(
        'ep i',
        ConfigValue(default=1e-5, domain=PositiveFloat, description='',
                    doc=''))

    CONFIG.declare(
        'ep delta',
        ConfigValue(default=1e-5, domain=PositiveFloat, description='',
                    doc=''))

    CONFIG.declare(
        'ep chi',
        ConfigValue(default=1e-3, domain=PositiveFloat, description='',
                    doc=''))

    CONFIG.declare(
        'delta min',
        ConfigValue(default=1e-6,
                    domain=PositiveFloat,
                    description='delta min <= ep delta',
                    doc=''))

    CONFIG.declare(
        'max it',
        ConfigValue(default=20, domain=PositiveInt, description='', doc=''))

    # Compatibility Check Parameters
    CONFIG.declare(
        'kappa delta',
        ConfigValue(default=0.8, domain=PositiveFloat, description='', doc=''))

    CONFIG.declare(
        'kappa mu',
        ConfigValue(default=1.0, domain=PositiveFloat, description='', doc=''))

    CONFIG.declare(
        'mu',
        ConfigValue(default=0.5, domain=PositiveFloat, description='', doc=''))

    CONFIG.declare(
        'ep compatibility',
        ConfigValue(default=CONFIG.ep_i,
                    domain=PositiveFloat,
                    description='Suggested value: ep compatibility == ep i',
                    doc=''))

    CONFIG.declare(
        'compatibility penalty',
        ConfigValue(default=0.0,
                    domain=NonNegativeFloat,
                    description='',
                    doc=''))

    # Criticality Check Parameters
    CONFIG.declare(
        'criticality check',
        ConfigValue(default=0.1, domain=PositiveFloat, description='', doc=''))

    # Trust region update parameters
    CONFIG.declare(
        'gamma c',
        ConfigValue(default=0.5, domain=PositiveFloat, description='', doc=''))

    CONFIG.declare(
        'gamma e',
        ConfigValue(default=2.5, domain=PositiveFloat, description='', doc=''))

    # Switching Condition
    CONFIG.declare(
        'gamma s',
        ConfigValue(default=2.0, domain=PositiveFloat, description='', doc=''))

    CONFIG.declare(
        'kappa theta',
        ConfigValue(default=0.1, domain=PositiveFloat, description='', doc=''))

    CONFIG.declare(
        'theta min',
        ConfigValue(default=1e-4, domain=PositiveFloat, description='',
                    doc=''))

    # Filter
    CONFIG.declare(
        'gamma f',
        ConfigValue(
            default=0.01,
            domain=PositiveFloat,
            description='gamma_f and gamma_theta in (0,1) are fixed parameters',
            doc=''))

    CONFIG.declare(
        'gamma theta',
        ConfigValue(
            default=0.01,
            domain=PositiveFloat,
            description='gamma_f and gamma_theta in (0,1) are fixed parameters',
            doc=''))

    CONFIG.declare(
        'theta max',
        ConfigValue(default=50, domain=PositiveInt, description='', doc=''))

    # Ratio test parameters (for theta steps)
    CONFIG.declare(
        'eta1',
        ConfigValue(default=0.05, domain=PositiveFloat, description='',
                    doc=''))

    CONFIG.declare(
        'eta2',
        ConfigValue(default=0.2, domain=PositiveFloat, description='', doc=''))

    # Output level (replace with real printlevels!!!)
    CONFIG.declare(
        'print variables',
        ConfigValue(default=False, domain=bool, description='', doc=''))

    # Sample Radius reset parameter
    CONFIG.declare(
        'sample radius adjust',
        ConfigValue(default=0.5, domain=PositiveFloat, description='', doc=''))

    # Default romtype
    CONFIG.declare(
        'reduced model type',
        ConfigValue(default=1,
                    domain=In([0, 1]),
                    description='0 = Linear, 1 = Quadratic',
                    doc=''))

    def __init__(self, **kwds):
        # set persistent config options
        tmp_kwds = {'type': kwds.pop('type', 'trustregion')}
        self.config = self.CONFIG(kwds, preserve_implicit=True)

        #
        # Call base class constructor
        #

        tmp_kwds['solver'] = self.config.solver
        OptSolver.__init__(self, **tmp_kwds)

    def available(self, exception_flag=True):
        """Check if solver is available.

        TODO: For now, it is always available. However, sub-solvers may not
        always be available, and so this should reflect that possibility.

        """
        return True

    def version(self):
        """Return a 3-tuple describing the solver version."""
        return __version__

    def solve(self, model, eflist, **kwds):
        # set customized config parameters
        self._local_config = self.config(kwds, preserve_implicit=True)

        # first store all data we will need to change in original model as a tuple
        # [0]=Var component, [1]=external function list, [2]=config block
        model._tmp_trf_data = (list(model.component_data_objects(Var)), eflist,
                               self._local_config)
        # now clone the model
        inst = model.clone()

        # call TRF on cloned model
        TRF(inst, inst._tmp_trf_data[1], inst._tmp_trf_data[2])

        # copy potentially changed variable values back to original model and return
        for inst_var, orig_var in zip(inst._tmp_trf_data[0],
                                      model._tmp_trf_data[0]):
            orig_var.set_value(value(inst_var))
Example #13
0
class BigM_Transformation(Transformation):
    """Relax disjunctive model using big-M terms.

    Relaxes a disjunctive model into an algebraic model by adding Big-M
    terms to all disjunctive constraints.

    This transformation accepts the following keyword arguments:
        bigM: A user-specified value (or dict) of M values to use (see below)
        targets: the targets to transform [default: the instance]

    M values are determined as follows:
       1) if the constraint CUID appears in the bigM argument dict
       2) if the constraint parent_component CUID appears in the bigM
          argument dict
       3) if 'None' is in the bigM argument dict
       4) if the constraint or the constraint parent_component appear in
          a BigM Suffix attached to any parent_block() beginning with the
          constraint's parent_block and moving up to the the root model.
       5) if None appears in a BigM Suffix attached to any
          parent_block() between the constraint and the root model.
       6) if the constraint is linear, estimate M using the variable bounds

    M values may be a single value or a 2-tuple specifying the M for the
    lower bound and the upper bound of the constraint body.

    Specifying "bigM=N" is automatically mapped to "bigM={None: N}".

    After transformation, every transformed disjunct will have a
    "_gdp_transformation_info" dict containing 2 entries:

        'relaxed': True,
        'bigm': {
            'relaxationBlock': <block>,
            'relaxedConstraints': ComponentMap(constraint: relaxed_constraint)
        }

    In addition, any block or disjunct containind a relaxed disjunction
    will have a "_gdp_transformation_info" dict with the following
    entry:

        'disjunction_or_constraint': <constraint>

    Finally, the transformation will create a new Block with a unique
    name beginning "_pyomo_gdp_bigm_relaxation".  That Block will
    contain an indexed Block named "relaxedDisjuncts", which will hold
    the relaxed disjuncts.  This block is indexed by an integer
    indicating the order in which the disjuncts were relaxed.  Each
    block will have a "_gdp_transformation_info" dict with the following
    entries:

        'src': <source disjunct>
        'srcConstraints': ComponentMap(relaxed_constraint: constraint)
    """

    alias('gdp.bigm', doc=textwrap.fill(textwrap.dedent(__doc__.strip())))

    CONFIG = ConfigBlock("gdp.bigm")
    CONFIG.declare(
        'bigM',
        ConfigValue(default=None,
                    domain=_to_dict,
                    description="Big-M value used for constraint relaxation",
                    doc="""

            A user-specified value (or dict) of M values that override
            M-values found through model Suffixes or that would
            otherwise be calculated using variable domains."""))

    def __init__(self):
        """Initialize transformation object."""
        super(BigM_Transformation, self).__init__()
        self.handlers = {
            Constraint: self._xform_constraint,
            Var: False,
            Connector: False,
            Suffix: False,
            Param: False,
            Set: False,
            Disjunction: self._warn_for_active_disjunction,
            Disjunct: self._warn_for_active_disjunct,
            Block: self._transform_block_on_disjunct,
        }

    def _get_bigm_suffix_list(self, block):
        # Note that you can only specify suffixes on BlockData objects or
        # SimpleBlocks. Though it is possible at this point to stick them
        # on whatever components you want, we won't pick them up.
        suffix_list = []
        while block is not None:
            bigm = block.component('BigM')
            if type(bigm) is Suffix:
                suffix_list.append(bigm)
            block = block.parent_block()
        return suffix_list

    def _apply_to(self, instance, targets=None, **kwds):
        config = self.CONFIG().set_value(kwds.pop('options', {}))

        # For now, we're not accepting options. We will let args override
        # suffixes and estimate as a last resort. More specific args/suffixes
        # override ones anywhere in the tree. Suffixes lower down in the tree
        # override ones higher up.
        if 'default_bigM' in kwds:
            logger.warn("DEPRECATED: the 'default_bigM=' argument has been "
                        "replaced by 'bigM='")
            config.bigM = kwds.pop('default_bigM')

        config.set_value(kwds)
        bigM = config.bigM

        # make a transformation block to put transformed disjuncts on
        transBlockName = unique_component_name(instance,
                                               '_pyomo_gdp_bigm_relaxation')
        transBlock = Block()
        instance.add_component(transBlockName, transBlock)
        transBlock.relaxedDisjuncts = Block(Any)
        transBlock.lbub = Set(initialize=['lb', 'ub'])
        # this is a dictionary for keeping track of IndexedDisjuncts
        # and IndexedDisjunctions so that, at the end of the
        # transformation, we can check that the ones with no active
        # DisjstuffDatas are deactivated.
        transBlock.disjContainers = ComponentSet()

        if targets is None:
            targets = (instance, )
            _HACK_transform_whole_instance = True
        else:
            _HACK_transform_whole_instance = False
        for _t in targets:
            t = _t.find_component(instance)
            if t is None:
                raise GDP_Error(
                    "Target %s is not a component on the instance!" % _t)
            if not t.active:
                continue

            if t.type() is Disjunction:
                if t.parent_component() is t:
                    self._transformDisjunction(t, transBlock, bigM)
                else:
                    self._transformDisjunctionData(t, transBlock, bigM,
                                                   t.index())
            elif t.type() in (Block, Disjunct):
                if t.parent_component() is t:
                    self._transformBlock(t, transBlock, bigM)
                else:
                    self._transformBlockData(t, transBlock, bigM)
            else:
                raise GDP_Error(
                    "Target %s was not a Block, Disjunct, or Disjunction. "
                    "It was of type %s and can't be transformed." %
                    (t.name, type(t)))

        # Go through our dictionary of indexed things and deactivate
        # the containers that don't have any active guys inside of
        # them. So the invalid component logic will tell us if we
        # missed something getting transformed.
        for obj in transBlock.disjContainers:
            if not obj.active:
                continue
            for i in obj:
                if obj[i].active:
                    break
            else:
                # HACK due to active flag implementation.
                #
                # Ideally we would not have to do any of this (an
                # ActiveIndexedComponent would get its active status by
                # querring the active status of all the contained Data
                # objects).  As a fallback, we would like to call:
                #
                #    obj._deactivate_without_fixing_indicator()
                #
                # However, the sreaightforward implementation of that
                # method would have unintended side effects (fixing the
                # contained _DisjunctData's indicator_vars!) due to our
                # class hierarchy.  Instead, we will directly call the
                # relevant base class (safe-ish since we are verifying
                # that all the contained _DisjunctionData are
                # deactivated directly above).
                ActiveComponent.deactivate(obj)

        # HACK for backwards compatibility with the older GDP transformations
        #
        # Until the writers are updated to find variables on things
        # other than active blocks, we need to reclassify the Disjuncts
        # as Blocks after transformation so that the writer will pick up
        # all the variables that it needs (in this case, indicator_vars).
        if _HACK_transform_whole_instance:
            HACK_GDP_Disjunct_Reclassifier().apply_to(instance)

    def _transformBlock(self, obj, transBlock, bigM):
        for i in sorted(iterkeys(obj)):
            self._transformBlockData(obj[i], transBlock, bigM)

    def _transformBlockData(self, obj, transBlock, bigM):
        # Transform every (active) disjunction in the block
        for disjunction in obj.component_objects(
                Disjunction,
                active=True,
                sort=SortComponents.deterministic,
                descend_into=(Block, Disjunct),
                descent_order=TraversalStrategy.PostfixDFS):
            self._transformDisjunction(disjunction, transBlock, bigM)

    def _getXorConstraint(self, disjunction):
        # Put the disjunction constraint on its parent block and
        # determine whether it is an OR or XOR constraint.

        # We never do this for just a DisjunctionData because we need
        # to know about the index set of its parent component. So if
        # we called this on a DisjunctionData, we did something wrong.
        assert isinstance(disjunction, Disjunction)
        parent = disjunction.parent_block()
        if hasattr(parent, "_gdp_transformation_info"):
            infodict = parent._gdp_transformation_info
            if type(infodict) is not dict:
                raise GDP_Error(
                    "Component %s contains an attribute named "
                    "_gdp_transformation_info. The transformation requires "
                    "that it can create this attribute!" % parent.name)
            try:
                # On the off-chance that another GDP transformation went
                # first, the infodict may exist, but the specific map we
                # want will not be present
                orConstraintMap = infodict['disjunction_or_constraint']
            except KeyError:
                orConstraintMap = infodict['disjunction_or_constraint'] \
                                  = ComponentMap()
        else:
            infodict = parent._gdp_transformation_info = {}
            orConstraintMap = infodict['disjunction_or_constraint'] \
                              = ComponentMap()

        # If the Constraint already exists, return it
        if disjunction in orConstraintMap:
            return orConstraintMap[disjunction]

        # add the XOR (or OR) constraints to parent block (with unique name)
        # It's indexed if this is an IndexedDisjunction, not otherwise
        orC = Constraint(disjunction.index_set()) if \
            disjunction.is_indexed() else Constraint()
        # The name used to indicate if thee were OR or XOR disjunctions,
        # however now that Disjunctions ae allowed to mix the state we
        # can no longer make that distinction in the name.
        #    nm = '_xor' if xor else '_or'
        nm = '_xor'
        orCname = unique_component_name(
            parent, '_gdp_bigm_relaxation_' + disjunction.name + nm)
        parent.add_component(orCname, orC)
        orConstraintMap[disjunction] = orC
        return orC

    def _transformDisjunction(self, obj, transBlock, bigM):
        # relax each of the disjunctionDatas
        for i in sorted(iterkeys(obj)):
            self._transformDisjunctionData(obj[i], transBlock, bigM, i)

        # deactivate so we know we relaxed
        obj.deactivate()

    def _transformDisjunctionData(self, obj, transBlock, bigM, index):
        parent_component = obj.parent_component()
        transBlock.disjContainers.add(parent_component)
        orConstraint = self._getXorConstraint(parent_component)

        xor = obj.xor
        or_expr = 0
        for disjunct in obj.disjuncts:
            or_expr += disjunct.indicator_var
            # make suffix list. (We don't need it until we are
            # transforming constraints, but it gets created at the
            # disjunct level, so more efficient to make it here and
            # pass it down.
            suffix_list = self._get_bigm_suffix_list(disjunct)
            # relax the disjunct
            self._bigM_relax_disjunct(disjunct, transBlock, bigM, suffix_list)
        # add or (or xor) constraint
        if xor:
            orConstraint.add(index, (or_expr, 1))
        else:
            orConstraint.add(index, (1, or_expr, None))
        obj.deactivate()

    def _bigM_relax_disjunct(self, obj, transBlock, bigM, suffix_list):
        if hasattr(obj, "_gdp_transformation_info"):
            infodict = obj._gdp_transformation_info
            # If the user has something with our name that is not a dict, we
            # scream. If they have a dict with this name then we are just going
            # to use it...
            if type(infodict) is not dict:
                raise GDP_Error(
                    "Disjunct %s contains an attribute named "
                    "_gdp_transformation_info. The transformation requires "
                    "that it can create this attribute!" % obj.name)
        else:
            infodict = obj._gdp_transformation_info = {}

        # deactivated -> either we've already transformed or user deactivated
        if not obj.active:
            if obj.indicator_var.is_fixed():
                if value(obj.indicator_var) == 0:
                    # The user cleanly deactivated the disjunct: there
                    # is nothing for us to do here.
                    return
                else:
                    raise GDP_Error(
                        "The disjunct %s is deactivated, but the "
                        "indicator_var is fixed to %. This makes no sense." %
                        (obj.name, value(obj.indicator_var)))
            if not infodict.get('relaxed', False):
                raise GDP_Error(
                    "The disjunct %s is deactivated, but the "
                    "indicator_var is not fixed and the disjunct does not "
                    "appear to have been relaxed. This makes no sense." %
                    (obj.name, ))

        if 'bigm' in infodict:
            # we've transformed it (with BigM), so don't do it again.
            return

        # add reference to original disjunct to info dict on transformation
        # block
        relaxedDisjuncts = transBlock.relaxedDisjuncts
        relaxationBlock = relaxedDisjuncts[len(relaxedDisjuncts)]
        relaxationBlock._gdp_transformation_info = {
            'src': obj,
            'srcConstraints': ComponentMap(),
        }

        # add reference to transformation block on original disjunct
        assert 'bigm' not in infodict
        infodict['bigm'] = {
            'relaxationBlock': relaxationBlock,
            'relaxedConstraints': ComponentMap()
        }

        # if this is a disjunctData from an indexed disjunct, we are
        # going to want to check at the end that the container is
        # deactivated if everything in it is. So we save it in our
        # dictionary of things to check if it isn't there already.
        disjParent = obj.parent_component()
        if disjParent.is_indexed() and \
           disjParent not in transBlock.disjContainers:
            transBlock.disjContainers.add(disjParent)

        # Transform each component within this disjunct
        self._transform_block_components(obj, obj, infodict, bigM, suffix_list)

        # deactivate disjunct so we know we've relaxed it
        obj._deactivate_without_fixing_indicator()
        infodict['relaxed'] = True

    def _transform_block_components(self, block, disjunct, infodict, bigM,
                                    suffix_list):
        # Look through the component map of block and transform
        # everything we have a handler for. Yell if we don't know how
        # to handle it.
        for name, obj in list(iteritems(block.component_map())):
            if hasattr(obj, 'active') and not obj.active:
                continue
            handler = self.handlers.get(obj.type(), None)
            if not handler:
                if handler is None:
                    raise GDP_Error(
                        "No BigM transformation handler registered "
                        "for modeling components of type %s" % obj.type())
                continue
            # obj is what we are transforming, we pass disjunct
            # through so that we will have access to the indicator
            # variables down the line.
            handler(obj, disjunct, infodict, bigM, suffix_list)

    def _warn_for_active_disjunction(self, disjunction, disjunct, infodict,
                                     bigMargs, suffix_list):
        # this should only have gotten called if the disjunction is active
        assert disjunction.active
        problemdisj = disjunction
        if disjunction.is_indexed():
            for i in disjunction:
                if disjunction[i].active:
                    # a _DisjunctionData is active, we will yell about
                    # it specifically.
                    problemdisj = disjunction[i]
                    break
            # None of the _DisjunctionDatas were actually active. We
            # are OK and we can deactivate the container.
            else:
                disjunction.deactivate()
                return
        parentblock = problemdisj.parent_block()
        # the disjunction should only have been active if it wasn't transformed
        assert (not hasattr(parentblock, "_gdp_transformation_info")) or \
            problemdisj.name not in parentblock._gdp_transformation_info
        raise GDP_Error("Found untransformed disjunction %s in disjunct %s! "
                        "The disjunction must be transformed before the "
                        "disjunct. If you are using targets, put the "
                        "disjunction before the disjunct in the list." %
                        (problemdisj.name, disjunct.name))

    def _warn_for_active_disjunct(self, innerdisjunct, outerdisjunct, infodict,
                                  bigMargs, suffix_list):
        assert innerdisjunct.active
        problemdisj = innerdisjunct
        if innerdisjunct.is_indexed():
            for i in innerdisjunct:
                if innerdisjunct[i].active:
                    # This is shouldn't be true, we will complain about it.
                    problemdisj = innerdisjunct[i]
                    break
            # None of the _DisjunctDatas were actually active, so we
            # are fine and we can deactivate the container.
            else:
                # HACK: See above about _deactivate_without_fixing_indicator
                ActiveComponent.deactivate(innerdisjunct)
                return
        raise GDP_Error("Found active disjunct {0} in disjunct {1}! "
                        "Either {0} "
                        "is not in a disjunction or the disjunction it is in "
                        "has not been transformed. "
                        "{0} needs to be deactivated "
                        "or its disjunction transformed before {1} can be "
                        "transformed.".format(problemdisj.name,
                                              outerdisjunct.name))

    def _transform_block_on_disjunct(self, block, disjunct, infodict, bigMargs,
                                     suffix_list):
        # We look through everything on the component map of the block
        # and transform it just as we would if it was on the disjunct
        # directly.  (We are passing the disjunct through so that when
        # we find constraints, _xform_constraint will have access to
        # the correct indicator variable.
        self._transform_block_components(block, disjunct, infodict, bigMargs,
                                         suffix_list)

    def _xform_constraint(self, obj, disjunct, infodict, bigMargs,
                          suffix_list):
        # add constraint to the transformation block, we'll transform it there.

        relaxationBlock = infodict['bigm']['relaxationBlock']
        transBlock = relaxationBlock.parent_block()
        # Though rare, it is possible to get naming conflicts here
        # since constraints from all blocks are getting moved onto the
        # same block. So we get a unique name
        name = unique_component_name(relaxationBlock, obj.name)

        if obj.is_indexed():
            try:
                newConstraint = Constraint(obj.index_set(), transBlock.lbub)
            except TypeError:
                # The original constraint may have been indexed by a
                # non-concrete set (like an Any).  We will give up on
                # strict index verification and just blindly proceed.
                newConstraint = Constraint(Any)
        else:
            newConstraint = Constraint(transBlock.lbub)
        relaxationBlock.add_component(name, newConstraint)
        # add mapping of original constraint to transformed constraint
        # in transformation info dictionary
        infodict['bigm']['relaxedConstraints'][obj] = newConstraint
        # add mapping of transformed constraint back to original constraint (we
        # know that the info dict is already created because this only got
        # called if we were transforming a disjunct...)
        relaxationBlock._gdp_transformation_info['srcConstraints'][
            newConstraint] = obj

        for i in sorted(iterkeys(obj)):
            c = obj[i]
            if not c.active:
                continue
            c.deactivate()

            # first, we see if an M value was specified in the arguments.
            # (This returns None if not)
            M = self._get_M_from_args(c, bigMargs)

            if __debug__ and logger.isEnabledFor(logging.DEBUG):
                logger.debug("GDP(BigM): The value for M for constraint %s "
                             "from the BigM argument is %s." %
                             (obj.name, str(M)))

            # if we didn't get something from args, try suffixes:
            if M is None:
                M = self._get_M_from_suffixes(c, suffix_list)

            if __debug__ and logger.isEnabledFor(logging.DEBUG):
                logger.debug("GDP(BigM): The value for M for constraint %s "
                             "after checking suffixes is %s." %
                             (obj.name, str(M)))

            if not isinstance(M, (tuple, list)):
                if M is None:
                    M = (None, None)
                else:
                    try:
                        M = (-M, M)
                    except:
                        logger.error("Error converting scalar M-value %s "
                                     "to (-M,M).  Is %s not a numeric type?" %
                                     (M, type(M)))
                        raise
            if len(M) != 2:
                raise GDP_Error("Big-M %s for constraint %s is not of "
                                "length two. "
                                "Expected either a single value or "
                                "tuple or list of length two for M." %
                                (str(M), name))

            if c.lower is not None and M[0] is None:
                M = (self._estimate_M(c.body, name)[0] - c.lower, M[1])
            if c.upper is not None and M[1] is None:
                M = (M[0], self._estimate_M(c.body, name)[1] - c.upper)

            if __debug__ and logger.isEnabledFor(logging.DEBUG):
                logger.debug("GDP(BigM): The value for M for constraint %s "
                             "after estimating (if needed) is %s." %
                             (obj.name, str(M)))

            # Handle indices for both SimpleConstraint and IndexedConstraint
            if i.__class__ is tuple:
                i_lb = i + ('lb', )
                i_ub = i + ('ub', )
            elif obj.is_indexed():
                i_lb = (
                    i,
                    'lb',
                )
                i_ub = (
                    i,
                    'ub',
                )
            else:
                i_lb = 'lb'
                i_ub = 'ub'

            if c.lower is not None:
                if M[0] is None:
                    raise GDP_Error("Cannot relax disjunctive constraint %s "
                                    "because M is not defined." % name)
                M_expr = M[0] * (1 - disjunct.indicator_var)
                newConstraint.add(i_lb, c.lower <= c.body - M_expr)
            if c.upper is not None:
                if M[1] is None:
                    raise GDP_Error("Cannot relax disjunctive constraint %s "
                                    "because M is not defined." % name)
                M_expr = M[1] * (1 - disjunct.indicator_var)
                newConstraint.add(i_ub, c.body - M_expr <= c.upper)

    def _get_M_from_args(self, constraint, bigMargs):
        # check args: we only have to look for constraint, constraintdata, and
        # None
        if bigMargs is None:
            return None

        cuid = ComponentUID(constraint)
        parentcuid = ComponentUID(constraint.parent_component())
        if cuid in bigMargs:
            return bigMargs[cuid]
        elif parentcuid in bigMargs:
            return bigMargs[parentcuid]
        elif None in bigMargs:
            return bigMargs[None]
        return None

    def _get_M_from_suffixes(self, constraint, suffix_list):
        M = None
        # first we check if the constraint or its parent is a key in any of the
        # suffix lists
        for bigm in suffix_list:
            if constraint in bigm:
                M = bigm[constraint]
                break

            # if c is indexed, check for the parent component
            if constraint.parent_component() in bigm:
                M = bigm[constraint.parent_component()]
                break

        # if we didn't get an M that way, traverse upwards through the blocks
        # and see if None has a value on any of them.
        if M is None:
            for bigm in suffix_list:
                if None in bigm:
                    M = bigm[None]
                    break
        return M

    def _estimate_M(self, expr, name):
        # Calculate a best guess at M
        repn = generate_canonical_repn(expr)
        M = [0, 0]

        if isinstance(repn, LinearCanonicalRepn):
            if repn.constant is not None:
                for i in (0, 1):
                    if M[i] is not None:
                        M[i] += repn.constant

            for i, coef in enumerate(repn.linear or []):
                var = repn.variables[i]
                coef = repn.linear[i]
                bounds = (value(var.lb), value(var.ub))
                for i in (0, 1):
                    # reverse the bounds if the coefficient is negative
                    if coef > 0:
                        j = i
                    else:
                        j = 1 - i

                    if bounds[i] is not None:
                        M[j] += value(bounds[i]) * coef
                    else:
                        raise GDP_Error(
                            "Cannot estimate M for "
                            "expressions with unbounded variables."
                            "\n\t(found unbounded var %s while processing "
                            "constraint %s)" % (var.name, name))
        else:
            raise GDP_Error("Cannot estimate M for nonlinear "
                            "expressions.\n\t(found while processing "
                            "constraint %s)" % name)

        return tuple(M)
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')
    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
    fid = open(target, 'w')
    fid.write(config.generate_documentation())
    fid.close()

# tevasim
target = 'tevasim_config.yml'
if target in targets or not targets:
    if target in targets: targets.remove(target)
    run(wst + ['tevasim', '--template', target])

target = 'tevasim_config.tex'
if target in targets or not targets:
    if target in targets: targets.remove(target)
    sys.stdout.write("Writing documentation file %s\n" % target)
    fid = open(target, 'w')
    tevasim = ConfigBlock('tevasim configuration template')
    for k in ('network', 'scenario', 'configure'):
        tevasim.declare(k, config[k]())
    fid.write(tevasim.generate_documentation())
    fid.close()

# sim2Impact
target = 'sim2Impact_config.yml'
if target in targets or not targets:
    if target in targets: targets.remove(target)
    run(wst + ['sim2Impact', '--template', target])

target = 'sim2Impact_config.tex'
if target in targets or not targets:
    if target in targets: targets.remove(target)
    sys.stdout.write("Writing documentation file %s\n" % target)
Example #16
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) ).declare_as_argument('--solver', dest='solver')
    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.")).\
                   declare_as_argument('--solver-executable',
                                       dest="solver_executable", metavar="FILE"))
    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) ).declare_as_argument('--solver-io', dest='io_format', metavar="FORMAT")
    solver.declare('manager', ConfigValue(
                'serial',
                str,
                'The technique that is used to manage solver executions.',
                None) ).declare_as_argument('--solver-manager', dest="smanager_type", metavar="TYPE")
    solver.declare('pyro host', ConfigValue(
                None,
                str,
                "The hostname to bind on when searching for a Pyro nameserver.",
                None) ).declare_as_argument('--pyro-host', dest="pyro_host")
    solver.declare('pyro port', ConfigValue(
                None,
                int,
                "The port to bind on when searching for a Pyro nameserver.",
                None) ).declare_as_argument('--pyro-port', dest="pyro_port")
    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) ).declare_as_argument('--solver-options', dest='options_string', metavar="STRING")
    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) ).declare_as_argument('--solver-suffix', dest="solver_suffixes")
    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) )
    solver_list.append()

    #
    # 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 #17
0
def _get_GDPopt_config():
    _supported_strategies = {
        'LOA',  # Logic-based outer approximation
        'GLOA',  # Global logic-based outer approximation
        'LBB',  # Logic-based branch-and-bound
    }
    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="LOA",
                    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