Source code for idaes.core.plugins.variable_replace

##############################################################################
# Institute for the Design of Advanced Energy Systems Process Systems
# Engineering Framework (IDAES PSE Framework) Copyright (c) 2018-2019, by the
# software owners: The Regents of the University of California, through
# Lawrence Berkeley National Laboratory,  National Technology & Engineering
# Solutions of Sandia, LLC, Carnegie Mellon University, West Virginia
# University Research Corporation, et al. All rights reserved.
#
# Please see the files COPYRIGHT.txt and LICENSE.txt for full copyright and
# license information, respectively. Both files are also available online
# at the URL "https://github.com/IDAES/idaes-pse".
##############################################################################

__author__ = "John Eslick"

"""Transformation to replace variables with other variables."""
from pyomo.core.base.plugin import TransformationFactory
from pyomo.core.plugins.transform.hierarchy import NonIsomorphicTransformation
from pyomo.core.expr import current as EXPR
from pyomo.common.config import ConfigBlock, ConfigValue, add_docstring_list
from pyomo.core.base.var import _GeneralVarData, Var
from pyomo.core.base.constraint import Constraint
from pyomo.core.base.expression import Expression
from pyomo.core.base.objective import Objective


def _is_var(v):
    return isinstance(v, (_GeneralVarData, Var))

[docs]@TransformationFactory.register( 'replace_variables', doc="Replace variables with other variables.") class ReplaceVariables(NonIsomorphicTransformation): """Replace variables in a model or block with other variables. Keyword arguments below are specified for the ``apply_to(instance, **kwargs)`` method. """ CONFIG = ConfigBlock() CONFIG.declare("substitute", ConfigValue( default=[], description="List-like of tuples where the first item in a tuple is a " "Pyomo variable to be replaced and the second item in the " "tuple is a Pyomo variable to replace it with. This " "transformation is not reversible." )) __doc__ = add_docstring_list(__doc__, CONFIG) @staticmethod def replace(instance, substitute): # Create the replacement dict. Do some argument validation and indexed # var handling d = {} for r in substitute: if not (_is_var(r[0]) and _is_var(r[1])): raise TypeError( "Replace only allows variables to be replaced, {} is type {}" " and {} is type {}".format(r[0], type(r[0]), r[1], type(r[1])) ) if r[0].is_indexed() != r[1].is_indexed(): raise TypeError( "IndexedVars must be replaced by IndexedVars, {} is type {}" " and {} is type {}".format(r[0], type(r[0]), r[1], type(r[1])) ) if r[0].is_indexed() and r[1].is_indexed(): if not r[0].index_set().issubset(r[1].index_set()): raise ValueError( "The index set of {} must be a subset of" " {}.".format(r[0], r[1]) ) for i in r[0]: d[id(r[0][i])] = r[1][i] else: #scalar replace d[id(r[0])] = r[1] # Replacement Visitor vis = EXPR.ExpressionReplacementVisitor( substitute=d, descend_into_named_expressions=True, remove_named_expressions=False, ) # Do replacements in Expressions, Constraints, and Objectives for c in instance.component_data_objects( (Constraint, Expression, Objective), descend_into=True, active=True ): c.set_value(expr=vis.dfs_postorder_stack(c.expr)) def _apply_to(self, instance, **kwds): """ Apply the transformation. This is called by ``apply_to`` in the superclass, and should not be called directly. ``apply_to`` takes the same arguments. Args: instance: A block or model to apply the transformation to substitute: A list-like of two-element list-likes. Each two element list-like specifies a replacment of the first variable by the second. SimpleVar, IndexedVar, _GeneralVarData, and Reference are all accepted types. Returns: None """ config = self.CONFIG(kwds) self.replace(instance, config.substitute)