We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
contrib.deactivate_trivial_constraints can miss trivial constraints
## Summary

The `contrib.deactivate_trivial_constraints` transformation uses the polynomial degree of the constraint expression to decide if the expression is constant. That's not actually a reliable method of doing so, meaning that it can miss trivial constraints like in the example below, where the polynomial degree of the constraint body evaluates to 1.

### Steps to reproduce the issue

```
from pyomo.environ import *

m = ConcreteModel()
m.x = Var()
m.y = Var()
m.y.fix(0)
m.c = Constraint(expr=m.x*m.y >= 0)

TransformationFactory('contrib.deactivate_trivial_constraints').apply_to(m)

print(m.c.active) # True
```

### Information on your system

Pyomo version: main
Python version: 3.8
Operating system: linux
How Pyomo was installed (PyPI, conda, source): source
Solver (if applicable):


### Additional information

I think you could use `generate_standard_repn` to actually detect if a constraint body is constant. This isn't a bug in the sense that it does the wrong thing, but it does fall short on its promises.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyomo/contrib/preprocessing/plugins/remove_zero_terms.py`
Content:
```
1 #  ___________________________________________________________________________
2 #
3 #  Pyomo: Python Optimization Modeling Objects
4 #  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
5 #  Under the terms of Contract DE-NA0003525 with National Technology and 
6 #  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain 
7 #  rights in this software.
8 #  This software is distributed under the 3-clause BSD License.
9 #  ___________________________________________________________________________
10 
11 # -*- coding: UTF-8 -*-
12 """Transformation to remove zero terms from constraints."""
13 from __future__ import division
14 
15 from pyomo.core import quicksum
16 from pyomo.core.base.constraint import Constraint
17 from pyomo.core.base.transformation import TransformationFactory
18 from pyomo.core.expr import current as EXPR
19 from pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation
20 from pyomo.repn import generate_standard_repn
21 
22 
23 @TransformationFactory.register(
24         'contrib.remove_zero_terms',
25         doc="Remove terms 0 * var in constraints")
26 class RemoveZeroTerms(IsomorphicTransformation):
27     """Looks for :math:`0 v` in a constraint and removes it.
28 
29     Currently limited to processing linear constraints of the form :math:`x_1 =
30     0 x_3`, occurring as a result of fixing :math:`x_2 = 0`.
31 
32     .. note:: TODO: support nonlinear expressions
33 
34     """
35 
36     def _apply_to(self, model):
37         """Apply the transformation."""
38         m = model
39 
40         for constr in m.component_data_objects(
41                 ctype=Constraint, active=True, descend_into=True):
42             if not constr.body.polynomial_degree() == 1:
43                 continue  # we currently only process linear constraints
44             repn = generate_standard_repn(constr.body)
45 
46             # get the index of all nonzero coefficient variables
47             nonzero_vars_indx = [
48                 i for i, _ in enumerate(repn.linear_vars)
49                 if not repn.linear_coefs[i] == 0
50             ]
51             const = repn.constant
52 
53             # reconstitute the constraint, including only variable terms with
54             # nonzero coefficients
55             constr_body = quicksum(repn.linear_coefs[i] * repn.linear_vars[i]
56                                    for i in nonzero_vars_indx) + const
57             if constr.equality:
58                 constr.set_value(constr_body == constr.upper)
59             elif constr.has_lb() and not constr.has_ub():
60                 constr.set_value(constr_body >= constr.lower)
61             elif constr.has_ub() and not constr.has_lb():
62                 constr.set_value(constr_body <= constr.upper)
63             else:
64                 # constraint is a bounded inequality of form a <= x <= b.
65                 constr.set_value(EXPR.inequality(
66                     constr.lower, constr_body, constr.upper))
67
```

