Nonlinear Preprocessing Transformations

pyomo.contrib.preprocessing is a contributed library of preprocessing transformations intended to operate upon nonlinear and mixed-integer nonlinear programs (NLPs and MINLPs), as well as generalized disjunctive programs (GDPs).

This contributed package is maintained by Qi Chen and his colleagues from Carnegie Mellon University.

The following preprocessing transformations are available. However, some may later be deprecated or combined, depending on their usefulness.

var_aggregator.VariableAggregator

Aggregate model variables that are linked by equality constraints.

bounds_to_vars.ConstraintToVarBoundTransform

Change constraints to be a bound on the variable.

induced_linearity.InducedLinearity

Reformulate nonlinear constraints with induced linearity.

constraint_tightener.TightenConstraintFromVars

DEPRECATED.

deactivate_trivial_constraints.TrivialConstraintDeactivator

Deactivates trivial constraints.

detect_fixed_vars.FixedVarDetector

Detects variables that are de-facto fixed but not considered fixed.

equality_propagate.FixedVarPropagator

Propagate variable fixing for equalities of type \(x = y\).

equality_propagate.VarBoundPropagator

Propagate variable bounds for equalities of type \(x = y\).

init_vars.InitMidpoint

Initialize non-fixed variables to the midpoint of their bounds.

init_vars.InitZero

Initialize non-fixed variables to zero.

remove_zero_terms.RemoveZeroTerms

Looks for \(0 v\) in a constraint and removes it.

strip_bounds.VariableBoundStripper

Strip bounds from variables.

zero_sum_propagator.ZeroSumPropagator

Propagates fixed-to-zero for sums of only positive (or negative) vars.

Variable Aggregator

The following code snippet demonstrates usage of the variable aggregation transformation on a concrete Pyomo model:

>>> from pyomo.environ import *
>>> m = ConcreteModel()
>>> m.v1 = Var(initialize=1, bounds=(1, 8))
>>> m.v2 = Var(initialize=2, bounds=(0, 3))
>>> m.v3 = Var(initialize=3, bounds=(-7, 4))
>>> m.v4 = Var(initialize=4, bounds=(2, 6))
>>> m.c1 = Constraint(expr=m.v1 == m.v2)
>>> m.c2 = Constraint(expr=m.v2 == m.v3)
>>> m.c3 = Constraint(expr=m.v3 == m.v4)
>>> TransformationFactory('contrib.aggregate_vars').apply_to(m)

To see the results of the transformation, you could then use the command

>>> m.pprint()
class pyomo.contrib.preprocessing.plugins.var_aggregator.VariableAggregator(**kwds)[source]

Aggregate model variables that are linked by equality constraints.

Before:

\[\begin{split}x &= y \\ a &= 2x + 6y + 7 \\ b &= 5y + 6 \\\end{split}\]

After:

\[\begin{split}z &= x = y \\ a &= 8z + 7 \\ b &= 5z + 6\end{split}\]

Warning

TODO: unclear what happens to “capital-E” Expressions at this point in time.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

update_variables(model)[source]

Update the values of the variables that were replaced by aggregates.

TODO: reduced costs

Explicit Constraints to Variable Bounds

>>> from pyomo.environ import *
>>> m = ConcreteModel()
>>> m.v1 = Var(initialize=1)
>>> m.v2 = Var(initialize=2)
>>> m.v3 = Var(initialize=3)
>>> m.c1 = Constraint(expr=m.v1 == 2)
>>> m.c2 = Constraint(expr=m.v2 >= -2)
>>> m.c3 = Constraint(expr=m.v3 <= 5)
>>> TransformationFactory('contrib.constraints_to_var_bounds').apply_to(m)
class pyomo.contrib.preprocessing.plugins.bounds_to_vars.ConstraintToVarBoundTransform(**kwds)[source]

Change constraints to be a bound on the variable.

Looks for constraints of form: \(k*v + c_1 \leq c_2\). Changes variable lower bound on \(v\) to match \((c_2 - c_1)/k\) if it results in a tighter bound. Also does the same thing for lower bounds.

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:
  • tolerance (NonNegativeFloat, default=1e-13) – tolerance on bound equality (\(LB = UB\))

  • detect_fixed (bool, default=True) – If True, fix variable when \(| LB - UB | \leq tolerance\).

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

Induced Linearity Reformulation

class pyomo.contrib.preprocessing.plugins.induced_linearity.InducedLinearity(**kwds)[source]

Reformulate nonlinear constraints with induced linearity.

Finds continuous variables \(v\) where \(v = d_1 + d_2 + d_3\), where \(d\)’s are discrete variables. These continuous variables may participate nonlinearly in other expressions, which may then be induced to be linear.

The overall algorithm flow can be summarized as:

  1. Detect effectively discrete variables and the constraints that imply discreteness.

  2. Determine the set of valid values for each effectively discrete variable

  3. Find nonlinear expressions in which effectively discrete variables participate.

  4. Reformulate nonlinear expressions appropriately.

Note

Tasks 1 & 2 must incorporate scoping considerations (Disjuncts)

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:
  • equality_tolerance (NonNegativeFloat, default=1e-06) – Tolerance on equality constraints.

  • pruning_solver (default='glpk') – Solver to use when pruning possible values.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

