Source code for pyomo.contrib.preprocessing.plugins.constraint_tightener

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

import logging

from pyomo.common import deprecated
from pyomo.core import Constraint, value, TransformationFactory
from pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation
from pyomo.repn.standard_repn import generate_standard_repn

logger = logging.getLogger('pyomo.contrib.preprocessing')


[docs]@TransformationFactory.register( 'core.tighten_constraints_from_vars', doc="[DEPRECATED] Tightens upper and lower bound on linear constraints.", ) @deprecated( "Use of the constraint tightener transformation is deprecated. " "Its functionality may be partially replicated using " "`pyomo.contrib.fbbt.compute_bounds_on_expr(constraint.body)`.", version='5.7', ) class TightenConstraintFromVars(IsomorphicTransformation): """Tightens upper and lower bound on constraints based on variable bounds. Iterates through each variable and tightens the constraint bounds using the inferred values from the variable bounds. For now, this only operates on linear constraints. """ def __init__(self): super(TightenConstraintFromVars, self).__init__() def _apply_to(self, model): """Apply the transformation.""" for constr in model.component_data_objects( ctype=Constraint, active=True, descend_into=True ): repn = generate_standard_repn(constr.body) if not repn.is_linear(): continue # tighten the constraint bound as much as possible LB = UB = 0 if repn.constant: LB = UB = repn.constant # loop through each coefficient and variable pair for var, coef in zip(repn.linear_vars, repn.linear_coefs): # Calculate bounds using interval arithmetic if coef >= 0: if var.has_ub(): UB = UB + coef * value(var.ub) else: UB = float('Inf') if var.has_lb(): LB = LB + coef * value(var.lb) else: LB = float('-Inf') else: # coef is negative, so signs switch if var.has_lb(): UB = UB + coef * value(var.lb) else: UB = float('Inf') if var.has_ub(): LB = LB + coef * value(var.ub) else: LB = float('-Inf') # if inferred bound is tighter, replace bound new_ub = min(value(constr.upper), UB) if constr.has_ub() else UB new_lb = max(value(constr.lower), LB) if constr.has_lb() else LB constr.set_value((new_lb, constr.body, new_ub)) if UB < LB: logger.error( "Infeasible variable bounds: " "Constraint %s has inferred LB %s > UB %s" % (constr.name, new_lb, new_ub) )