Path: `pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 #  ___________________________________________________________________________
4 #
5 #  Pyomo: Python Optimization Modeling Objects
6 #  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
7 #  Under the terms of Contract DE-NA0003525 with National Technology and 
8 #  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain 
9 #  rights in this software.
10 #  This software is distributed under the 3-clause BSD License.
11 #  ___________________________________________________________________________
12 
13 """Transformation to deactivate trivial constraints."""
14 import logging
15 
16 from pyomo.common.collections import ComponentSet
17 from pyomo.common.config import (ConfigBlock, ConfigValue, NonNegativeFloat,
18                                  add_docstring_list)
19 from pyomo.common.errors import InfeasibleConstraintException
20 from pyomo.core.base.constraint import Constraint
21 from pyomo.core.base.transformation import TransformationFactory
22 from pyomo.core.expr.numvalue import value
23 from pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation
24 
25 logger = logging.getLogger('pyomo.contrib.preprocessing')
26 
27 @TransformationFactory.register(
28         'contrib.deactivate_trivial_constraints',
29         doc="Deactivate trivial constraints.")
30 class TrivialConstraintDeactivator(IsomorphicTransformation):
31     """Deactivates trivial constraints.
32 
33     Trivial constraints take form :math:`k_1 = k_2` or :math:`k_1 \\leq k_2`,
34     where :math:`k_1` and :math:`k_2` are constants. These constraints
35     typically arise when variables are fixed.
36 
37     Keyword arguments below are specified for the ``apply_to`` and
38     ``create_using`` functions.
39 
40     """
41 
42     CONFIG = ConfigBlock("TrivialConstraintDeactivator")
43     CONFIG.declare("tmp", ConfigValue(
44         default=False, domain=bool,
45         description="True to store a set of transformed constraints for future"
46         " reversion of the transformation."
47     ))
48     CONFIG.declare("ignore_infeasible", ConfigValue(
49         default=False, domain=bool,
50         description="True to skip over trivial constraints that are "
51         "infeasible instead of raising an InfeasibleConstraintException."
52     ))
53     CONFIG.declare("return_trivial", ConfigValue(
54         default=[],
55         description="a list to which the deactivated trivial"
56         "constraints are appended (side effect)"
57     ))
58     CONFIG.declare("tolerance", ConfigValue(
59         default=1E-13, domain=NonNegativeFloat,
60         description="tolerance on constraint violations"
61     ))
62 
63     __doc__ = add_docstring_list(__doc__, CONFIG)
64 
65 
66     def _apply_to(self, instance, **kwargs):
67         config = self.CONFIG(kwargs)
68         if config.tmp and not hasattr(instance, '_tmp_trivial_deactivated_constrs'):
69             instance._tmp_trivial_deactivated_constrs = ComponentSet()
70         elif config.tmp:
71             logger.warning(
72                 'Deactivating trivial constraints on the block {} for which '
73                 'trivial constraints were previously deactivated. '
74                 'Reversion will affect all deactivated constraints.'.format(
75                     instance.name))
76 
77         # Trivial constraints are those that do not contain any variables, ie.
78         # the polynomial degree is 0
79         trivial_constraints = (
80             constr
81             for constr in instance.component_data_objects(
82                 ctype=Constraint, active=True, descend_into=True)
83             if constr.body.polynomial_degree() == 0)
84 
85         for constr in trivial_constraints:
86             # We need to check each constraint to sure that it is not violated.
87             constr_lb = value(
88                 constr.lower) if constr.has_lb() else float('-inf')
89             constr_ub = value(
90                 constr.upper) if constr.has_ub() else float('inf')
91             constr_value = value(constr.body)
92 
93             # Check if the lower bound is violated outside a given tolerance
94             if (constr_value + config.tolerance <= constr_lb):
95                 if config.ignore_infeasible:
96                     continue
97                 else:
98                     raise InfeasibleConstraintException(
99                         'Trivial constraint {} violates LB {} ≤ BODY {}.'
100                         .format(constr.name, constr_lb, constr_value))
101 
102             # Check if the upper bound is violated outside a given tolerance
103             if (constr_value >= constr_ub + config.tolerance):
104                 if config.ignore_infeasible:
105                     continue
106                 else:
107                     raise InfeasibleConstraintException(
108                         'Trivial constraint {} violates BODY {} ≤ UB {}.'
109                         .format(constr.name, constr_value, constr_ub))
110 
111             # Constraint is not infeasible. Deactivate it.
112             if config.tmp:
113                 instance._tmp_trivial_deactivated_constrs.add(constr)
114             config.return_trivial.append(constr)
115             constr.deactivate()
116 
117     def revert(self, instance):
118         """Revert constraints deactivated by the transformation.
119 
120         Args:
121             instance: the model instance on which trivial constraints were
122                 earlier deactivated.
123         """
124         for constr in instance._tmp_trivial_deactivated_constrs:
125             constr.activate()
126         del instance._tmp_trivial_deactivated_constrs
127
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py b/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py
--- a/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py
+++ b/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py
@@ -21,6 +21,7 @@
 from pyomo.core.base.transformation import TransformationFactory
 from pyomo.core.expr.numvalue import value
 from pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation
+from pyomo.repn import generate_standard_repn
 
 logger = logging.getLogger('pyomo.contrib.preprocessing')
 
@@ -65,7 +66,8 @@
 
     def _apply_to(self, instance, **kwargs):
         config = self.CONFIG(kwargs)
-        if config.tmp and not hasattr(instance, '_tmp_trivial_deactivated_constrs'):
+        if config.tmp and not hasattr(instance,
+                                      '_tmp_trivial_deactivated_constrs'):
             instance._tmp_trivial_deactivated_constrs = ComponentSet()
         elif config.tmp:
             logger.warning(
@@ -76,19 +78,20 @@
 
         # Trivial constraints are those that do not contain any variables, ie.
         # the polynomial degree is 0
-        trivial_constraints = (
-            constr
-            for constr in instance.component_data_objects(
-                ctype=Constraint, active=True, descend_into=True)
-            if constr.body.polynomial_degree() == 0)
+        for constr in instance.component_data_objects(ctype=Constraint,
+                                                      active=True,
+                                                      descend_into=True):
+            repn = generate_standard_repn(constr.body)
+            if not repn.is_constant():
+                # This constraint is not trivial
+                continue
 
-        for constr in trivial_constraints:
             # We need to check each constraint to sure that it is not violated.
             constr_lb = value(
                 constr.lower) if constr.has_lb() else float('-inf')
             constr_ub = value(
                 constr.upper) if constr.has_ub() else float('inf')
-            constr_value = value(constr.body)
+            constr_value = repn.constant
 
             # Check if the lower bound is violated outside a given tolerance
             if (constr_value + config.tolerance <= constr_lb):
diff --git a/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py b/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py
--- a/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py
+++ b/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py
@@ -39,9 +39,12 @@
 
         for constr in m.component_data_objects(
                 ctype=Constraint, active=True, descend_into=True):
-            if not constr.body.polynomial_degree() == 1:
-                continue  # we currently only process linear constraints
             repn = generate_standard_repn(constr.body)
+            if not repn.is_linear() or repn.is_constant():
+                continue  # we currently only process linear constraints, and we
+                          # assume that trivial constraints have already been
+                          # deactivated or will be deactivated in a different
+                          # step
 
             # get the index of all nonzero coefficient variables
             nonzero_vars_indx = [

{"golden_diff": "diff --git a/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py b/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py\n--- a/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py\n+++ b/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py\n@@ -21,6 +21,7 @@\n from pyomo.core.base.transformation import TransformationFactory\n from pyomo.core.expr.numvalue import value\n from pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation\n+from pyomo.repn import generate_standard_repn\n \n logger = logging.getLogger('pyomo.contrib.preprocessing')\n \n@@ -65,7 +66,8 @@\n \n     def _apply_to(self, instance, **kwargs):\n         config = self.CONFIG(kwargs)\n-        if config.tmp and not hasattr(instance, '_tmp_trivial_deactivated_constrs'):\n+        if config.tmp and not hasattr(instance,\n+                                      '_tmp_trivial_deactivated_constrs'):\n             instance._tmp_trivial_deactivated_constrs = ComponentSet()\n         elif config.tmp:\n             logger.warning(\n@@ -76,19 +78,20 @@\n \n         # Trivial constraints are those that do not contain any variables, ie.\n         # the polynomial degree is 0\n-        trivial_constraints = (\n-            constr\n-            for constr in instance.component_data_objects(\n-                ctype=Constraint, active=True, descend_into=True)\n-            if constr.body.polynomial_degree() == 0)\n+        for constr in instance.component_data_objects(ctype=Constraint,\n+                                                      active=True,\n+                                                      descend_into=True):\n+            repn = generate_standard_repn(constr.body)\n+            if not repn.is_constant():\n+                # This constraint is not trivial\n+                continue\n \n-        for constr in trivial_constraints:\n             # We need to check each constraint to sure that it is not violated.\n             constr_lb = value(\n                 constr.lower) if constr.has_lb() else float('-inf')\n             constr_ub = value(\n                 constr.upper) if constr.has_ub() else float('inf')\n-            constr_value = value(constr.body)\n+            constr_value = repn.constant\n \n             # Check if the lower bound is violated outside a given tolerance\n             if (constr_value + config.tolerance <= constr_lb):\ndiff --git a/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py b/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py\n--- a/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py\n+++ b/pyomo/contrib/preprocessing/plugins/remove_zero_terms.py\n@@ -39,9 +39,12 @@\n \n         for constr in m.component_data_objects(\n                 ctype=Constraint, active=True, descend_into=True):\n-            if not constr.body.polynomial_degree() == 1:\n-                continue  # we currently only process linear constraints\n             repn = generate_standard_repn(constr.body)\n+            if not repn.is_linear() or repn.is_constant():\n+                continue  # we currently only process linear constraints, and we\n+                          # assume that trivial constraints have already been\n+                          # deactivated or will be deactivated in a different\n+                          # step\n \n             # get the index of all nonzero coefficient variables\n             nonzero_vars_indx = [\n", "issue": "contrib.deactivate_trivial_constraints can miss trivial constraints\n## Summary\r\n\r\nThe `contrib.deactivate_trivial_constraints` transformation uses the polynomial degree of the constraint expression to decide if the expression is constant. That's not actually a reliable method of doing so, meaning that it can miss trivial constraints like in the example below, where the polynomial degree of the constraint body evaluates to 1.\r\n\r\n### Steps to reproduce the issue\r\n\r\n```\r\nfrom pyomo.environ import *\r\n\r\nm = ConcreteModel()\r\nm.x = Var()\r\nm.y = Var()\r\nm.y.fix(0)\r\nm.c = Constraint(expr=m.x*m.y >= 0)\r\n\r\nTransformationFactory('contrib.deactivate_trivial_constraints').apply_to(m)\r\n\r\nprint(m.c.active) # True\r\n```\r\n\r\n### Information on your system\r\n\r\nPyomo version: main\r\nPython version: 3.8\r\nOperating system: linux\r\nHow Pyomo was installed (PyPI, conda, source): source\r\nSolver (if applicable):\r\n\r\n\r\n### Additional information\r\n\r\nI think you could use `generate_standard_repn` to actually detect if a constraint body is constant. This isn't a bug in the sense that it does the wrong thing, but it does fall short on its promises.\r\n\n", "before_files": [{"content": "#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and \n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain \n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  ___________________________________________________________________________\n\n# -*- coding: UTF-8 -*-\n\"\"\"Transformation to remove zero terms from constraints.\"\"\"\nfrom __future__ import division\n\nfrom pyomo.core import quicksum\nfrom pyomo.core.base.constraint import Constraint\nfrom pyomo.core.base.transformation import TransformationFactory\nfrom pyomo.core.expr import current as EXPR\nfrom pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation\nfrom pyomo.repn import generate_standard_repn\n\n\n@TransformationFactory.register(\n        'contrib.remove_zero_terms',\n        doc=\"Remove terms 0 * var in constraints\")\nclass RemoveZeroTerms(IsomorphicTransformation):\n    \"\"\"Looks for :math:`0 v` in a constraint and removes it.\n\n    Currently limited to processing linear constraints of the form :math:`x_1 =\n    0 x_3`, occurring as a result of fixing :math:`x_2 = 0`.\n\n    .. note:: TODO: support nonlinear expressions\n\n    \"\"\"\n\n    def _apply_to(self, model):\n        \"\"\"Apply the transformation.\"\"\"\n        m = model\n\n        for constr in m.component_data_objects(\n                ctype=Constraint, active=True, descend_into=True):\n            if not constr.body.polynomial_degree() == 1:\n                continue  # we currently only process linear constraints\n            repn = generate_standard_repn(constr.body)\n\n            # get the index of all nonzero coefficient variables\n            nonzero_vars_indx = [\n                i for i, _ in enumerate(repn.linear_vars)\n                if not repn.linear_coefs[i] == 0\n            ]\n            const = repn.constant\n\n            # reconstitute the constraint, including only variable terms with\n            # nonzero coefficients\n            constr_body = quicksum(repn.linear_coefs[i] * repn.linear_vars[i]\n                                   for i in nonzero_vars_indx) + const\n            if constr.equality:\n                constr.set_value(constr_body == constr.upper)\n            elif constr.has_lb() and not constr.has_ub():\n                constr.set_value(constr_body >= constr.lower)\n            elif constr.has_ub() and not constr.has_lb():\n                constr.set_value(constr_body <= constr.upper)\n            else:\n                # constraint is a bounded inequality of form a <= x <= b.\n                constr.set_value(EXPR.inequality(\n                    constr.lower, constr_body, constr.upper))\n", "path": "pyomo/contrib/preprocessing/plugins/remove_zero_terms.py"}, {"content": "# -*- coding: utf-8 -*-\n\n#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and \n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain \n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  ___________________________________________________________________________\n\n\"\"\"Transformation to deactivate trivial constraints.\"\"\"\nimport logging\n\nfrom pyomo.common.collections import ComponentSet\nfrom pyomo.common.config import (ConfigBlock, ConfigValue, NonNegativeFloat,\n                                 add_docstring_list)\nfrom pyomo.common.errors import InfeasibleConstraintException\nfrom pyomo.core.base.constraint import Constraint\nfrom pyomo.core.base.transformation import TransformationFactory\nfrom pyomo.core.expr.numvalue import value\nfrom pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation\n\nlogger = logging.getLogger('pyomo.contrib.preprocessing')\n\n@TransformationFactory.register(\n        'contrib.deactivate_trivial_constraints',\n        doc=\"Deactivate trivial constraints.\")\nclass TrivialConstraintDeactivator(IsomorphicTransformation):\n    \"\"\"Deactivates trivial constraints.\n\n    Trivial constraints take form :math:`k_1 = k_2` or :math:`k_1 \\\\leq k_2`,\n    where :math:`k_1` and :math:`k_2` are constants. These constraints\n    typically arise when variables are fixed.\n\n    Keyword arguments below are specified for the ``apply_to`` and\n    ``create_using`` functions.\n\n    \"\"\"\n\n    CONFIG = ConfigBlock(\"TrivialConstraintDeactivator\")\n    CONFIG.declare(\"tmp\", ConfigValue(\n        default=False, domain=bool,\n        description=\"True to store a set of transformed constraints for future\"\n        \" reversion of the transformation.\"\n    ))\n    CONFIG.declare(\"ignore_infeasible\", ConfigValue(\n        default=False, domain=bool,\n        description=\"True to skip over trivial constraints that are \"\n        \"infeasible instead of raising an InfeasibleConstraintException.\"\n    ))\n    CONFIG.declare(\"return_trivial\", ConfigValue(\n        default=[],\n        description=\"a list to which the deactivated trivial\"\n        \"constraints are appended (side effect)\"\n    ))\n    CONFIG.declare(\"tolerance\", ConfigValue(\n        default=1E-13, domain=NonNegativeFloat,\n        description=\"tolerance on constraint violations\"\n    ))\n\n    __doc__ = add_docstring_list(__doc__, CONFIG)\n\n\n    def _apply_to(self, instance, **kwargs):\n        config = self.CONFIG(kwargs)\n        if config.tmp and not hasattr(instance, '_tmp_trivial_deactivated_constrs'):\n            instance._tmp_trivial_deactivated_constrs = ComponentSet()\n        elif config.tmp:\n            logger.warning(\n                'Deactivating trivial constraints on the block {} for which '\n                'trivial constraints were previously deactivated. '\n                'Reversion will affect all deactivated constraints.'.format(\n                    instance.name))\n\n        # Trivial constraints are those that do not contain any variables, ie.\n        # the polynomial degree is 0\n        trivial_constraints = (\n            constr\n            for constr in instance.component_data_objects(\n                ctype=Constraint, active=True, descend_into=True)\n            if constr.body.polynomial_degree() == 0)\n\n        for constr in trivial_constraints:\n            # We need to check each constraint to sure that it is not violated.\n            constr_lb = value(\n                constr.lower) if constr.has_lb() else float('-inf')\n            constr_ub = value(\n                constr.upper) if constr.has_ub() else float('inf')\n            constr_value = value(constr.body)\n\n            # Check if the lower bound is violated outside a given tolerance\n            if (constr_value + config.tolerance <= constr_lb):\n                if config.ignore_infeasible:\n                    continue\n                else:\n                    raise InfeasibleConstraintException(\n                        'Trivial constraint {} violates LB {} \u2264 BODY {}.'\n                        .format(constr.name, constr_lb, constr_value))\n\n            # Check if the upper bound is violated outside a given tolerance\n            if (constr_value >= constr_ub + config.tolerance):\n                if config.ignore_infeasible:\n                    continue\n                else:\n                    raise InfeasibleConstraintException(\n                        'Trivial constraint {} violates BODY {} \u2264 UB {}.'\n                        .format(constr.name, constr_value, constr_ub))\n\n            # Constraint is not infeasible. Deactivate it.\n            if config.tmp:\n                instance._tmp_trivial_deactivated_constrs.add(constr)\n            config.return_trivial.append(constr)\n            constr.deactivate()\n\n    def revert(self, instance):\n        \"\"\"Revert constraints deactivated by the transformation.\n\n        Args:\n            instance: the model instance on which trivial constraints were\n                earlier deactivated.\n        \"\"\"\n        for constr in instance._tmp_trivial_deactivated_constrs:\n            constr.activate()\n        del instance._tmp_trivial_deactivated_constrs\n", "path": "pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py"}], "after_files": [{"content": "#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and \n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain \n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  ___________________________________________________________________________\n\n# -*- coding: UTF-8 -*-\n\"\"\"Transformation to remove zero terms from constraints.\"\"\"\nfrom __future__ import division\n\nfrom pyomo.core import quicksum\nfrom pyomo.core.base.constraint import Constraint\nfrom pyomo.core.base.transformation import TransformationFactory\nfrom pyomo.core.expr import current as EXPR\nfrom pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation\nfrom pyomo.repn import generate_standard_repn\n\n\n@TransformationFactory.register(\n        'contrib.remove_zero_terms',\n        doc=\"Remove terms 0 * var in constraints\")\nclass RemoveZeroTerms(IsomorphicTransformation):\n    \"\"\"Looks for :math:`0 v` in a constraint and removes it.\n\n    Currently limited to processing linear constraints of the form :math:`x_1 =\n    0 x_3`, occurring as a result of fixing :math:`x_2 = 0`.\n\n    .. note:: TODO: support nonlinear expressions\n\n    \"\"\"\n\n    def _apply_to(self, model):\n        \"\"\"Apply the transformation.\"\"\"\n        m = model\n\n        for constr in m.component_data_objects(\n                ctype=Constraint, active=True, descend_into=True):\n            repn = generate_standard_repn(constr.body)\n            if not repn.is_linear() or repn.is_constant():\n                continue  # we currently only process linear constraints, and we\n                          # assume that trivial constraints have already been\n                          # deactivated or will be deactivated in a different\n                          # step\n\n            # get the index of all nonzero coefficient variables\n            nonzero_vars_indx = [\n                i for i, _ in enumerate(repn.linear_vars)\n                if not repn.linear_coefs[i] == 0\n            ]\n            const = repn.constant\n\n            # reconstitute the constraint, including only variable terms with\n            # nonzero coefficients\n            constr_body = quicksum(repn.linear_coefs[i] * repn.linear_vars[i]\n                                   for i in nonzero_vars_indx) + const\n            if constr.equality:\n                constr.set_value(constr_body == constr.upper)\n            elif constr.has_lb() and not constr.has_ub():\n                constr.set_value(constr_body >= constr.lower)\n            elif constr.has_ub() and not constr.has_lb():\n                constr.set_value(constr_body <= constr.upper)\n            else:\n                # constraint is a bounded inequality of form a <= x <= b.\n                constr.set_value(EXPR.inequality(\n                    constr.lower, constr_body, constr.upper))\n", "path": "pyomo/contrib/preprocessing/plugins/remove_zero_terms.py"}, {"content": "# -*- coding: utf-8 -*-\n\n#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and \n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain \n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  ___________________________________________________________________________\n\n\"\"\"Transformation to deactivate trivial constraints.\"\"\"\nimport logging\n\nfrom pyomo.common.collections import ComponentSet\nfrom pyomo.common.config import (ConfigBlock, ConfigValue, NonNegativeFloat,\n                                 add_docstring_list)\nfrom pyomo.common.errors import InfeasibleConstraintException\nfrom pyomo.core.base.constraint import Constraint\nfrom pyomo.core.base.transformation import TransformationFactory\nfrom pyomo.core.expr.numvalue import value\nfrom pyomo.core.plugins.transform.hierarchy import IsomorphicTransformation\nfrom pyomo.repn import generate_standard_repn\n\nlogger = logging.getLogger('pyomo.contrib.preprocessing')\n\n@TransformationFactory.register(\n        'contrib.deactivate_trivial_constraints',\n        doc=\"Deactivate trivial constraints.\")\nclass TrivialConstraintDeactivator(IsomorphicTransformation):\n    \"\"\"Deactivates trivial constraints.\n\n    Trivial constraints take form :math:`k_1 = k_2` or :math:`k_1 \\\\leq k_2`,\n    where :math:`k_1` and :math:`k_2` are constants. These constraints\n    typically arise when variables are fixed.\n\n    Keyword arguments below are specified for the ``apply_to`` and\n    ``create_using`` functions.\n\n    \"\"\"\n\n    CONFIG = ConfigBlock(\"TrivialConstraintDeactivator\")\n    CONFIG.declare(\"tmp\", ConfigValue(\n        default=False, domain=bool,\n        description=\"True to store a set of transformed constraints for future\"\n        \" reversion of the transformation.\"\n    ))\n    CONFIG.declare(\"ignore_infeasible\", ConfigValue(\n        default=False, domain=bool,\n        description=\"True to skip over trivial constraints that are \"\n        \"infeasible instead of raising an InfeasibleConstraintException.\"\n    ))\n    CONFIG.declare(\"return_trivial\", ConfigValue(\n        default=[],\n        description=\"a list to which the deactivated trivial\"\n        \"constraints are appended (side effect)\"\n    ))\n    CONFIG.declare(\"tolerance\", ConfigValue(\n        default=1E-13, domain=NonNegativeFloat,\n        description=\"tolerance on constraint violations\"\n    ))\n\n    __doc__ = add_docstring_list(__doc__, CONFIG)\n\n\n    def _apply_to(self, instance, **kwargs):\n        config = self.CONFIG(kwargs)\n        if config.tmp and not hasattr(instance,\n                                      '_tmp_trivial_deactivated_constrs'):\n            instance._tmp_trivial_deactivated_constrs = ComponentSet()\n        elif config.tmp:\n            logger.warning(\n                'Deactivating trivial constraints on the block {} for which '\n                'trivial constraints were previously deactivated. '\n                'Reversion will affect all deactivated constraints.'.format(\n                    instance.name))\n\n        # Trivial constraints are those that do not contain any variables, ie.\n        # the polynomial degree is 0\n        for constr in instance.component_data_objects(ctype=Constraint,\n                                                      active=True,\n                                                      descend_into=True):\n            repn = generate_standard_repn(constr.body)\n            if not repn.is_constant():\n                # This constraint is not trivial\n                continue\n\n            # We need to check each constraint to sure that it is not violated.\n            constr_lb = value(\n                constr.lower) if constr.has_lb() else float('-inf')\n            constr_ub = value(\n                constr.upper) if constr.has_ub() else float('inf')\n            constr_value = repn.constant\n\n            # Check if the lower bound is violated outside a given tolerance\n            if (constr_value + config.tolerance <= constr_lb):\n                if config.ignore_infeasible:\n                    continue\n                else:\n                    raise InfeasibleConstraintException(\n                        'Trivial constraint {} violates LB {} \u2264 BODY {}.'\n                        .format(constr.name, constr_lb, constr_value))\n\n            # Check if the upper bound is violated outside a given tolerance\n            if (constr_value >= constr_ub + config.tolerance):\n                if config.ignore_infeasible:\n                    continue\n                else:\n                    raise InfeasibleConstraintException(\n                        'Trivial constraint {} violates BODY {} \u2264 UB {}.'\n                        .format(constr.name, constr_value, constr_ub))\n\n            # Constraint is not infeasible. Deactivate it.\n            if config.tmp:\n                instance._tmp_trivial_deactivated_constrs.add(constr)\n            config.return_trivial.append(constr)\n            constr.deactivate()\n\n    def revert(self, instance):\n        \"\"\"Revert constraints deactivated by the transformation.\n\n        Args:\n            instance: the model instance on which trivial constraints were\n                earlier deactivated.\n        \"\"\"\n        for constr in instance._tmp_trivial_deactivated_constrs:\n            constr.activate()\n        del instance._tmp_trivial_deactivated_constrs\n", "path": "pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.py"}]}