Source code for pyomo.core.kernel.expression

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

from pyomo.common.deprecation import deprecated
from pyomo.common.modeling import NOTSET
import pyomo.core.expr as EXPR
from pyomo.core.kernel.base import ICategorizedObject, _abstract_readwrite_property
from pyomo.core.kernel.container_utils import define_simple_containers
from pyomo.core.expr.numvalue import (
    NumericValue,
    is_fixed,
    is_constant,
    is_potentially_variable,
    is_numeric_data,
    value,
)


[docs] class IIdentityExpression(NumericValue): """The interface for classes that simply wrap another expression and perform no additional operations. Derived classes should declare an _expr attribute or override all implemented methods. """ __slots__ = () PRECEDENCE = 0 ASSOCIATIVITY = EXPR.OperatorAssociativity.NON_ASSOCIATIVE @property def expr(self): return self._expr # # Implement the NumericValue abstract methods # def __call__(self, exception=False): """Compute the value of this expression. Args: exception (bool): Indicates if an exception should be raised when instances of NumericValue fail to evaluate due to one or more objects not being initialized to a numeric value (e.g, one or more variables in an algebraic expression having the value None). Default is :const:`True`. Returns: numeric value or None """ return value(self._expr, exception=exception)
[docs] def is_fixed(self): """A boolean indicating whether this expression is fixed.""" return is_fixed(self._expr)
[docs] def is_parameter_type(self): """A boolean indicating whether this expression is a parameter object.""" return False
[docs] def is_variable_type(self): """A boolean indicating whether this expression is a variable object.""" return False
[docs] def is_named_expression_type(self): """A boolean indicating whether this in a named expression.""" return True
[docs] def is_expression_type(self, expression_system=None): """A boolean indicating whether this in an expression.""" return True
@property def _args_(self): """A tuple of subexpressions involved in this expressions operation.""" return (self._expr,) @property def args(self): """A tuple of subexpressions involved in this expressions operation.""" return (self._expr,)
[docs] def nargs(self): """Length of self._nargs()""" return 1
def arg(self, i): if i != 0: raise KeyError("Unexpected argument id") return self._expr
[docs] def polynomial_degree(self): """The polynomial degree of the stored expression.""" if self.is_fixed(): return 0 return self._expr.polynomial_degree()
def _compute_polynomial_degree(self, values): return values[0]
[docs] def to_string(self, verbose=None, labeler=None, smap=None, compute_values=False): """Convert this expression into a string.""" return EXPR.expression_to_string( self, verbose=verbose, labeler=labeler, smap=smap, compute_values=compute_values, )
def _to_string(self, values, verbose, smap): if verbose: name = self.getname() if name == None: return "<%s>{%s}" % (self.__class__.__name__, values[0]) else: if name[0] == '<': name = "" return "%s{%s}" % (name, values[0]) if self._expr is None: return "%s{Undefined}" % str(self) return values[0] def _apply_operation(self, result): return result[0] def _is_fixed(self, values): return values[0]
[docs] def create_node_with_local_data(self, values): """ Construct an expression after constructing the contained expression. This class provides a consistent interface for constructing a node, which is used in tree visitor scripts. """ return self.__class__(expr=values[0])
[docs] def is_constant(self): raise NotImplementedError # pragma:nocover
[docs] def is_potentially_variable(self): raise NotImplementedError # pragma:nocover
def clone(self): raise NotImplementedError # pragma:nocover
[docs] @deprecated( "noclone() is deprecated and can be omitted: " "Pyomo expressions natively support shared subexpressions.", version='6.6.2', ) def noclone(expr): try: if expr.is_potentially_variable(): return expression(expr) except AttributeError: pass try: if is_constant(expr): return expr except: return expr return data_expression(expr)
[docs] class IExpression(ICategorizedObject, IIdentityExpression): """ The interface for mutable expressions. """ __slots__ = () # # Implementations can choose to define these # properties as using __slots__, __dict__, or # by overriding the @property method # expr = _abstract_readwrite_property(doc="The stored expression") # # Override some of the NumericValue methods implemented # by the base class #
[docs] def is_constant(self): """A boolean indicating whether this expression is constant.""" return False
[docs] def is_potentially_variable(self): """A boolean indicating whether this expression can reference variables.""" return True
[docs] def clone(self): """Return a clone of this expression (no-op).""" return self
[docs] class expression(IExpression): """A named, mutable expression.""" _ctype = IExpression __slots__ = ("_parent", "_storage_key", "_active", "_expr", "__weakref__")
[docs] def __init__(self, expr=None): self._parent = None self._storage_key = None self._active = True self._expr = None # call the setter self.expr = expr
# # Define the IExpression abstract methods # @property def expr(self): return self._expr @expr.setter def expr(self, expr): self._expr = expr
[docs] class data_expression(expression): """A named, mutable expression that is restricted to storage of data expressions. An exception will be raised if an expression is assigned that references (or is allowed to reference) variables.""" __slots__ = () # # Overload a few methods #
[docs] def is_potentially_variable(self): """A boolean indicating whether this expression can reference variables.""" return False
[docs] def polynomial_degree(self): """Always return zero because we always validate that the stored expression can never reference variables.""" return 0
@property def expr(self): return self._expr @expr.setter def expr(self, expr): if (expr is not None) and (not is_numeric_data(expr)): raise ValueError("Expression is not restricted to numeric data.") self._expr = expr
# inserts class definitions for simple _tuple, _list, and # _dict containers into this module define_simple_containers(globals(), "expression", IExpression)