Example #1
0
 def _canonical_expression(self, e):
     e_ = None
     if e.__class__ is _EqualityExpression:
         if e._args[1].is_fixed():
             _e = (e._args[1], e._args[0])
         #
         # The first argument of an equality is never fixed
         #
         #elif e._args[0].is_fixed():
         #    _e = (e._args[0], e._args[1])
         else:
             tmp = generate_expression_bypassCloneCheck(
                 _sub, e._args[0], e._args[1])
             _e = (ZeroConstant, tmp)
     elif e.__class__ is _InequalityExpression:
         if len(e._args) == 3:
             _e = (e._args[0], e._args[1], e._args[2])
         else:
             if e._args[1].is_fixed():
                 _e = (None, e._args[0], e._args[1])
             elif e._args[0].is_fixed():
                 _e = (e._args[0], e._args[1], None)
             else:
                 _e = (ZeroConstant,
                       generate_expression_bypassCloneCheck(
                           _sub, e._args[1], e._args[0]), None)
     else:
         _e = (None, e, None)
     return _e
Example #2
0
 def _canonical_expression(self, e):
     e_ = None
     if e.__class__ is _EqualityExpression:
         if e._args[1].is_fixed():
             _e = (e._args[1], e._args[0])
         #
         # The first argument of an equality is never fixed
         #
         #elif e._args[0].is_fixed():
         #    _e = (e._args[0], e._args[1])
         else:
             tmp = generate_expression_bypassCloneCheck(_sub, e._args[0], e._args[1])
             _e = ( ZeroConstant, tmp)
     elif e.__class__ is _InequalityExpression:
         if len(e._args) == 3:
             _e = (e._args[0], e._args[1], e._args[2])
         else:
             if e._args[1].is_fixed():
                 _e = (None, e._args[0], e._args[1])
             elif e._args[0].is_fixed():
                 _e = (e._args[0], e._args[1], None)
             else:
                 _e = ( ZeroConstant, generate_expression_bypassCloneCheck(
                         _sub, e._args[1], e._args[0]), None )
     else:
         _e = (None, e, None)
     return _e
