3939 RangedExpression ,
4040)
4141from pyomo .core .expr .expr_common import _type_check_exception_arg
42+ from pyomo .core .expr .relational_expr import TrivialRelationalExpression
4243from pyomo .core .expr .template_expr import templatize_constraint
4344from pyomo .core .base .component import ActiveComponentData , ModelComponentFactory
4445from pyomo .core .base .global_set import UnindexedComponent_index
6364
6465_inf = float ('inf' )
6566_nonfinite_values = {_inf , - _inf }
66- _known_relational_expressions = {
67+ _known_relational_expression_types = {
6768 EqualityExpression ,
6869 InequalityExpression ,
6970 RangedExpression ,
71+ TrivialRelationalExpression ,
7072}
7173_strict_relational_exprs = {True , (False , True ), (True , False ), (True , True )}
7274_rule_returned_none_error = """Constraint '%s': rule returned None.
@@ -382,9 +384,7 @@ def get_value(self):
382384
383385 def set_value (self , expr ):
384386 """Set the expression on this constraint."""
385- # Clear any previously-cached normalized constraint
386- self ._expr = None
387- if expr .__class__ in _known_relational_expressions :
387+ if expr .__class__ in _known_relational_expression_types :
388388 if getattr (expr , 'strict' , False ) in _strict_relational_exprs :
389389 raise ValueError (
390390 "Constraint '%s' encountered a strict "
@@ -393,6 +393,7 @@ def set_value(self, expr):
393393 "using '<=', '>=', or '=='." % (self .name ,)
394394 )
395395 self ._expr = expr
396+ return
396397
397398 elif expr .__class__ is tuple : # or expr_type is list:
398399 for arg in expr :
@@ -407,7 +408,7 @@ def set_value(self, expr):
407408 "Constraint expressions expressed as tuples must "
408409 "contain native numeric types or Pyomo NumericValue "
409410 "objects. Tuple %s contained invalid type, %s"
410- % (self .name , expr , arg . __class__ .__name__ )
411+ % (self .name , expr , type ( arg ) .__name__ )
411412 )
412413 if len (expr ) == 2 :
413414 #
@@ -420,6 +421,7 @@ def set_value(self, expr):
420421 "cannot contain None [received %s]" % (self .name , expr )
421422 )
422423 self ._expr = EqualityExpression (expr )
424+ return
423425 elif len (expr ) == 3 :
424426 #
425427 # Form (ranged) inequality expression
@@ -430,6 +432,7 @@ def set_value(self, expr):
430432 self ._expr = InequalityExpression (expr [:2 ], False )
431433 else :
432434 self ._expr = RangedExpression (expr , False )
435+ return
433436 else :
434437 raise ValueError (
435438 "Constraint '%s' does not have a proper value. "
@@ -442,25 +445,9 @@ def set_value(self, expr):
442445 #
443446 # Ignore an 'empty' constraint
444447 #
445- elif expr . __class__ is type :
448+ if expr is Constraint . Skip :
446449 del self .parent_component ()[self .index ()]
447- if expr is Constraint .Skip :
448- return
449- elif expr is Constraint .Infeasible :
450- # TODO: create a trivial infeasible constraint. This
451- # could be useful in the case of GDP where certain
452- # disjuncts are trivially infeasible, but we would still
453- # like to express the disjunction.
454- # del self.parent_component()[self.index()]
455- raise ValueError ("Constraint '%s' is always infeasible" % (self .name ,))
456- else :
457- raise ValueError (
458- "Constraint '%s' does not have a proper "
459- "value. Found '%s'\n Expecting a tuple or "
460- "relational expression. Examples:"
461- "\n sum(model.costs) == model.income"
462- "\n (0, model.price[item], 50)" % (self .name , str (expr ))
463- )
450+ return
464451
465452 elif expr is None :
466453 raise ValueError (_rule_returned_none_error % (self .name ,))
@@ -479,17 +466,18 @@ def set_value(self, expr):
479466 try :
480467 if expr .is_expression_type (ExpressionType .RELATIONAL ):
481468 self ._expr = expr
469+ return
482470 except AttributeError :
483471 pass
484- if self . _expr is None :
485- msg = (
486- "Constraint '%s' does not have a proper "
487- "value. Found '%s'\n Expecting a tuple or "
488- "relational expression. Examples:"
489- "\n sum(model.costs) == model.income"
490- "\n (0, model.price[item], 50)" % ( self . name , str ( expr ))
491- )
492- raise ValueError ( msg )
472+
473+ raise ValueError (
474+ "Constraint '%s' does not have a proper "
475+ "value. Found %s '%s'\n Expecting a tuple or "
476+ "relational expression. Examples:"
477+ "\n sum(model.costs) == model.income"
478+ "\n (0, model.price[item], 50)"
479+ % ( self . name , type ( expr ). __name__ , str ( expr ) )
480+ )
493481
494482 def lslack (self ):
495483 """
@@ -619,10 +607,9 @@ class Constraint(ActiveIndexedComponent):
619607
620608 _ComponentDataClass = ConstraintData
621609
622- class Infeasible ( object ):
623- pass
610+ Infeasible = TrivialRelationalExpression ( ' Infeasible' , ( 1 , 0 ))
611+ Feasible = TrivialRelationalExpression ( 'Feasible' , ( 0 , 0 ))
624612
625- Feasible = ActiveIndexedComponent .Skip
626613 NoConstraint = ActiveIndexedComponent .Skip
627614 Violated = Infeasible
628615 Satisfied = Feasible
@@ -640,11 +627,11 @@ def __new__(cls: Type[IndexedConstraint], *args, **kwds) -> IndexedConstraint: .
640627
641628 def __new__ (cls , * args , ** kwds ):
642629 if cls != Constraint :
643- return super (Constraint , cls ).__new__ (cls )
630+ return super ().__new__ (cls )
644631 if not args or (args [0 ] is UnindexedComponent_set and len (args ) == 1 ):
645- return super (Constraint , cls ).__new__ (AbstractScalarConstraint )
632+ return super ().__new__ (AbstractScalarConstraint )
646633 else :
647- return super (Constraint , cls ).__new__ (IndexedConstraint )
634+ return super ().__new__ (IndexedConstraint )
648635
649636 @overload
650637 def __init__ (self , * indexes , expr = None , rule = None , name = None , doc = None ): ...
@@ -901,7 +888,7 @@ def set_value(self, expr):
901888 """Set the expression on this constraint."""
902889 if not self ._data :
903890 self ._data [None ] = self
904- return super (ScalarConstraint , self ).set_value (expr )
891+ return super ().set_value (expr )
905892
906893 #
907894 # Leaving this method for backward compatibility reasons.
@@ -928,6 +915,7 @@ class SimpleConstraint(metaclass=RenamedClass):
928915 'add' ,
929916 'set_value' ,
930917 'to_bounded_expression' ,
918+ 'expr' ,
931919 'body' ,
932920 'lower' ,
933921 'upper' ,
@@ -981,7 +969,7 @@ def __init__(self, **kwargs):
981969 _rule = kwargs .pop ('rule' , None )
982970 self ._starting_index = kwargs .pop ('starting_index' , 1 )
983971
984- super (ConstraintList , self ).__init__ (Set (dimen = 1 ), ** kwargs )
972+ super ().__init__ (Set (dimen = 1 ), ** kwargs )
985973
986974 self .rule = Initializer (
987975 _rule , treat_sequences_as_mappings = False , allow_generators = True
0 commit comments