Пример #1
0
 def expr(self):
     """Get the expression on this constraint."""
     body_expr = self.body
     if body_expr is None:
         return None
     if self.equality:
         return body_expr == self.rhs
     else:
         if self.lb is None:
             return body_expr <= self.ub
         elif self.ub is None:
             return self.lb <= body_expr
         return logical_expr.RangedExpression((self.lb, body_expr, self.ub), (False, False))
Пример #2
0
    def set_value(self, expr):
        """Set the expression on this constraint."""
        # Clear any previously-cached normalized constraint
        self._lower = self._upper = self._body = self._expr = None

        _expr_type = expr.__class__
        if hasattr(expr, 'is_relational'):
            if not expr.is_relational():
                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)))
            self._expr = expr

        elif _expr_type is tuple:  # or expr_type is list:
            for arg in expr:
                if arg is None or arg.__class__ in native_numeric_types \
                   or isinstance(arg, NumericValue):
                    continue
                raise ValueError(
                    "Constraint '%s' does not have a proper value. "
                    "Constraint expressions expressed as tuples must "
                    "contain native numeric types or Pyomo NumericValue "
                    "objects. Tuple %s contained invalid type, %s" %
                    (self.name, expr, arg.__class__.__name__))
            if len(expr) == 2:
                #
                # Form equality expression
                #
                if expr[0] is None or expr[1] is None:
                    raise ValueError(
                        "Constraint '%s' does not have a proper value. "
                        "Equality Constraints expressed as 2-tuples "
                        "cannot contain None [received %s]" % (
                            self.name,
                            expr,
                        ))
                self._expr = logical_expr.EqualityExpression(expr)
            elif len(expr) == 3:
                #
                # Form (ranged) inequality expression
                #
                if expr[0] is None:
                    self._expr = logical_expr.InequalityExpression(
                        expr[1:], False)
                elif expr[2] is None:
                    self._expr = logical_expr.InequalityExpression(
                        expr[:2], False)
                else:
                    self._expr = logical_expr.RangedExpression(expr, False)
            else:
                raise ValueError(
                    "Constraint '%s' does not have a proper value. "
                    "Found 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)))
        #
        # Ignore an 'empty' constraint
        #
        elif _expr_type is type:
            del self.parent_component()[self.index()]
            if expr is Constraint.Skip:
                return
            elif expr is Constraint.Infeasible:
                # TODO: create a trivial infeasible constraint.  This
                # could be useful in the case of GDP where certain
                # disjuncts are trivially infeasible, but we would still
                # like to express the disjunction.
                #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)))
            raise ValueError(msg)
        #
        # Normalize the incoming expressions, if we can
        #
        args = self._expr.args
        if self._expr.__class__ is logical_expr.InequalityExpression:
            if self._expr.strict:
                raise ValueError("Constraint '%s' encountered a strict "
                                 "inequality expression ('>' or '< '). All"
                                 " constraints must be formulated using "
                                 "using '<=', '>=', or '=='." % (self.name, ))
            if args[1] is None or args[1].__class__ in native_numeric_types \
               or not args[1].is_potentially_variable():
                self._body = args[0]
                self._upper = args[1]
            elif args[0] is None or args[0].__class__ in native_numeric_types \
               or not args[0].is_potentially_variable():
                self._lower = args[0]
                self._body = args[1]
            else:
                self._body = args[0] - args[1]
                self._upper = 0
        elif self._expr.__class__ is logical_expr.EqualityExpression:
            if args[0] is None or args[1] is None:
                # Error check: ensure equality does not have infinite RHS
                raise ValueError("Equality constraint '%s' defined with "
                                 "non-finite term (%sHS == None)." %
                                 (self.name, 'L' if args[0] is None else 'R'))
            if args[0].__class__ in native_numeric_types or \
               not args[0].is_potentially_variable():
                self._lower = self._upper = args[0]
                self._body = args[1]
            elif args[1].__class__ in native_numeric_types or \
               not args[1].is_potentially_variable():
                self._lower = self._upper = args[1]
                self._body = args[0]
            else:
                self._lower = self._upper = 0
                self._body = args[0] - args[1]
            # The following logic is caught below when checking for
            # invalid non-finite bounds:
            #
            # if self._lower.__class__ in native_numeric_types and \
            #    not math.isfinite(self._lower):
            #     raise ValueError(
            #         "Equality constraint '%s' defined with "
            #         "non-finite term." % (self.name))
        elif self._expr.__class__ is logical_expr.RangedExpression:
            if any(self._expr.strict):
                raise ValueError("Constraint '%s' encountered a strict "
                                 "inequality expression ('>' or '< '). All"
                                 " constraints must be formulated using "
                                 "using '<=', '>=', or '=='." % (self.name, ))
            if all((arg is None or arg.__class__ in native_numeric_types
                    or not arg.is_potentially_variable())
                   for arg in (args[0], args[2])):
                self._lower, self._body, self._upper = args
        else:
            # Defensive programming: we currently only support three
            # relational expression types.  This will only be hit if
            # someone defines a fourth...
            raise DeveloperError(
                "Unrecognized relational expression type: %s" %
                (self._expr.__class__.__name__, ))

        # We have historically mapped incoming inf to None
        if self._lower.__class__ in native_numeric_types:
            if self._lower == -_inf:
                self._lower = None
            elif not math.isfinite(self._lower):
                raise ValueError(
                    "Constraint '%s' created with an invalid non-finite "
                    "lower bound (%s)." % (self.name, self._lower))
        if self._upper.__class__ in native_numeric_types:
            if self._upper == _inf:
                self._upper = None
            elif not math.isfinite(self._upper):
                raise ValueError(
                    "Constraint '%s' created with an invalid non-finite "
                    "upper bound (%s)." % (self.name, self._upper))