示例#1
0
 def test_is_constant(self):
     v = variable()
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, False)
     self.assertEqual(v.value, None)
     v.value = 1.0
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, False)
     self.assertEqual(v.value, 1.0)
     v.fix()
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, True)
     self.assertEqual(v.value, 1.0)
     v.value = None
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, True)
     self.assertEqual(v.value, None)
     v.free()
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, False)
     self.assertEqual(v.value, None)
示例#2
0
 def test_is_constant(self):
     v = variable()
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, False)
     self.assertEqual(v.value, None)
     v.value = 1.0
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, False)
     self.assertEqual(v.value, 1.0)
     v.fix()
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, True)
     self.assertEqual(v.value, 1.0)
     v.value = None
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, True)
     self.assertEqual(v.value, None)
     v.free()
     self.assertEqual(v.is_constant(), False)
     self.assertEqual(is_constant(v), False)
     self.assertEqual(v.fixed, False)
     self.assertEqual(v.value, None)
示例#3
0
 def test_is_constant(self):
     f = functional_value()
     self.assertEqual(f.is_constant(), False)
     self.assertEqual(is_constant(f), False)
     f.fn = lambda: 2
     self.assertEqual(f.is_constant(), False)
     self.assertEqual(is_constant(f), False)
示例#4
0
 def test_is_constant(self):
     p = parameter()
     self.assertEqual(p.is_constant(), False)
     self.assertEqual(is_constant(p), False)
     p.value = 1.0
     self.assertEqual(p.is_constant(), False)
     self.assertEqual(is_constant(p), False)
示例#5
0
 def test_is_constant(self):
     p = parameter()
     self.assertEqual(p.is_constant(), False)
     self.assertEqual(is_constant(p), False)
     p.value = 1.0
     self.assertEqual(p.is_constant(), False)
     self.assertEqual(is_constant(p), False)
示例#6
0
 def test_is_constant(self):
     f = functional_value()
     self.assertEqual(f.is_constant(), False)
     self.assertEqual(is_constant(f), False)
     f.fn = lambda: 2
     self.assertEqual(f.is_constant(), False)
     self.assertEqual(is_constant(f), False)
示例#7
0
 def test_is_constant(self):
     e = self._ctype_factory()
     self.assertEqual(e.is_constant(), False)
     self.assertEqual(is_constant(e), False)
     e.expr = 1
     self.assertEqual(e.is_constant(), False)
     self.assertEqual(is_constant(e), False)
     p = parameter()
     self.assertEqual(p.is_constant(), False)
     self.assertEqual(is_constant(p), False)
     p.value = 2
     e.expr = p + 1
     self.assertEqual(e.is_constant(), False)
     self.assertEqual(is_constant(e), False)
示例#8
0
 def test_is_constant(self):
     e = self._ctype_factory()
     self.assertEqual(e.is_constant(), False)
     self.assertEqual(is_constant(e), False)
     e.expr = 1
     self.assertEqual(e.is_constant(), False)
     self.assertEqual(is_constant(e), False)
     p = parameter()
     self.assertEqual(p.is_constant(), False)
     self.assertEqual(is_constant(p), False)
     p.value = 2
     e.expr = p + 1
     self.assertEqual(e.is_constant(), False)
     self.assertEqual(is_constant(e), False)
示例#9
0
    def test_is_constant(self):
        v = variable()
        e = noclone(v)
        self.assertEqual(e.is_constant(), False)
        self.assertEqual(is_constant(e), False)
        v.fix(1)
        self.assertEqual(e.is_constant(), False)
        self.assertEqual(is_constant(e), False)

        p = parameter()
        e = noclone(p)
        self.assertEqual(p.is_constant(), False)
        self.assertEqual(is_constant(p), False)

        self.assertEqual(is_constant(noclone(1)), True)
示例#10
0
    def test_is_constant(self):
        v = variable()
        e = noclone(v)
        self.assertEqual(e.is_constant(), False)
        self.assertEqual(is_constant(e), False)
        v.fix(1)
        self.assertEqual(e.is_constant(), False)
        self.assertEqual(is_constant(e), False)

        p = parameter()
        e = noclone(p)
        self.assertEqual(p.is_constant(), False)
        self.assertEqual(is_constant(p), False)

        self.assertEqual(is_constant(noclone(1)), True)
示例#11
0
def _diff_abs(node, val_dict, der_dict):
    """
    Reverse automatic differentiation on the abs function.
    This will raise an exception at 0.

    Parameters
    ----------
    node: pyomo.core.expr.numeric_expr.UnaryFunctionExpression
    val_dict: ComponentMap
    der_dict: ComponentMap
    """
    assert len(node.args) == 1
    arg = node.args[0]
    der = der_dict[node]
    val = val_dict[arg]
    if not is_constant(val):
        raise DifferentiationException(
            'Cannot perform symbolic differentiation of abs(x). Please use numeric differentiation'
        )
    if val == 0:
        raise DifferentiationException('Cannot differentiate abs(x) at x=0')
    elif val < 0:
        der_dict[arg] -= der
    else:
        der_dict[arg] += der
示例#12
0
def _diff_abs(node, val_dict, der_dict):
    """
    Reverse automatic differentiation on the abs function.
    This will raise an exception at 0.

    Parameters
    ----------
    node: pyomo.core.expr.numeric_expr.UnaryFunctionExpression
    val_dict: ComponentMap
    der_dict: ComponentMap
    """
    assert len(node.args) == 1
    arg = node.args[0]
    der = der_dict[node]
    val = val_dict[arg]
    if is_constant(val) and val == 0:
        raise DifferentiationException('Cannot differentiate abs(x) at x=0')
    der_dict[arg] += der * val / abs(val)
