Skip to content

Commit

Permalink
Rename normalize_constraint -> to_bounded_expression
Browse files Browse the repository at this point in the history
  • Loading branch information
jsiirola committed Jul 24, 2024
1 parent 7f84d3e commit 08ccf40
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 17 deletions.
2 changes: 1 addition & 1 deletion pyomo/contrib/appsi/cmodel/src/fbbt_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ void process_fbbt_constraints(FBBTModel *model, PyomoExprTypes &expr_types,
py::handle con_body;

for (py::handle c : cons) {
lower_body_upper = c.attr("normalize_constraint")();
lower_body_upper = c.attr("to_bounded_expression")();
con_lb = lower_body_upper[0];
con_body = lower_body_upper[1];
con_ub = lower_body_upper[2];
Expand Down
2 changes: 1 addition & 1 deletion pyomo/contrib/appsi/cmodel/src/lp_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ void process_lp_constraints(py::list cons, py::object writer) {
py::object nonlinear_expr;
PyomoExprTypes expr_types = PyomoExprTypes();
for (py::handle c : cons) {
lower_body_upper = c.attr("normalize_constraint")();
lower_body_upper = c.attr("to_bounded_expression")();
cname = getSymbol(c, labeler);
repn = generate_standard_repn(
lower_body_upper[1], "compute_values"_a = false, "quadratic"_a = true);
Expand Down
2 changes: 1 addition & 1 deletion pyomo/contrib/appsi/cmodel/src/nl_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ void process_nl_constraints(NLWriter *nl_writer, PyomoExprTypes &expr_types,
py::handle repn_nonlinear_expr;

for (py::handle c : cons) {
lower_body_upper = c.attr("normalize_constraint")();
lower_body_upper = c.attr("to_bounded_expression")();
repn = generate_standard_repn(
lower_body_upper[1], "compute_values"_a = false, "quadratic"_a = false);
_const = appsi_expr_from_pyomo_expr(repn.attr("constant"), var_map,
Expand Down
45 changes: 36 additions & 9 deletions pyomo/core/base/constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,35 @@ def __init__(self, expr=None, component=None):

def __call__(self, exception=True):
"""Compute the value of the body of this constraint."""
body = self.normalize_constraint()[1]
body = self.to_bounded_expression()[1]
if body.__class__ not in native_numeric_types:
body = value(self.body, exception=exception)
return body

def normalize_constraint(self):
def to_bounded_expression(self):
"""Convert this constraint to a tuple of 3 expressions (lb, body, ub)
This method "standardizes" the expression into a 3-tuple of
expressions: (`lower_bound`, `body`, `upper_bound`). Upon
conversion, `lower_bound` and `upper_bound` are guaranteed to be
`None`, numeric constants, or fixed (not necessarily constant)
expressions.
Note
----
As this method operates on the *current state* of the
expression, the any required expression manipulations (and by
extension, the result) can change after fixing / unfixing
:py:class:`Var` objects.
Raises
------
ValueError: Raised if the expression cannot be mapped to this
form (i.e., :py:class:`RangedExpression` constraints with
variable lower of upper bounds.
"""
expr = self._expr
if expr.__class__ is RangedExpression:
lb, body, ub = ans = expr.args
Expand Down Expand Up @@ -217,8 +240,12 @@ def normalize_constraint(self):
def body(self):
"""Access the body of a constraint expression."""
try:
ans = self.normalize_constraint()[1]
ans = self.to_bounded_expression()[1]
except ValueError:
# It is possible that the expression is not currently valid
# (i.e., a ranged expression with a non-fixed bound). We
# will catch that exception here and - if this actually *is*
# a RangedExpression - return the body.
if self._expr.__class__ is RangedExpression:
_, ans, _ = self._expr.args
else:
Expand All @@ -229,14 +256,14 @@ def body(self):
#
# [JDS 6/2024: it would be nice to remove this behavior,
# although possibly unnecessary, as people should use
# normalize_constraint() instead]
# to_bounded_expression() instead]
return as_numeric(ans)
return ans

@property
def lower(self):
"""Access the lower bound of a constraint expression."""
ans = self.normalize_constraint()[0]
ans = self.to_bounded_expression()[0]
if ans.__class__ in native_types and ans is not None:
# Historically, constraint.lower was guaranteed to return a type
# derived from Pyomo NumericValue (or None). Replicate that
Expand All @@ -250,7 +277,7 @@ def lower(self):
@property
def upper(self):
"""Access the upper bound of a constraint expression."""
ans = self.normalize_constraint()[2]
ans = self.to_bounded_expression()[2]
if ans.__class__ in native_types and ans is not None:
# Historically, constraint.upper was guaranteed to return a type
# derived from Pyomo NumericValue (or None). Replicate that
Expand All @@ -264,7 +291,7 @@ def upper(self):
@property
def lb(self):
"""Access the value of the lower bound of a constraint expression."""
bound = self.normalize_constraint()[0]
bound = self.to_bounded_expression()[0]
if bound is None:
return None
if bound.__class__ not in native_numeric_types:
Expand All @@ -282,7 +309,7 @@ def lb(self):
@property
def ub(self):
"""Access the value of the upper bound of a constraint expression."""
bound = self.normalize_constraint()[2]
bound = self.to_bounded_expression()[2]
if bound is None:
return None
if bound.__class__ not in native_numeric_types:
Expand Down Expand Up @@ -824,7 +851,7 @@ class SimpleConstraint(metaclass=RenamedClass):
{
'add',
'set_value',
'normalize_constraint',
'to_bounded_expression',
'body',
'lower',
'upper',
Expand Down
2 changes: 1 addition & 1 deletion pyomo/core/kernel/constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class _MutableBoundsConstraintMixin(object):
# Define some of the IConstraint abstract methods
#

def normalize_constraint(self):
def to_bounded_expression(self):
return self.lower, self.body, self.upper

@property
Expand Down
2 changes: 1 addition & 1 deletion pyomo/gdp/plugins/bilinear.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _transformBlock(self, block, instance):
for component in block.component_data_objects(
Constraint, active=True, descend_into=False
):
lb, body, ub = component.normalize_constraint()
lb, body, ub = component.to_bounded_expression()
expr = self._transformExpression(body, instance)
instance.bilinear_data_.c_body[id(component)] = body
component.set_value((lb, expr, ub))
Expand Down
4 changes: 2 additions & 2 deletions pyomo/gdp/plugins/cuttingplane.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ def back_off_constraint_with_calculated_cut_violation(
val = value(transBlock_rHull.infeasibility_objective) - TOL
if val <= 0:
logger.info("\tBacking off cut by %s" % val)
lb, body, ub = cut.normalize_constraint()
lb, body, ub = cut.to_bounded_expression()
cut.set_value((lb, body + abs(val), ub))
# else there is nothing to do: restore the objective
transBlock_rHull.del_component(transBlock_rHull.infeasibility_objective)
Expand All @@ -425,7 +425,7 @@ def back_off_constraint_by_fixed_tolerance(
this callback
TOL: An absolute tolerance to be added to make cut more conservative.
"""
lb, body, ub = cut.normalize_constraint()
lb, body, ub = cut.to_bounded_expression()
cut.set_value((lb, body + TOL, ub))


Expand Down
2 changes: 1 addition & 1 deletion pyomo/solvers/plugins/solvers/persistent_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ def _add_and_collect_column_data(self, var, obj_coef, constraints, coefficients)
coeff_list = list()
constr_list = list()
for val, c in zip(coefficients, constraints):
lb, body, ub = c.normalize_constraint()
lb, body, ub = c.to_bounded_expression()
body += val * var
c.set_value((lb, body, ub))
self._vars_referenced_by_con[c].add(var)
Expand Down

0 comments on commit 08ccf40

Please sign in to comment.