Source code for pyomo.core.kernel.suffix

#  ___________________________________________________________________________
#
#  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.collections import ComponentMap
from pyomo.common.deprecation import deprecated
from pyomo.core.kernel.base import ICategorizedObject, _abstract_readonly_property
from pyomo.core.kernel.dict_container import DictContainer
from pyomo.core.kernel.container_utils import define_homogeneous_container_type

logger = logging.getLogger('pyomo.core')

_noarg = object()


# Note: ComponentMap is first in the inheritance chain
#       because its __getstate__ / __setstate__ methods
#       contain some special hacks that allow it to be used
#       for the AML-Suffix object as well (hopefully,
#       temporary). As a result, we need to override the
#       __str__ method on this class so that suffix behaves
#       like ICategorizedObject instead of ComponentMap
[docs] class ISuffix(ComponentMap, ICategorizedObject): """The interface for suffixes.""" __slots__ = () # # Implementations can choose to define these # properties as using __slots__, __dict__, or # by overriding the @property method # direction = _abstract_readonly_property(doc="The suffix direction") datatype = _abstract_readonly_property(doc="The suffix datatype") # # Interface # def __str__(self): return ICategorizedObject.__str__(self)
[docs] class suffix(ISuffix): """A container for storing extraneous model data that can be imported to or exported from a solver.""" _ctype = ISuffix __slots__ = ( "_parent", "_storage_key", "_active", "_direction", "_datatype", "__weakref__", ) # neither sent to solver or received from solver LOCAL = 0 # sent to solver or other external location EXPORT = 1 # obtained from solver or other external source IMPORT = 2 # both IMPORT_EXPORT = 3 _directions = { LOCAL: 'suffix.LOCAL', EXPORT: 'suffix.EXPORT', IMPORT: 'suffix.IMPORT', IMPORT_EXPORT: 'suffix.IMPORT_EXPORT', } # datatypes (numbers are compatible with ASL bitcodes) FLOAT = 4 INT = 0 _datatypes = {FLOAT: 'suffix.FLOAT', INT: 'suffix.INT', None: str(None)}
[docs] def __init__(self, *args, **kwds): self._parent = None self._storage_key = None self._active = True self._direction = None self._datatype = None # call the setters self.direction = kwds.pop('direction', suffix.LOCAL) self.datatype = kwds.pop('datatype', suffix.FLOAT) super(suffix, self).__init__(*args, **kwds)
# # Interface #
[docs] def export_enabled(self): """Returns :const:`True` when this suffix is enabled for export to solvers.""" return bool(self._direction & suffix.EXPORT)
[docs] def import_enabled(self): """Returns :const:`True` when this suffix is enabled for import from solutions.""" return bool(self._direction & suffix.IMPORT)
@property def datatype(self): """Return the suffix datatype.""" return self._datatype @datatype.setter def datatype(self, datatype): """Set the suffix datatype.""" if datatype not in self._datatypes: raise ValueError( "Suffix datatype must be one of: %s. \n" "Value given: %s" % (list(self._datatypes.values()), datatype) ) self._datatype = datatype @property def direction(self): """Return the suffix direction.""" return self._direction @direction.setter def direction(self, direction): """Set the suffix direction.""" if not direction in self._directions: raise ValueError( "Suffix direction must be one of: %s. \n" "Value given: %s" % (list(self._directions.values()), direction) ) self._direction = direction # # Methods that are deprecated #
[docs] @deprecated("suffix.set_all_values will be removed in the future.", version='5.3') def set_all_values(self, value): for ndx in self: self[ndx] = value
[docs] @deprecated( "suffix.clear_value will be removed in the future. " "Use 'del suffix[key]' instead.", version='5.3', ) def clear_value(self, component): try: del self[component] except KeyError: pass
[docs] @deprecated("suffix.clear_all_values is replaced with suffix.clear", version='5.3') def clear_all_values(self): self.clear()
[docs] @deprecated( "suffix.get_datatype is replaced with the property suffix.datatype", version='5.3', ) def get_datatype(self): return self.datatype
[docs] @deprecated( "suffix.set_datatype is replaced with the property setter suffix.datatype", version='5.3', ) def set_datatype(self, datatype): self.datatype = datatype
[docs] @deprecated( "suffix.get_direction is replaced with the property suffix.direction", version='5.3', ) def get_direction(self): return self.direction
[docs] @deprecated( "suffix.set_direction is replaced with the property setter suffix.direction", version='5.3', ) def set_direction(self, direction): self.direction = direction
# A list of convenient suffix generators, including: # - export_suffix_generator # **(used by problem writers) # - import_suffix_generator # **(used by OptSolver and PyomoModel._load_solution) # - local_suffix_generator # - suffix_generator
[docs] def export_suffix_generator(blk, datatype=_noarg, active=True, descend_into=True): """ Generates an efficient traversal of all suffixes that have been declared for exporting data. Args: blk: A block object. datatype: Restricts the suffixes included in the returned generator to those matching the provided suffix datatype. active (:const:`True`/:const:`None`): Controls whether or not to filter the iteration to include only the active part of the storage tree. The default is :const:`True`. Setting this keyword to :const:`None` causes the active status of objects to be ignored. descend_into (bool, function): Indicates whether or not to descend into a heterogeneous container. Default is True, which is equivalent to `lambda x: True`, meaning all heterogeneous containers will be descended into. Returns: iterator of suffixes """ for suf in filter( lambda x: ( x.export_enabled() and ((datatype is _noarg) or (x.datatype is datatype)) ), blk.components(ctype=suffix._ctype, active=active, descend_into=descend_into), ): yield suf
[docs] def import_suffix_generator(blk, datatype=_noarg, active=True, descend_into=True): """ Generates an efficient traversal of all suffixes that have been declared for importing data. Args: blk: A block object. datatype: Restricts the suffixes included in the returned generator to those matching the provided suffix datatype. active (:const:`True`/:const:`None`): Controls whether or not to filter the iteration to include only the active part of the storage tree. The default is :const:`True`. Setting this keyword to :const:`None` causes the active status of objects to be ignored. descend_into (bool, function): Indicates whether or not to descend into a heterogeneous container. Default is True, which is equivalent to `lambda x: True`, meaning all heterogeneous containers will be descended into. Returns: iterator of suffixes """ for suf in filter( lambda x: ( x.import_enabled() and ((datatype is _noarg) or (x.datatype is datatype)) ), blk.components(ctype=suffix._ctype, active=active, descend_into=descend_into), ): yield suf
[docs] def local_suffix_generator(blk, datatype=_noarg, active=True, descend_into=True): """ Generates an efficient traversal of all suffixes that have been declared local data storage. Args: blk: A block object. datatype: Restricts the suffixes included in the returned generator to those matching the provided suffix datatype. active (:const:`True`/:const:`None`): Controls whether or not to filter the iteration to include only the active part of the storage tree. The default is :const:`True`. Setting this keyword to :const:`None` causes the active status of objects to be ignored. descend_into (bool, function): Indicates whether or not to descend into a heterogeneous container. Default is True, which is equivalent to `lambda x: True`, meaning all heterogeneous containers will be descended into. Returns: iterator of suffixes """ for suf in filter( lambda x: ( x.direction is suffix.LOCAL and ((datatype is _noarg) or (x.datatype is datatype)) ), blk.components(ctype=suffix._ctype, active=active, descend_into=descend_into), ): yield suf
[docs] def suffix_generator(blk, datatype=_noarg, active=True, descend_into=True): """ Generates an efficient traversal of all suffixes that have been declared. Args: blk: A block object. datatype: Restricts the suffixes included in the returned generator to those matching the provided suffix datatype. active (:const:`True`/:const:`None`): Controls whether or not to filter the iteration to include only the active part of the storage tree. The default is :const:`True`. Setting this keyword to :const:`None` causes the active status of objects to be ignored. descend_into (bool, function): Indicates whether or not to descend into a heterogeneous container. Default is True, which is equivalent to `lambda x: True`, meaning all heterogeneous containers will be descended into. Returns: iterator of suffixes """ for suf in filter( lambda x: ((datatype is _noarg) or (x.datatype is datatype)), blk.components(ctype=suffix._ctype, active=active, descend_into=descend_into), ): yield suf
# inserts class definition for simple a # simple suffix_dict into this module define_homogeneous_container_type( globals(), "suffix_dict", DictContainer, ISuffix, doc=("A dict-style container for objects with category type " + ISuffix.__name__), use_slots=True, )