def test_generator_fcn(self): m = ConcreteModel() def a_init(m): yield 0 yield 3 with self.assertRaisesRegex( ValueError, "Generator functions are not allowed"): a = Initializer(a_init) a = Initializer(a_init, allow_generators=True) self.assertIs(type(a), ScalarCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, 1)), [0,3]) m.x = Var([1,2,3]) def x_init(m, i): yield i yield i+1 a = Initializer(x_init, allow_generators=True) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, 1)), [1,2]) m.y = Var([1,2,3], [4,5,6]) def y_init(m, i, j): yield j yield i+1 a = Initializer(y_init, allow_generators=True) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, (1, 4))), [4,2])
def test_method(self): class Init(object): def a_init(self, m): return 0 def x_init(self, m, i): return i+1 def x2_init(self, m): return 0 def y_init(self, m, i, j): return j*(i+1) init = Init() m = ConcreteModel() a = Initializer(init.a_init) self.assertIs(type(a), ScalarCallInitializer) self.assertTrue(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), 0) m.x = Var([1,2,3]) a = Initializer(init.x_init) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), 2) a = Initializer(init.x2_init) self.assertIs(type(a), ScalarCallInitializer) self.assertTrue(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), 0) m.y = Var([1,2,3], [4,5,6]) a = Initializer(init.y_init) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, (1, 4)), 8) b = CountedCallInitializer(m.x, a) self.assertIs(type(b), CountedCallInitializer) self.assertFalse(b.constant()) self.assertFalse(b.verified) self.assertFalse(a.contains_indices()) self.assertFalse(b._scalar) self.assertIs(a._fcn, b._fcn) c = b(None, 1) self.assertIs(type(c), CountedCallGenerator) self.assertEqual(next(c), 2) self.assertEqual(next(c), 3) self.assertEqual(next(c), 4)
def test_function(self): m = ConcreteModel() def a_init(m): return 0 a = Initializer(a_init) self.assertIs(type(a), ScalarCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), 0) m.x = Var([1, 2, 3]) def x_init(m, i): return i + 1 a = Initializer(x_init) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), 2) def x2_init(m): return 0 a = Initializer(x2_init) self.assertIs(type(a), ScalarCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), 0) m.y = Var([1, 2, 3], [4, 5, 6]) def y_init(m, i, j): return j * (i + 1) a = Initializer(y_init) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, (1, 4)), 8) b = CountedCallInitializer(m.x, a) self.assertIs(type(b), CountedCallInitializer) self.assertFalse(b.constant()) self.assertFalse(b.verified) self.assertFalse(a.contains_indices()) self.assertFalse(b._scalar) self.assertIs(a._fcn, b._fcn) c = b(None, 1) self.assertIs(type(c), CountedCallGenerator) self.assertEqual(next(c), 2) self.assertEqual(next(c), 3) self.assertEqual(next(c), 4)
def test_sequence(self): m = ConcreteModel() a = Initializer([0,5]) self.assertIs(type(a), ItemInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertTrue(a.contains_indices()) self.assertEqual(list(a.indices()), [0,1]) self.assertEqual(a(None, 1), 5) a = Initializer([0,5], treat_sequences_as_mappings=False) self.assertIs(type(a), ConstantInitializer) self.assertTrue(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) self.assertEqual(a(None, 1), [0,5])
def test_dict(self): m = ConcreteModel() a = Initializer({1:5}) self.assertIs(type(a), ItemInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertTrue(a.contains_indices()) self.assertEqual(list(a.indices()), [1]) self.assertEqual(a(None, 1), 5)
def test_constant(self): m = ConcreteModel() a = Initializer(5) self.assertIs(type(a), ConstantInitializer) self.assertTrue(a.constant()) self.assertFalse(a.verified) self.assertFalse(a.contains_indices()) with self.assertRaisesRegex( RuntimeError, "Initializer ConstantInitializer does " "not contain embedded indices"): a.indices() self.assertEqual(a(None, 1), 5)
def test_initializer_initializer(self): d = {'col1': [1, 2, 4], 'col2': [10, 20, 40]} df = pd.DataFrame(data=d) a = Initializer(DataFrameInitializer(df, 'col2')) self.assertIs(type(a), DataFrameInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertTrue(a.contains_indices()) self.assertEqual(list(a.indices()), [0, 1, 2]) self.assertEqual(a(None, 0), 10) self.assertEqual(a(None, 1), 20) self.assertEqual(a(None, 2), 40)
def test_generator_method(self): class Init(object): def a_init(self, m): yield 0 yield 3 def x_init(self, m, i): yield i yield i + 1 def y_init(self, m, i, j): yield j yield i + 1 init = Init() m = ConcreteModel() with self.assertRaisesRegex(ValueError, "Generator functions are not allowed"): a = Initializer(init.a_init) a = Initializer(init.a_init, allow_generators=True) self.assertIs(type(a), ScalarCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, 1)), [0, 3]) m.x = Var([1, 2, 3]) a = Initializer(init.x_init, allow_generators=True) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, 1)), [1, 2]) m.y = Var([1, 2, 3], [4, 5, 6]) a = Initializer(init.y_init, allow_generators=True) self.assertIs(type(a), IndexedCallInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, (1, 4))), [4, 2])
def test_dataframe(self): d = {'col1': [1, 2, 4]} df = pd.DataFrame(data=d) a = Initializer(df) self.assertIs(type(a), DataFrameInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertTrue(a.contains_indices()) self.assertEqual(list(a.indices()), [0, 1, 2]) self.assertEqual(a(None, 0), 1) self.assertEqual(a(None, 1), 2) self.assertEqual(a(None, 2), 4) d = {'col1': [1, 2, 4], 'col2': [10, 20, 40]} df = pd.DataFrame(data=d) with self.assertRaisesRegex( ValueError, 'DataFrameInitializer for DataFrame with multiple columns'): a = Initializer(df) a = DataFrameInitializer(df, 'col2') self.assertIs(type(a), DataFrameInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertTrue(a.contains_indices()) self.assertEqual(list(a.indices()), [0, 1, 2]) self.assertEqual(a(None, 0), 10) self.assertEqual(a(None, 1), 20) self.assertEqual(a(None, 2), 40) df = pd.DataFrame([10, 20, 30, 40], index=[[0, 0, 1, 1], [0, 1, 0, 1]]) a = Initializer(df) self.assertIs(type(a), DataFrameInitializer) self.assertFalse(a.constant()) self.assertFalse(a.verified) self.assertTrue(a.contains_indices()) self.assertEqual(list(a.indices()), [(0, 0), (0, 1), (1, 0), (1, 1)]) self.assertEqual(a(None, (0, 0)), 10) self.assertEqual(a(None, (0, 1)), 20) self.assertEqual(a(None, (1, 0)), 30) self.assertEqual(a(None, (1, 1)), 40)
def test_generators(self): m = ConcreteModel() with self.assertRaisesRegex(ValueError, "Generators are not allowed"): a = Initializer(iter([0, 3])) a = Initializer(iter([0, 3]), allow_generators=True) self.assertIs(type(a), ConstantInitializer) self.assertTrue(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, 1)), [0, 3]) def x_init(): yield 0 yield 3 with self.assertRaisesRegex(ValueError, "Generators are not allowed"): a = Initializer(x_init()) a = Initializer(x_init(), allow_generators=True) self.assertIs(type(a), ConstantInitializer) self.assertTrue(a.constant()) self.assertFalse(a.verified) self.assertEqual(list(a(None, 1)), [0, 3])
class Var(IndexedComponent, IndexedComponent_NDArrayMixin): """A numeric variable, which may be defined over an index. Args: domain (Set or function, optional): A Set that defines valid values for the variable (e.g., ``Reals``, ``NonNegativeReals``, ``Binary``), or a rule that returns Sets. Defaults to ``Reals``. within (Set or function, optional): An alias for ``domain``. bounds (tuple or function, optional): A tuple of ``(lower, upper)`` bounds for the variable, or a rule that returns tuples. Defaults to ``(None, None)``. initialize (float or function, optional): The initial value for the variable, or a rule that returns initial values. rule (float or function, optional): An alias for ``initialize``. dense (bool, optional): Instantiate all elements from :meth:`index_set` when constructing the Var (True) or just the variables returned by ``initialize``/``rule`` (False). Defaults to ``True``. units (pyomo units expression, optional): Set the units corresponding to the entries in this variable. name (str, optional): Name for this component. doc (str, optional): Text describing this component. """ _ComponentDataClass = _GeneralVarData def __new__(cls, *args, **kwargs): if cls is not Var: return super(Var, cls).__new__(cls) if not args or (args[0] is UnindexedComponent_set and len(args)==1): return super(Var, cls).__new__(AbstractScalarVar) else: return super(Var, cls).__new__(IndexedVar) @overload def __init__(self, *indexes, domain=Reals, within=Reals, bounds=None, initialize=None, rule=None, dense=True, units=None, name=None, doc=None): ... def __init__(self, *args, **kwargs): # # Default keyword values # self._rule_init = Initializer(self._pop_from_kwargs( 'Var', kwargs, ('rule', 'initialize'), None)) self._rule_domain = SetInitializer(self._pop_from_kwargs( 'Var', kwargs, ('domain', 'within'), Reals)) _bounds_arg = kwargs.pop('bounds', None) self._dense = kwargs.pop('dense', True) self._units = kwargs.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) # # Initialize the base class # kwargs.setdefault('ctype', Var) IndexedComponent.__init__(self, *args, **kwargs) # # Now that we can call is_indexed(), process bounds initializer # if self.is_indexed(): treat_bounds_sequences_as_mappings = not ( isinstance(_bounds_arg, Sequence) and len(_bounds_arg) == 2 and not isinstance(_bounds_arg[0], Sequence) ) else: treat_bounds_sequences_as_mappings = False if not self._dense: logger.warning( "ScalarVar object '%s': dense=False is not allowed " "for scalar variables; converting to dense=True" % (self.name,)) self._dense = True self._rule_bounds = Initializer( _bounds_arg, treat_sequences_as_mappings=treat_bounds_sequences_as_mappings ) def flag_as_stale(self): """ Set the 'stale' attribute of every variable data object to True. """ for var_data in self._data.values(): var_data.stale = True def get_values(self, include_fixed_values=True): """ Return a dictionary of index-value pairs. """ if include_fixed_values: return {idx:vardata.value for idx,vardata in self._data.items()} return {idx:vardata.value for idx, vardata in self._data.items() if not vardata.fixed} extract_values = get_values def set_values(self, new_values, skip_validation=False): """ Set the values of a dictionary. The default behavior is to validate the values in the dictionary. """ for index, new_value in new_values.items(): self[index].set_value(new_value, skip_validation) def get_units(self): """Return the units expression for this Var.""" return self._units # TODO: deprecate this? __getitem__ is generally preferable" def add(self, index): """Add a variable with a particular index.""" return self[index] def construct(self, data=None): """ Construct the _VarData objects for this variable """ if self._constructed: return self._constructed=True timer = ConstructionTimer(self) if is_debug_set(logger): logger.debug("Constructing Variable %s" % (self.name,)) # Note: define 'index' to avoid 'variable referenced before # assignment' in the error message generated in the 'except:' # block below. index = None try: # We do not (currently) accept data for constructing Variables assert data is None if not self.index_set().isfinite() and self._dense: # Note: if the index is not finite, then we cannot # iterate over it. This used to be fatal; now we # just warn logger.warning( "Var '%s' indexed by a non-finite set, but declared " "with 'dense=True'. Reverting to 'dense=False' as " "it is not possible to make this variable dense. " "This warning can be suppressed by specifying " "'dense=False'" % (self.name,)) self._dense = False if ( self._rule_init is not None and self._rule_init.contains_indices() ): # Historically we have allowed Vars to be initialized by # a sparse map (i.e., a dict containing only some of the # keys). We will wrap the incoming initializer to map # KeyErrors to None self._rule_init = DefaultInitializer( self._rule_init, None, KeyError) # The index is coming in externally; we need to validate it for index in self._rule_init.indices(): self[index] # If this is a dense object, we need to ensure that it # has been filled in. if self._dense: for index in self.index_set(): if index not in self._data: self._getitem_when_not_present(index) elif not self.is_indexed(): # As there is only a single VarData to populate, just do # so and bypass all special-case testing below self._getitem_when_not_present(None) elif self._dense: # Special case: initialize every VarData. For the # initializers that are constant, we can avoid # re-calling (and re-validating) the inputs in certain # cases. To support this, we will create the first # _VarData and then use it as a template to initialize # (constant portions of) every VarData so as to not # repeat all the domain/bounds validation. try: ref = self._getitem_when_not_present( next(iter(self.index_set()))) except StopIteration: # Empty index! return call_domain_rule = not self._rule_domain.constant() call_bounds_rule = self._rule_bounds is not None and ( not self._rule_bounds.constant()) call_init_rule = self._rule_init is not None and ( not self._rule_init.constant() # If either the domain or bounds change, then we # need to re-verify the initial value, even if it is # constant: or call_domain_rule or call_bounds_rule ) # Initialize all the component datas with the common data for index in self.index_set(): self._data[index] = self._ComponentDataClass.copy(ref) # Now go back and initialize any index-specific data block = self.parent_block() if call_domain_rule: for index, obj in self._data.items(): # We can directly set the attribute (not the # property) because the SetInitializer ensures # that the value is a proper Set. obj._domain = self._rule_domain(block, index) if call_bounds_rule: for index, obj in self._data.items(): obj.lower, obj.upper = self._rule_bounds(block, index) if call_init_rule: for index, obj in self._data.items(): obj.set_value(self._rule_init(block, index)) else: # non-dense indexed var with generic # (non-index-containing) initializer: nothing to do pass except Exception: err = sys.exc_info()[1] logger.error( "Rule failed when initializing variable for " "Var %s with index %s:\n%s: %s" % (self.name, str(index), type(err).__name__, err)) raise finally: timer.report() # # This method must be defined on subclasses of # IndexedComponent that support implicit definition # def _getitem_when_not_present(self, index): """Returns the default component data value.""" if index is None and not self.is_indexed(): obj = self._data[index] = self else: obj = self._data[index] = self._ComponentDataClass(component=self) parent = self.parent_block() # We can directly set the attribute (not the property) because # the SetInitializer ensures that the value is a proper Set. obj._domain = self._rule_domain(parent, index) if self._rule_bounds is not None: obj.lower, obj.upper = self._rule_bounds(parent, index) if self._rule_init is not None: obj.set_value(self._rule_init(parent, index)) return obj # # Because we need to do more initialization than simply calling # set_value(), we need to override _setitem_when_not_present # def _setitem_when_not_present(self, index, value=NOTSET): if value is self.Skip: return None try: obj = self._getitem_when_not_present(index) if value is not NOTSET: obj.set_value(value) except: self._data.pop(index, None) raise return obj def _pprint(self): """Print component information.""" headers = [ ("Size", len(self)), ("Index", self._index if self.is_indexed() else None), ] if self._units is not None: headers.append(('Units', str(self._units))) return ( headers, self._data.items(), ( "Lower","Value","Upper","Fixed","Stale","Domain"), lambda k, v: [ value(v.lb), v.value, value(v.ub), v.fixed, v.stale, v.domain ] )