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
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
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)))
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