Example #3
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 arg1.is_fixed():
                    self._lower = self._upper = arg1
                    self._body = arg0
                elif arg0 is None or arg0.is_fixed():
                    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 not arg0.is_fixed():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the lower "
                            "value was non-constant."
                            % (self.cname(True)))

                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 not arg2.is_fixed():
                        raise ValueError(
                            "Constraint '%s' found a 3-tuple (lower,"
                            " expression, upper) but the upper "
                            "value was non-constant."
                            % (self.cname(True)))

                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.cname(True), 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   summation(model.costs) == model.income"
                        "\n   (0, model.price[item], 50)"
                        % (self.cname(True), str(expr)))
            except AttributeError:
                msg = ("Constraint '%s' does not have a proper "
                       "value. Found '%s'\nExpecting a tuple or "
                       "equation. Examples:"
                       "\n   summation(model.costs) == model.income"
                       "\n   (0, model.price[item], 50)"
                       % (self.cname(True), 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.generate_relational_expression.\
           chainedInequality is not None:
            from expr import chainedInequalityErrorMessage
            raise TypeError(chainedInequalityErrorMessage())
        #
        # Process relational expressions
        # (i.e. explicit '==', '<', and '<=')
        #
        if relational_expr:
            if _expr_type is EXPR._EqualityExpression:
                # Equality expression: only 2 arguments!
                self._equality = True
                try:
                    _args = (expr._lhs, expr._rhs)
                except AttributeError:
                    _args = expr._args
                if _args[1].is_fixed():
                    self._lower = self._upper = _args[1]
                    self._body = _args[0]
                elif _args[0].is_fixed():
                    self._lower = self._upper = _args[0]
                    self._body = _args[1]
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = \
                        EXPR.generate_expression_bypassCloneCheck(
                            _sub,
                            _args[0],
                            _args[1])
            else:
                # Inequality expression: 2 or 3 arguments
                if expr._strict:
                    try:
                        _strict = \
                            sum(1 if _s else 0
                                for _s in expr._strict) > 0
                    except:
                        _strict = True
                    if _strict:
                        #
                        # We can relax this when:
                        #   (a) we have a need for this
                        #   (b) we have problem writer that
                        #       explicitly handles this
                        #   (c) we make sure that all problem writers
                        #       that don't handle this make it known
                        #       to the user through an error or
                        #       warning
                        #
                        raise ValueError(
                            "Constraint '%s' encountered a strict "
                            "inequality expression ('>' or '<'). All"
                            " constraints must be formulated using "
                            "using '<=', '>=', or '=='."
                            % (self.cname(True)))

                try:
                    _args = (expr._lhs, expr._rhs)
                    if expr._lhs.__class__ is \
                       EXPR._InequalityExpression:
                        _args = (expr._lhs._lhs,
                                 expr._lhs._rhs,
                                 expr._rhs)
                    elif expr._lhs.__class__ is \
                         EXPR._InequalityExpression:
                        _args = (expr._lhs,
                                 expr._rhs._lhs,
                                 expr._rhs._rhs)
                except AttributeError:
                    _args = expr._args

                if len(_args) == 3:

                    if not _args[0].is_fixed():
                        raise ValueError(
                            "Constraint '%s' found a double-sided "
                            "inequality expression (lower <= "
                            "expression <= upper) but the lower "
                            "bound was non-constant."
                            % (self.cname(True)))
                    if not _args[2].is_fixed():
                        raise ValueError(
                            "Constraint '%s' found a double-sided "\
                            "inequality expression (lower <= "
                            "expression <= upper) but the upper "
                            "bound was non-constant."
                            % (self.cname(True)))

                    self._lower = _args[0]
                    self._body  = _args[1]
                    self._upper = _args[2]

                else:

                    if _args[1].is_fixed():
                        self._lower = None
                        self._body  = _args[0]
                        self._upper = _args[1]
                    elif _args[0].is_fixed():
                        self._lower = _args[0]
                        self._body  = _args[1]
                        self._upper = None
                    else:
                        self._lower = None
                        self._body  = \
                            EXPR.\
                            generate_expression_bypassCloneCheck(
                                _sub,
                                _args[0],
                                _args[1])
                        self._upper = ZeroConstant

        #
        # Replace numeric bound values with a NumericConstant object,
        # and reset the values to 'None' if they are 'infinite'
        #
        if self._lower is not None:
            val = self._lower()
            if not pyutilib.math.is_finite(val):
                if val > 0:
                    raise ValueError(
                        "Constraint '%s' created with a +Inf lower "
                        "bound." % (self.cname(True)))
                self._lower = None
            elif bool(val > 0) == bool(val <= 0):
                raise ValueError(
                    "Constraint '%s' created with a non-numeric "
                    "lower bound." % (self.cname(True)))

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

        #
        # 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 != self._upper: #pragma:nocover
                raise RuntimeError(
                    "Equality constraint '%s' has non-equal lower "
                    "and upper bounds (this is indicitive of a "
                    "SERIOUS internal error in Pyomo)."
                    % (self.cname(True)))
            if self._lower is None:
                raise ValueError(
                    "Equality constraint '%s' defined with "
                    "non-finite term." % (self.cname(True)))
Example #4
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._potentially_variable()):
                    self._lower = self._upper = arg1
                    self._body = arg0
                elif arg0 is None or (not arg0._potentially_variable()):
                    self._lower = self._upper = arg0
                    self._body = arg1
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = EXPR.generate_expression_bypassCloneCheck(
                        _sub, arg0, arg1)
            #
            # Form inequality expression
            #
            elif len(expr) == 3:
                arg0 = expr[0]
                if arg0 is not None:
                    arg0 = as_numeric(arg0)
                    if arg0._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._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   summation(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   summation(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.generate_relational_expression.chainedInequality is not None:
            raise TypeError(EXPR.chainedInequalityErrorMessage())
        #
        # Process relational expressions
        # (i.e. explicit '==', '<', and '<=')
        #
        if relational_expr:
            if _expr_type is EXPR._EqualityExpression:
                # Equality expression: only 2 arguments!
                self._equality = True
                _args = expr._args
                # Explicitly dereference the original arglist (otherwise
                # this runs afoul of the getrefcount logic)
                expr._args = []

                if not _args[1]._potentially_variable():
                    self._lower = self._upper = _args[1]
                    self._body = _args[0]
                elif not _args[0]._potentially_variable():
                    self._lower = self._upper = _args[0]
                    self._body = _args[1]
                else:
                    self._lower = self._upper = ZeroConstant
                    self._body = EXPR.generate_expression_bypassCloneCheck(
                        _sub, _args[0], _args[1] )
            else:
                # Inequality expression: 2 or 3 arguments
                if expr._strict:
                    try:
                        _strict = any(expr._strict)
                    except:
                        _strict = True
                    if _strict:
                        #
                        # We can relax this when:
                        #   (a) we have a need for this
                        #   (b) we have problem writer that
                        #       explicitly handles this
                        #   (c) we make sure that all problem writers
                        #       that don't handle this make it known
                        #       to the user through an error or
                        #       warning
                        #
                        raise ValueError(
                            "Constraint '%s' encountered a strict "
                            "inequality expression ('>' or '<'). All"
                            " constraints must be formulated using "
                            "using '<=', '>=', or '=='."
                            % (self.name))

                _args = expr._args
                # Explicitly dereference the original arglist (otherwise
                # this runs afoul of the getrefcount logic)
                expr._args = []

                if len(_args) == 3:

                    if _args[0]._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 _args[2]._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 = _args[0]
                    self._body  = _args[1]
                    self._upper = _args[2]

                else:
                    if not _args[1]._potentially_variable():
                        self._lower = None
                        self._body  = _args[0]
                        self._upper = _args[1]
                    elif not _args[0]._potentially_variable():
                        self._lower = _args[0]
                        self._body  = _args[1]
                        self._upper = None
                    else:
                        self._lower = None
                        self._body  = EXPR.generate_expression_bypassCloneCheck(
                            _sub, _args[0], _args[1])
                        self._upper = ZeroConstant

        #
        # Replace numeric bound values with a NumericConstant object,
        # and reset the values to 'None' if they are 'infinite'
        #
        if (self._lower is not None) and is_constant(self._lower):
            val = 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 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