示例#13
0
    def _build_relaxation(self):
        clb, cub = _get_bounds(self._c)
        slb, sub = _get_bounds(self._s)
        vmsq_1_lb, vmsq_1_ub = _get_bounds(self._vmsq_1)
        vmsq_2_lb, vmsq_2_ub = _get_bounds(self._vmsq_2)

        if None in {
                clb, cub, slb, sub, vmsq_1_lb, vmsq_1_ub, vmsq_2_lb, vmsq_2_ub
        }:
            return None

        if vmsq_1_lb == vmsq_1_ub and vmsq_2_lb == vmsq_2_ub:
            if clb == cub or slb == sub:
                rhs = [vmsq_1_lb * vmsq_2_lb]
            else:
                rhs = [math.sqrt(vmsq_1_lb * vmsq_2_lb)]
        elif vmsq_1_lb == vmsq_1_ub:
            if clb == cub or slb == sub:
                rhs = [vmsq_1_lb * self._vmsq_2]
            else:
                m = (math.sqrt(vmsq_2_ub) -
                     math.sqrt(vmsq_2_lb)) / (vmsq_2_ub - vmsq_2_lb)
                b = math.sqrt(vmsq_2_ub) - m * vmsq_2_ub
                rhs = [math.sqrt(vmsq_1_lb) * (m * self._vmsq_2 + b)]
        elif vmsq_2_lb == vmsq_2_ub:
            if clb == cub or slb == sub:
                rhs = [vmsq_2_lb * self._vmsq_1]
            else:
                m = (math.sqrt(vmsq_1_ub) -
                     math.sqrt(vmsq_1_lb)) / (vmsq_1_ub - vmsq_1_lb)
                b = math.sqrt(vmsq_1_ub) - m * vmsq_1_ub
                rhs = [math.sqrt(vmsq_2_lb) * (m * self._vmsq_1 + b)]
        else:
            if clb == cub or slb == sub:
                rhs = [
                    vmsq_1_lb * self._vmsq_2 + self._vmsq_1 * vmsq_2_lb -
                    vmsq_1_lb * vmsq_2_lb, vmsq_1_ub * self._vmsq_2 +
                    self._vmsq_1 * vmsq_2_ub - vmsq_1_ub * vmsq_2_ub
                ]
            else:
                cm = [
                    sqrt(vmsq_1_lb) / (sqrt(vmsq_2_lb) + sqrt(vmsq_2_ub)),
                    sqrt(vmsq_1_ub) / (sqrt(vmsq_2_lb) + sqrt(vmsq_2_ub))
                ]
                bm = [
                    sqrt(vmsq_2_lb) / (sqrt(vmsq_1_lb) + sqrt(vmsq_1_ub)),
                    sqrt(vmsq_2_ub) / (sqrt(vmsq_1_lb) + sqrt(vmsq_1_ub))
                ]
                am = [
                    sqrt(vmsq_1_lb * vmsq_2_lb) - bm[0] * vmsq_1_lb -
                    cm[0] * vmsq_2_lb,
                    sqrt(vmsq_1_ub * vmsq_2_ub) - bm[1] * vmsq_1_ub -
                    cm[1] * vmsq_2_ub
                ]
                rhs = list()
                for i in [0, 1]:
                    rhs.append(am[i] + bm[i] * self._vmsq_1 +
                               cm[i] * self._vmsq_2)

        if clb == cub and slb == sub:
            lhs = [clb**2 + slb**2]
        elif clb == cub:
            m = (sub**2 - slb**2) / (sub - slb)
            b = sub**2 - m * sub
            lhs = [clb**2 + m * self._s + b]
        elif slb == sub:
            m = (cub**2 - clb**2) / (cub - clb)
            b = cub**2 - m * cub
            lhs = [m * self._c + b + slb**2]
        else:
            if sqrt(cub**2 + sub**2) + sqrt(clb**2 + slb**2) - sqrt(
                    cub**2 + slb**2) - sqrt(clb**2 + sub**2) <= 0:
                cn = [(sqrt(clb**2 + sub**2) - sqrt(clb**2 + slb**2)) /
                      (sub - slb),
                      (sqrt(cub**2 + sub**2) - sqrt(cub**2 + slb**2)) /
                      (sub - slb)]
                bn = [(sqrt(cub**2 + slb**2) - sqrt(clb**2 + slb**2)) /
                      (cub - clb),
                      (sqrt(cub**2 + sub**2) - sqrt(clb**2 + sub**2)) /
                      (cub - clb)]
                an = [
                    sqrt(clb**2 + slb**2) - bn[0] * clb - cn[0] * slb,
                    sqrt(cub**2 + sub**2) - bn[1] * cub - cn[1] * sub
                ]
            else:
                cn = [(sqrt(clb**2 + sub**2) - sqrt(clb**2 + slb**2)) /
                      (sub - slb),
                      (sqrt(cub**2 + sub**2) - sqrt(cub**2 + slb**2)) /
                      (sub - slb)]
                bn = [(sqrt(cub**2 + sub**2) - sqrt(clb**2 + sub**2)) /
                      (cub - clb),
                      (sqrt(cub**2 + slb**2) - sqrt(clb**2 + slb**2)) /
                      (cub - clb)]
                an = [
                    sqrt(clb**2 + slb**2) - bn[0] * clb - cn[0] * slb,
                    sqrt(cub**2 + sub**2) - bn[1] * cub - cn[1] * sub
                ]
            lhs = list()
            for i in [0, 1]:
                lhs.append(an[i] + bn[i] * self._c + cn[i] * self._s)

        self.underestimators = pe.ConstraintList()
        for _lhs in lhs:
            for _rhs in rhs:
                if is_constant(_lhs) and is_constant(_rhs):
                    continue
                self.underestimators.add(_lhs >= _rhs)
