Changeset 10880


Ignore:
Timestamp:
Nov 5, 2015 9:09:45 AM (4 years ago)
Author:
jdsiiro
Message:

Adding a warning for iterating over an empty indexed component when the
underlying set is both concrete and non-empty.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pyomo/trunk/pyomo/core/base/indexed_component.py

    r10875 r10880  
    1515
    1616from six import PY3, itervalues, iteritems
     17
     18import logging
     19logger = logging.getLogger('pyomo.core')
    1720
    1821UnindexedComponent_set = set([None])
     
    154157        if not getattr(self._index, 'concrete', True):
    155158            #
    156             # If the index set is virtual (e.g., Any) then
    157             # return the data iterator
     159            # If the index set is virtual (e.g., Any) then return the
     160            # data iterator.  Note that since we cannot check the length
     161            # of the underlying Set, there should be no warning if the
     162            # user iterates over the set when the _data dict is empty.
    158163            #
    159164            return self._data.__iter__()
     
    163168            #
    164169            return self._index.__iter__()
    165         elif not hasattr(self._index, 'ordered') or not self._index.ordered:
    166             #
    167             # If the index set is not ordered, then return the
    168             # data iterator.  This is in an arbitrary order, which is
    169             # fine because the data is unordered.
    170             #
    171             return self._data.__iter__()
    172170        else:
    173             #
    174             # Test each element of a sparse data with an ordered index set
    175             # in order.  This is potentially *slow*: if the component is in fact
    176             # very sparse, we could be iterating over a huge (dense)
    177             # index in order to sort a small number of indices.
    178             # However, this provides a consistent ordering that the user
    179             # expects.
    180             #
    181             def _sparse_iter_gen(self):
    182                 for idx in self._index.__iter__():
    183                     if idx in self._data:
    184                         yield idx
    185             return _sparse_iter_gen(self)
     171            if not self._data and self._index:
     172                logger.warning(
     173"""Iterating over a Component (%s)
     174defined by a non-empty concrete set before any data objects have
     175actually been added to the Component.  The iterator will be empty.
     176This is usually caused by Concrete models where you declare the
     177component (e.g., a Var) and apply component-level operations (e.g.,
     178x.fix(0)) before you use the component members (in something like a
     179constraint).
     180
     181You can silence this warning by one of three ways:
     182    1) Declare the component to be dense with the 'dense=True' option.
     183       This will cause all data objects to be immediately created and
     184       added to the Component.
     185    2) Defer component-level iteration until after the component data
     186       members have been added (through explicit use).
     187    3) If you intend to iterate over a component that may be empty, test
     188       if the component is empty first and avoid iteration in the case
     189       where it is empty.
     190""" % (self.cname(True),) )
     191
     192            if not hasattr(self._index, 'ordered') or not self._index.ordered:
     193                #
     194                # If the index set is not ordered, then return the
     195                # data iterator.  This is in an arbitrary order, which is
     196                # fine because the data is unordered.
     197                #
     198                return self._data.__iter__()
     199            else:
     200                #
     201                # Test each element of a sparse data with an ordered
     202                # index set in order.  This is potentially *slow*: if
     203                # the component is in fact very sparse, we could be
     204                # iterating over a huge (dense) index in order to sort a
     205                # small number of indices.  However, this provides a
     206                # consistent ordering that the user expects.
     207                #
     208                def _sparse_iter_gen(self):
     209                    for idx in self._index.__iter__():
     210                        if idx in self._data:
     211                            yield idx
     212                return _sparse_iter_gen(self)
    186213
    187214    def keys(self):
Note: See TracChangeset for help on using the changeset viewer.