Source code for pyomo.opt.results.container

#  ___________________________________________________________________________
#
#  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 copy
import enum
from io import StringIO
from math import inf

from pyomo.common.collections import Bunch


[docs] class ScalarType(str, enum.Enum): int = 'int' time = 'time' string = 'string' float = 'float' enum = 'enum' undefined = 'undefined' # Overloading __str__ is needed to match the behavior of the old # pyutilib.enum class (removed June 2020). There are spots in the # code base that expect the string representation for items in the # enum to not include the class name. New uses of enum shouldn't # need to do this. def __str__(self): return self.value
default_print_options = Bunch(schema=False, ignore_time=False) strict = False
[docs] class UndefinedData(object): def __str__(self): return "<undefined>"
undefined = UndefinedData() ignore = UndefinedData()
[docs] class ScalarData(object):
[docs] def __init__( self, value=undefined, description=None, units=None, scalar_description=None, type=ScalarType.undefined, required=False, ): self.value = value self.description = description self.units = units self.scalar_description = scalar_description self.scalar_type = type self._required = required
def get_value(self): if isinstance(self.value, enum.Enum): value = str(self.value) elif type(self.value) is UndefinedData: value = '<undefined>' else: value = self.value return value def _repn_(self, option): if not option.schema and not self._required and self.value is undefined: return ignore if option.ignore_time and str(self.scalar_type) == str(ScalarType.time): return ignore value = self.get_value() if option.schema: tmp = {'value': value} if not self.description is None: tmp['description'] = self.description if not self.units is None: tmp['units'] = self.units if not self.scalar_description is None: tmp['description'] = self.scalar_description if not self.scalar_type is ScalarType.undefined: tmp['type'] = self.scalar_type return tmp if not (self.description is None and self.units is None): tmp = {'value': value} if not self.description is None: tmp['description'] = self.description if not self.units is None: tmp['units'] = self.units return tmp return value def pprint(self, ostream, option, prefix="", repn=None): if not option.schema and not self._required and self.value is undefined: return ignore if option.ignore_time and str(self.scalar_type) == str(ScalarType.time): return ignore value = self.yaml_fix(self.get_value()) if value is inf: value = '.inf' elif value is -inf: value = '-.inf' if not option.schema and self.description is None and self.units is None: ostream.write(str(value) + '\n') else: ostream.write("\n") ostream.write(prefix + 'Value: ' + str(value) + '\n') if not option.schema: if not self.description is None: ostream.write( prefix + 'Description: ' + self.yaml_fix(self.description) + '\n' ) if not self.units is None: ostream.write(prefix + 'Units: ' + str(self.units) + '\n') else: if not self.scalar_description is None: ostream.write( prefix + 'Description: ' + self.yaml_fix(self.scalar_description) + '\n' ) if not self.scalar_type is ScalarType.undefined: ostream.write( prefix + 'Type: ' + self.yaml_fix(self.scalar_type) + '\n' ) def yaml_fix(self, val): if not isinstance(val, str): return val return val.replace(':', '\\x3a') def load(self, repn): if type(repn) is dict: for key in repn: setattr(self, key, repn[key]) else: self.value = repn
# # This class manages a list of MapContainer objects. #
[docs] class ListContainer(object):
[docs] def __init__(self, cls): self._cls = cls self._list = [] self._active = True self._required = False
def __len__(self): if '_list' in self.__dict__: return len(self.__dict__['_list']) return 0 def __getitem__(self, i): return self._list[i] def clear(self): self._list = [] def delete(self, i): del self._list[i] def __call__(self, i=0): return self._list[i] def __getattr__(self, name): try: return self.__dict__[name] except: pass if len(self) == 0: self.add() return getattr(self._list[0], name) def __setattr__(self, name, val): if name == "__class__": self.__class__ = val return if name[0] == "_": self.__dict__[name] = val return if len(self) == 0: self.add() setattr(self._list[0], name, val) def insert(self, obj): self._active = True self._list.append(obj) def add(self): self._active = True obj = self._cls() self._list.append(obj) return obj def _repn_(self, option): if not option.schema and not self._active and not self._required: return ignore if option.schema and len(self) == 0: self.add() tmp = [] for item in self._list: tmp.append(item._repn_(option)) return tmp def pprint(self, ostream, option, prefix="", repn=None): if not option.schema and not self._active and not self._required: return ignore ostream.write("\n") i = 0 for i in range(len(self._list)): item = self._list[i] ostream.write(prefix + '- ') item.pprint( ostream, option, from_list=True, prefix=prefix + " ", repn=repn[i] ) def load(self, repn): for data in repn: item = self.add() item.load(data) def __getstate__(self): return copy.copy(self.__dict__) def __setstate__(self, state): self.__dict__.update(state) def __str__(self): ostream = StringIO() option = default_print_options self.pprint(ostream, self._option, repn=self._repn_(self._option)) return ostream.getvalue()
# # This class manages use-defined attributes in # a dictionary. Attributes are translated into # a string where '_' is replaced by ' ', and where the # first letter is capitalized. #
[docs] class MapContainer(dict): def __getnewargs_ex__(self): # Pass arguments to __new__ when unpickling return ((0, 0), {}) def __getnewargs__(self): # Pass arguments to __new__ when unpickling return (0, 0) def __new__(cls, *args, **kwargs): # # If the user provides "too many" arguments, then # pre-initialize the '_order' attribute. This pre-initializes # the class during unpickling. # _instance = super(MapContainer, cls).__new__(cls, *args, **kwargs) if len(args) > 1: super(MapContainer, _instance).__setattr__('_order', []) return _instance
[docs] def __init__(self, ordered=False): dict.__init__(self) self._active = True self._required = False self._ordered = ordered self._order = [] self._option = default_print_options
[docs] def keys(self): return self._order
def __getattr__(self, name): try: return self.__dict__[name] except: pass try: self._active = True return self[self._convert(name)] except Exception: pass raise AttributeError( "Unknown attribute `" + str(name) + "' for object with type " + str(type(self)) ) def __setattr__(self, name, val): if name == "__class__": self.__class__ = val return if name[0] == "_": self.__dict__[name] = val return self._active = True tmp = self._convert(name) if tmp not in self: if strict: raise AttributeError( "Unknown attribute `" + str(name) + "' for object with type " + str(type(self)) ) self.declare(tmp) self._set_value(tmp, val) def __setitem__(self, name, val): self._active = True tmp = self._convert(name) if tmp not in self: if strict: raise AttributeError( "Unknown attribute `" + str(name) + "' for object with type " + str(type(self)) ) self.declare(tmp) self._set_value(tmp, val) def _set_value(self, name, val): if isinstance(val, ListContainer) or isinstance(val, MapContainer): dict.__setitem__(self, name, val) elif isinstance(val, ScalarData): dict.__getitem__(self, name).value = val.value else: dict.__getitem__(self, name).value = val def __getitem__(self, name): tmp = self._convert(name) if tmp not in self: raise AttributeError( "Unknown attribute `" + str(name) + "' for object with type " + str(type(self)) ) item = dict.__getitem__(self, tmp) if isinstance(item, ListContainer) or isinstance(item, MapContainer): return item return item.value def declare(self, name, **kwds): if name in self or type(name) is int: return tmp = self._convert(name) self._order.append(tmp) if 'value' in kwds and ( isinstance(kwds['value'], MapContainer) or isinstance(kwds['value'], ListContainer) ): if 'active' in kwds: kwds['value']._active = kwds['active'] if 'required' in kwds and kwds['required'] is True: kwds['value']._required = True dict.__setitem__(self, tmp, kwds['value']) else: data = ScalarData(**kwds) if 'required' in kwds and kwds['required'] is True: data._required = True # # This logic would setup a '_default' value, which copies the # initial value of an attribute. I don't think we need this, # but for now I'm going to leave this logic in the code. # # if 'value' in kwds: # data._default = kwds['value'] dict.__setitem__(self, tmp, data) def _repn_(self, option): if not option.schema and not self._active and not self._required: return ignore if self._ordered: tmp = [] for key in self._order: rep = dict.__getitem__(self, key)._repn_(option) if not rep == ignore: tmp.append({key: rep}) else: tmp = {} for key in self.keys(): rep = dict.__getitem__(self, key)._repn_(option) if not rep == ignore: tmp[key] = rep return tmp def _convert(self, name): if not isinstance(name, str): return name tmp = name.replace('_', ' ') return tmp[0].upper() + tmp[1:] def __repr__(self): return str(self._repn_(self._option)) def __str__(self): ostream = StringIO() option = default_print_options self.pprint(ostream, self._option, repn=self._repn_(self._option)) return ostream.getvalue() def pprint(self, ostream, option, from_list=False, prefix="", repn=None): if from_list: _prefix = "" else: _prefix = prefix ostream.write('\n') for key in self._order: if not key in repn: continue item = dict.__getitem__(self, key) ostream.write(_prefix + key + ": ") _prefix = prefix if isinstance(item, ListContainer): item.pprint(ostream, option, prefix=_prefix, repn=repn[key]) else: item.pprint(ostream, option, prefix=_prefix + " ", repn=repn[key]) def load(self, repn): for key in repn: tmp = self._convert(key) if tmp not in self: self.declare(tmp) item = dict.__getitem__(self, tmp) item._active = True item.load(repn[key]) def __getnewargs__(self): return (False, False) def __getstate__(self): return copy.copy(self.__dict__) def __setstate__(self, state): self.__dict__.update(state)
if __name__ == '__main__': d = MapContainer() d.declare('f') d.declare('g') d.declare('h') d.declare('i', value=ListContainer(UndefinedData)) d.declare('j', value=ListContainer(UndefinedData), active=False) print("X") d.f = 1 print("Y") print(d.f) print(d.keys()) d.g = None print(d.keys()) try: print(d.f, d.g, d.h) except: pass d['h'] = None print("") print("FINAL") print(d.f, d.g, d.h, d.i, d.j) print(d.i._active, d.j._active) d.j.add() print(d.i._active, d.j._active)