示例#14
0
 def is_constant(self):
     """A boolean indicating whether this expression is constant."""
     return is_constant(self._expr)
示例#15
0
    def set_value(self, expr):
        """Set the expression on this constraint."""

        _expr_type = expr.__class__
        if hasattr(expr, 'is_relational'):
            relational_expr = expr.is_relational()
            if not relational_expr:
                raise ValueError("Constraint '%s' does not have a proper "
                                 "value. Found '%s'\nExpecting a tuple or "
                                 "equation. Examples:"
                                 "\n   sum(model.costs) == model.income"
                                 "\n   (0, model.price[item], 50)" %
                                 (self.name, str(expr)))

        elif _expr_type is tuple:  # or expr_type is list:
            #
            # Form equality expression
            #
            if len(expr) == 2:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                self._equality = True
                if arg1 is None or (not arg1.is_potentially_variable()):
                    self._lower = self._upper = arg1
                    self._body = arg0
                elif arg0 is None or (not arg0.is_potentially_variable()):
                    self._lower = self._upper = arg0
                    self._body = arg1
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = arg0 - arg1
            #
            # Form inequality expression
            #
            elif len(expr) == 3:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                    if arg0.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the lower "
                            "value was not data or an expression "
                            "restricted to storage of data." % (self.name))

                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                arg2 = expr[2]
                if arg2 is not None:
                    arg2 = as_numeric(arg2)
                    if arg2.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the upper "
                            "value was not data or an expression "
                            "restricted to storage of data." % (self.name))

                self._lower = arg0
                self._body = arg1
                self._upper = arg2
            else:
                raise ValueError(
                    "Constructor rule for constraint '%s' returned "
                    "a tuple of length %d. Expecting a tuple of "
                    "length 2 or 3:\n"
                    "Equality:   (left, right)\n"
                    "Inequality: (lower, expression, upper)" %
                    (self.name, len(expr)))

            relational_expr = False
        #
        # Ignore an 'empty' constraint
        #
        elif _expr_type is type:
            self._body = None
            self._lower = None
            self._upper = None
            self._equality = False

            if expr is Constraint.Skip:
                del self.parent_component()[self.index()]
                return
            elif expr is Constraint.Infeasible:
                del self.parent_component()[self.index()]
                raise ValueError("Constraint '%s' is always infeasible" %
                                 (self.name, ))
            else:
                raise ValueError("Constraint '%s' does not have a proper "
                                 "value. Found '%s'\nExpecting a tuple or "
                                 "equation. Examples:"
                                 "\n   sum(model.costs) == model.income"
                                 "\n   (0, model.price[item], 50)" %
                                 (self.name, str(expr)))

        elif expr is None:
            raise ValueError(_rule_returned_none_error % (self.name, ))

        elif _expr_type is bool:
            #
            # There are cases where a user thinks they are generating
            # a valid 2-sided inequality, but Python's internal
            # systems for handling chained inequalities is doing
            # something very different and resolving it to True /
            # False.  In this case, chainedInequality will be
            # non-None, but the expression will be a bool.  For
            # example, model.a < 1 > 0.
            #
            if logical_expr._using_chained_inequality \
               and logical_expr._chainedInequality.prev is not None:

                buf = StringIO()
                logical_expr._chainedInequality.prev.pprint(buf)
                #
                # We are about to raise an exception, so it's OK to
                # reset chainedInequality
                #
                logical_expr._chainedInequality.prev = None
                raise ValueError(
                    "Invalid chained (2-sided) inequality detected. "
                    "The expression is resolving to %s instead of a "
                    "Pyomo Expression object. This can occur when "
                    "the middle term of a chained inequality is a "
                    "constant or immutable parameter, for example, "
                    "'model.a <= 1 >= 0'.  The proper form for "
                    "2-sided inequalities is '0 <= model.a <= 1'."
                    "\n\nError thrown for Constraint '%s'"
                    "\n\nUnresolved (dangling) inequality "
                    "expression: %s" % (expr, self.name, buf))
            else:
                raise ValueError(
                    "Invalid constraint expression. The constraint "
                    "expression resolved to a trivial Boolean (%s) "
                    "instead of a Pyomo object. Please modify your "
                    "rule to return Constraint.%s instead of %s."
                    "\n\nError thrown for Constraint '%s'" %
                    (expr, "Feasible" if expr else "Infeasible", expr,
                     self.name))

        else:
            msg = ("Constraint '%s' does not have a proper "
                   "value. Found '%s'\nExpecting a tuple or "
                   "equation. Examples:"
                   "\n   sum(model.costs) == model.income"
                   "\n   (0, model.price[item], 50)" % (self.name, str(expr)))
            if type(expr) is bool:
                msg += ("\nNote: constant Boolean expressions "
                        "are not valid constraint expressions. "
                        "Some apparently non-constant compound "
                        "inequalities (e.g. 'expr >= 0 <= 1') "
                        "can return boolean values; the proper "
                        "form for compound inequalities is "
                        "always 'lb <= expr <= ub'.")
            raise ValueError(msg)
        #
        # Special check for chainedInequality errors like "if var <
        # 1:" within rules.  Catching them here allows us to provide
        # the user with better (and more immediate) debugging
        # information.  We don't want to check earlier because we
        # want to provide a specific debugging message if the
        # construction rule returned True/False; for example, if the
        # user did ( var < 1 > 0 ) (which also results in a non-None
        # chainedInequality value)
        #
        if logical_expr._using_chained_inequality \
           and logical_expr._chainedInequality.prev is not None:
            raise TypeError(logical_expr._chainedInequality.error_message())
        #
        # Process relational expressions
        # (i.e. explicit '==', '<', and '<=')
        #
        if relational_expr:
            if _expr_type is logical_expr.EqualityExpression:
                # Equality expression: only 2 arguments!
                self._equality = True

                if expr.arg(
                        1).__class__ in native_numeric_types or not expr.arg(
                            1).is_potentially_variable():
                    self._lower = self._upper = as_numeric(expr.arg(1))
                    self._body = expr.arg(0)
                elif expr.arg(
                        0).__class__ in native_numeric_types or not expr.arg(
                            0).is_potentially_variable():
                    self._lower = self._upper = as_numeric(expr.arg(0))
                    self._body = expr.arg(1)
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = expr.arg(0) - expr.arg(1)

            elif _expr_type is logical_expr.InequalityExpression:
                if expr._strict:
                    raise ValueError("Constraint '%s' encountered a strict "
                                     "inequality expression ('>' or '<'). All"
                                     " constraints must be formulated using "
                                     "using '<=', '>=', or '=='." %
                                     (self.name))

                if not expr.arg(1).is_potentially_variable():
                    self._lower = None
                    self._body = expr.arg(0)
                    self._upper = as_numeric(expr.arg(1))
                elif not expr.arg(0).is_potentially_variable():
                    self._lower = as_numeric(expr.arg(0))
                    self._body = expr.arg(1)
                    self._upper = None
                else:
                    self._lower = None
                    self._body = expr.arg(0)
                    self._body -= expr.arg(1)
                    self._upper = ZeroConstant

            else:  # RangedExpression
                if any(expr._strict):
                    raise ValueError("Constraint '%s' encountered a strict "
                                     "inequality expression ('>' or '<'). All"
                                     " constraints must be formulated using "
                                     "using '<=', '>=', or '=='." %
                                     (self.name))

                #if expr.arg(0).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the lower "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))
                #if expr.arg(2).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "\
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the upper "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))

                self._lower = as_numeric(expr.arg(0))
                self._body = expr.arg(1)
                self._upper = as_numeric(expr.arg(2))

        #
        # Reset the values to 'None' if they are 'infinite'
        #
        if (self._lower is not None) and is_constant(self._lower):
            val = self._lower if self._lower.__class__ in native_numeric_types else self._lower(
            )
            if not pyutilib.math.is_finite(val):
                if val > 0:
                    raise ValueError(
                        "Constraint '%s' created with a +Inf lower "
                        "bound." % (self.name))
                self._lower = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError("Constraint '%s' created with a non-numeric "
                                 "lower bound." % (self.name))

        if (self._upper is not None) and is_constant(self._upper):
            val = self._upper if self._upper.__class__ in native_numeric_types else self._upper(
            )
            if not pyutilib.math.is_finite(val):
                if val < 0:
                    raise ValueError(
                        "Constraint '%s' created with a -Inf upper "
                        "bound." % (self.name))
                self._upper = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError("Constraint '%s' created with a non-numeric "
                                 "upper bound." % (self.name))

        #
        # Error check, to ensure that we don't have a constraint that
        # doesn't depend on any variables / parameters.
        #
        # Error check, to ensure that we don't have an equality
        # constraint with 'infinite' RHS
        #
        if self._equality:
            if self._lower is None:
                raise ValueError("Equality constraint '%s' defined with "
                                 "non-finite term." % (self.name))
            assert self._lower is self._upper