Constraint Bounds Tightener

This transformation was developed by Sunjeev Kale at Carnegie Mellon University.

class pyomo.contrib.preprocessing.plugins.constraint_tightener.TightenConstraintFromVars[source]

DEPRECATED.

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.

Deprecated since version 5.7: Use of the constraint tightener transformation is deprecated. Its functionality may be partially replicated using pyomo.contrib.fbbt.compute_bounds_on_expr(constraint.body).

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

Trivial Constraint Deactivation

class pyomo.contrib.preprocessing.plugins.deactivate_trivial_constraints.TrivialConstraintDeactivator(**kwds)[source]

Deactivates trivial constraints.

Trivial constraints take form \(k_1 = k_2\) or \(k_1 \leq k_2\), where \(k_1\) and \(k_2\) are constants. These constraints typically arise when variables are fixed.

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:
  • tmp (bool, default=False) – True to store a set of transformed constraints for future reversion of the transformation.

  • ignore_infeasible (bool, default=False) – True to skip over trivial constraints that are infeasible instead of raising an InfeasibleConstraintException.

  • return_trivial (default=[]) – a list to which the deactivated trivialconstraints are appended (side effect)

  • tolerance (NonNegativeFloat, default=1e-13) – tolerance on constraint violations

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

revert(instance)[source]

Revert constraints deactivated by the transformation.

Parameters:

instance – the model instance on which trivial constraints were earlier deactivated.

Fixed Variable Detection

class pyomo.contrib.preprocessing.plugins.detect_fixed_vars.FixedVarDetector(**kwds)[source]

Detects variables that are de-facto fixed but not considered fixed.

For each variable \(v\) found on the model, check to see if its lower bound \(v^{LB}\) is within some tolerance of its upper bound \(v^{UB}\). If so, fix the variable to the value of \(v^{LB}\).

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:
  • tmp (bool, default=False) – True to store the set of transformed variables and their old values so that they can be restored.

  • tolerance (NonNegativeFloat, default=1e-13) – tolerance on bound equality (LB == UB)

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

revert(instance)[source]

Revert variables fixed by the transformation.

Fixed Variable Equality Propagator

class pyomo.contrib.preprocessing.plugins.equality_propagate.FixedVarPropagator(**kwds)[source]

Propagate variable fixing for equalities of type \(x = y\).

If \(x\) is fixed and \(y\) is not fixed, then this transformation will fix \(y\) to the value of \(x\).

This transformation can also be performed as a temporary transformation, whereby the transformed variables are saved and can be later unfixed.

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:

tmp (bool, default=False) – True to store the set of transformed variables and their old states so that they can be later restored.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

revert(instance)[source]

Revert variables fixed by the transformation.

Variable Bound Equality Propagator

class pyomo.contrib.preprocessing.plugins.equality_propagate.VarBoundPropagator(**kwds)[source]

Propagate variable bounds for equalities of type \(x = y\).

If \(x\) has a tighter bound then \(y\), then this transformation will adjust the bounds on \(y\) to match those of \(x\).

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:

tmp (bool, default=False) – True to store the set of transformed variables and their old states so that they can be later restored.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

revert(instance)[source]

Revert variable bounds.

Variable Midpoint Initializer

class pyomo.contrib.preprocessing.plugins.init_vars.InitMidpoint(**kwds)[source]

Initialize non-fixed variables to the midpoint of their bounds.

  • If the variable does not have bounds, set the value to zero.

  • If the variable is missing one bound, set the value to that of the existing bound.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

Variable Zero Initializer

class pyomo.contrib.preprocessing.plugins.init_vars.InitZero(**kwds)[source]

Initialize non-fixed variables to zero.

  • If setting the variable value to zero will violate a bound, set the variable value to the relevant bound value.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

Zero Term Remover

class pyomo.contrib.preprocessing.plugins.remove_zero_terms.RemoveZeroTerms(**kwds)[source]

Looks for \(0 v\) in a constraint and removes it.

Currently limited to processing linear constraints of the form \(x_1 = 0 x_3\), occurring as a result of fixing \(x_2 = 0\).

Note

TODO: support nonlinear expressions

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

Variable Bound Remover

class pyomo.contrib.preprocessing.plugins.strip_bounds.VariableBoundStripper(**kwds)[source]

Strip bounds from variables.

Keyword arguments below are specified for the apply_to and create_using functions.

Keyword Arguments:
  • strip_domains (bool, default=True) – strip the domain for discrete variables as well

  • reversible (bool, default=False) – Whether the bound stripping will be temporary. If so, store information for reversion.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation

revert(instance)[source]

Revert variable bounds and domains changed by the transformation.

Zero Sum Propagator

class pyomo.contrib.preprocessing.plugins.zero_sum_propagator.ZeroSumPropagator(**kwds)[source]

Propagates fixed-to-zero for sums of only positive (or negative) vars.

If \(z\) is fixed to zero and \(z = x_1 + x_2 + x_3\) and \(x_1\), \(x_2\), \(x_3\) are all non-negative or all non-positive, then \(x_1\), \(x_2\), and \(x_3\) will be fixed to zero.

apply_to(model, **kwds)

Apply the transformation to the given model.

create_using(model, **kwds)

Create a new model with this transformation