prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  TranformationFactory('core.fix_discrete') doesn't work for cloned models
  # Summary
  I have noticed that often times `TransformationFactory('core.fix_discrete')` doesn't work for a model, i.e. it doesn't actually fix the variables. I have found out that it happens to cloned models (whereas 'normal' models work as expected).
  
  ## Minimal working example
  ```python
  from pyomo.environ import *
  m = ConcreteModel()
  m.y = Var(domain=Integers, bounds=(0,10), initialize=0)
  m_clone = m.clone()
  TransformationFactory('core.fix_discrete').apply_to(m_clone)
  m_clone.pprint()
  ```
  yields
  ```
  1 Var Declarations
      y : Size=1, Index=None
          Key  : Lower : Value : Upper : Fixed : Stale : Domain
          None :     0 :     0 :    10 : False : False : Integers
  1 Suffix Declarations
      _fixed_discrete_vars : Direction=Suffix.LOCAL, Datatype=Suffix.FLOAT
          Key  : Value
          None :    []
  2 Declarations: y _fixed_discrete_vars
  ```
  Notice that the variable `y` didn't actually get fixed. If the `TranformationFactory` is intead applied to model `m`, the behaviour is as expected.
  
  ## Looking into the code
  When diving into the code, the problem ends up being when the domain of the variable `y` is checked against a list of domains [here](https://github.com/Pyomo/pyomo/blob/ea161615a67b93c2540384eae4cce55e998dc8cc/pyomo/core/plugins/transform/discrete_vars.py#L116-L119)
  
  The expression `var.domain in _discrete_relaxation_map` will yield `False`, even though `var` is an Integer.
  
  --- 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/core/plugins/transform/discrete_vars.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 import logging
  12 logger = logging.getLogger('pyomo.core')
  13 
  14 from six import itervalues
  15 
  16 from pyomo.core.base import ( 
  17     Transformation,
  18     TransformationFactory,
  19     Binary,
  20     Boolean,
  21     Integers,
  22     Reals, 
  23     PositiveIntegers,
  24     PositiveReals, 
  25     NonPositiveIntegers,
  26     NonPositiveReals, 
  27     NegativeIntegers,
  28     NegativeReals,
  29     NonNegativeIntegers,
  30     NonNegativeReals,
  31     IntegerInterval,
  32     RealInterval,
  33     Var,
  34     Suffix,
  35 )
  36 
  37 _discrete_relaxation_map = {
  38     Binary : NonNegativeReals,
  39     Boolean : NonNegativeReals,
  40     Integers : Reals, 
  41     PositiveIntegers : PositiveReals, 
  42     NonPositiveIntegers : NonPositiveReals, 
  43     NegativeIntegers : NegativeReals,
  44     NonNegativeIntegers : NonNegativeReals,
  45     IntegerInterval : RealInterval,
  46 }
  47 
  48 
  49 #
  50 # This transformation relaxes known discrete domains to their continuous
  51 # counterparts
  52 #
  53 @TransformationFactory.register( 'core.relax_discrete', 
  54            doc="Relax known discrete domains to continuous counterparts" )
  55 class RelaxDiscreteVars(Transformation):
  56 
  57     def __init__(self):
  58         super(RelaxDiscreteVars, self).__init__()
  59 
  60     def _apply_to(self, model, **kwds): 
  61         options = kwds.pop('options', {})
  62         if kwds.get('undo', options.get('undo', False)):
  63             for v, d in itervalues(model._relaxed_discrete_vars[None]):
  64                 v.domain = d
  65             model.del_component("_relaxed_discrete_vars")
  66             return
  67         
  68         # Relax the model
  69         relaxed_vars = {}
  70         _base_model_vars = model.component_data_objects(
  71             Var, active=True, descend_into=True )
  72         for var in _base_model_vars:
  73             if var.domain in _discrete_relaxation_map:
  74                 if var.domain is Binary or var.domain is Boolean:
  75                     var.setlb(0)
  76                     var.setub(1)
  77                 # Note: some indexed components can only have their
  78                 # domain set on the parent component (the individual
  79                 # indices cannot be set independently)
  80                 _c = var.parent_component()
  81                 if id(_c) in _discrete_relaxation_map:
  82                     continue
  83                 try:
  84                     _domain = var.domain
  85                     var.domain = _discrete_relaxation_map[_domain]
  86                     relaxed_vars[id(var)] = (var, _domain)
  87                 except:
  88                     _domain = _c.domain
  89                     _c.domain = _discrete_relaxation_map[_domain]
  90                     relaxed_vars[id(_c)] = (_c, _domain)
  91         model._relaxed_discrete_vars = Suffix(direction=Suffix.LOCAL)
  92         model._relaxed_discrete_vars[None] = relaxed_vars
  93 
  94 
  95 #
  96 # This transformation fixes known discrete domains to their current values
  97 #
  98 @TransformationFactory.register('core.fix_discrete', 
  99            doc="Fix known discrete domains to continuous counterparts" )
  100 class FixDiscreteVars(Transformation):
  101 
  102     def __init__(self):
  103         super(FixDiscreteVars, self).__init__()
  104 
  105     def _apply_to(self, model, **kwds): 
  106         options = kwds.pop('options', {})
  107         if kwds.get('undo', options.get('undo', False)):
  108             for v in model._fixed_discrete_vars[None]:
  109                 v.unfix()
  110             model.del_component("_fixed_discrete_vars")
  111             return
  112         
  113         fixed_vars = []
  114         _base_model_vars = model.component_data_objects(
  115             Var, active=True, descend_into=True )
  116         for var in _base_model_vars:
  117             if var.domain in _discrete_relaxation_map and not var.is_fixed():
  118                 fixed_vars.append(var)
  119                 var.fix()
  120         model._fixed_discrete_vars = Suffix(direction=Suffix.LOCAL)
  121         model._fixed_discrete_vars[None] = fixed_vars
  122 
  123
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/pyomo/core/plugins/transform/discrete_vars.py b/pyomo/core/plugins/transform/discrete_vars.py
  --- a/pyomo/core/plugins/transform/discrete_vars.py
  +++ b/pyomo/core/plugins/transform/discrete_vars.py
  @@ -95,26 +95,29 @@
   #
   # This transformation fixes known discrete domains to their current values
   #
  -@TransformationFactory.register('core.fix_discrete', 
  -           doc="Fix known discrete domains to continuous counterparts" )
  +@TransformationFactory.register('core.fix_discrete',
  +           doc="Fix known discrete domains to continuous counterparts")
   class FixDiscreteVars(Transformation):
   
       def __init__(self):
           super(FixDiscreteVars, self).__init__()
   
  -    def _apply_to(self, model, **kwds): 
  +    def _apply_to(self, model, **kwds):
           options = kwds.pop('options', {})
           if kwds.get('undo', options.get('undo', False)):
               for v in model._fixed_discrete_vars[None]:
                   v.unfix()
               model.del_component("_fixed_discrete_vars")
               return
  -        
  +
           fixed_vars = []
           _base_model_vars = model.component_data_objects(
  -            Var, active=True, descend_into=True )
  +            Var, active=True, descend_into=True)
           for var in _base_model_vars:
  -            if var.domain in _discrete_relaxation_map and not var.is_fixed():
  +            # Instead of checking against `_discrete_relaxation_map.keys()` 
  +            # we just check the item properties to fix #995 
  +            # When #326 has been resolved, we can check against the dict-keys again
  +            if not var.is_continuous() and not var.is_fixed():
                   fixed_vars.append(var)
                   var.fix()
           model._fixed_discrete_vars = Suffix(direction=Suffix.LOCAL)
  