示例#16
0
    def set_value(self, expr):
        """Set the expression on this constraint."""

        _expr_type = expr.__class__
        if hasattr(expr, 'is_relational'):
            relational_expr = expr.is_relational()
            if not relational_expr:
                raise ValueError(
                    "Constraint '%s' does not have a proper "
                    "value. Found '%s'\nExpecting a tuple or "
                    "equation. Examples:"
                    "\n   sum(model.costs) == model.income"
                    "\n   (0, model.price[item], 50)"
                    % (self.name, str(expr)))

        elif _expr_type is tuple: # or expr_type is list:
            #
            # Form equality expression
            #
            if len(expr) == 2:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                self._equality = True
                if arg1 is None or (not arg1.is_potentially_variable()):
                    self._lower = self._upper = arg1
                    self._body = arg0
                elif arg0 is None or (not arg0.is_potentially_variable()):
                    self._lower = self._upper = arg0
                    self._body = arg1
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = arg0 - arg1
            #
            # Form inequality expression
            #
            elif len(expr) == 3:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                    if arg0.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the lower "
                            "value was not data or an expression "
                            "restricted to storage of data."
                            % (self.name))

                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                arg2 = expr[2]
                if arg2 is not None:
                    arg2 = as_numeric(arg2)
                    if arg2.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the upper "
                            "value was not data or an expression "
                            "restricted to storage of data."
                            % (self.name))

                self._lower = arg0
                self._body  = arg1
                self._upper = arg2
            else:
                raise ValueError(
                    "Constructor rule for constraint '%s' returned "
                    "a tuple of length %d. Expecting a tuple of "
                    "length 2 or 3:\n"
                    "Equality:   (left, right)\n"
                    "Inequality: (lower, expression, upper)"
                    % (self.name, len(expr)))

            relational_expr = False
        #
        # Ignore an 'empty' constraint
        #
        elif _expr_type is type:
            self._body = None
            self._lower = None
            self._upper = None
            self._equality = False

            if expr is Constraint.Skip:
                del self.parent_component()[self.index()]
                return
            elif expr is Constraint.Infeasible:
                del self.parent_component()[self.index()]
                raise ValueError(
                    "Constraint '%s' is always infeasible"
                    % (self.name,) )
            else:
                raise ValueError(
                    "Constraint '%s' does not have a proper "
                    "value. Found '%s'\nExpecting a tuple or "
                    "equation. Examples:"
                    "\n   sum(model.costs) == model.income"
                    "\n   (0, model.price[item], 50)"
                    % (self.name, str(expr)))

        elif expr is None:
            raise ValueError(_rule_returned_none_error % (self.name,))

        elif _expr_type is bool:
            raise ValueError(
                "Invalid constraint expression. The constraint "
                "expression resolved to a trivial Boolean (%s) "
                "instead of a Pyomo object. Please modify your "
                "rule to return Constraint.%s instead of %s."
                "\n\nError thrown for Constraint '%s'"
                % (expr, "Feasible" if expr else "Infeasible",
                   expr, self.name))

        else:
            msg = ("Constraint '%s' does not have a proper "
                   "value. Found '%s'\nExpecting a tuple or "
                   "equation. Examples:"
                   "\n   sum(model.costs) == model.income"
                   "\n   (0, model.price[item], 50)"
                   % (self.name, str(expr)))
            if type(expr) is bool:
                msg += ("\nNote: constant Boolean expressions "
                        "are not valid constraint expressions. "
                        "Some apparently non-constant compound "
                        "inequalities (e.g. 'expr >= 0 <= 1') "
                        "can return boolean values; the proper "
                        "form for compound inequalities is "
                        "always 'lb <= expr <= ub'.")
            raise ValueError(msg)

        #
        # Process relational expressions
        # (i.e. explicit '==', '<', and '<=')
        #
        if relational_expr:
            if _expr_type is logical_expr.EqualityExpression:
                # Equality expression: only 2 arguments!
                self._equality = True

                if expr.arg(1).__class__ in native_numeric_types or not expr.arg(1).is_potentially_variable():
                    self._lower = self._upper = as_numeric(expr.arg(1))
                    self._body = expr.arg(0)
                elif expr.arg(0).__class__ in native_numeric_types or not expr.arg(0).is_potentially_variable():
                    self._lower = self._upper = as_numeric(expr.arg(0))
                    self._body = expr.arg(1)
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = expr.arg(0) - expr.arg(1)

            elif _expr_type is logical_expr.InequalityExpression:
                if expr._strict:
                    raise ValueError(
                        "Constraint '%s' encountered a strict "
                        "inequality expression ('>' or '<'). All"
                        " constraints must be formulated using "
                        "using '<=', '>=', or '=='."
                        % (self.name))

                arg0 = as_numeric(expr.arg(0))
                arg1 = as_numeric(expr.arg(1))
                if not arg1.is_potentially_variable():
                    self._lower = None
                    self._body  = arg0
                    self._upper = arg1
                elif not arg0.is_potentially_variable():
                    self._lower = arg0
                    self._body  = arg1
                    self._upper = None
                else:
                    self._lower = None
                    self._body = arg0
                    self._body -= arg1
                    self._upper = ZeroConstant


            else:   # RangedExpression
                if any(expr._strict):
                    raise ValueError(
                        "Constraint '%s' encountered a strict "
                        "inequality expression ('>' or '<'). All"
                        " constraints must be formulated using "
                        "using '<=', '>=', or '=='."
                        % (self.name))

                #if expr.arg(0).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the lower "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))
                #if expr.arg(2).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "\
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the upper "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))

                self._lower = as_numeric(expr.arg(0))
                self._body  = expr.arg(1)
                self._upper = as_numeric(expr.arg(2))

        #
        # Reset the values to 'None' if they are 'infinite'
        #
        if (self._lower is not None) and is_constant(self._lower):
            val = self._lower if self._lower.__class__ in native_numeric_types else self._lower()
            if not math.isfinite(val):
                if val > 0:
                    raise ValueError(
                        "Constraint '%s' created with a +Inf lower "
                        "bound." % (self.name))
                self._lower = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError(
                    "Constraint '%s' created with a non-numeric "
                    "lower bound." % (self.name))

        if (self._upper is not None) and is_constant(self._upper):
            val = self._upper if self._upper.__class__ in native_numeric_types else self._upper()
            if not math.isfinite(val):
                if val < 0:
                    raise ValueError(
                        "Constraint '%s' created with a -Inf upper "
                        "bound." % (self.name))
                self._upper = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError(
                    "Constraint '%s' created with a non-numeric "
                    "upper bound." % (self.name))

        #
        # Error check, to ensure that we don't have a constraint that
        # doesn't depend on any variables / parameters.
        #
        # Error check, to ensure that we don't have an equality
        # constraint with 'infinite' RHS
        #
        if self._equality:
            if self._lower is None:
                raise ValueError(
                    "Equality constraint '%s' defined with "
                    "non-finite term." % (self.name))
            assert self._lower is self._upper
