Skip to content

Commit

Permalink
Using the validate argument with indexed set objects now allows acces…
Browse files Browse the repository at this point in the history
…s to the index. Original pyomo tests pass.
  • Loading branch information
Pedro L. Magalhães committed Jun 13, 2024
1 parent c783037 commit c109901
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 10 deletions.
4 changes: 2 additions & 2 deletions examples/pyomo/tutorials/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ def P_init(model, i, j):
# Validation of set arrays can also be performed with the _validate_ option.
# This is applied to all sets in the array:
#
def T_validate(model, value):
def T_validate(model, value, index):
return value in model.A


model.T = Set(model.B, validate=M_validate)
model.T = Set(model.B, validate=T_validate)


##
Expand Down
14 changes: 13 additions & 1 deletion pyomo/core/base/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,19 @@ def add(self, *values):

if self._validate is not None:
try:
flag = self._validate(_block, _value)
# differentiate between indexed and non-indexed sets
if self._index is not None:
# indexed set: the value and the index are given
pass
if type(_value) == tuple:
# _value is a tuple: unpack it for the method arguments' tuple
flag = self._validate(_block, (*_value, self._index))
else:
# _value is not a tuple: no need to unpack it for the method arguments' tuple
flag = self._validate(_block, (_value, self._index))
else:
# non-indexed set: only the tentative member is given
flag = self._validate(_block, _value)
except:
logger.error(
"Exception raised while validating element '%s' "
Expand Down
8 changes: 5 additions & 3 deletions pyomo/core/tests/unit/test_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -4319,15 +4319,15 @@ def _lt_3(model, i):

m = ConcreteModel()

def _validate(model, i, j):
def _validate_I(model, i, j):
self.assertIs(model, m)
if i + j < 2:
return True
if i - j > 2:
return False
raise RuntimeError("Bogus value")

m.I = Set(validate=_validate)
m.I = Set(validate=_validate_I)
output = StringIO()
with LoggingIntercept(output, 'pyomo.core'):
self.assertTrue(m.I.add((0, 1)))
Expand All @@ -4347,7 +4347,9 @@ def _validate(model, i, j):

# Note: one of these indices will trigger the exception in the
# validot when it is called for the index.
m.J = Set([(0, 0), (2, 2)], validate=_validate)
def _validate_J(model, i, j, index):
return _validate_I(model, i, j)
m.J = Set([(0, 0), (2, 2)], validate=_validate_J)
output = StringIO()
with LoggingIntercept(output, 'pyomo.core'):
self.assertTrue(m.J[2, 2].add((0, 1)))
Expand Down
8 changes: 4 additions & 4 deletions pyomo/core/tests/unit/test_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2790,7 +2790,7 @@ def test_validation1(self):
# Create A with an error
#
self.model.Z = Set()
self.model.A = Set(self.model.Z, validate=lambda model, x: x < 6)
self.model.A = Set(self.model.Z, validate=lambda model, x, i: x < 6)
try:
self.instance = self.model.create_instance(currdir + "setA.dat")
except ValueError:
Expand All @@ -2809,7 +2809,7 @@ def test_validation2(self):
# Create A with an error
#
self.model.Z = Set()
self.model.A = Set(self.model.Z, validate=lambda model, x: x < 6)
self.model.A = Set(self.model.Z, validate=lambda model, x, i: x < 6)
try:
self.instance = self.model.create_instance(currdir + "setA.dat")
except ValueError:
Expand All @@ -2822,7 +2822,7 @@ def test_other1(self):
self.model.A = Set(
self.model.Z,
initialize={'A': [1, 2, 3, 'A']},
validate=lambda model, x: x in Integers,
validate=lambda model, x, i: x in Integers,
)
try:
self.instance = self.model.create_instance()
Expand Down Expand Up @@ -2853,7 +2853,7 @@ def tmp_init(model, i):
self.model.n = Param(initialize=5)
self.model.Z = Set(initialize=['A'])
self.model.A = Set(
self.model.Z, initialize=tmp_init, validate=lambda model, x: x in Integers
self.model.Z, initialize=tmp_init, validate=lambda model, x, i: x in Integers
)
try:
self.instance = self.model.create_instance()
Expand Down

0 comments on commit c109901

Please sign in to comment.