verification_info: {"golden_diff": "diff --git a/pyomo/core/plugins/transform/discrete_vars.py b/pyomo/core/plugins/transform/discrete_vars.py\n--- a/pyomo/core/plugins/transform/discrete_vars.py\n+++ b/pyomo/core/plugins/transform/discrete_vars.py\n@@ -95,26 +95,29 @@\n #\n # This transformation fixes known discrete domains to their current values\n #\n-@TransformationFactory.register('core.fix_discrete', \n-           doc=\"Fix known discrete domains to continuous counterparts\" )\n+@TransformationFactory.register('core.fix_discrete',\n+           doc=\"Fix known discrete domains to continuous counterparts\")\n class FixDiscreteVars(Transformation):\n \n     def __init__(self):\n         super(FixDiscreteVars, self).__init__()\n \n-    def _apply_to(self, model, **kwds): \n+    def _apply_to(self, model, **kwds):\n         options = kwds.pop('options', {})\n         if kwds.get('undo', options.get('undo', False)):\n             for v in model._fixed_discrete_vars[None]:\n                 v.unfix()\n             model.del_component(\"_fixed_discrete_vars\")\n             return\n-        \n+\n         fixed_vars = []\n         _base_model_vars = model.component_data_objects(\n-            Var, active=True, descend_into=True )\n+            Var, active=True, descend_into=True)\n         for var in _base_model_vars:\n-            if var.domain in _discrete_relaxation_map and not var.is_fixed():\n+            # Instead of checking against `_discrete_relaxation_map.keys()` \n+            # we just check the item properties to fix #995 \n+            # When #326 has been resolved, we can check against the dict-keys again\n+            if not var.is_continuous() and not var.is_fixed():\n                 fixed_vars.append(var)\n                 var.fix()\n         model._fixed_discrete_vars = Suffix(direction=Suffix.LOCAL)\n", "issue": "TranformationFactory('core.fix_discrete') doesn't work for cloned models\n# Summary\r\nI have noticed that often times `TransformationFactory('core.fix_discrete')` doesn't work for a model, i.e. it doesn't actually fix the variables. I have found out that it happens to cloned models (whereas 'normal' models work as expected).\r\n\r\n## Minimal working example\r\n```python\r\nfrom pyomo.environ import *\r\nm = ConcreteModel()\r\nm.y = Var(domain=Integers, bounds=(0,10), initialize=0)\r\nm_clone = m.clone()\r\nTransformationFactory('core.fix_discrete').apply_to(m_clone)\r\nm_clone.pprint()\r\n```\r\nyields\r\n```\r\n1 Var Declarations\r\n    y : Size=1, Index=None\r\n        Key  : Lower : Value : Upper : Fixed : Stale : Domain\r\n        None :     0 :     0 :    10 : False : False : Integers\r\n1 Suffix Declarations\r\n    _fixed_discrete_vars : Direction=Suffix.LOCAL, Datatype=Suffix.FLOAT\r\n        Key  : Value\r\n        None :    []\r\n2 Declarations: y _fixed_discrete_vars\r\n```\r\nNotice that the variable `y` didn't actually get fixed. If the `TranformationFactory` is intead applied to model `m`, the behaviour is as expected.\r\n\r\n## Looking into the code\r\nWhen diving into the code, the problem ends up being when the domain of the variable `y` is checked against a list of domains [here](https://github.com/Pyomo/pyomo/blob/ea161615a67b93c2540384eae4cce55e998dc8cc/pyomo/core/plugins/transform/discrete_vars.py#L116-L119)\r\n\r\nThe expression `var.domain in _discrete_relaxation_map` will yield `False`, even though `var` is an Integer.\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\nimport logging\nlogger = logging.getLogger('pyomo.core')\n\nfrom six import itervalues\n\nfrom pyomo.core.base import ( \n    Transformation,\n    TransformationFactory,\n    Binary,\n    Boolean,\n    Integers,\n    Reals, \n    PositiveIntegers,\n    PositiveReals, \n    NonPositiveIntegers,\n    NonPositiveReals, \n    NegativeIntegers,\n    NegativeReals,\n    NonNegativeIntegers,\n    NonNegativeReals,\n    IntegerInterval,\n    RealInterval,\n    Var,\n    Suffix,\n)\n\n_discrete_relaxation_map = {\n    Binary : NonNegativeReals,\n    Boolean : NonNegativeReals,\n    Integers : Reals, \n    PositiveIntegers : PositiveReals, \n    NonPositiveIntegers : NonPositiveReals, \n    NegativeIntegers : NegativeReals,\n    NonNegativeIntegers : NonNegativeReals,\n    IntegerInterval : RealInterval,\n}\n\n\n#\n# This transformation relaxes known discrete domains to their continuous\n# counterparts\n#\n@TransformationFactory.register( 'core.relax_discrete', \n           doc=\"Relax known discrete domains to continuous counterparts\" )\nclass RelaxDiscreteVars(Transformation):\n\n    def __init__(self):\n        super(RelaxDiscreteVars, self).__init__()\n\n    def _apply_to(self, model, **kwds): \n        options = kwds.pop('options', {})\n        if kwds.get('undo', options.get('undo', False)):\n            for v, d in itervalues(model._relaxed_discrete_vars[None]):\n                v.domain = d\n            model.del_component(\"_relaxed_discrete_vars\")\n            return\n        \n        # Relax the model\n        relaxed_vars = {}\n        _base_model_vars = model.component_data_objects(\n            Var, active=True, descend_into=True )\n        for var in _base_model_vars:\n            if var.domain in _discrete_relaxation_map:\n                if var.domain is Binary or var.domain is Boolean:\n                    var.setlb(0)\n                    var.setub(1)\n                # Note: some indexed components can only have their\n                # domain set on the parent component (the individual\n                # indices cannot be set independently)\n                _c = var.parent_component()\n                if id(_c) in _discrete_relaxation_map:\n                    continue\n                try:\n                    _domain = var.domain\n                    var.domain = _discrete_relaxation_map[_domain]\n                    relaxed_vars[id(var)] = (var, _domain)\n                except:\n                    _domain = _c.domain\n                    _c.domain = _discrete_relaxation_map[_domain]\n                    relaxed_vars[id(_c)] = (_c, _domain)\n        model._relaxed_discrete_vars = Suffix(direction=Suffix.LOCAL)\n        model._relaxed_discrete_vars[None] = relaxed_vars\n\n\n#\n# This transformation fixes known discrete domains to their current values\n#\n@TransformationFactory.register('core.fix_discrete', \n           doc=\"Fix known discrete domains to continuous counterparts\" )\nclass FixDiscreteVars(Transformation):\n\n    def __init__(self):\n        super(FixDiscreteVars, self).__init__()\n\n    def _apply_to(self, model, **kwds): \n        options = kwds.pop('options', {})\n        if kwds.get('undo', options.get('undo', False)):\n            for v in model._fixed_discrete_vars[None]:\n                v.unfix()\n            model.del_component(\"_fixed_discrete_vars\")\n            return\n        \n        fixed_vars = []\n        _base_model_vars = model.component_data_objects(\n            Var, active=True, descend_into=True )\n        for var in _base_model_vars:\n            if var.domain in _discrete_relaxation_map and not var.is_fixed():\n                fixed_vars.append(var)\n                var.fix()\n        model._fixed_discrete_vars = Suffix(direction=Suffix.LOCAL)\n        model._fixed_discrete_vars[None] = fixed_vars\n\n", "path": "pyomo/core/plugins/transform/discrete_vars.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\nimport logging\nlogger = logging.getLogger('pyomo.core')\n\nfrom six import itervalues\n\nfrom pyomo.core.base import ( \n    Transformation,\n    TransformationFactory,\n    Binary,\n    Boolean,\n    Integers,\n    Reals, \n    PositiveIntegers,\n    PositiveReals, \n    NonPositiveIntegers,\n    NonPositiveReals, \n    NegativeIntegers,\n    NegativeReals,\n    NonNegativeIntegers,\n    NonNegativeReals,\n    IntegerInterval,\n    RealInterval,\n    Var,\n    Suffix,\n)\n\n_discrete_relaxation_map = {\n    Binary : NonNegativeReals,\n    Boolean : NonNegativeReals,\n    Integers : Reals, \n    PositiveIntegers : PositiveReals, \n    NonPositiveIntegers : NonPositiveReals, \n    NegativeIntegers : NegativeReals,\n    NonNegativeIntegers : NonNegativeReals,\n    IntegerInterval : RealInterval,\n}\n\n\n#\n# This transformation relaxes known discrete domains to their continuous\n# counterparts\n#\n@TransformationFactory.register( 'core.relax_discrete', \n           doc=\"Relax known discrete domains to continuous counterparts\" )\nclass RelaxDiscreteVars(Transformation):\n\n    def __init__(self):\n        super(RelaxDiscreteVars, self).__init__()\n\n    def _apply_to(self, model, **kwds): \n        options = kwds.pop('options', {})\n        if kwds.get('undo', options.get('undo', False)):\n            for v, d in itervalues(model._relaxed_discrete_vars[None]):\n                v.domain = d\n            model.del_component(\"_relaxed_discrete_vars\")\n            return\n        \n        # Relax the model\n        relaxed_vars = {}\n        _base_model_vars = model.component_data_objects(\n            Var, active=True, descend_into=True )\n        for var in _base_model_vars:\n            if var.domain in _discrete_relaxation_map:\n                if var.domain is Binary or var.domain is Boolean:\n                    var.setlb(0)\n                    var.setub(1)\n                # Note: some indexed components can only have their\n                # domain set on the parent component (the individual\n                # indices cannot be set independently)\n                _c = var.parent_component()\n                if id(_c) in _discrete_relaxation_map:\n                    continue\n                try:\n                    _domain = var.domain\n                    var.domain = _discrete_relaxation_map[_domain]\n                    relaxed_vars[id(var)] = (var, _domain)\n                except:\n                    _domain = _c.domain\n                    _c.domain = _discrete_relaxation_map[_domain]\n                    relaxed_vars[id(_c)] = (_c, _domain)\n        model._relaxed_discrete_vars = Suffix(direction=Suffix.LOCAL)\n        model._relaxed_discrete_vars[None] = relaxed_vars\n\n\n#\n# This transformation fixes known discrete domains to their current values\n#\n@TransformationFactory.register('core.fix_discrete',\n           doc=\"Fix known discrete domains to continuous counterparts\")\nclass FixDiscreteVars(Transformation):\n\n    def __init__(self):\n        super(FixDiscreteVars, self).__init__()\n\n    def _apply_to(self, model, **kwds):\n        options = kwds.pop('options', {})\n        if kwds.get('undo', options.get('undo', False)):\n            for v in model._fixed_discrete_vars[None]:\n                v.unfix()\n            model.del_component(\"_fixed_discrete_vars\")\n            return\n\n        fixed_vars = []\n        _base_model_vars = model.component_data_objects(\n            Var, active=True, descend_into=True)\n        for var in _base_model_vars:\n            # Instead of checking against `_discrete_relaxation_map.keys()` \n            # we just check the item properties to fix #995 \n            # When #326 has been resolved, we can check against the dict-keys again\n            if not var.is_continuous() and not var.is_fixed():\n                fixed_vars.append(var)\n                var.fix()\n        model._fixed_discrete_vars = Suffix(direction=Suffix.LOCAL)\n        model._fixed_discrete_vars[None] = fixed_vars\n\n", "path": "pyomo/core/plugins/transform/discrete_vars.py"}]}