示例#17
0
文件: expression.py 项目: Pyomo/pyomo
 def is_constant(self):
     """A boolean indicating whether this expression is constant."""
     return is_constant(self._expr)
示例#18
0
    def set_value(self, expr):
        """Set the expression on this constraint."""

        if expr is None:
            self._body = None
            self._lower = None
            self._upper = None
            self._equality = False
            return

        _expr_type = expr.__class__
        if _expr_type is tuple:  # or expr_type is list:
            #
            # Form equality expression
            #
            if len(expr) == 2:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                self._equality = True
                if arg1 is None or (not arg1.is_potentially_variable()):
                    self._lower = self._upper = arg1
                    self._body = arg0
                elif arg0 is None or (not arg0.is_potentially_variable()):
                    self._lower = self._upper = arg0
                    self._body = arg1
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = arg0 - arg1
            #
            # Form inequality expression
            #
            elif len(expr) == 3:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                    if arg0.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the lower "
                            "value was not data or an expression "
                            "restricted to storage of data." % (self.name))

                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                arg2 = expr[2]
                if arg2 is not None:
                    arg2 = as_numeric(arg2)
                    if arg2.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the upper "
                            "value was not data or an expression "
                            "restricted to storage of data." % (self.name))

                self._lower = arg0
                self._body = arg1
                self._upper = arg2
            else:
                raise ValueError(
                    "Constructor rule for constraint '%s' returned "
                    "a tuple of length %d. Expecting a tuple of "
                    "length 2 or 3:\n"
                    "Equality:   (left, right)\n"
                    "Inequality: (lower, expression, upper)" %
                    (self.name, len(expr)))

            relational_expr = False
        else:
            try:
                relational_expr = expr.is_relational()
                if not relational_expr:
                    raise ValueError("Constraint '%s' does not have a proper "
                                     "value. Found '%s'\nExpecting a tuple or "
                                     "equation. Examples:"
                                     "\n   sum(model.costs) == model.income"
                                     "\n   (0, model.price[item], 50)" %
                                     (self.name, str(expr)))
            except AttributeError:
                msg = ("Constraint '%s' does not have a proper "
                       "value. Found '%s'\nExpecting a tuple or "
                       "equation. Examples:"
                       "\n   sum(model.costs) == model.income"
                       "\n   (0, model.price[item], 50)" %
                       (self.name, str(expr)))
                if type(expr) is bool:
                    msg += ("\nNote: constant Boolean expressions "
                            "are not valid constraint expressions. "
                            "Some apparently non-constant compound "
                            "inequalities (e.g. 'expr >= 0 <= 1') "
                            "can return boolean values; the proper "
                            "form for compound inequalities is "
                            "always 'lb <= expr <= ub'.")
                raise ValueError(msg)
        #
        # Special check for chainedInequality errors like "if var <
        # 1:" within rules.  Catching them here allows us to provide
        # the user with better (and more immediate) debugging
        # information.  We don't want to check earlier because we
        # want to provide a specific debugging message if the
        # construction rule returned True/False; for example, if the
        # user did ( var < 1 > 0 ) (which also results in a non-None
        # chainedInequality value)
        #
        if EXPR._using_chained_inequality and EXPR._chainedInequality.prev is not None:
            raise TypeError(EXPR._chainedInequality.error_message())
        #
        # Process relational expressions
        # (i.e. explicit '==', '<', and '<=')
        #
        if relational_expr:
            if _expr_type is EXPR.EqualityExpression:
                # Equality expression: only 2 arguments!
                self._equality = True

                if expr.arg(
                        1).__class__ in native_numeric_types or not expr.arg(
                            1).is_potentially_variable():
                    self._lower = self._upper = expr.arg(1)
                    self._body = expr.arg(0)
                elif expr.arg(
                        0).__class__ in native_numeric_types or not expr.arg(
                            0).is_potentially_variable():
                    self._lower = self._upper = expr.arg(0)
                    self._body = expr.arg(1)
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = expr.arg(0) - expr.arg(1)

            elif _expr_type is EXPR.InequalityExpression:
                if expr._strict:
                    raise ValueError("Constraint '%s' encountered a strict "
                                     "inequality expression ('>' or '<'). All"
                                     " constraints must be formulated using "
                                     "using '<=', '>=', or '=='." %
                                     (self.name))

                if not expr.arg(1).is_potentially_variable():
                    self._lower = None
                    self._body = expr.arg(0)
                    self._upper = expr.arg(1)
                elif not expr.arg(0).is_potentially_variable():
                    self._lower = expr.arg(0)
                    self._body = expr.arg(1)
                    self._upper = None
                else:
                    self._lower = None
                    self._body = expr.arg(0)
                    self._body -= expr.arg(1)
                    self._upper = ZeroConstant

            else:  # RangedExpression
                if any(expr._strict):
                    raise ValueError("Constraint '%s' encountered a strict "
                                     "inequality expression ('>' or '<'). All"
                                     " constraints must be formulated using "
                                     "using '<=', '>=', or '=='." %
                                     (self.name))

                #if expr.arg(0).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the lower "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))
                #if expr.arg(2).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "\
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the upper "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))

                self._lower = expr.arg(0)
                self._body = expr.arg(1)
                self._upper = expr.arg(2)

        #
        # Reset the values to 'None' if they are 'infinite'
        #
        if (self._lower is not None) and is_constant(self._lower):
            val = self._lower if self._lower.__class__ in native_numeric_types else self._lower(
            )
            if not pyutilib.math.is_finite(val):
                if val > 0:
                    raise ValueError(
                        "Constraint '%s' created with a +Inf lower "
                        "bound." % (self.name))
                self._lower = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError("Constraint '%s' created with a non-numeric "
                                 "lower bound." % (self.name))

        if (self._upper is not None) and is_constant(self._upper):
            val = self._upper if self._upper.__class__ in native_numeric_types else self._upper(
            )
            if not pyutilib.math.is_finite(val):
                if val < 0:
                    raise ValueError(
                        "Constraint '%s' created with a -Inf upper "
                        "bound." % (self.name))
                self._upper = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError("Constraint '%s' created with a non-numeric "
                                 "upper bound." % (self.name))

        #
        # Error check, to ensure that we don't have a constraint that
        # doesn't depend on any variables / parameters.
        #
        # Error check, to ensure that we don't have an equality
        # constraint with 'infinite' RHS
        #
        if self._equality:
            if self._lower is None:
                raise ValueError("Equality constraint '%s' defined with "
                                 "non-finite term." % (self.name))
            assert self._lower is self._upper
示例#19
0
def _relax_leaf_to_root_PowExpression(node, values, aux_var_map, degree_map, parent_block, relaxation_side_map, counter):
    arg1, arg2 = values
    degree1 = degree_map[arg1]
    degree2 = degree_map[arg2]
    if degree2 == 0:
        if degree1 == 0:
            res = arg1 ** arg2
            degree_map[res] = 0
            return res
        if not is_constant(arg2):
            logger.warning('Only constant exponents are supported: ' + str(arg1**arg2) + '\nReplacing ' + str(arg2) + ' with its value.')
        arg2 = pe.value(arg2)
        if arg2 == 1:
            return arg1
        elif arg2 == 0:
            res = 1
            degree_map[res] = 0
            return res
        elif arg2 == 2:
            return _relax_quadratic(arg1=arg1, aux_var_map=aux_var_map, relaxation_side=relaxation_side_map[node],
                                    degree_map=degree_map, parent_block=parent_block, counter=counter)
        elif arg2 >= 0:
            if arg2 == round(arg2):
                if arg2 % 2 == 0 or compute_bounds_on_expr(arg1)[0] >= 0:
                    return _relax_convex_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                             relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                             parent_block=parent_block, counter=counter)
                elif compute_bounds_on_expr(arg1)[1] <= 0:
                    return _relax_concave_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                              relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                              parent_block=parent_block, counter=counter)
                else:  # reformulate arg1 ** arg2 as arg1 * arg1 ** (arg2 - 1)
                    _new_relaxation_side_map = ComponentMap()
                    _reformulated = arg1 * arg1 ** (arg2 - 1)
                    _new_relaxation_side_map[_reformulated] = relaxation_side_map[node]
                    res = _relax_expr(expr=_reformulated, aux_var_map=aux_var_map, parent_block=parent_block,
                                      relaxation_side_map=_new_relaxation_side_map, counter=counter,
                                      degree_map=degree_map)
                    degree_map[res] = 1
                    return res
            else:
                if arg2 < 1:
                    return _relax_concave_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                              relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                              parent_block=parent_block, counter=counter)
                else:
                    return _relax_convex_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                             relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                             parent_block=parent_block, counter=counter)
        else:
            if arg2 == round(arg2):
                if compute_bounds_on_expr(arg1)[0] >= 0:
                    return _relax_convex_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                             relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                             parent_block=parent_block, counter=counter)
                elif compute_bounds_on_expr(arg1)[1] <= 0:
                    if arg2 % 2 == 0:
                        return _relax_convex_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                                 relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                                 parent_block=parent_block, counter=counter)
                    else:
                        return _relax_concave_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                                  relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                                  parent_block=parent_block, counter=counter)
                else:
                    # reformulate arg1 ** arg2 as 1 / arg1 ** (-arg2)
                    _new_relaxation_side_map = ComponentMap()
                    _reformulated = 1 / (arg1 ** (-arg2))
                    _new_relaxation_side_map[_reformulated] = relaxation_side_map[node]
                    res = _relax_expr(expr=_reformulated, aux_var_map=aux_var_map, parent_block=parent_block,
                                      relaxation_side_map=_new_relaxation_side_map, counter=counter,
                                      degree_map=degree_map)
                    degree_map[res] = 1
                    return res
            else:
                assert compute_bounds_on_expr(arg1)[0] >= 0
                return _relax_convex_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                         relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                         parent_block=parent_block, counter=counter)
    elif degree1 == 0:
        if not is_constant(arg1):
            logger.warning('Found {0} raised to a variable power. However, {0} does not appear to be constant (maybe '
                           'it is or depends on a mutable Param?). Replacing {0} with its value.'.format(str(arg1)))
            arg1 = pe.value(arg1)
        if arg1 < 0:
            raise ValueError('Cannot raise a negative base to a variable exponent: ' + str(arg1**arg2))
        return _relax_convex_pow(arg1=arg1, arg2=arg2, aux_var_map=aux_var_map,
                                 relaxation_side=relaxation_side_map[node], degree_map=degree_map,
                                 parent_block=parent_block, counter=counter, swap=True)
    else:
        if (id(arg1), id(arg2), 'pow') in aux_var_map:
            _aux_var, relaxation = aux_var_map[id(arg1), id(arg2), 'pow']
            if relaxation_side_map[node] != relaxation.relaxation_side:
                relaxation.relaxation_side = RelaxationSide.BOTH
            return _aux_var
        else:
            assert compute_bounds_on_expr(arg1)[0] >= 0
            _new_relaxation_side_map = ComponentMap()
            _reformulated = pe.exp(arg2 * pe.log(arg1))
            _new_relaxation_side_map[_reformulated] = relaxation_side_map[node]
            res = _relax_expr(expr=_reformulated, aux_var_map=aux_var_map, parent_block=parent_block,
                              relaxation_side_map=_new_relaxation_side_map, counter=counter,
                              degree_map=degree_map)
            degree_map[res] = 1
            return res
示例#20
0
文件: constraint.py 项目: Pyomo/pyomo
    def set_value(self, expr):
        """Set the expression on this constraint."""

        if expr is None:
            self._body = None
            self._lower = None
            self._upper = None
            self._equality = False
            return

        _expr_type = expr.__class__
        if _expr_type is tuple: # or expr_type is list:
            #
            # Form equality expression
            #
            if len(expr) == 2:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                self._equality = True
                if arg1 is None or (not arg1.is_potentially_variable()):
                    self._lower = self._upper = arg1
                    self._body = arg0
                elif arg0 is None or (not arg0.is_potentially_variable()):
                    self._lower = self._upper = arg0
                    self._body = arg1
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = arg0 - arg1
            #
            # Form inequality expression
            #
            elif len(expr) == 3:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                    if arg0.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the lower "
                            "value was not data or an expression "
                            "restricted to storage of data."
                            % (self.name))

                arg1 = expr[1]
                if arg1 is not None:
                    arg1 = as_numeric(arg1)

                arg2 = expr[2]
                if arg2 is not None:
                    arg2 = as_numeric(arg2)
                    if arg2.is_potentially_variable():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the upper "
                            "value was not data or an expression "
                            "restricted to storage of data."
                            % (self.name))

                self._lower = arg0
                self._body  = arg1
                self._upper = arg2
            else:
                raise ValueError(
                    "Constructor rule for constraint '%s' returned "
                    "a tuple of length %d. Expecting a tuple of "
                    "length 2 or 3:\n"
                    "Equality:   (left, right)\n"
                    "Inequality: (lower, expression, upper)"
                    % (self.name, len(expr)))

            relational_expr = False
        else:
            try:
                relational_expr = expr.is_relational()
                if not relational_expr:
                    raise ValueError(
                        "Constraint '%s' does not have a proper "
                        "value. Found '%s'\nExpecting a tuple or "
                        "equation. Examples:"
                        "\n   sum(model.costs) == model.income"
                        "\n   (0, model.price[item], 50)"
                        % (self.name, str(expr)))
            except AttributeError:
                msg = ("Constraint '%s' does not have a proper "
                       "value. Found '%s'\nExpecting a tuple or "
                       "equation. Examples:"
                       "\n   sum(model.costs) == model.income"
                       "\n   (0, model.price[item], 50)"
                       % (self.name, str(expr)))
                if type(expr) is bool:
                    msg += ("\nNote: constant Boolean expressions "
                            "are not valid constraint expressions. "
                            "Some apparently non-constant compound "
                            "inequalities (e.g. 'expr >= 0 <= 1') "
                            "can return boolean values; the proper "
                            "form for compound inequalities is "
                            "always 'lb <= expr <= ub'.")
                raise ValueError(msg)
        #
        # Special check for chainedInequality errors like "if var <
        # 1:" within rules.  Catching them here allows us to provide
        # the user with better (and more immediate) debugging
        # information.  We don't want to check earlier because we
        # want to provide a specific debugging message if the
        # construction rule returned True/False; for example, if the
        # user did ( var < 1 > 0 ) (which also results in a non-None
        # chainedInequality value)
        #
        if logical_expr._using_chained_inequality and logical_expr._chainedInequality.prev is not None:
            raise TypeError(logical_expr._chainedInequality.error_message())
        #
        # Process relational expressions
        # (i.e. explicit '==', '<', and '<=')
        #
        if relational_expr:
            if _expr_type is logical_expr.EqualityExpression:
                # Equality expression: only 2 arguments!
                self._equality = True

                if expr.arg(1).__class__ in native_numeric_types or not expr.arg(1).is_potentially_variable():
                    self._lower = self._upper = as_numeric(expr.arg(1))
                    self._body = expr.arg(0)
                elif expr.arg(0).__class__ in native_numeric_types or not expr.arg(0).is_potentially_variable():
                    self._lower = self._upper = as_numeric(expr.arg(0))
                    self._body = expr.arg(1)
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = expr.arg(0) - expr.arg(1)

            elif _expr_type is logical_expr.InequalityExpression:
                if expr._strict:
                    raise ValueError(
                        "Constraint '%s' encountered a strict "
                        "inequality expression ('>' or '<'). All"
                        " constraints must be formulated using "
                        "using '<=', '>=', or '=='."
                        % (self.name))

                if not expr.arg(1).is_potentially_variable():
                    self._lower = None
                    self._body  = expr.arg(0)
                    self._upper = as_numeric(expr.arg(1))
                elif not expr.arg(0).is_potentially_variable():
                    self._lower = as_numeric(expr.arg(0))
                    self._body  = expr.arg(1)
                    self._upper = None
                else:
                    self._lower = None
                    self._body = expr.arg(0)
                    self._body -= expr.arg(1)
                    self._upper = ZeroConstant

            
            else:   # RangedExpression
                if any(expr._strict):
                    raise ValueError(
                        "Constraint '%s' encountered a strict "
                        "inequality expression ('>' or '<'). All"
                        " constraints must be formulated using "
                        "using '<=', '>=', or '=='."
                        % (self.name))

                #if expr.arg(0).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the lower "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))
                #if expr.arg(2).is_potentially_variable():
                #    raise ValueError(
                #        "Constraint '%s' found a double-sided "\
                #        "inequality expression (lower <= "
                #        "expression <= upper) but the upper "
                #        "bound was not data or an expression "
                #        "restricted to storage of data."
                #        % (self.name))

                self._lower = as_numeric(expr.arg(0))
                self._body  = expr.arg(1)
                self._upper = as_numeric(expr.arg(2))

        #
        # Reset the values to 'None' if they are 'infinite'
        #
        if (self._lower is not None) and is_constant(self._lower):
            val = self._lower if self._lower.__class__ in native_numeric_types else self._lower()
            if not pyutilib.math.is_finite(val):
                if val > 0:
                    raise ValueError(
                        "Constraint '%s' created with a +Inf lower "
                        "bound." % (self.name))
                self._lower = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError(
                    "Constraint '%s' created with a non-numeric "
                    "lower bound." % (self.name))

        if (self._upper is not None) and is_constant(self._upper):
            val = self._upper if self._upper.__class__ in native_numeric_types else self._upper()
            if not pyutilib.math.is_finite(val):
                if val < 0:
                    raise ValueError(
                        "Constraint '%s' created with a -Inf upper "
                        "bound." % (self.name))
                self._upper = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError(
                    "Constraint '%s' created with a non-numeric "
                    "upper bound." % (self.name))

        #
        # Error check, to ensure that we don't have a constraint that
        # doesn't depend on any variables / parameters.
        #
        # Error check, to ensure that we don't have an equality
        # constraint with 'infinite' RHS
        #
        if self._equality:
            if self._lower is None:
                raise ValueError(
                    "Equality constraint '%s' defined with "
                    "non-finite term." % (self.name))
            assert self._lower is self._upper